如何获取可打开指定文件的所有应用列表并存储到ArrayList?
Android 获取可打开指定文件的应用列表方案
前置适配说明
Android 11(API 30)及以上系统对应用查询做了限制,需要先在AndroidManifest.xml中添加如下配置,否则查询结果会为空:
<queries> <intent> <action android:name="android.intent.action.VIEW" /> <!-- 可根据你要查询的文件类型调整mimeType,不需要全量查询就不要写*/*,减少权限范围 --> <data android:mimeType="*/*" /> </intent> </queries>
如果有特殊场景需要查询全量应用,可申请权限(上架Google Play需额外说明使用理由,非必要不建议使用):
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
核心实现代码
1. 直接存储系统返回的ResolveInfo列表
// 构造和你原有打开逻辑完全一致的Intent Intent intent = new Intent(Intent.ACTION_VIEW); Uri fileUri = Uri.fromFile(new File(_path)); intent.setDataAndType(fileUri, _type); PackageManager pm = getPackageManager(); // 查询匹配的应用列表 List<ResolveInfo> matchList = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); // 转换为ArrayList存储 ArrayList<ResolveInfo> appList = new ArrayList<>(matchList);
2. 自定义实体类存储(方便后续展示和调用)
先定义实体类:
public class OpenAppInfo { // 应用名称 public String appName; // 应用图标 public Drawable appIcon; // 应用包名 public String pkgName; // 对应启动的Activity全路径 public String activityName; // 系统返回的原始信息,可直接用于启动 public ResolveInfo rawInfo; }
查询封装逻辑:
ArrayList<OpenAppInfo> customAppList = new ArrayList<>(); PackageManager pm = getPackageManager(); for (ResolveInfo info : matchList) { OpenAppInfo appInfo = new OpenAppInfo(); appInfo.appName = info.loadLabel(pm).toString(); appInfo.appIcon = info.loadIcon(pm); appInfo.pkgName = info.activityInfo.packageName; appInfo.activityName = info.activityInfo.name; appInfo.rawInfo = info; customAppList.add(appInfo); }
后续启动指定应用打开文件的代码
// 取列表中第position个应用为例 ResolveInfo targetApp = appList.get(position); Intent launchIntent = new Intent(Intent.ACTION_VIEW); launchIntent.setDataAndType(fileUri, _type); // 指定目标应用的启动信息,避免弹出系统选择器 launchIntent.setClassName(targetApp.activityInfo.packageName, targetApp.activityInfo.name); // 非Activity场景启动需要加这个Flag launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(launchIntent);
注意事项
- Android 7.0及以上直接使用
Uri.fromFile会抛出FileUriExposedException,建议替换为FileProvider生成content类型的Uri,查询和启动逻辑保持不变即可。 - 如果你不需要自定义选择器,原有代码中调用
Intent.createChooser弹出的系统选择器展示的应用列表和上述查询结果完全一致。
内容的提问来源于stack exchange,提问作者Star4Droid
相关产品推荐
相关产品推荐

