dodola

概述

VitrualAPK 是滴滴开源的一款插件化框架

VirtualAPK 地址:https://github.com/didi/VirtualAPK

前两天鸿洋分析了插件的四大组件启动流程,这里针对一些具体的点分析一下。

本篇先从资源下手分析。VirtualAPK的插件资源加载分为两种方式:

一种是插件存在一份独立的 Resources 自己使用,一种是COMBINE_RESOURCES模式,将插件的资源全部添加到宿主的 Resources

首先我们要先看一下系统是如何加载资源的。

Android 资源加载

此处简单探讨一下Android系统里资源加载查找的过程,这是插件加载资源的理论基础。

Resources对象的生成

从下向上一直可以追溯到生成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 资源加载

在VirtualAPK里插件所有相关的内容都被封装到LoadedPlugin里,插件的加载行为一般都在这个类的构造方法的实现里,我们这里只关注与资源相关部分的代码