Android实现免安装APK插件(四)

4、 资源如何加载

在获取资源时,有三个重要的类Resources, AssetManager, Theme,我们通过Context获取它们的对象

@Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }

    @Override
    public Resources getResources() {
        return mResources;
}

    @Override
    public Resources.Theme getTheme() {
        synchronized (mSync) {
            if (mTheme != null) {
                return mTheme;
            }

            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                    getOuterContext().getApplicationInfo().targetSdkVersion);
            initializeTheme();

            return mTheme;
        }
}

我们要做的就是依葫芦画瓢重写这几个方法,构造自己对象。对于插件Activity,我们需要给它设置一个Resources,让其包含插件中的资源。但是,这里不能替换掉宿主应用中的Resources,不然宿主就出问题了。Resources的构造函数如下:

    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
        this(null);
        mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
    }

它需要三个对象,这里的关键是AssetManager,它可以通过addAssetPath制定资源所在apk的路径,而另外两个我们就用宿主的即可。这里我们需要自己创建一个AssetManager,由于addAssetPath是hide的,所以只能通过反射调用。

mDexAM = AssetManager.class.newInstance();
            Method method = mDexAM.getClass().getDeclaredMethod("addAssetPath", String.class);
            method.setAccessible(true);
            method.invoke(mDexAM, LoadDexUtils.getPlugApkPath());

接下来就可以构造一个Resources对象了

Resources res = getResources();
            mDexResources = new Resources(mDexAM, res.getDisplayMetrics(), res.getConfiguration());

上面的Theme获取要复杂些,不过我们也可以仿照获取

Class resources = Class.forName("android.content.res.Resources");
            Method selectDefaultTheme = resources.getDeclaredMethod("selectDefaultTheme", int.class, int.class);
            selectDefaultTheme.setAccessible(true);
            int defaultTheme = (Integer) selectDefaultTheme.invoke(mDexResources, 0, getApplicationInfo().targetSdkVersion);
            mDexTheme = mDexResources.newTheme();
            mDexTheme.applyStyle(defaultTheme, true);

我们重写了Application的getResources、getTheme、getAssets方法,返回以上新创建的对象,而对应的插件Activity也重写以上三个方法:

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

    @Override
    public Resources.Theme getTheme() {
        return getApplication() == null ? super.getTheme() : getApplication().getTheme();
    }

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

到这里,插件Activity就可以正常启动了,最终实现无需安装APK,就可以实现插件化了。

代码路径:
https://github.com/rhythmjay/Plug-Activity.git

猜你喜欢

转载自blog.csdn.net/rhythmjay/article/details/80705838
今日推荐