从零开始实现一个插件化框架(三) - 完结篇

本文详细介绍了从零开始创建一个插件化框架的过程,包括如何替换资源加载器、处理不同API版本的适配以及解决AppCompatActivity相关问题。通过创建自定义AssetManager和Resources,实现了插件资源的加载,并在不同API版本下进行了适配,确保了框架的兼容性。此外,还提供了解决AppCompatActivity报错的方案,即在插件中加载自己的资源。
摘要由CSDN通过智能技术生成

final AssetManager assets = createAssetManager(key);

if (assets == null) {

return null;

}

final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);

final Configuration config = generateConfig(key, dm);

final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);

if (DEBUG) {

Slog.d(TAG, “- creating impl=” + impl + " with key: " + key);

}

return impl;

}

AssetManager是在这里创建的!它的功能不用多说了吧,可以加载任意路径下的资源,那么我们就自己创建一个AssetManager来替换掉原来的,怎么创建呢,继续看它怎么创建的

protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {

final AssetManager.Builder builder = new AssetManager.Builder();

// resDir can be null if the ‘android’ package is creating a new Resources object.

// This is fine, since each AssetManager automatically loads the ‘android’ package

// already.

if (key.mResDir != null) {

try {

// 添加 ApkAssets 对象,加载apk资源

builder.addApkAssets(loadApkAssets(key.mResDir, false /sharedLib/,

false /overlay/));

} catch (IOException e) {

Log.e(TAG, "failed to add asset path " + key.mResDir);

return null;

}

}

// 。。。

return builder.build();

}

可以看到,AssetManager在创建的时候,添加了一个ApkAssets对象,这里好像无从下手。怎么办?其实看过API26的同学都知道,AssetManager中有一个addAssetPath方法,在API26以前,都是通过这个方法创建的,虽然这个方法 现在被标记为过时了,但还是可以反射到的。

插件资源加载

下面我们就来撸码,替换掉插件的资源加载器:

fun loadAsset(context: Context): Resources? {

try {

// 创建AssetManager对象

val assetManager = AssetManager::class.java.newInstance()

// 执行addAssetPath方法,添加资源加载路径

val addAssetPathMethod =

assetManager::class.java.getDeclaredMethod(“addAssetPath”, String::class.java)

addAssetPathMethod.isAccessible = true

addAssetPathMethod.invoke(assetManager, “sdcard/plugin-debug.apk”)

// 创建Resources

return Resources(

assetManager,

context.resources.displayMetrics,

context.resources.configuration

)

} catch (e: Exception) {

e.printStackTrace()

}

return null

}

在这里我们创建一个插件的资源加载器,然后在应用启动的时候替换掉,在Application中:

class DynamicApp : Application() {

// 插件的资源

private var mResources: Resources? = null

override fun onCreate() {

super.onCreate()

// 获取插件的资源

mResources = LoadUtils.loadAsset(this)

}

// 在这里重写getResources方法进行替换

override fun getResources(): Resources {

if (mResources == null) {

return super.getResources()

}

return mResources!!

}

}

在宿主里面替换完成,插件里面要使用宿主的Resources怎么办?很简单,直接使用application的Resources不就可以了吗。因为插件中的类是会合并到宿主的,所以他们的Application是相同的。

所以可以在插件里面创建一个BaseActivity, 重写getResources方法,让它使用application中的:

abstract class BaseActivity : Activity() {

override fun getResources(): Resources {

if (application != null && application.resou

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值