需求

为更方便的实现插件与宿主之间的通信,设计了一套基于URL的插件间通信服务

总体流程是:

1 实现Processor的receive函数提供服务,服务执行完成后,手动调用DispatchAgent的reply返回结果

2 注册Processor使得使用方能找到这个服务

3 使用方调用DispatchAgent的call函数调用服务,并在回调中接受结果

结构

该服务我们目前简称dispatch服务,它主要由俩方面构成
1. URI 
   dispatch服务路由
   uri是全局唯一的,优先注册的uri有效。
2. Processor
   Processor服务实现

使用

1. Processor实现

    1. public class UserInfoProcessor extends Processor {
    2.    private DispatchAgent agent=null;
    3.    public UserInfoProcessor(BundleContext context){
    4.        super(context);
    5.        this.agent=new DispatchAgent(context);
    6.    }
    7.    @Override
    8.    public void Receive(URI uri, HashMap<String, Object> parameter){
    9.        agent.reply(getMsgId(),"fail","no user_id");
    10.    }
    11.}
  • 这是一个最简单的Processor实现。
  • 它需要继承org.apkplug.Bundle.dispatch.Processor
  • 第9行代表回复,(dispatch需要显式回复调用)
  • Processor每一次调用都会new一个新的对象,因此这个类里面不适用来保存状态信息

2. 注册dispatch服务

1.代码方式注册:(注册使用的url建议:“apkplug://+你的插件名称+/+插件功能名称”)

DispatchAgent dispatchAgent=new DispatchAgent(BundleContext);
dispatchAgent.register(BundleContext,"apkplug://host/userinfo",UserInfoProcessor.class.getName());

2.plugin.xml中注册:

  • 代码注册适合与宿主中注册服务,提供给插件调用
  • plugin.xml中注册适合插件
  • 调用服务的流程:
    1. 框架启动时会遍历所有插件plugin.xml注册的dispatch服务,并注册到系统中
    2. 当查询dispatch服务时直接从系统查找
    3. 当找到dispatch服务时先判断插件是否已启动(如未启动会先启动插件)
    4. 调用插件的processor实现

3. 调用dispatch服务

DispatchAgent agent=new DispatchAgent(context);
URI uri=new URI("apkplug://plug/userinfo");
agent.call(uri,null,new WorkerCallback(){
        @Override
        public void reply(URI uri,Object ...replyObj){
            System.err.println(replyObj[0]);
        }
        @Override
        public void timeout(URI uri) throws Exception {
            System.err.println("timeout");
        }
        @Override
        public void Exception(URI uri,Throwable throwable) {
            throwable.printStackTrace();
        }
},timeout);
  1. dispatch调用是异步的,但都会放在主线程操作,WorkerCallback回调也同样在主线程中
  2. reply 函数是processor正常回复的调用
  3. Exception 函数是当dispatch调用出现任何异常时都会调用

    1. NotFoundException 表示未找到dispatch服务,可能是由于插件没有安装
    2. RunException 表示执行错误,可能是系统内部错误,也有可能是processor执行其间发送异常
  4. timeout 函数表示服务响应超时:

    当processor调用成功,但agent.reply(getMsgId(),"fail","no user_id");未在规定时间内响应时,会调用timeout函数
    

但请注意:如果timeout<0是不会出现超时的,默认情况下timeout=-1

4 传参

调用dispatch服务时传参:
   HashMap<String, Object> parameter作为参数
processor回复参数:
   是一个Object ...replyObj 也就是一个Object[] 数组

因此dispatch服务的参数类型需要由开发者自行约定。

eg1:
    Object ...replyObj
    String result_code=(String)replyObj[0];
    if("success".equals(result_code)){
       String result_msg=replyObj[1]
    }else{
       String error_msg=replyObj[1]
    }

eg2:
    Object ...replyObj
    HashMap<String,String> result=(HashMap<String,String>)replyObj[0]
    String result_code=(String)result.get("result_code");
    String result_msg=(String)result.get("result_msg");

dispatch回复机制

1. dispatch是异步回复,当Processor.Receive() 函数执行完成时并不意味着这个服务执行完。
2. dispatch需要调用 reply(getMsgId(),Object ...replyObj);显式回复,
这样处理的原因是:
  大部分情况下服务没有办法在Receive中就能完成所有操作。
例如:
  实现一个用户登录服务:
  1. 首先需要一个activity来接收用户输入
  2. 当用户输入完成以后需要进行网络操作
  3. 最后才返回登录状态信息

 以上情况是,dispatch需要放到activity里面回复。
 而dispatch的reply(int msg_id,Object ...replyObj)机制正好解决了这样的问题。开发者只需要保持本次服务调用的msg_id即可在任何其他类里面进行回复

注意:
 每一个msg_id只能成功回复一次,如果Processor.Receive()执行过程中出现异常也是没法再回复的。

示例demo:

DispatchDemoHost

DispatchDemoPlug

*