Comment filtrer des applications spécifiques pour L'ACTION Envoyer l'intention (et définir un texte différent pour chaque application))

comment filtrer des applications spécifiques lorsque vous utilisez ACTION_SEND intent? cette question a été posée de différentes façons, mais je n'ai pas été en mesure de trouver une solution basée sur les réponses données. J'espère que quelqu'un peut vous aider. J'aimerais donner la possibilité de partager au sein d'une application. Après Android Dev Alexander Lucas conseil , je préfère le faire en utilisant intents et de ne pas utiliser les API Facebook/Twitter.

Sharing using ACTION_SEND intent

partager en utilisant L'intention D'ACTION_SEND est génial, mais le problème est (1) Je ne veux pas toutes les options de partage là-bas, je préfère le limiter à FB, Twitter, et E-Mail, et (2) Je ne veux pas partager la même chose à chaque application de partage . Par exemple, dans mon twitter partager je vais inclure quelques mentions et les hashtags limité à 140 caractères ou moins, tandis que le facebook partager va inclure un lien et une image.

Est-il possible de limiter les options pour ACTION_SEND (action) intention? J'ai vu quelque chose à propos de L'utilisation de PackageManager et queryIntentActivities, mais je n'ai pas été capable de comprendre la connexion entre le PackageManager et L'intention ACTION_SEND.

ou

plutôt que de filtrer les applications de partage, mon problème pourrait aussi être résolu si je pouvais utiliser L'intention D'ACTION_SEND d'aller directement sur facebook ou twitter plutôt que de faire la boîte de dialogue. Si c'était le cas, je pourrais créer mon propre dialogue et quand ils cliquent "Facebook" créer une intention spécifique Facebook et juste les envoyer tout le chemin à Facebook. Même chose avec Twitter.

ou est-ce impossible? Est-ce que les API Facebook et Twitter sont le seul moyen?

159
demandé sur Community 2012-03-16 04:33:32

11 réponses

à ma connaissance, StackOverflow a beaucoup de gens qui posent cette question de différentes façons, mais personne n'a encore répondu complètement.

mon spec a appelé à l'utilisateur pour être en mesure de choisir le courrier électronique, twitter, facebook, ou SMS, avec un texte personnalisé pour chacun. Voici comment j'ai accompli cela:

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);       
}

j'ai trouvé des bouts de comment faire cela dans divers endroits, mais je n'ai pas vu tout cela dans un seul endroit ailleurs.

Notez que cette méthode cache aussi toutes les options idiotes que je ne veux pas, comme le partage sur wifi et bluetooth.

J'espère que ça aidera quelqu'un.

Edit: Dans un commentaire, on m'a demandé d'expliquer ce que fait ce code. En gros, cela crée une intention ACTION_SEND pour le client de messagerie natif seulement, puis en pointant d'autres intentions sur le chooser. Faire l'intention originale spécifique email se débarrasse de tous les trucs supplémentaires comme le wifi et bluetooth, puis j'attrape les autres intentions que je veux d'un générique ACTION_SEND de type texte simple, et les tack sur avant de montrer le chooser.

quand je prends les intentions supplémentaires, je mets le texte personnalisé pour chacun d'eux.

Edit 2: Cela fait longtemps que j'ai posté ceci, et les choses ont un peu changé. Si vous voyez gmail deux fois dans la liste des options, essayez de supprimer la manipulation spéciale pour "android.gm" comme suggéré dans un commentaire de @h_k ci-dessous.

puisque cette réponse est la source de presque tous mes points de réputation stackoverflow, je dois au moins essayer de le garder à jour.

287
répondu dacoinminster 2018-03-15 11:38:08

si vous voulez une option personnalisée, alors vous ne devriez pas compter sur la boîte de dialogue par défaut fournie par android pour cette action.

ce que vous devez faire à la place est de déployer votre propre. Vous devrez interroger le PackageManager sur lequel les paquets gèrent l'action dont vous avez besoin et ensuite sur la base de la réponse, vous appliquez le filtrage et le texte personnalisé.

plus précisément, jetez un coup d'oeil à la méthode activités de queryintente de la classe PackageManager . Vous construisez l'intention qui lancerait la boîte de dialogue par défaut (l'intention ACTION_SEND), passez cela à cette méthode et vous recevrez une liste d'objets qui contiennent des informations sur les activités qui peuvent gérer cette intention. Avec ça, vous pouvez choisir ceux que vous voulez.

une fois que vous avez créé votre liste de paquets que vous voulez présenter, vous devez créer votre propre dialogue de liste (de préférence une activité avec le thème de dialogue) ce qui permet d'afficher cette liste.

une chose à noter cependant est qu'il est très difficile de faire que le dialogue personnalisé ressemble à celui par défaut. Le problème est que le thème utilisé dans ce dialogue est un thème interne et ne peut pas être utilisé par votre application. Vous pouvez soit essayer de le rendre aussi similaire à celui que vous voulez ou aller pour un look complètement personnalisé (de nombreuses applications font cela comme l'application galerie etc)

25
répondu Savvas Dalkitsis 2012-03-18 02:44:54

trouvé une solution qui fonctionne pour moi à la recherche ici (voir le troisième commentaire sur la première réponse). Ce code recherche un client twitter valide et l'utilise pour poster le tweet. Note: il ne vous donne pas une intention avec les différents clients Twitter et vous permet de choisir.

Partager sur twitter:

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

appelant cette méthode:

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 sera similaire en utilisant " com.Facebook.katana ", bien que vous ne puissiez toujours pas définir le texte du message (déprécié juillet 2011).

Code source: intention d'ouvrir twitter client sur Android

21
répondu Kyle Clegg 2018-03-16 12:04:57

essayez celui-ci pour partager seulement trois applications-Facebook, Twitter, KakaoStory.

public void onShareClick(View v){
    List<Intent> targetShareIntents=new ArrayList<Intent>();
    Intent shareIntent=new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.setType("text/plain");
    List<ResolveInfo> resInfos=getPackageManager().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.kakao.story")){
                Intent intent=new Intent();
                intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
                intent.setAction(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_TEXT, "Text");
                intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
                intent.setPackage(packageName);
                targetShareIntents.add(intent);
            }
        }
        if(!targetShareIntents.isEmpty()){
            System.out.println("Have Intent");
            Intent chooserIntent=Intent.createChooser(targetShareIntents.remove(0), "Choose app to share");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{}));
            startActivity(chooserIntent);
        }else{
            System.out.println("Do not Have Intent");
            showDialaog(this);
        }
    }
}
19
répondu user3098538 2014-03-13 03:40:08

cette solution affiche une liste d'applications dans un dialogue ListView qui ressemble au chooser:

screenshot

C'est à vous de:

  1. obtenir la liste des dossiers de demande pertinents
  2. étant donné le nom du paquet, invoquer l'intention pertinente

la classe d'adaptateur:

import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class ChooserArrayAdapter extends ArrayAdapter<String> {
    PackageManager mPm;
    int mTextViewResourceId;
    List<String> mPackages;

    public ChooserArrayAdapter(Context context, int resource, int textViewResourceId, List<String> packages) {
        super(context, resource, textViewResourceId, packages);
        mPm = context.getPackageManager();
        mTextViewResourceId = textViewResourceId;
        mPackages = packages;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String pkg = mPackages.get(position);
        View view = super.getView(position, convertView, parent);

        try {
            ApplicationInfo ai = mPm.getApplicationInfo(pkg, 0);

            CharSequence appName = mPm.getApplicationLabel(ai);
            Drawable appIcon = mPm.getApplicationIcon(pkg);

            TextView textView = (TextView) view.findViewById(mTextViewResourceId);
            textView.setText(appName);
            textView.setCompoundDrawablesWithIntrinsicBounds(appIcon, null, null, null);
            textView.setCompoundDrawablePadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getContext().getResources().getDisplayMetrics()));
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

        return view;
    }

}

et son usage:

    void doXxxButton() {
        final List<String> packages = ...;
        if (packages.size() > 1) {
            ArrayAdapter<String> adapter = new ChooserArrayAdapter(MyActivity.this, android.R.layout.select_dialog_item, android.R.id.text1, packages);

            new AlertDialog.Builder(MyActivity.this)
            .setTitle(R.string.app_list_title)
            .setAdapter(adapter, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int item ) {
                    invokeApplication(packages.get(item));
                }
            })
            .show();
        } else if (packages.size() == 1) {
            invokeApplication(packages.get(0));
        }
    }

    void invokeApplication(String packageName) {
        // given a package name, create an intent and fill it with data
        ...
        startActivityForResult(intent, rq);
    }
7
répondu 18446744073709551615 2013-09-24 12:23:57

Vous pouvez essayer le code ci-dessous, il fonctionne parfaitement.

ici, nous partageons certaines applications spécifiques, qui sont Facebook, Messenger, Twitter, Google Plus et 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);
        }
    }
7
répondu Dang Nguyen 2016-07-20 04:13:09

merci à @dacoinminster. Je fais quelques modifications à sa réponse, y compris les noms de paquets des applications populaires et le tri de ces applications.

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();
    }
}
4
répondu Oguz Ozcan 2017-01-26 12:24:27

le moyen le plus propre est de copier les classes suivantes: ShareActionProvider, ActivityChooserView, ActivityChooserModel. Ajouter la possibilité de filtrer les intentions dans le modèle ActivityChooserModel, et les méthodes de soutien appropriées dans le fournisseur D'actions. J'ai créé les classes nécessaires, vous pouvez les copier dans votre projet ( https://gist.github.com/saulpower/10557956 ). Cela ajoute non seulement la possibilité de filtrer les applications que vous souhaitez partager (si vous connaissez le nom du paquet), mais aussi pour désactiver l'historique.

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);
}
3
répondu saulpower 2014-04-12 21:44:52
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..."));
2
répondu murugan 2018-05-15 10:07:19

j'ai amélioré la réponse @dacoinminster et c'est le résultat avec un exemple pour partager votre application:

// Intents with SEND action
PackageManager packageManager = context.getPackageManager();
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(sendIntent, 0);

List<LabeledIntent> intentList = new ArrayList<LabeledIntent>();
Resources resources = context.getResources();

for (int j = 0; j < resolveInfoList.size(); j++) {
    ResolveInfo resolveInfo = resolveInfoList.get(j);
    String packageName = resolveInfo.activityInfo.packageName;
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_SEND);
    intent.setComponent(new ComponentName(packageName,
    resolveInfo.activityInfo.name));
    intent.setType("text/plain");

    if (packageName.contains("twitter")) {
        intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.twitter) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());
    } else {
        // skip android mail and gmail to avoid adding to the list twice
        if (packageName.contains("android.email") || packageName.contains("android.gm")) {
            continue;
        }
        intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForFacebookWhatsapp) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());
    }

    intentList.add(new LabeledIntent(intent, packageName, resolveInfo.loadLabel(packageManager), resolveInfo.icon));
}

Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.subjectForMailApps));
emailIntent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForMailApps) + "https://play.google.com/store/apps/details?id=" + context.getPackageName());

context.startActivity(Intent.createChooser(emailIntent, resources.getString(R.string.compartirEn)).putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new LabeledIntent[intentList.size()])));
1
répondu 2014-08-04 14:17:02

j'ai eu le même problème et cette solution acceptée ne m'a pas aidé, si quelqu'un a le même problème, vous pouvez utiliser mon code snippet:

// 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);

}
1
répondu jemo mgebrishvili 2016-03-28 14:39:07