有个需求需要获取App内的安装列表,但是现在在高版本Android中,只能获取到一部分App效果,我获取的代码如下:
kotlin
val calendar = Calendar.getInstance()
val packageManager = context.packageManager
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val queryList = usageStatsManager.queryAndAggregateUsageStats(
calendar.timeInMillis ,
System.currentTimeMillis()
)
for (entry in queryList.entries){
val packageName = entry.value.packageName
if (packageManager.getLaunchIntentForPackage(packageName) != null){
val applicationInfo = findPackageManager(packageManager, packageName) ?: continue
// app Name
val appName = applicationInfo.loadLabel(packageManager).toString()
// 获取 app icon
val appIcon = BaseSystemUtils.getAppIcon(context, packageName)
BLog.d("show the data : ${appName}, ${appIcon}")
}
private fun findPackageManager(packageManager: PackageManager, packageName : String)
: ApplicationInfo? {
return try {
packageManager.getApplicationInfo(packageName, 0)
} catch (e: Exception) {
return null
}
}
但是只能获取到一部分App的数据,这是因为在 Android 11(API 30)及以上的版本, 由于系统隐私政策的更新,直接使用getApplicationInfo
可能无法获取应用信息,那么我们可以添加 Queries
标签进行辅助查询:
首先,我们来了解一下Queries
是什么东西,它是一种在Android 11以上设定的特定的包可见机制, 不需要特定的权限,就可以查看指定的App包名.
我们看一下该如何去做:
我们需要在AndroidManifest.xml
中声明我们需要查询的App, 举个例子:
xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name">
<!-- 不需要额外的权限声明 -->
<queries>
<!-- 声明需要查询的包名 -->
<package android:name="com.example.app1" />
<package android:name="com.example.app2" />
<!-- 或者声明需要查询的intent -->
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent>
</queries>
<application>
<!-- 应用配置 -->
</application>
</manifest>
有几个常用的用法:
- 查询特定包名:
xml
<queries>
<package android:name="com.target.app" />
</queries>
- 查询所有浏览器:
xml
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
</queries>
- 查询所有启动器应用:
xml
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent>
</queries>
- 查询所有支持分享的应用:
xml
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="text/plain" />
</intent>
</queries>
- 查询所有图片查看器:
xml
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="image/*" />
</intent>
</queries>
我们声明Queries
之后,其它代码不需要改动,即可查询到所有的App数据, 因为这里我想查询的是所有启动器应用:
xml
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent>
</queries>
我们可以看到Queries
是静态声明的,是我们先声明再去获取的,不能做到动态的获取,啥意思呢?
比如我们在QUeries
中定义了如下:
xml
<queries>
<package android:name="com.target.one.app" />
<package android:name="com.target.two.app" />
</queries>
那么我们在查询数据时,只能查询包名com.target.one.app
和 com.target.two.app
de数据, 不能查询新的com.target.three.app
数据, 这个是一个比较硬的伤, 一般遇到这种情况,我们多数情况下会使用 Intent 来声明, 或者使用申请更高级别权限:android.permission.QUERY_ALL_PACKAGES
, 当然了,这个需要更高的隐私权限, 不同的厂商对这个权限的敏感度不同.
最后,贴一张Android14获取全部App的效果图: