Android换肤:从外存中读取皮肤包资源实现换肤

效果图:
在这里插入图片描述

简介

经过上篇的介绍(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哒哒呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值