Replugin Demo的简单使用与分析(二)

来源:互联网 发布:python重构是什么意思 编辑:程序博客网 时间:2024/06/08 11:21

参考资料: 插件的组件

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();                }
原创粉丝点击