资源的插件化
--摘自《android插件化开发指南》
1.android资源文件分为两类:
第一类是res目录下存放的可编译资源文件,编译时,系统会自动在R.java中生成资源文件的十六进制值
Resources resources = getResources();
String appName = resources.getString(R.string.app_name);
第二类是assets目录下存放的原始资源文件,apk在编译时不会编译assets下的资源文件
Resources resources = getResources();
AssetManager am = getResources().getAssets();
InputStream is = getResources().getAssets().open("filename");
2.Resources内部各种方法其实都是间接调用AssetManager的内部方法。AssetManager的addAssetPath方法会在app启动的时候把当前apk的路径传进去,就能访问apk的所有资源了。在这里可以把插件apk的资源塞进去
3.apk打包时会生成一个resource.arsc文件,它就是一个Hash表,存放着每个十六进制值和资源的对应关系
***资源的插件化解决方案***
public class Dynamic implements IDynamic {
@Override
public String getStringForResId(Context context) {
return context.getResources().getString(R.string.myplugin1_hello_world);
}
}
<resources>
<string name="app_name">Plugin1</string>
<string name="myplugin1_hello_world">myplugin1_hello_world</string>
</resources>
public class BaseActivity extends Activity {
private AssetManager mAssetManager;
private Resources mResources;
private Resources.Theme mTheme;
private String dexpath = null; //apk文件地址
private File fileRelease = null; //释放目录
protected DexClassLoader classLoader = null;
private String pluginName = "plugin1.apk";
TextView tv;
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
Utils.extractAssets(newBase, pluginName);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//第三步:加载外部的插件,生成插件对应的ClassLoader
File extractFile = this.getFileStreamPath(pluginName);
dexpath = extractFile.getPath();
fileRelease = getDir("dex", 0);
classLoader = new DexClassLoader(dexpath, fileRelease.getAbsolutePath(), null, getClassLoader());
}
/**
* 第一步:通过反射,创建AssetManager对象,调用addAssetPath方法,把插件Plugin的路径添加到这个AssetManager对象中
**/
protected void loadResources() {
try {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, dexpath);
mAssetManager = assetManager;
} catch (Exception e) {
e.printStackTrace();
}
Resources superRes = super.getResources();
superRes.getDisplayMetrics();
superRes.getConfiguration();
mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
mTheme = mResources.newTheme();
mTheme.setTo(super.getTheme());
}
/**
* 第二步:重写Acitivity的getAsset,getResources和getTheme方法
**/
@Override
public AssetManager getAssets() {
return mAssetManager == null ? super.getAssets() : mAssetManager;
}
@Override
public Resources getResources() {
return mResources == null ? super.getResources() : mResources;
}
@Override
public Resources.Theme getTheme() {
return mTheme == null ? super.getTheme() : mTheme;
}
}
public class MainActivity extends BaseActivity {
TextView tv;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_6 = (Button) findViewById(R.id.btn_6);
tv = (TextView)findViewById(R.id.tv);
//带资源文件的调用
btn_6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
loadResources();
Class mLoadClassDynamic = null;
try {
//第四步:通过反射,获取插件中的类,构造出插件类的对象dynamicObject,然后就可以让插件中的类读取插件中的资源了
mLoadClassDynamic = classLoader.loadClass("jianqiang.com.plugin1.Dynamic");
Object dynamicObject = mLoadClassDynamic.newInstance();
IDynamic dynamic = (IDynamic) dynamicObject;
String content = dynamic.getStringForResId(MainActivity.this);
tv.setText(content);
Toast.makeText(getApplicationContext(), content + "", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("DEMO", "msg:" + e.getMessage());
}
}
});
}
}
还有换肤
欢迎关注我的微信公众号:安卓圈
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2017-12-11 Android Studio奇技淫巧