197

ACTION_SEND インテントを使用するときに特定のアプリを除外するにはどうすればよいですか? この質問はさまざまな方法で尋ねられましたが、与えられた回答に基づいて解決策をまとめることができませんでした. うまくいけば、誰かが助けてくれるでしょう。アプリ内で共有できる機能を提供したいと考えています。Android Dev Alexander Lucas のアドバイスに従い、Facebook/Twitter API を使用せずにインテントを使用することをお勧めします。

ACTION_SEND インテントを使用した共有

ACTION_SEND インテントを使用した共有は素晴らしいのですが、問題は (1) そこにすべての共有オプションが必要なわけではなく、FB、Twitter、および電子メールに制限したい、(2) 共有したくないことです。各共有アプリに同じこと。たとえば、私の Twitter の共有では、140 文字以下に制限されたいくつかのメンションとハッシュタグを含めますが、Facebook の共有にはリンクとフィーチャー画像を含めます。

ACTION_SEND (共有) インテントのオプションを制限することは可能ですか? PackageManager と queryIntentActivities の使用について何かを見てきましたが、PackageManager と ACTION_SEND インテントの間の接続を理解できませんでした。

また

共有アプリをフィルタリングするのではなく、ACTION_SEND インテントを使用して、ダイアログをポップアップするのではなく、Facebook や Twitter に直接アクセスできれば、私の問題も解決できます。その場合は、独自のダイアログを作成し、「Facebook」をクリックすると、Facebook 固有のインテントを作成して、Facebook に送信することができます。ツイッターも同じ。

またはそれは不可能ですか?Facebook と Twitter API が唯一の方法ですか?

4

12 に答える 12

331

私の知る限り、StackOverflow にはさまざまな方法でこの質問をする人がたくさんいますが、まだ完全に答えた人はいません。

私の仕様では、ユーザーがメール、Twitter、Facebook、または SMS を選択し、それぞれにカスタム テキストを使用できるようにする必要がありました。これが私がそれを達成した方法です:

public void onShareClick(View v) {
    Resources resources = getResources();

    Intent emailIntent = new Intent();
    emailIntent.setAction(Intent.ACTION_SEND);
    // Native email client doesn't currently support HTML, but it doesn't hurt to try in case they fix it
    emailIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_native)));
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));
    emailIntent.setType("message/rfc822");

    PackageManager pm = getPackageManager();
    Intent sendIntent = new Intent(Intent.ACTION_SEND);     
    sendIntent.setType("text/plain");


    Intent openInChooser = Intent.createChooser(emailIntent, resources.getString(R.string.share_chooser_text));

    List<ResolveInfo> resInfo = pm.queryIntentActivities(sendIntent, 0);
    List<LabeledIntent> intentList = new ArrayList<LabeledIntent>();        
    for (int i = 0; i < resInfo.size(); i++) {
        // Extract the label, append it, and repackage it in a LabeledIntent
        ResolveInfo ri = resInfo.get(i);
        String packageName = ri.activityInfo.packageName;
        if(packageName.contains("android.email")) {
            emailIntent.setPackage(packageName);
        } else if(packageName.contains("twitter") || packageName.contains("facebook") || packageName.contains("mms") || packageName.contains("android.gm")) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(packageName, ri.activityInfo.name));
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("text/plain");
            if(packageName.contains("twitter")) {
                intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_twitter));
            } else if(packageName.contains("facebook")) {
                // Warning: Facebook IGNORES our text. They say "These fields are intended for users to express themselves. Pre-filling these fields erodes the authenticity of the user voice."
                // One workaround is to use the Facebook SDK to post, but that doesn't allow the user to choose how they want to share. We can also make a custom landing page, and the link
                // will show the <meta content ="..."> text from that page with our link in Facebook.
                intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_facebook));
            } else if(packageName.contains("mms")) {
                intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_sms));
            } else if(packageName.contains("android.gm")) { // If Gmail shows up twice, try removing this else-if clause and the reference to "android.gm" above
                intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_gmail)));
                intent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject));               
                intent.setType("message/rfc822");
            }

            intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon));
        }
    }

    // convert intentList to array
    LabeledIntent[] extraIntents = intentList.toArray( new LabeledIntent[ intentList.size() ]);

    openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents);
    startActivity(openInChooser);       
}

さまざまな場所でこれを行う方法を少し見つけましたが、他の場所ですべてを 1 か所で見たことはありません。

この方法では、wifi や Bluetooth での共有など、私が望まないばかげたオプションもすべて非表示になることに注意してください。

これが誰かに役立つことを願っています。

編集: コメントで、このコードが何をしているかを説明するように求められました。基本的にACTION_SENDは、ネイティブ メール クライアント専用のインテントを作成してから、他のインテントをチューザーに追加します。元のインテントを電子メール固有にすることで、wifi や bluetooth などの余分なジャンクをすべて取り除き、ACTION_SENDプレーンテキスト タイプのジェネリックから必要な他のインテントを取得し、セレクターを表示する前にそれらを追加します。

追加のインテントを取得したら、それぞれにカスタム テキストを設定します。

Edit2:これを投稿してからしばらく経ちましたが、状況が少し変わりました。オプションのリストに gmail が 2 回表示される場合は、以下の @h_k によるコメントで提案されているように、「android.gm」の特別な処理を削除してみてください。

この 1 つの回答が、私のスタックオーバーフローのレピュテーション ポイントのほぼすべてのソースであるため、少なくとも最新の状態に保つ必要があります。

于 2013-08-05T21:32:42.117 に答える
28

カスタマイズされたオプションが必要な場合は、このアクションで Android が提供するデフォルトのダイアログに依存しないでください。

代わりに、独自の展開を行う必要があります。パッケージが必要なアクションを処理するPackageManagerにクエリを実行し、応答に基づいてフィルタリングとカスタマイズされたテキストを適用する必要があります。

具体的には、PackageManagerクラスのメソッドqueryIntentActivitiesを見てください。デフォルト ダイアログを起動するインテント (ACTION_SEND インテント) を作成し、それをこのメソッドに渡すと、そのインテントを処理できるアクティビティに関する情報を含むオブジェクトのリストを受け取ります。それを使用して、必要なものを選択できます。

表示するパッケージのリストを作成したら、そのリストを表示する独自のリスト ダイアログ (できればダイアログ テーマのアクティビティ) を作成する必要があります。

ただし、そのカスタム ダイアログをデフォルトのように見せるのは非常に難しいことに注意してください。問題は、そのダイアログで使用されているテーマが内部テーマであり、アプリケーションで使用できないことです。必要に応じてネイティブのものに似せて作成するか、完全にカスタムの外観にすることができます (多くのアプリはギャラリー アプリなどのようにそれを行います)。

于 2012-03-18T02:38:28.143 に答える
24

ここを見るとうまくいく解決策が見つかりました(最初の回答の3番目のコメントを参照してください)。このコードは、有効な Twitter クライアントを探し、それを使用してツイートを投稿します。注: さまざまな Twitter クライアントでインテントが提供されるわけではなく、ユーザーが選択できるようになります。

ツイッターでシェア:

Intent shareIntent = findTwitterClient(); 
shareIntent.putExtra(Intent.EXTRA_TEXT, "test");
startActivity(Intent.createChooser(shareIntent, "Share"));

このメソッドを呼び出す:

public Intent findTwitterClient() {
    final String[] twitterApps = {
            // package // name - nb installs (thousands)
            "com.twitter.android", // official - 10 000
            "com.twidroid", // twidroid - 5 000
            "com.handmark.tweetcaster", // Tweecaster - 5 000
            "com.thedeck.android" }; // TweetDeck - 5 000 };
    Intent tweetIntent = new Intent();
    tweetIntent.setType("text/plain");
    final PackageManager packageManager = getPackageManager();
    List<ResolveInfo> list = packageManager.queryIntentActivities(
            tweetIntent, PackageManager.MATCH_DEFAULT_ONLY);

    for (int i = 0; i < twitterApps.length; i++) {
        for (ResolveInfo resolveInfo : list) {
            String p = resolveInfo.activityInfo.packageName;
            if (p != null && p.startsWith(twitterApps[i])) {
                tweetIntent.setPackage(p);
                return tweetIntent;
            }
        }
    }

    return null;
}

Facebook は「com.facebook.katana」を使用して似ていますが、メッセージ テキストを設定することはできません (2011 年 7 月に非推奨)。

コード ソース: Android で Twitter クライアントを開く意図

于 2012-04-05T20:48:31.017 に答える
15

@dacoinminster に感謝します。人気のあるアプリのパッケージ名やそれらのアプリの並べ替えなど、彼の回答にいくつかの変更を加えます。

List<Intent> targetShareIntents = new ArrayList<Intent>();
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
PackageManager pm = getActivity().getPackageManager();
List<ResolveInfo> resInfos = pm.queryIntentActivities(shareIntent, 0);
if (!resInfos.isEmpty()) {
    System.out.println("Have package");
    for (ResolveInfo resInfo : resInfos) {
        String packageName = resInfo.activityInfo.packageName;
        Log.i("Package Name", packageName);

        if (packageName.contains("com.twitter.android") || packageName.contains("com.facebook.katana")
                || packageName.contains("com.whatsapp") || packageName.contains("com.google.android.apps.plus")
                || packageName.contains("com.google.android.talk") || packageName.contains("com.slack")
                || packageName.contains("com.google.android.gm") || packageName.contains("com.facebook.orca")
                || packageName.contains("com.yahoo.mobile") || packageName.contains("com.skype.raider")
                || packageName.contains("com.android.mms")|| packageName.contains("com.linkedin.android")
                || packageName.contains("com.google.android.apps.messaging")) {
            Intent intent = new Intent();

            intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
            intent.putExtra("AppName", resInfo.loadLabel(pm).toString());
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TEXT, "https://website.com/");
            intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_text));
            intent.setPackage(packageName);
            targetShareIntents.add(intent);
        }
    }
    if (!targetShareIntents.isEmpty()) {
        Collections.sort(targetShareIntents, new Comparator<Intent>() {
            @Override
            public int compare(Intent o1, Intent o2) {
                return o1.getStringExtra("AppName").compareTo(o2.getStringExtra("AppName"));
            }
        });
        Intent chooserIntent = Intent.createChooser(targetShareIntents.remove(0), "Select app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{}));
        startActivity(chooserIntent);
    } else {
        Toast.makeText(getActivity(), "No app to share.", Toast.LENGTH_LONG).show();
    }
}
于 2017-01-26T12:24:27.173 に答える
11

以下のコードを試すことができます。完全に機能します。

ここでは、Facebook、Messenger、Twitter、Google Plus、Gmail などの特定のアプリに共有します。

public void shareIntentSpecificApps() {
        List<Intent> intentShareList = new ArrayList<Intent>();
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.setType("text/plain");
        List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(shareIntent, 0);

        for (ResolveInfo resInfo : resolveInfoList) {
            String packageName = resInfo.activityInfo.packageName;
            String name = resInfo.activityInfo.name;
            Log.d(TAG, "Package Name : " + packageName);
            Log.d(TAG, "Name : " + name);

            if (packageName.contains("com.facebook") ||
                    packageName.contains("com.twitter.android") ||
                    packageName.contains("com.google.android.apps.plus") ||
                    packageName.contains("com.google.android.gm")) {

                if (name.contains("com.twitter.android.DMActivity")) {
                    continue;
                }

                Intent intent = new Intent();
                intent.setComponent(new ComponentName(packageName, name));
                intent.setAction(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_SUBJECT, "Your Subject");
                intent.putExtra(Intent.EXTRA_TEXT, "Your Content");
                intentShareList.add(intent);
            }
        }

        if (intentShareList.isEmpty()) {
            Toast.makeText(MainActivity.this, "No apps to share !", Toast.LENGTH_SHORT).show();
        } else {
            Intent chooserIntent = Intent.createChooser(intentShareList.remove(0), "Share via");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentShareList.toArray(new Parcelable[]{}));
            startActivity(chooserIntent);
        }
    }
于 2016-07-20T04:13:09.587 に答える
4

最もクリーンな方法は、ShareActionProvider、ActivityChooserView、ActivityChooserModel のクラスをコピーすることです。ActivityChooserModel でインテントをフィルタリングする機能を追加し、ShareActionProvider で適切なサポート メソッドを追加します。必要なクラスを作成しました。プロジェクトにコピーできます ( https://gist.github.com/saulpower/10557956 )。これにより、共有したいアプリをフィルタリングする機能が追加されるだけでなく (パッケージ名がわかっている場合)、履歴をオフにすることもできます.

private final String[] INTENT_FILTER = new String[] {
    "com.twitter.android",
    "com.facebook.katana"
};

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.journal_entry_menu, menu);

    // Set up ShareActionProvider's default share intent
    MenuItem shareItem = menu.findItem(R.id.action_share);

    if (shareItem instanceof SupportMenuItem) {
        mShareActionProvider = new ShareActionProvider(this);
        mShareActionProvider.setShareIntent(ShareUtils.share(mJournalEntry));
        mShareActionProvider.setIntentFilter(Arrays.asList(INTENT_FILTER));
        mShareActionProvider.setShowHistory(false);
        ((SupportMenuItem) shareItem).setSupportActionProvider(mShareActionProvider);
    }

    return super.onCreateOptionsMenu(menu);
}
于 2014-04-12T21:44:52.660 に答える
3
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, 
    Uri.fromParts("mailto", "android@gmail.com", null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, text);
startActivity(Intent.createChooser(emailIntent, "Send email..."));
于 2015-01-02T09:26:25.107 に答える
3

私は同じ問題を抱えていましたが、この受け入れられた解決策は役に立ちませんでした.誰かが同じ問題を抱えている場合は、私のコードスニペットを使用できます:

// example of filtering and sharing multiple images with texts
// remove facebook from sharing intents
private void shareFilter(){

    String share = getShareTexts();
    ArrayList<Uri> uris = getImageUris();

    List<Intent> targets = new ArrayList<>();
    Intent template = new Intent(Intent.ACTION_SEND_MULTIPLE);
    template.setType("image/*");
    List<ResolveInfo> candidates = getActivity().getPackageManager().
            queryIntentActivities(template, 0);

    // remove facebook which has a broken share intent
    for (ResolveInfo candidate : candidates) {
        String packageName = candidate.activityInfo.packageName;
        if (!packageName.equals("com.facebook.katana")) {
            Intent target = new Intent(Intent.ACTION_SEND_MULTIPLE);
            target.setType("image/*");
            target.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris);
            target.putExtra(Intent.EXTRA_TEXT, share);
            target.setPackage(packageName);
            targets.add(target);
        }
    }
    Intent chooser = Intent.createChooser(targets.remove(0), "Share Via");
    chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[targets.size()]));
    startActivity(chooser);

}
于 2016-03-28T14:29:32.860 に答える