android插件化开发交流群,android插件化开发activity篇

现在都使用过支付宝吧,支付宝里边有好多功能就是采用插件化开发的,例如支付宝里边的小黄车,小蓝车等功能,都是采用的插件化做的。一开始我认为是WebView做的,

后来打开手机里的显示边框布局发现不是WebView,是原生的。他采用的是插件化加载第三方应用。

采用插件化开发的好处有宿主app与插件进行分开编译;并发开发节约时间和成本;按需要下载模块,但是第一次加载比较慢。

下边我们来讲解一下这个插件化开发:在进行插件化开发的时候要,有个桥梁将宿主APP和插件进行互相连接,这个连接也就是一个标准,那么这个标准是什么呢,就是一个

接口,让宿主app和插件都使用这套标准接口,这个接口就写有关activity的生命周期的方法。

/*** 两端都使用的标准* Created by yzl on 2017/10/10.*/public interfacePayInterface {

public voidonCreate(Bundle savedInstance);

public voidonStart();

public voidonResume();

public voidonPause();

public voidonStop();

public voidonDestroy();

public voidonSaveInstanceState(Bundle outState);

public booleanonTouchEvent(MotionEvent event);

public voidonBackPressed();

public voidattach(Activity activity);

}

标准接口写好了,然后进行写插件,我们这里写简单的插件,两个activity的展示。

在插件里我们要抽出一个基类activity,BaseActivity。让她继承activity并实现PayInterface. 插件中的主activity(mainactivity)继承BaseActivity。

现在mainactivity中要查找控件,使用this是不可以的,因为MainActivity.this是系统注入如入的上下文,插件只可以使用宿主注入的上下文也就是这里的that(所以

在接口中写里attach(Activity,activity),这个拿到的上下文就是宿主APP注入的上下文。

**** 重写关于上下文的父方法* Created by yzl on 2017/10/10.*/public classBaseActivty extendsActivity implementsPayInterface{

protectedActivity that;

@Overridepublic voidsetContentView(@LayoutResintlayoutResID) {

if(that== null){

super.setContentView(layoutResID);

}else{

that.setContentView(layoutResID);

}

}

@Overridepublic TfindViewById(intid) {

if(that== null){

return super.findViewById(id);

}else{

returnthat.findViewById(id);

}

}

@OverridepublicClassLoader getClassLoader() {

if(that== null){

return super.getClassLoader();

}else{

returnthat.getClassLoader();

}

}

@NonNull@OverridepublicLayoutInflater getLayoutInflater() {

if(that== null){

return super.getLayoutInflater();

}else{

returnthat.getLayoutInflater();

}

}

@OverridepublicWindow getWindow() {

if(that== null){

return super.getWindow();

}else{

returnthat.getWindow();

}

}

@OverridepublicWindowManager getWindowManager() {

if(that== null){

return super.getWindowManager();

}else{

returnthat.getWindowManager();

}

}

@Overridepublic voidonCreate(Bundle savedInstance) {

}

@Overridepublic voidonStart() {

}

@Overridepublic voidonResume() {

}

@Overridepublic voidonPause() {

}

@Overridepublic voidonStop() {

}

@Overridepublic voidonDestroy() {

}

@Overridepublic voidonSaveInstanceState(Bundle outState) {

}

@Overridepublic voidattach(Activity activity) {

this.that= activity;

}}public classMainActivity extendsBaseActivty implementsView.OnClickListener {

privateTextView tv_chajian;

@Overridepublic voidonCreate(Bundle savedInstance) {

super.onCreate(savedInstance);

setContentView(R.layout.activity_main);

tv_chajian= that.findViewById(R.id.tv_chajian);

}

}现在插件写好了,在说说宿主App。宿主app就是先加载在内存卡里存放的pak,然后找到要加载的activity的classname然后加载对应的class文件,在加载对应资源文件。

这里加载很明显分为四步,apk文件,classname,class文件,资源文件。加载apk我们简单现在不说明,现在说说其余三个。现在我们写一个插件管理器pluginManger

工具类,将类设计为单利的,保证对象的唯一性。找加载的第一个activity的classname,

File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);

dexClassLoader= newDexClassLoader(path,dexOutFile.getAbsolutePath(),null,context.getClassLoader());

PackageManager packageManager = context.getPackageManager();

PackageInfo packageInfo = packageManager.getPackageArchiveInfo(path,packageManager.GET_ACTIVITIES);

entryActivityName= packageInfo.activities[0].name;接下来在准备资源,利用反射的方法zhao daoAssetManager assetManager = AssetManager.class.newInstance();

Method addAssetPath = AssetManager.class.getMethod("addAssetPath",String.class);

addAssetPath.invoke(assetManager,path);

resources= newResources(assetManager,context.getResources().getDisplayMetrics(),context.getResources().getConfiguration());pluginManger工具类的代码如下:/*** Created by yzl on 2017/10/10.*/public classpluginManger {

privateContext context;

privateDexClassLoader dexClassLoader;

privateResources resources;

privateString entryActivityName;

private static finalpluginManger ourInstance= newpluginManger();

public staticpluginManger getInstance() {

returnourInstance;

}

privatepluginManger() {

}

public voidloadpath(String path){

File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);

dexClassLoader= newDexClassLoader(path,dexOutFile.getAbsolutePath(),null,context.getClassLoader());

PackageManager packageManager = context.getPackageManager();

PackageInfo packageInfo = packageManager.getPackageArchiveInfo(path,packageManager.GET_ACTIVITIES);

entryActivityName= packageInfo.activities[0].name;

Log.i("插件activity的classname",entryActivityName);

try{

AssetManager assetManager = AssetManager.class.newInstance();

Method addAssetPath = AssetManager.class.getMethod("addAssetPath",String.class);

addAssetPath.invoke(assetManager,path);

resources= newResources(assetManager,context.getResources().getDisplayMetrics(),context.getResources().getConfiguration());

} catch(Exception e) {

e.printStackTrace();

}

}

publicDexClassLoader getDexClassLoader() {

returndexClassLoader;

}

publicResources getResources() {

returnresources;

}

publicString getEntryActivityName() {

returnentryActivityName;

}

public voidsetContext(Context context) {

this.context= context.getApplicationContext();

}

}现在要加载的class文件的名字与资源都准备好了,接下来去加载对应的class文件,并显示。name宿主APP显示一个界面,那就必须的有容器去放置这个内容,那么我们去插件一个宿主activity(ProxyActivity)className= getIntent().getStringExtra("classname");//得到要加载的全类名

Class activityClazz = getClassLoader().loadClass(className);

Constructor constructor = activityClazz.getConstructor(newClass[]{});//创建构造方法

Object instance = constructor.newInstance(newObject[]{});

payInterface= (PayInterface) instance;//将得到的实力转化为标准的接口类型

payInterface.attach(this);

Bundle bundle = newBundle();//创建bundle对象便于传递参数

payInterface.onCreate(bundle);//创建这样界面还是空白的因为她还没有生命周期,我们要将对应的生命周期加上就完美了。/*** Created by yzl on 2017/10/10.*/public classProxyActivity extendsActivity {

privateString className;//要跳转的activityprivatePayInterface payInterface;

@Overrideprotected voidonCreate(@NullableBundle savedInstanceState) {

super.onCreate(savedInstanceState);

className= getIntent().getStringExtra("classname");//得到要加载的全类名Log.i("传递过来的class名称为",className);

try{

Class activityClazz = getClassLoader().loadClass(className);

Constructor constructor = activityClazz.getConstructor(newClass[]{});

Object instance = constructor.newInstance(newObject[]{});

payInterface= (PayInterface) instance;

payInterface.attach(this);

Bundle bundle = newBundle();

payInterface.onCreate(bundle);

} catch(Exception e) {

e.printStackTrace();

}

//利用反射加载class对应的class文件//因为插件不在art虚拟机里安装的,所以直接使用凡事是找不到class文件的,//这个类所加载的class都是插件中的class,不能是宿主中的class,所以要重写getclassloader();}

@Overrideprotected voidonStart() {

super.onStart();

payInterface.onStart();

}

@Overrideprotected voidonResume() {

super.onResume();

payInterface.onResume();

}

@Overrideprotected voidonPause() {

super.onPause();

payInterface.onPause();

}

@Overrideprotected voidonStop() {

super.onStop();

payInterface.onStop();

}

@Overrideprotected voidonDestroy() {

super.onDestroy();

payInterface.onDestroy();

}

@OverridepublicClassLoader getClassLoader() {

returnpluginManger.getInstance().getDexClassLoader();

//由于super是系统注入的上下文(也就是本宿主的上下文)xi}

@OverridepublicResources getResources() {

returnpluginManger.getInstance().getResources();

}

@Overridepublic voidstartActivity(Intent intent) {

String twoActivityClass = intent.getStringExtra("className");

Intent intent1 = newIntent(this,ProxyActivity.class);

intent1.putExtra("classname",twoActivityClass);

super.startActivity(intent1);

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值