三、插件包plugin_package中,首先实现BaseActivity类
/** * @Author: ly * @Date: 2023/7/14 * @Description: 插件包中Activity基础类, 拿到宿主的上下文环境 */ public class BaseActivity extends Activity implements ActivityInterface { private static final String TAG = "BaseActivity"; /** * 宿主的环境 */ public Activity appActivity; @Override public void insertAppContext(Activity appActivity) { this.appActivity = appActivity; } @SuppressLint("MissingSuperCall") @Override public void onCreate(Bundle savedInstanceState) { String appName = savedInstanceState.getString("appName"); Log.i(TAG, "appName: " + appName); } @SuppressLint("MissingSuperCall") @Override public void onStart() { } @SuppressLint("MissingSuperCall") @Override public void onResume() { } @SuppressLint("MissingSuperCall") @Override public void onPause() { } @SuppressLint("MissingSuperCall") @Override public void onStop() { } @SuppressLint("MissingSuperCall") @Override public void onDestroy() { } public void setContentView(int resId) { appActivity.setContentView(resId); } public View findViewById(int id) { return appActivity.findViewById(id); } /** * 启动插件包内的第二个Activity:TestActivity * * @param intent 意图数据 */ public void startActivity(Intent intent) { Intent newIntent = new Intent(); newIntent.putExtra("className", intent.getComponent().getClassName()); appActivity.startActivity(newIntent); } public ComponentName startService(Intent serviceIntent) { Intent newIntent = new Intent(); //serviceIntent.getComponent().getClassName() 这里拿到的是TestService的全类名 newIntent.putExtra("className", serviceIntent.getComponent().getClassName()); return appActivity.startService(newIntent); } /** * 注册广播 * * @param receiver * @param intentFilter * @return */ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter) { return appActivity.registerReceiver(receiver, intentFilter); } /** * 发送广播 * * @param intent */ public void sendBroadcast(Intent intent) { appActivity.sendBroadcast(intent); } }
3.2 插件包中首页PluginActivity,代码如下
/** * 首先加载该页面PluginActivity */ public class PluginActivity extends BaseActivity { private static final String TAG = "PluginActivity"; private static final String ACTION = "com.example.plugin_package.ACTION"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String appName = savedInstanceState.getString("appName"); Log.i(TAG, "appName: " + appName); setContentView(R.layout.activity_plugin); Toast.makeText(appActivity, "我是插件", Toast.LENGTH_SHORT).show(); //点击按钮跳转到TestActivity findViewById(R.id.btn_start_activity).setOnClickListener(v -> { startActivity(new Intent(appActivity, TestActivity.class)); }); //点击按钮跳转到TestService findViewById(R.id.btn_start_service).setOnClickListener(v -> { startService(new Intent(appActivity, TestService.class)); }); //插件内部注册插件的广播接收者 findViewById(R.id.btn_register_receiver).setOnClickListener(v -> { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION); registerReceiver(new MyReceiver(), filter); }); //插件内部发送插件的广播接收者 findViewById(R.id.btn_send_receiver).setOnClickListener(v -> { Intent intent = new Intent(); intent.setAction(ACTION); sendBroadcast(intent); }); } }
3.3 点击PluginActivity中的按钮,可以跳转到TestActivity,代码如下:
public class TestActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); } }
3.4、BaseService类
/** * @Author: ly * @Date: 2023/7/15 * @Description: 基础Service继承标准库中ServiceInterface接口 */ public class BaseService extends Service implements ServiceInterface { private Service appService; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void insertAppContext(Service appService) { this.appService = appService; } @Override public void onCreate() { } @SuppressLint("WrongConstant") @Override public int onStartCommand(Intent intent, int flags, int startId) { return 0; } @Override public void onDestroy() { } }
3.5、TestService类
/** * @Author: ly * @Date: 2023/7/15 * @Description: 插件中的Service */ public class TestService extends BaseService { private static final String TAG = "TestService"; @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //开启子线程 new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } finally { Log.i(TAG, "插件里面的服务正在执行中!"); } } } }).start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); } }
3.6、插件中的广播接收者MyReceiver
/** * @Author: ly * @Date: 2023/7/15 * @Description: 插件中的广播接收者 */ public class MyReceiver extends BroadcastReceiver implements ReceiverInterface { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "我是插件里面的广播接收者,我收到了广播!", Toast.LENGTH_SHORT).show(); } }
一、这个是宿主APP启动插件Activity流程:
二、这个是插件中启动Activity的流程如下图:
三、下面是插件中启动Service的流程图如下:
四、插件中启动BroadcastReceiver,这是在插件中动态注册广播接收者,并在插件内部发送广播。
五、宿主app中获取插件包中静态注册的广播接收者StaticeReceiver,并在宿主app中发送静态广播请看这篇文章
Android手写占位式插件化框架之apk解析原理系统源码分析
六、编写代码后,将plugin_package包手动放到宿主app的私有目录下,便可以正常运行,在公司项目中会将插件包放到服务器用户使用某个功能模块的时候,会下载到本地。
七、具体问题思考
1、为什么在插件中不能使用this?
因为插件是没有在手机上安装的,是无法拥有组件环境的。
2、为什么要有代理的Activity?
由于插件中的Activity并不是一个能够运行的组件,所以需要代理的Activity去代替插件中的Activity(例如Activity进出栈)
3、这种插件化,在写插件开发的时候,有什么要注意的事项?
所有关于操作组件环境的地方,都必须使用宿主的环境。