参考资料: 插件的组件
Replugin Demo的简单使用与分析(二)主要分析demo1中RePlugin的用法。
其实Demo1最主要的主题就是:RePlugin的其中一个优势在于,开发RePlugin插件几乎和开发“单品”无异。
一、插件内可以标准的启动插件中的另一个Activity
(View v)
Intent intent = new Intent(v.getContext(), StandardActivity.class);
v.getContext().startActivity(intent);
二、插件内可以启动插件中的另一个没有标题栏的Activity,也就是theme设定了NoTitleBar ,
android:theme="@android:style/Theme.Black.NoTitleBar"
(View v)
Intent intent = new Intent(v.getContext(), ThemeBlackNoTitleBarActivity.class);
v.getContext().startActivity(intent);
三、插件内可以启动插件中的另一个没有标题栏且全屏的Activity,也就是theme设定了NoTitleBar.Fullscreen
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
(View v)
Intent intent = new Intent(v.getContext(), ThemeBlackNoTitleBarFullscreenActivity.class);
v.getContext().startActivity(intent);
四、插件内可以启动插件中的另一个theme为Dialog的Activity,也就是theme设定了Theme.Dialog
android:theme="@android:style/Theme.Dialog"
(View v)
Intent intent = new Intent(v.getContext(), ThemeDialogActivity.class);
v.getContext().startActivity(intent);
五、同理就不再贴代码了,同样能启动定义了launchMode、taskAffinity。以及通过intent的addCategory、Action来启动插件内的Activity。以及广播,service,provider参考demo即可。
六、启动宿主中的Activity
Intent intent = new Intent();
intent.setComponent(new ComponentName(RePlugin.getHostContext().getPackageName(), "com.qihoo360.replugin.sample.host.MainActivity"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.startActivity(intent);
七、调用宿主Host的方法
// 虽然不是很推荐(版本控制问题,见FAQ),但毕竟需求较大,且我们是“相对安全的共享代码”方案,故可以使用
final String curTime = TimeUtils.getNowString();
if (!TextUtils.isEmpty(curTime)) {
Toast.makeText(v.getContext(), "current time: " + TimeUtils.getNowString(), Toast.LENGTH_SHORT).show();
// 打印其ClassLoader
Log.d("MainActivity", "Use Host Method: cl=" + TimeUtils.class.getClassLoader());
} else {
Toast.makeText(v.getContext(), "Failed to obtain current time(from host)", Toast.LENGTH_SHORT).show();
}
这块的写法其实很有迷惑性。点开TimeUtils发现是demo1中的一个jar包,但实际调用的ClassLoader是”/data/app/com.qihoo360.replugin.sample.host-1/base.apk”。
发现使用的是宿主的TimeUtils方法。 此为RePlugin的一种做法,可直接调用宿主的Utils。实现的方式是:
1、在宿主中有该方法的实现,并将其制作为jar包
2、在demo1中以provided files的方式引用该jar包(provided files(‘libs/common-utils-lib-1.0.0.jar’)//这个jar就是从Host的utils中编译生成的,其目的是为了骗过编译期)
具体原理后面再分析(其实是后面等我研究一下)
八、插件demo1能直接开启插件demo2中的一个Activity
RePlugin.startActivity(v.getContext(), new Intent(), "demo2", "com.qihoo360.replugin.sample.demo2.activity.appcompat.AppCompatActivityDemo");
九、 demo1通过反射调用demo2的方法(推荐玩法):
ClassLoader cl = RePlugin.fetchClassLoader("demo2");
if (cl == null) {
Toast.makeText(v.getContext(), "Not install Demo2", Toast.LENGTH_SHORT).show();
return;
}
try {
Class clz = cl.loadClass("com.qihoo360.replugin.sample.demo2.MainApp");
Method m = clz.getDeclaredMethod("helloFromDemo1", Context.class, String.class);
m.invoke(null, v.getContext(), "Demo1");
} catch (Exception e) {
// 有可能Demo2根本没有这个类,也有可能没有相应方法(通常出现在"插件版本升级"的情况)
Toast.makeText(v.getContext(), "", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
这种调用方式是RePlugin推荐使用的方法,因为通过反射调用必然要try catch。能避免某插件修改类名或删除某方法造成的crash问题。
十、获取插件中的资源文件
//加载插件,并获取插件的资源信息
Resources res = RePlugin.fetchResources("demo2");
//获取布局from_demo1的资源id
int id = res.getIdentifier("com.qihoo360.replugin.sample.demo2:layout/from_demo1", null, null);
if (id == 0) {
Toast.makeText(v.getContext(), "from_demo1 Not Found", Toast.LENGTH_SHORT).show();
return;
}
// 这块儿得拿demo2的Context,才能Inflate到资源
View contentView = LayoutInflater.from(RePlugin.fetchContext("demo2")).inflate(id, null);
Dialog d = new Dialog(v.getContext());
d.setContentView(contentView);
d.show();
十一、获取获取插件定义的IBinder并用AIDL通信
IBinder b = RePlugin.fetchBinder("demo2", "demo2test");
if (b == null) {
return;
}
IDemo2 demo2 = IDemo2.Stub.asInterface(b);
try {
demo2.hello("helloooooooooooo");
} catch (RemoteException e) {
e.printStackTrace();
}