1. ホーム
  2. android

[解決済み】ACTION_SENDインテントを特定のアプリでフィルタリングする方法(アプリごとに異なるテキストを設定することも可能です)

2022-04-19 18:55:03

質問

ACTION_SENDインテントを使用する際に、特定のアプリをフィルタリングするにはどうすればよいですか? この質問はいろいろとされていますが、与えられた回答から解決策を収集することができません。誰かが助けてくれるといいのですが。アプリ内で共有する機能を提供したいと思います。以下 Android DevのAlexander Lucasのアドバイス FacebookやTwitterのAPIを使わず、インテントを使うことを希望しています。

ACTION_SENDインテントを使った共有は素晴らしいが 問題は、(1) すべての共有オプションが必要なわけではなく、FB、Twitter、メールに限定したいこと、(2) それぞれの共有アプリに同じものを共有したくないことです。 . 例えば、twitterの共有では、140文字以内に限定して言及やハッシュタグを入れ、facebookの共有では、リンクと特徴的な画像を入れる予定です。

ACTION_SEND(共有)インテントのオプションを制限することは可能でしょうか?PackageManagerとqueryIntentActivitiesの使用について何かで見たことがありますが、PackageManagerとACTION_SENDインテントの間の関連性を把握することができていません。

または

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

それとも不可能なのでしょうか?FacebookとTwitterのAPIが唯一の方法なのでしょうか?

解決方法は?

私の知る限り、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);       
}

この方法の断片はいろいろなところで見つけましたが、すべてを一箇所にまとめたものは他では見たことがありません。

この方法では、無線LANやブルートゥースでの共有のような、私が望まないバカげたオプションもすべて隠されていることに注意してください。

これが誰かの役に立つといいのですが。

編集する コメントで、このコードが何をしているのか説明してほしいと言われました。基本的には、このコードは ACTION_SEND インテントをネイティブのメールクライアント専用にし、他のインテントをチューザーに追加しています。元のインテントをメール専用にすることで、wifi や bluetooth などの余分なジャンクをすべて取り除き、次に、必要な他のインテントを一般的な ACTION_SEND をplain-text型で表示し、chooserを表示する前にそれらを貼り付けます。

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

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

この回答が私のstackoverflowの評価ポイントのほぼ全ての源なので、少なくとも最新の状態に保つよう努力しなければならないのです。