EP7-资源替换

资源替换

前两回分析了如何动态加载dex并且执行里面的函数。这时候已经可以动态升级dex/apk了。那么apk的资源怎么动态替换呢。DexClassLoader只能加载dex,无法加载apk中的资源。

有的解决方案是,所有的XML呈现的布局全部用Java代码实现。这样做是可行的,真的有人在用,但很繁琐,比如分辨率等问题实现起来也会比较复杂。

dynamic-load-apk方案用的是这样的:
首先,Activity继承了Context,Context中有两个抽象方法:

/** Return an AssetManager instance for your application's package. */
/** 为应用程序的包返回一个AssetManager实例。 */
public abstract AssetManager getAssets();

/** Return a Resources instance for your application's package. */
/** 为应用程序包返回一个Resources实例 */
public abstract Resources getResources();

context就是通过这两个方法在Activity中获取资源的。这两个方法的实现在ContextImpl中。getResuorces返回的resources是这样的:

Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
    if (displayId != Display.DEFAULT_DISPLAY
            || overrideConfiguration != null
            || (compatInfo != null && compatInfo.applicationScale
                    != resources.getCompatibilityInfo().applicationScale)) {
        //getTopLevelResources根据资源目录、分隔资源目录..等参数提供顶级资源给application
        resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                overrideConfiguration, compatInfo);
    }
}

我们也想通过getResources获取资源,那么可以模仿它这样来写。

  • 1.AssetManager中有addAssetsPath方法,参数可以是一个dircetory或者一个ZIP file。它里面有个native方法可以把资源加载到res中。

  • 2.嗯,然后用assetManager来反射调用(为什么addAssetPath是隐藏的API?)addAssetPath方法,参数是mDexPath,也就是外部apk的路径。如下。

addAssetPath.invoke(assetManager, mDexPath);
  • 3.然后用这个assetManager创建一个新的资源:
Resources superRes = super.getResources();  
mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),  
            superRes.getConfiguration());

最后,要覆写那两个抽象方法哦,不然的话会一直用父类默认得到的AssetManager和Resources:

@Override  
public AssetManager getAssets() {  
    return mAssetManager == null ? super.getAssets() : mAssetManager;  
}  

@Override  
public Resources getResources() {  
    return mResources == null ? super.getResources() : mResources;  
}

大概就是这样了。

-NOV29

你可能感兴趣的:(EP7-资源替换)