根据安装的Android软件包名称自定义过滤意图选择器

Kon*_*Kon 55 android android-intent

我想利用内置的意图选择器来显示自定义过滤的应用列表,供用户选择和启动.

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

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

此时,我想根据包名称中包含的特定字符串(或字符串的变体)过滤列表,我也可以弄清楚如何操作.

但是这里我被卡住了.据我所知,Intent.createChooser()只需要一个目标Intent作为参数.我希望有一个重载基于包和类名或其他东西的意图列表.但我没有看到类似的东西.我在某处错过了吗?

所以问题是,这可能与内置选择器有关,还是我必须使用AlertDialog Builder构建自己的选择器?我希望避免后者.

提前致谢.

小智 106

这是我掀起的解决方案.我使用它为选择器中的每个选择提供不同的意图数据,但您也可以轻松地从列表中删除意图.希望这可以帮助:

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);
}
Run Code Online (Sandbox Code Playgroud)

编辑

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

 targetedShareIntent.setClassName(
                        resolveInfo.activityInfo.packageName,
                        resolveInfo.activityInfo.name);
Run Code Online (Sandbox Code Playgroud)

来源:Android分享意图Twitter:如何仅通过推文或直接消息分享?

  • 谢谢,还有一点建议:从`getPackageManager().queryIntentActivities(shareIntent,0);`,调用`Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1),"选择"应用程序分享");`,选择器将其初始化意图添加到extra_initial_intents的末尾:) (9认同)
  • 我根据这个答案为可重用的解决方案创建了一个要点https://gist.github.com/mediavrog/5625602 (8认同)
  • 我没有得到/导入StringUtils @gumbercules (2认同)

Mic*_*ael 25

选择器的唯一附加参数是Intent.EXTRA_INITIAL_INTENTS.它的描述是:

一个Parcelable []的Intent或LabeledIntent对象,使用putExtra(String,Parcelable [])设置其他活动,以便在向用户显示ACTION_CHOOSER时放置选项列表的前面.

我没有在Android源代码中找到任何方法从列表中排除其他活动,因此似乎无法使用选择器执行您想要执行的操作.

编辑:这很容易找到.只需检查ChooserActivityResolverActivity源代码即可.这些课程相当小.


ple*_*mik 7

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

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));
    }
Run Code Online (Sandbox Code Playgroud)

它与Makibo发布的解决方案几乎相同,但只需添加一个名称即可轻松选择您想要分享的应用程序,这样您就不会有任何问题,以防他们更改包名或类似名称这个.只要他们不改名字.


oxi*_*ied 6

我的自定义开放选择器的实现.

特征:

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

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 要获得与动作选择器显示的标签相同的标签,您应该使用`ResolveInfo.loadLabel(packageManager)`而不是`packageManager.getApplicationLabel(ResolveInfo.activityInfo.applicationInfo)`.结果并不总是一样的.(在步骤3中排序时,这用于覆盖`compare()`.例如,对于Dropbox,loadLabel()将返回"Add to Dropbox",getApplicationLabel()将返回"Dropbox". (3认同)