基于安装的Android软件包名称自定义筛选意向select器

我想利用内置的意向select器来显示一个自定义的过滤应用程序列表供用户select和启动。

我知道如何获得已安装软件包的列表:

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

在这一点上,我想根据包名称中包含的特定string(或string的变体)过滤列表,我可以弄清楚如何做。

但是这里是我卡住的地方。 据我所知, Intent.createChooser()只将一个目标Intent作为参数。 我希望有一个重载,基于包和类名称或其他意图的列表。 但是我没有看到这样的事情。 我有没有想念那个地方?

所以问题是,这可能与内置的select器,或者我必须构build我自己的AlertDialog生成器? 我希望避免后来。

提前致谢。

select器的唯一一个附加参数是Intent.EXTRA_INITIAL_INTENTS 。 其描述是:

Intent或者LabeledIntent对象的Parcelable []用putExtra(String,Parcelable [])设置的附加活动来放置select列表的前面,当用ACTION_CHOOSER向用户显示时。

我还没有find任何Android源的方式来排除列表中的其他活动,所以似乎没有办法做你想做的select使用select器。

编辑 :这很容易找出来。 只需检查ChooserActivity和ResolverActivity源代码。 这些课是相当小的。

这是我掀起的一个解决scheme。 我使用它来为select器中的每个select有不同的意图数据,但是您也可以轻松地从列表中删除一个意图。 希望这可以帮助:

 List<Intent> targetedShareIntents = new ArrayList<Intent>(); Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND); shareIntent.setType("text/plain"); List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(shareIntent, 0); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { String 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); } 

编辑

当使用这种方法,我得到一些应用程序的名称作为Android系统。 如果有人得到这个错误,请在targetedShareIntents.add(targetedShareIntent);之前添加下面的行targetedShareIntents.add(targetedShareIntent);

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

来源: Android共享意图Twitter:如何仅通过Tweet或直接信息分享?

我做了一个小小的修改,以获得您想要通过名称共享的应用程序列表。 这几乎是你已经发布,但添加的应用程序按名称共享

 String[] nameOfAppsToShareWith = new String[] { "facebook", "twitter", "gmail" }; String[] blacklist = new String[]{"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, String[] forbiddenChoices) { List<Intent> targetedShareIntents = new ArrayList<Intent>(); List<HashMap<String, String>> intentMetaInfo = new ArrayList<HashMap<String, String>>(); Intent chooserIntent; Intent dummy = new Intent(prototype.getAction()); dummy.setType(prototype.getType()); List<ResolveInfo> 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<String, String> info = new HashMap<String, String>(); info.put("packageName", resolveInfo.activityInfo.packageName); info.put("className", resolveInfo.activityInfo.name); String appName = String.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<HashMap<String, String>>() { @Override public int compare( HashMap<String, String> map, HashMap<String, String> map2) { return map.get("simpleName").compareTo( map2.get("simpleName")); } }); // create the custom intent list for (HashMap<String, String> metaInfo : intentMetaInfo) { Intent targetedShareIntent = (Intent) prototype.clone(); targetedShareIntent.setPackage(metaInfo.get("packageName")); targetedShareIntent.setClassName( metaInfo.get("packageName"), metaInfo.get("className")); targetedShareIntents.add(targetedShareIntent); } String shareVia = getString(R.string.offer_share_via); String shareTitle = shareVia.substring(0, 1).toUpperCase() + shareVia.substring(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, getString(R.string.offer_share_via)); } 

它几乎是Makibo发布的同样的解决scheme,但有一点点添加,只是通过添加名称,使您不会有任何问题,以便他们更改包名称或类似的东西这个。 只要他们不改名字。

我的自定义开放select器的实现。

特征:

  • 应用程序按字母顺序sorting
  • 处理用户定义的默认应用程序
  • 处理没有应用案例
  • 过滤自己

 public static Intent createOpenFileIntent(Context context, String pathToFile) { File file = new File(pathToFile); String extension = extensionFromName(file.getName()); String 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. Retrieve all apps for our intent. If there are no apps - return usual already created intent. List<Intent> targetedOpenIntents = new ArrayList<Intent>(); List<ResolveInfo> 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<ResolveInfo>() { @Override public int compare(ResolveInfo first, ResolveInfo second) { String firstName = packageManager.getApplicationLabel(first.activityInfo.applicationInfo).toString(); String secondName = packageManager.getApplicationLabel(second.activityInfo.applicationInfo).toString(); return firstName.compareToIgnoreCase(secondName); } }); for (ResolveInfo appInfo : appInfoList) { String 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.getString(R.string.context_menu_open_in)) .putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedOpenIntents.toArray(new Parcelable[] {})); return chooserIntent; } public static String extensionFromName(String fileName) { int dotPosition = fileName.lastIndexOf('.'); // If extension not present or empty if (dotPosition == -1 || dotPosition == fileName.length() - 1) { return ""; } else { return fileName.substring(dotPosition + 1).toLowerCase(Locale.getDefault()); } } 

我试图做同样的事情,但与ShareActionProvider。 在gumbercules的文章中的方法与ShareActionProvider无法正常工作,所以我复制并修改了ShareActionProvider相关的类,以允许自定义过滤ShareActionProviderbuild议。

唯一的变化是对ActivityChooserModel.loadActivitiesIfNeeded()方法。 就我而言,我想过滤掉YouTube的软件包。

 public static final String YOUTUBE_PACKAGE = "com.google.android.youtube"; private boolean loadActivitiesIfNeeded() { if (mReloadActivities && mIntent != null) { mReloadActivities = false; mActivities.clear(); List<ResolveInfo> 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; } 

代码在https://github.com/danghiskhan/FilteredShareActionProvider

这个解决scheme基于这个posthttps://rogerkeays.com/how-to-remove-the-facebook-android-sharing-intent

 // get available share intents final String packageToBeFiltered = "com.example.com" List<Intent> targets = new ArrayList<Intent>(); Intent template = new Intent(Intent.ACTION_SEND); template.setType("text/plain"); List<ResolveInfo> candidates = this.getPackageManager().queryIntentActivities(template, 0); // filter package here for (ResolveInfo candidate : candidates) { String 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); }