插件化开发是将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。由宿主APP去加载以及运行插件APP。
处境:开放出来的插件化开发框架比较多,他们各自都有自己的优势和和不足,实现的原理也有差别下面列举开源的插件化框架
https://github.com/Qihoo360/DroidPlugin
https://github.com/CtripMobile/DynamicAPK
https://github.com/mmin18/AndroidDynamicLoader
https://github.com/singwhatiwanna/dynamic-load-apk
https://github.com/houkx/android-pluginmgr
https://github.com/bunnyblue/ACDD
https://github.com/wequick/Small
此外存在缺点,插件化开发的APP不能在Google Play上线,也就是没有海外市场。
这里新建2个application:app包、otherapk包,以及一个library:plugin包
其中app包作为插件化宿主,作为apk的入口。otherapk作为第三方apk包,用于生成符合插件化开发标准的插件apk,不参与宿主的编译。plugin实现加载第三方apk的功能,并制定插件化开发的约束规范。
在这里,我们跳转到plugin包中的代理activity(ProxyActivity)中,传递全局的Context参数,第三方插件apk的SD卡路径(这个插件apk由other包生成),以及需要ProxyActivity代理的插件apk的页面(例如liuxingyu.otherapk.PluginMainActivity,这个可以由PluginManager动态查找得到)。
public void startApk(View view) {
/**
* 加载插件
*/
//设置上下文
PluginManager.getInstance().setContext(getApplicationContext());
//加载第三方插件apk 传入第三方插件apk的绝对路径
PluginManager.getInstance().loadApk(Environment.getExternalStorageDirectory().getAbsolutePath() + "/otherapk-debug.apk");
/**
* 跳转到代理Activity中去
*/
Intent intent = new Intent(this, ProxyActivity.class);
String otherApkMainActivityName = PluginManager.getInstance().getPluginPackageArchiveInfo().activities[0].name;
intent.putExtra("className", otherApkMainActivityName);
startActivity(intent);
}
这里我们新建简单页面,继承于plugin包中的BaseActivity,使之符合插件化开发规范。然后在开发工具中选中otherapk包,点击build -> Make Module ‘otherapk’,并将生成的包放到对应SD卡目录中
public class PluginMainActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plugin_main);
TextView textView=that.findViewById(R.id.textView);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(that,SecondActivity.class);
startActivity(intent);
}
});
}
}
这里是整个插件化开发能够运行的重点。这里首先我们需要实现app包中跳转过来的ProxyActivity,并接收传递过来的className参数。然后根据className参数从插件apk中查找到所要代理的activity类class。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//拿到要启动的Activity
String className = getIntent().getStringExtra("className");
try {
//加载该Activity的字节码对象
Class> aClass = PluginManager.getInstance().getPluginDexClassLoader().loadClass(className);
//创建该Activity的示例
Object newInstance = aClass.newInstance();
//是否遵循了我们的标准
if (newInstance instanceof PluginInterface) {
pluginInterface = (PluginInterface) newInstance;
//将代理Activity的上下文 传入到插件Apk中的activity里面
pluginInterface.attach(this);
//创建bundle用来与三方apk传输数据
Bundle bundle = new Bundle();
//去执行插件APK中的activity的onCreate
pluginInterface.onCreate(bundle);
}
} catch (Exception e) {
e.printStackTrace();
}
}
这里我们要实现ProxyActivity,最重要的功能就是实现PluginManager的插件化管理。我们用PluginManager来接收宿主apk传递过来的Context与插件apk的路径,进而可以获取到插件apk的资源与类。
public class PluginManager {
private static PluginManager ourInstance = new PluginManager();
private Context context;
private DexClassLoader pluginDexClassLoader;
private Resources pluginResources;
public PackageInfo getPluginPackageArchiveInfo() {
return pluginPackageArchiveInfo;
}
private PackageInfo pluginPackageArchiveInfo;
public static PluginManager getInstance() {
return ourInstance;
}
private PluginManager() {
}
public void setContext(Context context) {
this.context = context.getApplicationContext();
}
public void loadApk(String dexPath) {
//(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent)
pluginDexClassLoader = new DexClassLoader(dexPath, context.getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(), null, context.getClassLoader());
pluginPackageArchiveInfo = context.getPackageManager().getPackageArchiveInfo(dexPath, PackageManager.GET_ACTIVITIES);
//Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
AssetManager assets = null;
try {
assets = AssetManager.class.newInstance();
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
addAssetPath.invoke(assets, dexPath);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
pluginResources = new Resources(assets, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
}
public DexClassLoader getPluginDexClassLoader() {
return pluginDexClassLoader;
}
public Resources getPluginResources() {
return pluginResources;
}
}
这里我们通过PluginManager获取到的插件apk中的类让ProxyActivity直接代理并不可行,因为插件apk中的this上下文并不存在,所以我们需要让插件apk上下文使用ProxyActivity中的context上下文。
public class BaseActivity extends FragmentActivity implements PluginInterface {
//主APK的引用对象 也就是说 所有插件apk中用到上下文的地方都是用代理Activity的上下文代替(that)
protected Activity that;
@Override
public void setContentView(int layoutResID) {
that.setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
that.setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
that.setContentView(view, params);
}
@Override
public LayoutInflater getLayoutInflater() {
return that.getLayoutInflater();
}
@Override
public Window getWindow() {
return that.getWindow();
}
@Override
public View findViewById(int id) {
return that.findViewById(id);
}
@Override
public void attach(Activity activity) {
that = activity;
}
@Override
public ClassLoader getClassLoader() {
return that.getClassLoader();
}
@Override
public WindowManager getWindowManager() {
return that.getWindowManager();
}
@Override
public ApplicationInfo getApplicationInfo() {
return that.getApplicationInfo();
}
@Override
public void finish() {
that.finish();
}
@SuppressLint("MissingSuperCall")
@Override
public void onCreate(Bundle savedInstanceState) {
}
@SuppressLint("MissingSuperCall")
@Override
public void onStart() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onResume() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onRestart() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onPause() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onStop() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onDestroy() {
}
@SuppressLint("MissingSuperCall")
@Override
public void onSaveInstanceState(Bundle outState) {
}
public boolean onTouchEvent(MotionEvent event) {
return false;
}
public void onBackPressed() {
that.onBackPressed();
}
@Override
public void startActivity(Intent intent) {
that.startActivity(intent);
}
}
https://download.csdn.net/download/liuxingyuzaixian/12146022