插件机制之资源管理

2018-10-17  本文已影响21人  搬砖写Bug

<未完成,待续>

获取未安装 apk (插件)的 Resource

因为没有安装,所以不能得到 context,所以我们需要未安装 apk 的 Resource,我们可以通过反射来获取,代码如下

    /** 
     * @param apkPath  
     * @return 得到对应插件的Resource对象 
     */  
    private Resources getPluginResources(String apkPath) {  
        try {  
            AssetManager assetManager = AssetManager.class.newInstance(); 
            //反射调用方法addAssetPath(String path)
            Method addAssetPath = assetManager.getClass().getMethod(ADDSSETPATH, String.class);  
            //将未安装的Apk文件的添加进AssetManager中,第二个参数是apk的路径  
            addAssetPath.invoke(assetManager, apkPath);
            Resources superRes = this.getResources();  
            Resources mResources = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());  
            return mResources;  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }

用DexClassLoader加载apk资源文件替换背景

    /** 
     * 加载apk获得内部资源,并且替换背景
     * @param apkDir apk目录 
     * @param apkName apk名字,带.apk 
     * @throws Exception 
     */  
    private void dynamicLoadApk(String apkPath, String apkPackageName) throws Exception {
        //在应用安装目录下创建一个名为app_dex文件夹目录,如果已经存在则不创建,这个目录主要是最优化目录,用于缓存dex文件
        File optimizedDirectoryFile = getDir(DEX, Context.MODE_PRIVATE); 
        //打印路径 理论上是/data/data/package/app_dex
        Log.v(TAG, optimizedDirectoryFile.getPath().toString());  
        //构建DexClassLoader
        DexClassLoader dexClassLoader = new DexClassLoader(apkPath, optimizedDirectoryFile.getPath(), null, ClassLoader.getSystemClassLoader());  
        //通过使用apk自己的类加载器,反射出R类中相应的内部类进而获取我们需要的资源id
        Class<?> clazz = dexClassLoader.loadClass(apkPackageName + DRAWABLE);  
        //得到名为about_log的这张图片字段,这个图片是为安装apk里面的图片
        Field field = clazz.getDeclaredField(IMAGE_ID); 
        //得到图片id  
        int resId = field.getInt(R.id.class);
        //得到插件apk中的Resource  
        Resources mResources = getPluginResources(apkPath);
        if (mResources != null) {  
            //通过插件apk中的Resource得到resId对应的资源  
            Drawable btnDrawable = mResources.getDrawable(resId);
            mLayout.setBackgroundDrawable(btnDrawable);   
        } else {
            Log.d(TAG, "mResources is null");
        }
    }

reference:
Android插件化开发之用DexClassLoader加载未安装的APK资源文件来实现app切换背景皮肤

上一篇下一篇

猜你喜欢

热点阅读