美文网首页
Android插件化资源冲突

Android插件化资源冲突

作者: AntCoding | 来源:发表于2018-12-09 19:52 被阅读0次
timg.jpg

导 语

Android插件化一个重要问题就是插件资源访问,这也是面试官主要问及一个主要方面。在京东面试问到这个问题时回答的模模糊糊导致与我的人生转折点擦肩而过。哀哉!痛哉!
接下来我们就好好的深入研究一下这个话题吧!

问题列举

1.插件中资源是如何被加载的?
2.如何处理插件资源与宿主资源冲突?

原理分析

  • 资源链分析

这里我们将一个重要的概念 "上下文环境",也就是我们最最最常用的 Context 这是一个神奇的变量无论我们启动Activity、启Service也好都离不开Context , 包括我们要讲的加载资源同样也无法逃脱的它的魔爪.
资源链递进分析
  • context只是一个抽象类,其真正的实现类是ContextImpl
  • ContextImpl中有一个Resources成员变量mResources,可通过getResources()获取.
  • Resources内部的重要成员AssetManager,它可以指定APK的资源路径,最终通过AssetManager获取资源.

插件中的资源是如何被加载的呢?

1.封装反射管理类 RefInvoker.java

@SuppressWarnings("unchecked")
public class RefInvoker {
private static HashMap<String, Class> clazzCache = new HashMap<String, Class>();

    public static Class forName(String clazzName) throws ClassNotFoundException {
        Class clazz = clazzCache.get(clazzName);
        if (clazz == null) {
            clazz = Class.forName(clazzName);
            ClassLoader cl = clazz.getClassLoader();
            if (cl == system || cl == application || cl == bootloader) {
                clazzCache.put(clazzName, clazz);
            }
        }
        return clazz;
    }

public static Object invokeMethod(Object target, String className, String methodName, Class[] paramTypes,
            Object[] paramValues) {

        try {
            Class clazz = forName(className);
            return invokeMethod(target, clazz, methodName, paramTypes, paramValues);
        }catch (ClassNotFoundException e) {
            LogUtil.printException("ClassNotFoundException", e);
        }
        return null;
    }

    public static Object invokeMethod(Object target, Class clazz, String methodName, Class[] paramTypes,
                                      Object[] paramValues) {
        try {
            Method method = clazz.getDeclaredMethod(methodName, paramTypes);
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            return method.invoke(target, paramValues);
        } catch (SecurityException e) {
            LogUtil.printException("SecurityException", e);
        } catch (IllegalArgumentException e) {
            LogUtil.printException("IllegalArgumentException", e);
        } catch (IllegalAccessException e) {
            LogUtil.printException("IllegalAccessException", e);
        } catch (NoSuchMethodException e) {
            //这个日志...
            LogUtil.e("NoSuchMethodException", methodName);
        } catch (InvocationTargetException e) {
            LogUtil.printException("InvocationTargetException", e);
        }
        return null;
    }
}

2.我们需要对AssetManager进行Hook,创建出一个代理类HookAssetManager.java

public class HookAssetManager {

    private static final String ClassName = "android.content.res.AssetManager";
    private static final String Method_addAssetPath = "addAssetPath";
    private static final String Method_ensureStringBlocks = "ensureStringBlocks";
  
    private Object instance;

    public HookAssetManager(Object instance) {
        this.instance = instance;
    }
     
    /**
     * 加载apk对应的资源
     * @param path Apk路径 此处为插件APK的路径
     */
    public void addAssetPath(String path) {
        RefInvoker.invokeMethod(instance, ClassName, Method_addAssetPath, new Class[]{String.class}, new Object[]{path});
    }
    /**
     * 初始化其内部参数
     * @return
     */
    public Object[] ensureStringBlocks() {
        return (Object[])RefInvoker.invokeMethod(instance,
                ClassName, Method_ensureStringBlocks, null, null);
    }
}

3.插件资源创建

AssetManager assetMgr = AssetManager.class.newInstance();
HookAssetManager hookAssetManager = new hookAssetManager(assetMgr);
hookAssetManager.addAssetPath(path);
hookAssetManager.ensureStringBlocks();

如何处理插件资源与宿主资源冲突?

我看了一些插件化框架发现它们的处理方式都是对资源ID的PP段进行修改. 即在aapt工具编辑前后修改PP段.
  • 定制aapt在编译阶段进行修改PP段.
  • 编译后期重新对插件APK资源ID进行重新组织编排.
两者之间的区别在于前者的侵入编译流程,维护起来很不方便 ; 后者只是对资源ID和对应的索引表resorce.arsc进行了修改,不入侵编译流程. 两者之间高下立判,我个人比较赞同第二种方式

This ALL! Thanks EveryBody!

相关文章

  • Android插件化资源冲突

    导 语 Android插件化一个重要问题就是插件资源访问,这也是面试官主要问及一个主要方面。在京东面试问到这个问...

  • 插件化资源加载

    插件化框架实现:基于kotlin的插件化框架 Android 资源访问 android通过aapt将资源编译成R....

  • 插件化主流框架在 Android 中的应用,你了解多少?

    插件化主流框架 在 Android 中实现插件化框架,需要解决的问题主要如下: 资源和代码的加载Android 生...

  • Android资源冲突检测插件

    背景 之前我们写了一篇定义关于如何定义Gradle插件,有兴趣的朋友可以看一下,今天我们就来简单讲一个自定义Gra...

  • Android 进阶解密阅读笔记20

    资源插件化 在 VirtualApk 框架里,资源插件化有两种方案, 合并资源 插件资源(即仅插件使用,插件不能访...

  • Android插件化中资源错乱的解决方案

    摘要 本文介绍了Android插件化框架中,插件使用宿主资源时资源错乱的问题,以及错乱的原因、业界通用解决方案、我...

  • 插件化研究之资源冲突

    最近在研究Android应用的插件化开发, 插件化都是在解决以下几个问题: 如何把插件apk中的代码和资源加载到...

  • Android插件化——资源加载

    前言 资源,是APK包体积过大的病因之一。插件化技术将模块解耦,通过插件的形式加载。插件化技术中,每个插件都能够作...

  • Android资源的插件化

    资源的查找过程 在android中查找资源分为以下两种方式: ContextImpl#getResource()#...

  • Android插件化-资源加载

    Android项目中的资源是通过R文件来索引的。打包的时候aapt将工程中的资源名与id在R.文件中映射起来。使用...

网友评论

      本文标题:Android插件化资源冲突

      本文链接:https://www.haomeiwen.com/subject/brpacqtx.html