通过 AssestManager 加载外部皮肤包

一、Android APK 中的资源文件

在将程序打包成 APK 后,资源文件会单独打包成 resources.arsc 文件。它通过包名进行管理,通过ID,Name的方式通过 Resources 类进行加载。

二、加载外部的资源包

资源包实际上是一个 APK,它可以被 AssestManager进行加载,并通过 Resources 类加载其中的资源。

三、资源文件如果被Resources类引用

资源文件是通过 ID 被 Resources 引用到的。所以如果皮肤包中的资源和我们apk中原始的资源 ID 是一致的话,我们可以用通过这个ID在皮肤包的Resources中找到对应的资源,加载这个资源实现皮肤的替换

四、加载外部资源

1.外部资源可以通过AssestManager进行加载,所以首先需要创建一个AssestManager

注意这里不能使用Application.getAssest(),这种方式获得AssetManager会少初始化很多东西

     AssetManager assetManager = AssetManager.class.newInstance();

2.AssestManager加载皮肤包

AssestManager通过addAssetPath的函数加载资源包,但这个函数本身是隐藏的,需要通过反射的方式加载

    Method addAssetPath = assetManager.getClass().getDeclaredMethod(ADD_ASSET_PATH, String.class);
    // 设置私有方法可访问
    addAssetPath.setAccessible(true);
    // 执行addAssetPath方法
    addAssetPath.invoke(assetManager, skinPath);

3.读取皮肤包中的资源

有了AssestManager后,就可以获取到 Resources 类了

这里通过了apk已经准备好的资源类获取到了DsplayMetrics,Configuration 参数

 this.application = application;
        appResources = application.getResources();
 skinResources = new Resources(assetManager,
                    appResources.getDisplayMetrics(), appResources.getConfiguration());

4.通过ID映射实际的资源

需要找到皮肤包中对应的资源的 ID

 private int getSkinResourceIds(int resourceId) {
        if (isDefaultSkin) return resourceId;

        String resourceName = appResources.getResourceEntryName(resourceId);
        String resourceType = appResources.getResourceTypeName(resourceId);

        // 动态获取皮肤包内的指定资源ID
        // getResources().getIdentifier(“netease_bg”, “drawable”, “com.netease.skin.packages”);
        int skinResourceId = skinResources.getIdentifier(resourceName, resourceType, skinPackageName);

        isDefaultSkin = skinResourceId == 0;
        return skinResourceId == 0 ? resourceId : skinResourceId;
    }
5.加载皮肤包的资源

有了 ID 就可以加载皮肤包中的资源了,在需要换肤的时候通过这些通过使用皮肤包的 Resources 类加载其中的资源实现换肤

 public int getColor(int resourceId) {
        int ids = getSkinResourceIds(resourceId);
        return isDefaultSkin ? appResources.getColor(ids) : skinResources.getColor(ids);
    }

    public ColorStateList getColorStateList(int resourceId) {
        int ids = getSkinResourceIds(resourceId);
        return isDefaultSkin ? appResources.getColorStateList(ids) : skinResources.getColorStateList(ids);
    }

    // mipmap和drawable统一用法(待测)
    public Drawable getDrawableOrMipMap(int resourceId) {
        int ids = getSkinResourceIds(resourceId);
        return isDefaultSkin ? appResources.getDrawable(ids) : skinResources.getDrawable(ids);
    }

    public String getString(int resourceId) {
        int ids = getSkinResourceIds(resourceId);
        return isDefaultSkin ? appResources.getString(ids) : skinResources.getString(ids);
    }

你可能感兴趣的:(通过 AssestManager 加载外部皮肤包)