思路:打开插件包里边的activity时 统一都用 一个ProxyActivity作为代理
1、首先宿主APP提供ProxyActivity,当宿主需要打开插件包中的Activity时,一律是启动的ProxyActivity,
在启动ProxyActivity的intent中携带我们真正需要去打开的插件包中Activity的类全名。
public class ProxyActivity extends Activity { private IPluginActivity mPluginActivity;//用来接收插件包所有Activity的接口对象 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); String className = getIntent().getStringExtra("className"); try { Class activityClass = getClassLoader().loadClass(className); Constructor constructor = activityClass.getConstructor(new Class[]{}); Object instance = constructor.newInstance(new Object[]{}); mPluginActivity = (PluginBaseActivity) instance; mPluginActivity.onCreate(savedInstanceState); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onStart() { super.onStart(); mPluginActivity.onStart(); } @Override protected void onResume() { super.onResume(); mPluginActivity.onResume(); } @Override protected void onPause() { super.onPause(); mPluginActivity.onPause(); } @Override protected void onStop() { super.onStop(); mPluginActivity.onStop(); } @Override protected void onDestroy() { super.onDestroy(); mPluginActivity.onDestroy(); } }
在Activity中有很重要的两个回调方法:
@Override public ClassLoader getClassLoader() { return PluginManager.getInstance().getPluginBean().getDexClassLoader(); } @Override public Resources getResources() { return PluginManager.getInstance().getPluginBean().getResources(); }
- getClassLoader返回的是ClassLoader 对象,Activity内部在使用反射new对象时,都会去使用这里返回的ClassLoader 来进行反射,所以我们ProxyActivity中需要提供的应该是当前加载插件包对应的ClassLoader 。
- getResources返回的是Resources 对象,Activity内部在使用资源文件时,都会去使用这里返回的Resources 来获取资源,所以我们ProxyActivity中需要提供的应该是当前加载插件包对应的Resources 。
File pluginFile;//插件包文件 PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginFile.getAbsolutePath(), PackageManager.GET_ACTIVITIES); File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE); DexClassLoader dexClassLoader = new DexClassLoader(pluginFile.getAbsolutePath(), dexOutFile.getAbsolutePath() , null, context.getClassLoader()); AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, pluginFile.getAbsolutePath()); Resources resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
PackageInfo 可以获取插件包manifest中所有注册了的组件信息,例如主Activity的全类名的获取为:
packageInfo.activities[0].name
下面是完整的
public abstract class PluginBaseActivity extends AppCompatActivity implements IPluginActivity { protected Activity that;//宿主Activity @Override public void attach(ProxyActivity proxyActivity) { if (that != null) throw new RuntimeException("Plugin's activity already has been attached!"); this.that = proxyActivity; attachBaseContext(proxyActivity); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { if (that == null) { super.onCreate(savedInstanceState); } } @Override public void onStart() { if (that == null) { super.onStart(); } } @Override public void onResume() { if (that == null) { super.onResume(); } } @Override public void onPause() { if (that == null) { super.onPause(); } } @Override public void onStop() { if (that == null) { super.onStop(); } } @Override public void onDestroy() { if (that == null) { super.onDestroy(); } } @Override public void onSaveInstanceState(Bundle outState) { if (that == null) { super.onSaveInstanceState(outState); } } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { if (that == null) { super.onRestoreInstanceState(savedInstanceState); } } @Override public boolean onTouchEvent(MotionEvent event) { if (that == null) { return super.onTouchEvent(event); } return false; } @Override public void onBackPressed() { if (that == null) { super.onBackPressed(); } } @Override public void setContentView(View view) { if (that == null) { super.setContentView(view); } else { that.setContentView(view); } } @Override public void setContentView(int layoutResID) { if (that == null) { super.setContentView(layoutResID); } else { that.setContentView(layoutResID); } } @Override public void startActivity(Intent intent) { if (that == null) { super.startActivity(intent); } else {//篡改intent打开页面为proxyActivity intent.putExtra("className", intent.getComponent().getClassName()); intent.setClassName(intent.getComponent().getPackageName(), ProxyActivity.class.getName()); that.startActivity(intent); } } @Override public ComponentName startService(Intent intent) { if (that == null) { return super.startService(intent); } else { intent.putExtra("className", intent.getComponent().getClassName()); intent.setClassName(intent.getComponent().getPackageName(), ProxyService.class.getName()); return that.startService(intent); } } @Override public View findViewById(int id) { if (that == null) { return super.findViewById(id); } else { return that.findViewById(id); } } @Override public Intent getIntent() { if (that == null) { return super.getIntent(); } else { return that.getIntent(); } } @Override public Window getWindow() { if (that == null) { return super.getWindow(); } else { return that.getWindow(); } } @Override public WindowManager getWindowManager() { if (that == null) { return super.getWindowManager(); } else { return that.getWindowManager(); } } }
public interface IPluginActivity { void attach(ProxyActivity proxyActivity); void onCreate(@Nullable Bundle savedInstanceState); void onStart(); void onResume(); void onPause(); void onStop(); void onDestroy(); void onSaveInstanceState(Bundle outState); void onRestoreInstanceState(Bundle savedInstanceState); boolean onTouchEvent(MotionEvent event); void onBackPressed(); void setContentView(View view); void setContentView(int layoutResID); void startActivity(Intent intent); ComponentName startService(Intent intent); View findViewById(int id); Intent getIntent(); Window getWindow(); WindowManager getWindowManager(); }
以上步骤实则每次新打开的插件里的页面其实都是ProxyActivity 做的代理