getResource传入R.资源名称,通过资源名称可以找到对应的资源ID(通过R.java文件保证),之后AssetManager通过资源ID找到对应的资源文件名称(通过arsc文件保证)
插件和宿主使用aapt打包资源,aapt生成R和arsc文件是根据前缀信息(在aapt逻辑中apk默认为0X71)和资源顺序来进行命名的
因此会出现同一个资源ID在插件和宿主中都有对应的资源文件系统会出错。因此我们需要修改前缀即可保证,修改哪些前缀信息呢:
根据上面的原理,可知道两种解决方案:
修改aapt脚本。我在aapt创建R,arsc文件时的源头上进行拦截,aapt使用我自定义的前缀这样出来的R文件和arsc文件里面的前缀就会和宿主不一样。【默认0X71(系统会根据不同的包用不同的前缀信息),使用自定义生成的R和arsc使用我自定义的前缀】
我在aapt打包后进行修改替换R和arsc文件。需要在aapt第一步整理生成对应的R.java(对应编译类型会生成不同的R文件varint)进行拦截,捕获原始的r.java文件修改之后编译为class存储起来。 之后再javac的过程中使用我们的这个class文件,取出arsc文件修改对应的前缀。
简单直接,只需修改aapt中使用资源前缀的逻辑增加新case就好
缺点是需要进行修改aapt文件且不同SDK版本都需要生成一个aapt文件与之对应。
只需简单修改task名字即可,不需要根据不同sdk平台生成不同的aapt。复用性强。
缺点:需要修改的地方较多:1.生成R.java时还须修改完再次手动调用javac编译为class存储2.进行javac时在用之前生成的class。对arsc文件进行修改
方案二 不修改aapt,在打包后进行资源id冲突处理。将插件资源前缀改为0X71,72等 可自定义的数字防止资源冲突:同一个资源ID对应多个资源文件
很多情况下插件和宿主中的默认文件夹里面放的都是相同的资源比如android自动生成的那些图片等,占据着很多空间很少是自己独有的。
因此可以进行优化,提炼出一份名单位于这个名单里面的资源可以进行删除,时机是在生成我们修改后的R.java文件时我们可以根据这个名单删除对应资源 该方案是基于方案二提出的(方案一也可以进行该处理,只不过方案二更顺理成章).该方案已有开源框架实现~。
(默认的aapt在决定使用前缀时会进行case判断系统,library,apk然后使用不同的前缀。 方案一是对aapt进行修改,使用aapt时新增Bundle参数携带前缀信息,在使用前缀时增加新case,取出Bundle中的前缀信息,使用传入的前缀)。