dodola
VitrualAPK 是滴滴开源的一款插件化框架
VirtualAPK 地址:https://github.com/didi/VirtualAPK
前两天鸿洋分析了插件的四大组件启动流程,这里针对一些具体的点分析一下。
本篇先从资源下手分析。VirtualAPK的插件资源加载分为两种方式:
一种是插件存在一份独立的 Resources
自己使用,一种是COMBINE_RESOURCES
模式,将插件的资源全部添加到宿主的 Resources
里
首先我们要先看一下系统是如何加载资源的。
此处简单探讨一下Android系统里资源加载查找的过程,这是插件加载资源的理论基础。
从下向上一直可以追溯到生成Resources
对象的地方
class ContextImpl extends Context {
//...
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration) {
//....
Resources resources = packageInfo.getResources(mainThread);
//....
}
//...
}
这里不去关注packageInfo
是如何生成的,直接跟踪到下面去.
public final class LoadedApk {
private final String mResDir;
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode, boolean registerPackage) {
final int myUid = Process.myUid();
aInfo = adjustNativeLibraryPaths(aInfo);
mActivityThread = activityThread;
mApplicationInfo = aInfo;
mPackageName = aInfo.packageName;
mAppDir = aInfo.sourceDir;
mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
// 注意一下这个sourceDir,这个是我们宿主的APK包在手机中的路径,宿主的资源通过此地址加载。
// 该值的生成涉及到PMS,暂时不进行分析。
// Full path to the base APK for this application.
//....
}
//....
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
}
//....
}
进入到ActivityThread.getTopLevelResources()
的逻辑中
public final class ActivityThread {
Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {
//我们暂时只关注下面这一段代码
AssetManager assets = new AssetManager();
if (assets.addAssetPath(resDir) == 0) { //此处将上面的mResDir,也就是宿主的APK在手机中的路径当做资源包添加到AssetManager里,则Resources对象可以通过AssetManager查找资源,此处见(老罗博客:Android应用程序资源的查找过程分析)
return null;
}
// 创建Resources对象,此处依赖AssetManager类来实现资源查找功能。
r = new Resources(assets, metrics, getConfiguration(), compInfo);
}
}
从上面的代码中我们知道了我们常用的Resources
是如何生成的了,那么理论上插件也就按照如此方式生成一个Resources
对象给自己用就可以了。下面从VirtualAPK的代码里看一下对资源的处理
在VirtualAPK里插件所有相关的内容都被封装到LoadedPlugin
里,插件的加载行为一般都在这个类的构造方法的实现里,我们这里只关注与资源相关部分的代码