android架构师之路——以修改一个图片文件方式讲解APP内置换肤原理

本文详细介绍了App换肤技术的基本原理及其实现过程。通过修改资源包名称,利用getIdentifier方法获取新资源ID,最终实现界面样式的更换。文中还提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

app换肤,就是将我们设置的对应资源文件,比如drawable,style,textSize等,替换成资源包里面的数据

这里我们将以一个简单的替换drawable资源文件,来讲解其原理

先来开一个方法,当我们调用getMyResource(R.mipmap.ic_launcher)时候

    private int getMyResource(int resId) {
        Resources resources = getResources();
        String resourceEntryName = resources.getResourceEntryName(resId);//ic_launcher
        Log.d(TAG, "resourceEntryName: " + resourceEntryName);
        String resourcePackageName = resources.getResourcePackageName(resId);//com.example.invoke
        Log.d(TAG, "resourcePackageName: " + resourcePackageName);
        String resourceTypeName = resources.getResourceTypeName(resId);//mipmap
        Log.d(TAG, "resourceTypeName: " + resourceTypeName);
        String resourceName = resources.getResourceName(resId);//com.example.invoke:mipmap/ic_launcher
        Log.d(TAG, "resourceName: " + resourceName);
        int identifier = resources.getIdentifier(resourceEntryName, resourceTypeName, resourcePackageName); //ic_launcher  mipmap   com.example.invoke
        Log.d(TAG, "identifier: " + identifier);
        return identifier;
    }

所得到的log日志

com.example.invoke D/MainActivity: resourceEntryName: ic_launcher
com.example.invoke D/MainActivity: resourcePackageName: com.example.invoke
com.example.invoke D/MainActivity: resourceTypeName: mipmap
com.example.invoke D/MainActivity: resourceName: com.example.invoke:mipmap/ic_launcher
com.example.invoke D/MainActivity: identifier: 2131361792

在对应的R文件里面,我们可以找到与相 2131361792 对应的资源

 

换肤方法

我们先看一下主要方法getIdentifier,其中传入了三个参数name(ic_launcher) ,defType(mipmap ),以及defPackage(com.example.invoke),看到这里就看到了解决方式,我们只需要将defPackage修改成资源包(com.zkq.app_skin)的包名,通过getIdentifier获得资源包(com.zkq.app_skin)的资源ID,反相获得相应资源包的R.mipmap.ic_launcher文件,就可以达到换肤的目的

  public int getIdentifier(String name, String defType, String defPackage) {
        return mResourcesImpl.getIdentifier(name, defType, defPackage);
    }

步骤

了解了实现方式,现在正是开始实现代码

先看主项目(com.example.invoke)结构,我们需要换肤,修改test.png文件

资源文件(com.zkq.app_skin)的结构,同样的名字,存放规则,我们将资源文件生成的apk存放到sdcard中,命名为app_skin-debug.apk,并开启读取sdcard权限。当然一般资源包都是通过http请求,从服务器下载,并验证MD5等,我们这里主要讲解原理,就不实现了

 

在主项目中

  • 获取资源文件路径
 String path = Environment.getExternalStorageDirectory() + File.separator + "app_skin-debug.apk";
  • 获取资源文件的skinResources 
  //反射创建AssetManager
  AssetManager manager = AssetManager.class.newInstance();
  // 资料路径设置 目录或者压缩包
  Method addAssetPath = manager.getClass().getMethod("addAssetPath", String.class);
  addAssetPath.invoke(manager, path);
  Resources appResources = getResources();
  Resources skinResources = new Resources(manager, appResources.getDisplayMetrics(), appResources.getConfiguration());
  • 获得资源文件的包名
 //获取外部Apk(皮肤包) 包名
 PackageManager packageManager = getPackageManager();
 PackageInfo packageArchiveInfo = packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
 String packageName = packageArchiveInfo.packageName;
  • 通过资源包名,获得资源包相应资源在R文件中的id值
    /**
     * 获取相应报名下面的资源文件
     * @return
     */
    private int getMyResource(Resources skinResources, int resId,String packagePath) {
        Log.e(TAG, "---------------------------------------");
        String resName =getResources().getResourceEntryName(resId);//test   /colorPrimaryDark
        String resType =getResources().getResourceTypeName(resId);//mipmap
        int identifier = skinResources.getIdentifier(resName, resType, packagePath); //test  mipmap   com.example.invoke
        Log.d(TAG, "identifier: " + identifier);
        return identifier;
    }
  • 获得资源文件的R.mipmap.test文件的drawable
     int myResource = getMyResource(skinResources, R.mipmap.test, packageName);
     Drawable drawable = skinResources.getDrawable(myResource);
  • 给imageview设置相应的drawable资源
ImageView imageview = findViewById(R.id.imageview);
imageview.setImageDrawable(drawable);

到这里,我们修改R.mipmap.test的资源,就算完成了

总结

注意事项

  1. 资源文件名字,属性必须一直
  2. 需要打开sdcard存储权

demo下载地址使用demo时候,需要将app_skin中生成的apk考入到sdcard中

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值