文章首发:Android应用程序插件化研究之DexClassLoader|大利猫
最近在研究Android应用的插件化开发,看了好几个相关的开源项目。插件化都是在解决以下几个问题:
就这几个问题,我开始研究插件化开发实现的相关技术。在上篇文章中我讲了如何把插件apk中的class加载到当前进程的问题,本篇文章主要讲第一点的第二点:如何加载另一个apk中的资源到当前应用中。
/** Add an additional set of assets to the asset manager. * This can be either a directory or ZIP file. * Not for use by applications. Returns the cookie of the added asset, * or 0 on failure. *@{hide} */ public native final int addAssetPath(String path);
AssetManager assetManager = AssetManager.class.newInstance() ; // context .getAssets()? AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(assetManager, apkPath);
拷贝到测试机文件路径下:$ adb push <你的路径>/apkbeloaded-debug.apk sdcard/
在布局文件中定义一个文本控件和一个图片控件,分别用来显示插件中获取的文本和图片。
<ImageView android:layout_width="wrap_content" android:src="@mipmap/ic_launcher" android:id="@+id/icon" android:layout_height="wrap_content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/text" android:text="Hello World!" android:layout_below="@+id/icon" android:layout_centerInParent="true" />
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView imageView = (ImageView) findViewById(R.id.icon); TextView textView = (TextView) findViewById(R.id.text); /** * 插件apk路径 */ String apkPath = Environment.getExternalStorageDirectory()+"/apkbeloaded-debug.apk"; /** * 插件资源对象 */ Resources resources = getBundleResource(this,apkPath); /** *获取图片资源 */ Drawable drawable = resources.getDrawable(resources.getIdentifier("icon_be_load", "drawable", "laodresource.demo.com.apkbeloaded")); /** * 获取文本资源 */ String text = resources.getString(resources.getIdentifier("text_beload","string", "laodresource.demo.com.apkbeloaded")); imageView.setImageDrawable(drawable); textView.setText(text); }
创建Resource对象:
public Resources getBundleResource(Context context, String apkPath){ AssetManager assetManager = createAssetManager(apkPath); return new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration()); }
private AssetManager createAssetManager(String apkPath) { try { AssetManager assetManager = AssetManager.class.newInstance(); AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke( assetManager, apkPath); return assetManager; } catch (Throwable th) { th.printStackTrace(); } return null; }
到这里,我们完成了插件研究的第一个问题:加载插件apk的class和资源。下一篇文章开始研究插件中的组件注册问题。
markdown