构建RN与安卓通信的桥梁 - 架构篇

252 阅读3分钟

本篇文章介绍的搭建Android与Rn之间的简易通信架构,需要了解通信的基本使用的同学可以参考下面的链接

开篇先上图 - “简易版的通信架构图” RN与Android之间通信的架构图

本架构实现的功能有:

  • 自定义通信规则,并以Json作为数据传输格式进行传输
  • 实现通信场景分两种: 1) RN主动向Android获取数据 2)Android主动向RN传输数据

先着重介绍场景1(RN主动向Android获取数据),进行数据传输的格式

协议:rn://xxxmodule?funTarget=main_cache
协议的Schema:‘rn://’标识为此通信的标识,可验证通信正确性
协议的Host:‘xxxmodule’此标识为传递给对应的业务模块执行。包括:网络加载模块,本地数据缓存模块等等。
协议的queryParams: ‘funTarget’ 这个key用于标识模块需要执行的动作。比如网络模块需要拉取个人信息,需要拉取首页信息,此标识用于执行动作的区分

如下例子:
rn://networkmodule?funTarget=person_info, 到网络模块中拉取个人信息
rn://networkmodule?funTarget=main_page, 到网络模块中拉取首页信息

以上协议贯穿了整个架构的设计,下面介绍代码实现部分

  • 协议规则实现类BridgeUrlConfig, BridgeUrlConst
public interface BridgeUrlConst {
    String RN_SCHEMA = "rn";
    String RN_NETWORK_MODULE = "network";
    String COMPLETE_RN_SCHEMA = RN_SCHEMA + "://";
}

public enum BridgeUrlConfig {

    //target: 网络模块
    NETWORK_MODULE(BridgeUrlConst.COMPLETE_RN_SCHEMA + BridgeUrlConst.RN_NETWORK_MODULE),
    //action: 网络模块下执行main_cache动作
    NETWORK_SYNC_MAIN_CACHE(NETWORK_MODULE, "main_cache"),
    //action: 网络模块下执行second_cache动作
    NETWORK_SYNC_SECOND_CACHE(NETWORK_MODULE, "second_cache"),
     //action: 网络模块下执行request动作
    NETWORK_ASYNC_REQUEST(NETWORK_MODULE, "request");


    private String target;
    private BridgeUrlConfig parentConfig;

    BridgeUrlConfig(String target) {
        this.target = target;
        this.parentConfig = null;
    }

    BridgeUrlConfig(BridgeUrlConfig parentConfig, String target) {
        this.target = target;
        this.parentConfig = parentConfig;
    }

    public String getTarget() {
        return target;
    }

    public BridgeUrlConfig getParentConfig() {
        return parentConfig;
    }
}

以上使用接口常量与枚举实现规则定义, 更直观的方便我们后面的解析解析和判断的使用

  • 如何使用协议?RN与原生通信入口 BridgeUrlAnalysis
//用来声明模块
public interface IModuleExecuteEntry {
    /*
    * funTarget: 需要执行的action
    * argJson: 执行此action需要的参数
    * promise: 用于执行结果的回调,可查看官网文档,上方链接有说
    * 明。注意异步或同步兼用回调返回。
    */
    void execute(String funTarget, String argJson, Promise promise);
}

//通信协议执行入口类
public class BridgeUrlAnalysis {
    private static BridgeUrlAnalysis bridgeUrlAnalysis = new BridgeUrlAnalysis();

    private BridgeUrlAnalysis() {
    }

    public static BridgeUrlAnalysis getInstance() {
        return bridgeUrlAnalysis;
    }

    final Map<String, IModuleExecuteEntry> modules = new HashMap<>();
    
    //1.注册可执行模块
    {
        modules.put(URI.create(BridgeUrlConfig.NETWORK_MODULE.getTarget()).getHost(), new NetworkModule());
    }


    /**
     * //2.通信入口方法
     * 正确的url格式:‘ react_native://xxxmodule?funTarget='main_cache' "
     *
     * @param url
     * @param argsJson
     */
    public void analysis(String url, String argsJson, Promise promise) {
        if (TextUtils.isEmpty(url)) {
            throw new RuntimeException("please url not empty");
        }
        URI uri = URI.create(url);
        if (!uri.getScheme().equals(BridgeUrlConst.RN_SCHEMA)) {
            throw new RuntimeException("please url not correct");
        }

        //根据url中的host获取对应注册的module
        String host = uri.getHost();
        IModuleExecuteEntry entry = modules.get(host);
        if (entry == null) {
            throw new RuntimeException("this target module not init");
        }
        //解析url中的query,获取name为“funTarget”的值
        String paramString = uri.getQuery().split("#")[0];
        Matcher matcher = Pattern.compile("(^|&)" + "funTarget=" + "([^&]*)").matcher(paramString);
        matcher.lookingAt();

        entry.execute(matcher.group(2), argsJson, promise);

    }
}

以上类需要注意两点:

  • 1.注册可执行协议的模块
  • 2.通信协议的入口执行逻辑

然后介绍场景2,Android主动发送数据给RN 此处使用了事件发送技术,类似EventBus的用法。 因为比较简单就直接上Android代码

/**
 * 1.原生模块可以在没有被调用的情况下往 JavaScript 发送事件通知
 */
public interface INativeSendToRnBridge {
    /**
     * 发送事件到RN上
     * @param eventName 设置发送事件的名称,RN可对此名称的事件进行监听
     * @param jsonObj
     */
    void sendEvent(String eventName, String jsonObj);
}
/**
*具体实现类
*/
public class AndroidSendToRNBridge implements INativeSendToRnBridge {
    private ReactContext mReactContext;

    public AndroidSendToRNBridge(ReactContext context) {
        this.mReactContext = context;
    }

    /**
    * 发送数据的入口,规定了发送事件的格式
    * eventName: 用于区分事件,相当于key
    * jsonObj: 事件所包含的数据,相当于value。建议以Json格式数
    * 据发送
    */
    @Override
    public void sendEvent(String eventName, String jsonObj) {
        mReactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, jsonObj);
    }

    public ReactContext getReactContext() {
        return mReactContext;
    }

    public void setReactContext(ReactContext mReactContext) {
        this.mReactContext = mReactContext;
    }
}

本篇文章介绍完毕啦,需要源码的小伙伴可私信我。