一般安卓提取apk图标我们有两种常用方法:
1、如果已经获取到 ApplicationInfo 对象(假设名为 appInfo),那么我们获取方法为:
appInfo.loadIcon(packageManager)// 返回一个 Drawable 对象
2、 如果还没获取到 ApplicationInfo 对象,我们一般会先获取 packageInfo 对象,然后通过它来获取 ApplicationInfo 对象,
但是这个方法会存在一个 bug ,就是需要设置 sourceDir 、publicSourceDir 两个源路径
属性之后才能正常获取到图标。
然后设置上面两个属性之后,如果设置图标之后,相同包名,但是图标不相同的,就会导致后续获取的图标都相同
,也就是说,包名相同图标不同,但是获取到的图标竟然都相同!
初步分析,原因应该出现在包名、两个源路径身上。
这应该是 Android SDK 自己写 loadIcon 代码的时候也没考虑过的使用情况。
可能是包名作为类似 Key 之类的,然后通过包名找到源路径,然后通过源路径获取图标。
所以如果获取一次之后,只设置源路径而不修改包名,那么获取的将是旧的源路径对应的图标。
为了解决这个问题,以下是我改良之后的 Kotlin
代码
fun getAppIconFromApkPath(context: Context, apkFilePath: String): Drawable? {
// 1. 获取 包管理器,并通过包管理器、apk 路径获取 packageInfo
val packageManager: PackageManager = context.packageManager
val packageInfo = packageManager.getPackageArchiveInfo(
apkFilePath,
0//PackageManager.GET_ACTIVITIES//GET_META_DATA
)
// 2. 访问、修改 packageInfo 对象的 applicationInfo 对象里面一些属性,比如packageName、sourceDir、publicSourceDir、loadIcon
packageInfo?.applicationInfo?.apply {
// 2.1. 【关键步骤】设置 包名
val oldPackageName = packageName// 保存旧的包名,因为下面获取 apk 图标之后要恢复
packageName = apkFilePath// 将其包名改成一个任意的、唯一的其他字符串,这样获取到的图标才不会冲突
// 2.2. 【必须步骤】设置源路径:设置sourceDir和publicSourceDir属性为APK文件的路径。这样可以确保加载的是APK文件中的资源,而不是系统资源。
sourceDir = apkFilePath
publicSourceDir = apkFilePath// 设置这两个路径之后,同时也会把相关包名的文件设置。所以会导致已安装的和其他文件图标不一样!!!
// 2.3. 通过 loadIcon 来获取 apk 图标
val icon = loadIcon(packageManager)
// 2.4. 【关键步骤】获取到图标之后,先恢复前面修改的包名、源路径,最后才能返回图标
packageName = oldPackageName// 恢复成原来的包名(修改之前的)
sourceDir = null// 并且把其他的数据还原为null
publicSourceDir = null
// 2.5. 最后返回获取到的图标
return icon
}
return null
}