使用系统相关接口,可以根据 Intent 过滤查询对应的 Context
PackageManager.java
- queryIntentActivities 查询符合Intent Activity
- queryBroadcastReceivers 查询符合Intent BroadcastReceiver
- queryIntentServices 查询符合Intent Service
- queryIntentContentProviders 查询符合Intent ContentProvider
按照系统接口使用说明,查询桌面应用图标的 actvity 代码demo如下:
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List list = getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : list) {
Log.i(Activity_TAG, "resolveInfo " + resolveInfo);
}
实际打印中会发现,打印出来的 activity 不全。原因在于系统对查询的结果进行过滤了一部分
private @NonNull ListqueryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { if (!mUserManager.exists(userId)) return Collections.emptyList(); final String instantAppPkgName = getInstantAppPackageName(filterCallingUid); mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false , false , "query intent activities"); final String pkgName = intent.getPackage(); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart, comp != null || pkgName != null , isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); if (comp != null) { // 对指定了 ComponentName 的 Intent 查询 return result; } // reader boolean sortResult = false; boolean addInstant = false; List result; synchronized (mLock) { if (pkgName == null) { List matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); // 判断当前查询的应用是否跳过接下来配置文件 ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (xpResolveInfo != null) { List xpResult = new ArrayList<>(1); xpResult.add(xpResolveInfo); return applyPostResolutionFilter( filterIfNotSystemUser(xpResult, userId), instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); } // 判断当前用户是否是系统用户 result = filterIfNotSystemUser(mComponentResolver.queryActivities( intent, resolvedType, flags, userId), userId); addInstant = isInstantAppResolutionAllowed(intent, result, userId, false ); // Check for cross profile results. boolean hasNonNegativePriorityResult = hasNonNegativePriority(result); xpResolveInfo = queryCrossProfileIntents( matchingFilters, intent, resolvedType, flags, userId, hasNonNegativePriorityResult); if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) { boolean isVisibleToUser = filterIfNotSystemUser( Collections.singletonList(xpResolveInfo), userId).size() > 0; if (isVisibleToUser) { result.add(xpResolveInfo); sortResult = true; } } if (intent.hasWebURI()) { // 设置 weburi 的部分 } } else { // 设置了pkgName 的intent查询方式 } } ... ... // 进行过滤操作 return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); }
queryIntentActivitiesInternal 中初步对调用的应用做了判断,最后调用 applyPostResolutionFilter 对进行进一步判断,在 applyPostResolutionFilter 方法中,一般的APP都是通过 !mAppsFilter.shouldFilterApplication( filterCallingUid, callingSetting, resolvedSetting, userId) 进行判断是否需要过滤删除查询到的 ResolveInfo
AppsFilter -> shouldFilterApplication
方法中通过对 uid、sharedUserId 数据判断,进行过滤,按照系统默认规则:非 systemUid 应用只能获取到 systemUid 应用、静态库等模块中的 ResolveInfo。开启查询 pkg Feature 或者添加如下权限可以查询获取到全部模块中匹配项。
android.permission.QUERY_ALL_PACKAGES
这里已经安装应用 uid 等信息都是保存在 /data/system/packages.xml 。系统的 PkgSetting 类就是获取这里内容,debug时候可以手动导出来查看下相关内容。



