1. 概述 在Android 15.0系统产品ROM定制化开发过程中,部分产品需求要求替换Launcher3中显示的app图标。对于无源码的app,这一操作需通过修改PMS(PackageManagerService)在解析app时的行为来实现。具体来说,需在解析过程中替换app的icon资源。
2. 无源码app修改icon图标的相关核心类 核心类位于:
1 frameworks/base/core/java/android/content/pm/PackageParser.java
3. 无源码app修改icon图标的核心功能实现与分析 3.1 PMS(PackageManagerService)概述 PMS是Android提供的包管理系统服务,负责管理所有包的信息,包括应用的安装、卸载、更新以及解析AndroidManifest.xml文件。PMS通过解析每个安装应用的AndroidManifest.xml文件,保存其中的数据,并为AMS(ActivityManagerService)提供所需数据。
3.2 解析app的方法分析 在安装过程中,PMS首先遍历/data/app和/system/app文件夹,找到apk文件,然后通过submit()方法进行apk的解析。解析时,将apk文件路径传入PackageParser对象的parsePackage()方法进行解析。不同系统源码版本的解析方式可能有所不同。
3.2.1 parsePackage()方法 1 2 3 4 5 6 7 8 @UnsupportedAppUsage public Package parsePackage (File packageFile, int flags) throws PackageParserException { if (packageFile.isDirectory()) { return parseClusterPackage(packageFile, flags); } else { return parseMonolithicPackage(packageFile, flags); } }
在解析app时,PMS会优先调用parsePackage(File packageFile, int flags, boolean useCaches)方法(尽管示例中未直接展示,但根据描述可推断),进而调用parseMonolithicPackage(File apkFile, int flags)方法进行app资源的解析。
3.2.2 parseMonolithicPackage()方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public Package parseMonolithicPackage (File apkFile, int flags) throws PackageParserException { final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps) { if (!lite.coreApp) { throw new PackageParserException (INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "Not a coreApp: " + apkFile); } } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader (lite, flags); try { final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags); pkg.setCodePath(apkFile.getCanonicalPath()); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; } catch (IOException e) { throw new PackageParserException (INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to get path: " + apkFile, e); } finally { IoUtils.closeQuietly(assetLoader); } }
在parseMonolithicPackage()方法中,会调用parseBaseApk()方法进一步解析app。
3.2.3 parseBaseApk()方法 1 2 3 4 5 6 7 8 9 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Package parseBaseApk (String apkPath, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final String pkgName; final Package pkg = new Package (pkgName); return parseBaseApkCommon(pkg, null , res, parser, flags, outError); }
parseBaseApk()方法最终会调用parseBaseApkCommon()方法继续解析app的xml内容。当解析到TAG_APPLICATION标签时,会调用parseBaseApplication()方法解析application的相关内容。
3.2.4 parseBaseApplication()方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private boolean parseBaseApplication (Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final ApplicationInfo ai = owner.applicationInfo; final String pkgName = owner.applicationInfo.packageName; TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestApplication); ai.iconRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_icon, 0 ); ai.roundIconRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 0 ); if (!TextUtils.isEmpty(pkgName) && pkgName.equals("com.sprd.sprdnote" )) { ai.iconRes = com.android.internal.R.drawable.ic_battery; } }
在parseBaseApplication()方法中,首先获取ApplicationInfo的pkgName,然后解析application的属性。其中,ai.iconRes即为app的图标资源ID。因此,要修改app的图标,只需修改此属性即可。
本文链接: http://longzhiye.top/2025/08/31/2025-08-31/