系列文章
占位式插件化一Activity的跳转
占位式插件化二Service的启动
占位式插件化三BroadcastReceive的注册与接收
占位式插件化四静态BroadcastReceiver的注册
占位式插件化的本质,就是用代理Activity或者Service使用插件app中的资源或者方法,从而达到执行插件APP的目的。
仿照Activity的跳转,可以知道启动插件APP中的Service,需要新增以下几个类,ServiceInterface做协议支持,BaseService实现ServiceInterface接口,ProxyService在宿主APP中占位,通过ProxyService即可启动插件APP中的Service,与其说启动了插件APP中的Service,不如说调用了插件APP中Service的方法。这时候插件APP中的Service也就只是一个普通的类,而不是安卓的四大组件之一的Service。
接口协议
public interface ServiceInterface {
void insertAppService(Service appService);
int onStartCommand(Intent intent, int flags, int startId);
void onCreate();
}
插件APP的BaseService
public class BaseService implements ServiceInterface {
protected Service appService;
@Override
public void insertAppService(Service appService) {
this.appService = appService;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return 0;
}
@Override
public void onCreate() {
}
}
通过insertAppService这个方法,将宿主APP的Service注入,从而能够使用这个对象执行功能。
插件APP的TestService
public class TestService extends BaseService {
private static final String TAG = TestService.class.getSimpleName();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
} finally {
Log.i(TAG, "插件中的Service正在执行.....");
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
TestService中写了一个死循环打印log,如果启动了这个Service之后能打印出Log,即启动插件Service成功。
宿主APP的ProxyService
public class ProxyService extends Service {
public ProxyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String className = intent.getStringExtra("className");
try {
Class<?> clazz = PluginManager.getInstance().getDexClassLoder().loadClass(className);
Object o = clazz.newInstance();
ServiceInterface serviceInterface = (ServiceInterface) o;
// 注入
serviceInterface.insertAppService(this);
Bundle bundle = new Bundle();
bundle.putString("appName", "我是宿主传递过来的信息");
// 执行插件里面的onStartCommand方法
serviceInterface.onStartCommand(intent, flags, startId);
} catch (Exception e) {
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
}
使用插件APP的类加载器加载指定的Service.class,然后构造其对象,转换成标准ServiceInterface 对象之后,就可以调用注入方法,将本Service注入到插件APP中。 然后调用onStartCommand方法,执行插件APP的onStartCommand方法。
插件APP中启动插件APP的Service
在上篇文章中提到的PluginActivity增加按钮,并且增加点击事件
findViewById(R.id.btn_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(appActivity, TestService.class);
startService(intent);
}
});
代码要调用宿主APP的startService方法
public void startService(Intent intent) {
Intent proxyIntent = new Intent();
proxyIntent.putExtra("className", intent.getComponent().getClassName());
appActivity.startService(proxyIntent);
}
并且将要启动的Service的全限定名传过去,这样可以通过反射构造其对象。
@Override
public ComponentName startService(Intent service) {
String className = service.getStringExtra("className");
Intent proxyIntent = new Intent(this, ProxyService.class);
proxyIntent.putExtra("className", className);
return super.startService(proxyIntent);
}
宿主APP的ProxyActivity重写startService方法,将启动宿主APP的ProxyService,并且将启动的插件APP的Service的全限定名传入。最后由ProxyService执行插件APP中Service的方法。完成再插件APP中启动插件Service。