199 votes

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

Comment pouvez-vous filtrer des applications spécifiques lorsque vous utilisez l'intention ACTION_SEND ? Cette question a été posée de différentes manières, mais je n'ai pas réussi à rassembler une solution sur la base des réponses données. J'espère que quelqu'un pourra m'aider. J'aimerais offrir la possibilité de partager dans une application. Suivant Conseil d'Alexander Lucas, développeur Android Je préfère le faire en utilisant des intentions et non les API de Facebook et Twitter.

Sharing using ACTION_SEND intent

Le partage à l'aide de l'intention ACTION_SEND est très bien, mais le problème est que (1) je ne veux pas toutes les options de partage, je préfère les limiter à FB, Twitter et Email, et (2) je ne veux pas partager la même chose sur chaque application de partage. . Par exemple, dans mon partage sur Twitter, je vais inclure quelques mentions et hashtags limités à 140 caractères ou moins, tandis que le partage sur Facebook va inclure un lien et une image caractéristique.

Est-il possible de limiter les options de l'intention ACTION_SEND (partage) ? J'ai vu quelque chose à propos de l'utilisation de PackageManager et de queryIntentActivities, mais je n'ai pas réussi à comprendre le lien entre le PackageManager et l'intention ACTION_SEND.

OU

Plutôt que de filtrer les applications de partage, mon problème pourrait également être résolu si je pouvais utiliser l'intention ACTION_SEND pour aller directement sur Facebook ou Twitter plutôt que de faire apparaître la boîte de dialogue. Si c'était le cas, je pourrais créer ma propre boîte de dialogue et, lorsqu'ils cliquent sur "Facebook", créer une intention spécifique à Facebook et les envoyer directement sur Facebook. Même chose pour Twitter.

OU est-ce impossible ? Les API de Facebook et Twitter sont-elles le seul moyen ?

0 votes

Duplicata possible : [custom-filtering-of-intent-chooser-based-on-installed-android-package-name][1] [1] : stackoverflow.com/questions/5734678/

1 votes

Ce billet de blog semble être la réponse parfaite : hkdevtips.blogspot.com/2013/02/

2 votes

Hey ami... quand je clique sur mon bouton d'envoi puis ouvre le dialogue de partage et la liste du dialogue de partage est "gmail ,email ,zapiya , hookup "etc. mais ne montre pas facebook ,whatsapp,facebook messanger ,hike hangouts ... comment puis-je montrer son ? ?

330voto

dacoinminster Points 894

À ma connaissance, sur StackOverflow, de nombreuses personnes ont posé cette question de différentes manières, mais personne n'y a encore répondu complètement.

Mon cahier des charges prévoyait que l'utilisateur puisse choisir entre email, twitter, facebook ou SMS, avec un texte personnalisé pour chacun d'eux. Voici comment j'ai réalisé 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 éléments sur la façon de procéder à divers endroits, mais je n'ai pas vu tout cela en un seul endroit.

Notez que cette méthode masque également toutes les options stupides dont je ne veux pas, comme le partage par wifi et bluetooth.

J'espère que cela aidera quelqu'un.

Edit : Dans un commentaire, on m'a demandé d'expliquer ce que fait ce code. En gros, il crée un ACTION_SEND pour le client de messagerie natif UNIQUEMENT, puis en ajoutant d'autres intentions au sélecteur. Le fait de rendre l'intention originale spécifique au courrier électronique permet de se débarrasser de tous les éléments superflus comme le wifi et le bluetooth, puis je récupère les autres intents que je veux dans un sélecteur générique. ACTION_SEND de type plain-text, et les ajouter avant de les montrer au sélecteur.

Lorsque je saisis les intentions supplémentaires, je définis un texte personnalisé pour chacune d'elles.

Edit2 : Cela fait longtemps que je n'ai pas posté ce message, et les choses ont un peu changé. Si vous voyez deux fois gmail dans la liste des options, essayez de supprimer le traitement spécial pour "Android.gm" comme suggéré dans un commentaire de @h_k ci-dessous.

Puisque cette seule réponse est la source de presque tous mes points de réputation sur stackoverflow, je dois au moins essayer de la tenir à jour.

1 votes

J'utilise ce code, mais d'une manière ou d'une autre, evernote se faufile dans la liste. Quand je vérifie le nom des paquets, c'est com.evernote, donc je ne suis pas sûr de la raison de ce phénomène.

0 votes

@JamesHarpe Je parie qu'Evernote prend en charge le type d'intention "message/rfc822", il apparaît donc dans la liste réduite à partir de laquelle nous commençons. S'il existe un moyen sournois de personnaliser davantage ce système pour exclure Evernote, je serais intéressé de l'entendre !

0 votes

@dacoinminster Salut, j'ai ajouté ce code, il montre l'application gmail et facebook à choisir mais pas l'application de messagerie dans mon téléphone micromax canvas HD. Pouvez-vous m'aider ce que je peux changer ici ?

28voto

Savvas Dalkitsis Points 5865

Si vous souhaitez une option personnalisée, vous ne devez pas vous fier à la boîte de dialogue par défaut fournie par Android pour cette action.

Ce que vous devez faire à la place, c'est déployer le vôtre. Vous devrez interroger le PackageManager sur lesquels les paquets traitent l'action que vous demandez et ensuite, en fonction de la réponse, vous appliquez un filtrage et un texte personnalisé.

Plus précisément, jetez un coup d'œil à la méthode queryIntentActivities de la PackageManager classe. Vous construisez l'intention qui lancerait la boîte de dialogue par défaut (l'intention ACTION_SEND), vous la passez à cette méthode et vous recevrez une liste d'objets contenant des informations sur les activités qui peuvent gérer cette intention. En utilisant cette liste, vous pouvez choisir celles que vous voulez.

Une fois que vous avez établi la liste des paquets que vous souhaitez présenter, vous devez créer votre propre boîte de dialogue de liste (de préférence une activité sur le thème du dialogue) qui affichera cette liste.

Il faut cependant noter qu'il est très difficile de faire en sorte que cette boîte de dialogue personnalisée ressemble à celle par défaut. Le problème est que le thème utilisé dans cette boîte de dialogue est un thème interne et ne peut pas être utilisé par votre application. Vous pouvez soit essayer de la rendre aussi similaire à la boîte de dialogue native que vous le souhaitez, soit opter pour une apparence complètement personnalisée (de nombreuses applications le font, comme l'application Galerie, etc.)

1 votes

Cette réponse est correcte car elle répond le mieux à la question initiale, même si j'ai fini par emprunter une autre voie (voir ma réponse). Merci.

24voto

Kyle Clegg Points 8441

J'ai trouvé une solution qui fonctionne pour moi en regardant 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 Intent avec les différents clients Twitter et vous permet de choisir.

Partagez en utilisant twitter :

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

Appeler 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é en juillet 2011).

Source du code : Intention d'ouvrir le client twitter sur Android

4 votes

Je n'aime pas cette réponse car elle repose sur la connaissance des noms des paquets de toutes les applications Twitter. Pour une autre solution, voir stackoverflow.com/questions/6827407/

0 votes

Je suis d'accord avec vous, bien que la réponse dont vous avez donné le lien présente un problème similaire. Je n'aime pas me fier aux comparaisons de chaînes, surtout lorsque je n'ai aucun contrôle ou aucune garantie que la chaîne ne changera pas.

22voto

user3098538 Points 124

Essayez celui-ci pour ne partager que 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);
        }
    }
}

0 votes

Ce code fonctionne parfaitement si vous essayez de partager avec des applications spécifiques

8voto

Cette solution affiche une liste d'applications dans une boîte de dialogue ListView qui ressemble au sélecteur :

screenshot

C'est à vous de le faire :

  1. obtenir la liste des dossiers de candidature pertinents
  2. étant donné un nom de paquet, invoque l'intention pertinente

La classe de l'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 utilisation :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X