Filtrage personnalisé du sélecteur d’intention en fonction du nom du package Android installé

J’aimerais tirer parti du sélecteur d’intention intégré pour afficher une liste filtrée personnalisée d’applications que l’utilisateur peut sélectionner et lancer.

Je sais comment obtenir une liste des paquets installés:

final Intent myIntent = new Intent(android.content.Intent.ACTION_MAIN); List resInfoList = getPackageManager().queryIntentActivities(myIntent, 0); 

À ce stade, je souhaite filtrer la liste en fonction d’une chaîne spécifique (ou d’une variante de chaîne) contenue dans le nom du package, que je peux également déterminer comment procéder.

Mais voici où je suis coincé. Autant que je sache, Intent.createChooser() ne prend qu’un seul objective cible en tant que paramètre. J’espérais qu’il y avait une surcharge qui prenait une liste d’intentions basée sur les noms de paquet et de classe ou quelque chose. Mais je ne vois rien de tel. Est-ce que ça m’a manqué quelque part?

La question est donc la suivante: est-ce possible de faire avec un sélecteur intégré ou dois-je créer le mien avec AlertDialog Builder? J’espère éviter le plus tard.

Merci d’avance.

Le seul paramètre supplémentaire pour le sélecteur est Intent.EXTRA_INITIAL_INTENTS . Sa description est:

Un object Parcelable [] de Intent ou LabeledIntent défini avec putExtra (Ssortingng, Parcelable []) d’activités supplémentaires à placer en tête de la liste de choix, lorsqu’il est affiché à l’utilisateur avec un ACTION_CHOOSER.

Je n’ai trouvé aucun moyen dans les sources Android d’exclure d’autres activités de la liste, il semble donc qu’il n’y ait aucun moyen de faire ce que vous voulez faire en utilisant le sélecteur.

EDIT : C’est vraiment facile à trouver. Il suffit de vérifier le code source de ChooserActivity et ResolverActivity . Ces classes sont plutôt petites.

Voici une solution que j’ai imaginée. Je l’utilise pour avoir des données d’intention différentes pour chaque sélection dans le sélecteur, mais vous pouvez facilement supprimer une intention de la liste également. J’espère que cela t’aides:

 List targetedShareIntents = new ArrayList(); Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND); shareIntent.setType("text/plain"); List resInfo = getPackageManager().queryIntentActivities(shareIntent, 0); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { Ssortingng packageName = resolveInfo.activityInfo.packageName; Intent targetedShareIntent = new Intent(android.content.Intent.ACTION_SEND); targetedShareIntent.setType("text/plain"); targetedShareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "subject to be shared"); if (TextUtils.equals(packageName, "com.facebook.katana")) { targetedShareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "http://link-to-be-shared.com"); } else { targetedShareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "text message to shared"); } targetedShareIntent.setPackage(packageName); targetedShareIntents.add(targetedShareIntent); } Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[targetedShareIntents.size()])); startActivity(chooserIntent); } 

MODIFIER

En utilisant cette méthode, je reçois des noms de certaines applications en tant que système Android. Si quelqu’un obtient cette erreur, veuillez append les lignes ci-dessous avant targetedShareIntents.add(targetedShareIntent);

  targetedShareIntent.setClassName( resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); 

source: Android share intent Twitter: Comment partager uniquement par Tweet ou Direct Message?

Mon implémentation de sélecteur ouvert personnalisé.

Caractéristiques:

  • les applications sont sortingées par ordre alphabétique
  • gérer l’application par défaut définie par l’utilisateur
  • pas de cas d’application
  • se filtrer

 public static Intent createOpenFileIntent(Context context, Ssortingng pathToFile) { File file = new File(pathToFile); Ssortingng extension = extensionFromName(file.getName()); Ssortingng mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); if (mimeType == null) { //If android doesn't know extension we can check our own list. mimeType = KNOWN_MIME_TYPES.get(DataViewHelper.extensionFromName(file.getName())); } Intent openIntent = new Intent(); openIntent.setAction(android.content.Intent.ACTION_VIEW); openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); openIntent.setDataAndType(Uri.fromFile(file), mimeType); // 1. Check if there is a default app opener for this type of content. final PackageManager packageManager = context.getPackageManager(); ResolveInfo defaultAppInfo = packageManager.resolveActivity(openIntent, PackageManager.MATCH_DEFAULT_ONLY); if (!defaultAppInfo.activityInfo.name.endsWith("ResolverActivity")) { return openIntent; } // 2. Resortingeve all apps for our intent. If there are no apps - return usual already created intent. List targetedOpenIntents = new ArrayList(); List appInfoList = packageManager.queryIntentActivities(openIntent, PackageManager.MATCH_DEFAULT_ONLY); if (appInfoList.isEmpty()) { return openIntent; } // 3. Sort in alphabetical order, filter itself and create intent with the rest of the apps. Collections.sort(appInfoList, new Comparator() { @Override public int compare(ResolveInfo first, ResolveInfo second) { Ssortingng firstName = packageManager.getApplicationLabel(first.activityInfo.applicationInfo).toSsortingng(); Ssortingng secondName = packageManager.getApplicationLabel(second.activityInfo.applicationInfo).toSsortingng(); return firstName.compareToIgnoreCase(secondName); } }); for (ResolveInfo appInfo : appInfoList) { Ssortingng packageName = appInfo.activityInfo.packageName; if (packageName.equals(context.getPackageName())) { continue; } Intent targetedOpenIntent = new Intent(android.content.Intent.ACTION_VIEW) .setDataAndType(Uri.fromFile(file), mimeType) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .setPackage(packageName); targetedOpenIntents.add(targetedOpenIntent); } Intent chooserIntent = Intent.createChooser(targetedOpenIntents.remove(targetedOpenIntents.size() - 1), context.getSsortingng(R.ssortingng.context_menu_open_in)) .putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedOpenIntents.toArray(new Parcelable[] {})); return chooserIntent; } public static Ssortingng extensionFromName(Ssortingng fileName) { int dotPosition = fileName.lastIndexOf('.'); // If extension not present or empty if (dotPosition == -1 || dotPosition == fileName.length() - 1) { return ""; } else { return fileName.subssortingng(dotPosition + 1).toLowerCase(Locale.getDefault()); } } 

J’ai fait une petite modification pour avoir une liste des applications que vous souhaitez partager avec votre nom. C’est presque ce que vous avez déjà posté mais en ajoutant les applications à partager par nom

 Ssortingng[] nameOfAppsToShareWith = new Ssortingng[] { "facebook", "twitter", "gmail" }; Ssortingng[] blacklist = new Ssortingng[]{"com.any.package", "net.other.package"}; // your share intent Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "some text"); intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "a subject"); // ... anything else you want to add invoke custom chooser startActivity(generateCustomChooserIntent(intent, blacklist)); private Intent generateCustomChooserIntent(Intent prototype, Ssortingng[] forbiddenChoices) { List targetedShareIntents = new ArrayList(); List> intentMetaInfo = new ArrayList>(); Intent chooserIntent; Intent dummy = new Intent(prototype.getAction()); dummy.setType(prototype.getType()); List resInfo = getPackageManager().queryIntentActivities(dummy,0); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { if (resolveInfo.activityInfo == null || Arrays.asList(forbiddenChoices).contains( resolveInfo.activityInfo.packageName)) continue; //Get all the posible sharers HashMap info = new HashMap(); info.put("packageName", resolveInfo.activityInfo.packageName); info.put("className", resolveInfo.activityInfo.name); Ssortingng appName = Ssortingng.valueOf(resolveInfo.activityInfo .loadLabel(getPackageManager())); info.put("simpleName", appName); //Add only what we want if (Arrays.asList(nameOfAppsToShareWith).contains( appName.toLowerCase())) { intentMetaInfo.add(info); } } if (!intentMetaInfo.isEmpty()) { // sorting for nice readability Collections.sort(intentMetaInfo, new Comparator>() { @Override public int compare( HashMap map, HashMap map2) { return map.get("simpleName").compareTo( map2.get("simpleName")); } }); // create the custom intent list for (HashMap metaInfo : intentMetaInfo) { Intent targetedShareIntent = (Intent) prototype.clone(); targetedShareIntent.setPackage(metaInfo.get("packageName")); targetedShareIntent.setClassName( metaInfo.get("packageName"), metaInfo.get("className")); targetedShareIntents.add(targetedShareIntent); } Ssortingng shareVia = getSsortingng(R.ssortingng.offer_share_via); Ssortingng shareTitle = shareVia.subssortingng(0, 1).toUpperCase() + shareVia.subssortingng(1); chooserIntent = Intent.createChooser(targetedShareIntents .remove(targetedShareIntents.size() - 1), shareTitle); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {})); return chooserIntent; } } return Intent.createChooser(prototype, getSsortingng(R.ssortingng.offer_share_via)); } 

C’est presque la même solution que celle proposée par Makibo, mais avec un petit ajout pour faciliter le choix des applications que vous souhaitez partager en ajoutant simplement le nom afin de ne pas avoir de problème si elles changent le nom du paquet ou quelque chose comme ce. Tant qu’ils ne changent pas le nom.

J’essayais de faire la même chose mais avec un ShareActionProvider. La méthode dans le post de gumbercules ne fonctionnait pas bien avec ShareActionProvider, alors j’ai copié et modifié les classes liées à ShareActionProvider pour permettre le filtrage personnalisé des suggestions ShareActionProvider.

Le seul changement concerne la méthode ActivityChooserModel.loadActivitiesIfNeeded (). Dans mon cas, je voulais filtrer le package YouTube.

 public static final Ssortingng YOUTUBE_PACKAGE = "com.google.android.youtube"; private boolean loadActivitiesIfNeeded() { if (mReloadActivities && mIntent != null) { mReloadActivities = false; mActivities.clear(); List resolveInfos = mContext.getPackageManager() .queryIntentActivities(mIntent, 0); final int resolveInfoCount = resolveInfos.size(); for (int i = 0; i < resolveInfoCount; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); // Filter out the YouTube package from the suggestions list if (!resolveInfo.activityInfo.packageName.equals(YOUTUBE_PACKAGE)) { mActivities.add(new ActivityResolveInfo(resolveInfo)); } } return true; } return false; } 

Code à l' adresse https://github.com/danghiskhan/FilteredShareActionProvider

Cette solution est basée sur cet article https://rogerkeays.com/how-to-remove-the-facebook-android-sharing-intent

 // get available share intents final Ssortingng packageToBeFiltered = "com.example.com" List targets = new ArrayList(); Intent template = new Intent(Intent.ACTION_SEND); template.setType("text/plain"); List candidates = this.getPackageManager().queryIntentActivities(template, 0); // filter package here for (ResolveInfo candidate : candidates) { Ssortingng packageName = candidate.activityInfo.packageName; if (!packageName.equals(packageToBeFiltered)) { Intent target = new Intent(android.content.Intent.ACTION_SEND); target.setType("text/plain"); target.putExtra(Intent.EXTRA_TEXT, "Text to share")); target.setPackage(packageName); targets.add(target); } } if (!targets.isEmpty()) { Intent chooser = Intent.createChooser(targets.get(0), "Share dialog title goes here")); chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[]{})); startActivity(chooser); }