效果图:
简介
经过上篇的介绍(https://editor.csdn.net/md/?articleId=106350257),其实换肤的操作十分简单,简单的说就是A模式调用A资源文件,B模式调用B资源文件,C模式调用C资源文件,以此类推而已。
这个资源文件,其实就是皮肤包,直接开撸
资源文件包(皮肤包)
首先是资源文件包,它是资源文件,所以它仅仅有一些资源而已,没有代码。这些资源可以自定义。(但是资源名字要与主项目的资源名字一致)
然后build成apk文件后,就可以改成喜欢的名字,比如xx.skin,然后放入内置存储卡中:storage/emlated/0/
demo地址:https://github.com/lyx19970504/Dynamic-Skin-Change/tree/skinPackage
接着就是在代码中”拿出“这个资源文件包,然后解析并获取里面的资源,设置。
主项目APK
SkinManager.java
1、loadSkinResource(加载资源文件)
private static final String ADD_ASSETS_PATH = "addAssetPath";
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetsMethod = assetManager.getClass().getDeclaredMethod(ADD_ASSETS_PATH, String.class);
addAssetsMethod.setAccessible(true);
addAssetsMethod.invoke(assetManager, skinPath);
skinResource = new Resources(assetManager, appResource.getDisplayMetrics(), appResource.getConfiguration());
skinPackageName = application.getPackageManager().getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES).packageName;
首先需要通过AssetManager的addAssetPath方法将资源包的路径进行设置,由于addAssetPath方法是@hide注解,因此需要通过反射来完成,并且compileSdkVersion的版本和targetSdkVersion最大只能是28,29的话会出错。然后通过assetManager来生成skinResource对象,通过这个对象就可以得到资源包的所有资源文件。并通过路径获取资源包的PackageName.
2、获取资源的id
首先做个约定:本地apk的资源名称与路径与皮肤包的资源名称路径相同。
然后将主项目的apk拖到android studio中,会有一个叫resources.arsc的文件,它保存了所有的资源的id、文件名、路径的一一关系映射表:
然后在项目资源包的apk拖到android studio中,打开resources.arsc的文件看看:
可以发现他们的ID值一模一样!他们有相同的文件名,相同的文件路径。这样一来,如果想要获取资源apk中的资源文件,那么可以先通过本地资源的ID去获取它的名字,类型,因为这些信息跟资源包中的文件是一一对应的,代码如下:
private int tryGetSkinResourceId(int originResourceId) {
if (isDefaultSkin) {
return originResourceId;
}
/**
* 因为app的资源文件名称与皮肤包中的文件名称相同,因此名称和id也会相同
*/
Log.d(TAG, "originResourceId: " + originResourceId);
String resourceName = appResource.getResourceEntryName(originResourceId);
String resourceType = appResource.getResourceTypeName(originResourceId);
int skinResourceId = skinResource.getIdentifier(resourceName, resourceType, skinPackageName);
Log.d(TAG, "skinResourceId: " + skinResourceId);
isDefaultSkin = skinResourceId == 0;
return skinResourceId == 0 ? originResourceId : skinResourceId;
}
首先判断是否点击的是默认按钮,是的话那就不在获取资源文件。然后根据本地资源的ID获取资源的名字、类型,再根据这个名字、类型在皮肤资源包中寻找对应的资源ID,找到的话就可以返回并设置了。
demo地址:https://github.com/lyx19970504/Dynamic-Skin-Change/tree/DynamicSkinFromResource
资源包地址:https://github.com/lyx19970504/Dynamic-Skin-Change/tree/skinPackage