Rn 和 原生 通讯 流程。

RN 加载流程与通讯机制 分析

  • 求知

    • RN (js代码) 加载和运行环境
    • 在开启远程调试模式下
      • Native如何把命令 发送到JS中
      • JS如何执行原生方法
  • 源码查看和学习 总结

    • 启动服务
      在这里插入图片描述
  • 部分代码

    Native
    	#import <React/RCTView.h>
    	@interface ABCDView : UIView
    	@property (nonatomic, copy) RCTDirectEventBlock onAbcd;
    	@end
    	
    	@implementation ABCDViewManager
    	RCT_EXPORT_MODULE();
    	-(UIView*)view{
    	  return [[ABCDView alloc] init];
    	}
    	RCT_EXPORT_VIEW_PROPERTY(onAbcd, RCTDirectEventBlock);
    	RCT_REMAP_METHOD(domeMethod2, A:(NSString*)name B:(CGSize)size){}
    	@end
    RN
    	 <SourceView style={{ height: 100, width: 100, backgroundColor: "red", }}
                    onAbcd={(event) => {
    
                    }}>
       </SourceView>
    
    Native:
    	@interface TestToolManager : RCTEventEmitter
    	@end
    	
    	@implementation TestToolManager
    	RCT_EXPORT_MODULE()
    	-(NSArray<NSString *> *)supportedEvents{
    	  return @[@"TestEvent"];
    	}
    	
    	-(void)xxx{
    		[self sendEventWithName:@"TestEvent" body:@[@"111",@"ZZH"]];
    	}
    
    	@end
    
    RN:
    	const ToolEmitter = new NativeEventEmitter(TestToolManager);
    	ToolEmitter.addListener('TestEvent',(body) => {
    	
    	})
    
  • 通讯过程

    • Native ===> JS 原生调用js方法

      • [1] Native (iOS)
        在这里插入图片描述

      • [2] React (JS)

        • RN(js) 接受 Native 通讯 1 (开启远程调试)

          UI管理类 RCTViewManager

          • [1] 文件:http://localhost:8081/debugger-ui/

            function connectToDebuggerProxy() {
                const ws = new WebSocket('ws://' + window.location.host + '/debugger-proxy?role=debugger&name=Chrome');
                let worker;
                function createJSRuntime() {
                  worker = new Worker('debuggerWorker.js');
                  worker.onmessage = function(message) {
                    ws.send(JSON.stringify(message.data));
                  };
                }
                ws.onmessage = async function(message) {
            	    //接受服务器数据
                  const object = JSON.parse(message.data);
            
                  if (object.method === 'prepareJSRuntime') {
                  } else if (object.method === '$disconnected') {
                  } else if (object.method === 'executeApplicationScript') {
                  } else {
                  	/**
                  	{
                  		arguments:
            				"RCTEventEmitter"
            				"receiveEvent"
            				[
            					2, 
            					"topAbcd", 
            					{ASAS: 2121, target: 2}  参数 + 组件reactTag
            				]
            			id: 11511
            			method: "callFunctionReturnFlushedQueue"
                  	*/}
                  	/// 处理任务
                    worker.postMessage(object);
                  }
                };
            }
            
          • [2] http://localhost:8081/debugger-ui/debuggerWorker.js

            //执行完成回调原生的方法
            	var sendReply = function(result, error) {
            	 	postMessage({replyID: object.id, result: result, error: error});
            	};	
            
            //执行 
            	/**
            		__fbBatchedBridge == MessageQueue 
            		object.method == "callFunctionReturnFlushedQueue"
            		object.arguments  = [
            				"RCTEventEmitter"
            				"receiveEvent"
            				[2, "topAbcd", {ASAS: 2121, target: 2}]
            			]
            			
            		__fbBatchedBridge 见	 react-native/Libraries/BatchedBridge/BatchedBridge.js
            			处理队列 接受消息 处理 并派发处理
            	**/
            	returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments);
            
          • [3] node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js

            callFunctionReturnFlushedQueue(module: string, method: string, args: any[]) {
                this.__callFunction(module, method, args);
            	return this.flushedQueue();
            }
            
            
            __callFunction(module: string, method: string, args: any[]): any {
            	/**
            		args=[2,"topAbcd",{ASAS: 2121, target: 2}]
            		moduleMethods ==> RCTEventEmitter 模块
            	*/
            	const result = moduleMethods[method].apply(moduleMethods, args);
            	return result;
            }
            
          • [4] node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js

            /**
            *		rootNodeID 对应<ABCDView onAbcd={xx}> 对象ID
            *		topLevelType = topAbcd 对应 onAbcd 方法
            *	 	nativeEventParam  {ASAS: 2121,target: 2} 参数 + 组件reactTag(target)
            */
            function receiveEvent(rootNodeID, topLevelType, nativeEventParam) {
              _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
            } 
            
            /**
            	一系列的处理
            */
            function executeDispatch(event, simulated, listener, inst) {
              var type = event.type || "unknown-event";
              event.currentTarget = getNodeFromInstance(inst);
              ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(
                type,  //
                listener, // onAbcd 需要调用的方法
                undefined,
                event // 事件包含 (对应方法,组件实例,参数 。。。)
              );
              event.currentTarget = null;
            }
            
            .....
            
            var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) {
              var funcArgs = Array.prototype.slice.call(arguments, 3);
              try {
              	/**
              	* func 为对应组件实例下的对应方法 ABCDView.onAbcd
              	* funcArgs 为参数
              	*/
                func.apply(context, funcArgs);
              } catch (error) {
              }
            };
            
            
          • [5] 你xxx.js

            <SourceView  onAbcd={(params)=>{}}/>
            
        • RN 接受 Native 通讯 2 (开启远程调试)

          功能类 通知 (继承 RCTEventEmitter)

          • [1] 文件:http://localhost:8081/debugger-ui/

          • [2] http://localhost:8081/debugger-ui/debuggerWorker.js

          • [3] node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js

            __callFunction(module: string, method: string, args: any[]): any {
            	/**
            		method ==> 'emit'
            		moduleMethods ==> RCTDeviceEventEmitter 模块
            		args==>[
            					"TestEvent",
            					[111,ZZH]
            				]
            	*/
            	const result = moduleMethods[method].apply(moduleMethods, args);
            	return result;
            }
            
          • [4] RCTDeviceEventEmitter

             emit =>派发通知
            
          • [5] 接受通知

            ToolEmitter.addListener('TestEvent',(body) => {
            	
            })
            
    • JS ===> Native JS调用Native方法

      • JS

        • [1] 执行导出方法

          	NativeModules.ABCDViewManager.domeMethod2("朱子豪", [111, 222])
          
        • [2] node_modules/react-native/Libraries/BatchedBridge/NativeModules.js

          fn = function(...args: Array<any>) {
            BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess);
          };
          
        • [3] node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js

          enqueueNativeCall(
              moduleID: number,
              methodID: number,
              params: any[],
              onFail: ?Function,
              onSucc: ?Function,
            ) {
              this._callID++;
          
              this._queue[MODULE_IDS].push(moduleID);
              this._queue[METHOD_IDS].push(methodID);
          
              this._queue[PARAMS].push(params);
              
              /*
              	这里仅仅将 一次调用 存进 _queue队列中
              	那什么时候触发了
              */
            }	
          
        • [4] 回调时机

          MessageQueue
          
          	当我们进行一次JS=>Native 并不会立刻触发 仅仅存入_queue队列中
          	
          http://localhost:8081/debugger-ui/debuggerWorker.js 
          
          	return function(message) { 
          	    var object = message.data;
          	
          	    var sendReply = function(result, error) {
          	      postMessage({replyID: object.id, result: result, error: error});
          	    };
          		 returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments);
          	    sendReply(JSON.stringify(returnValue), error);
          	  };
          	  
          		有这么一段简化的代码
          		returnValue 最开始我以为是一次na=>js 的结果对调
          		后来发现 一次na=>js 调用后。会直接调用sendReply方法
          		查看代码后发现
          			returnValue = [[], [], [], 0];
          			不仅包含一次返回结果 returnValue[3]
          			returnValue[0] [1] [2] 分别值得什么意思了
          -----------------------------------------------
          			
          node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js
          
          	callFunctionReturnFlushedQueue(module: string, method: string, args: any[]) {
          	    this.__guard(() => {
          	      this.__callFunction(module, method, args);
          	    });
          	
          	    return this.flushedQueue();
          	  }
          	flushedQueue() {
          	    this.__guard(() => {
          	      this.__callImmediates();
          	    });
          	
          	    const queue = this._queue;
          	    this._queue = [[], [], [], this._callID];
          	    return queue[0].length ? queue : null;
          	  }
          	  
          	callFunctionReturnFlushedQueue 为一次na=>js 执行方法
          	会返回this.flushedQueue() 执行方法结果
          	flushedQueue() 返回_queue 并会清空_queue数组 
          
          总结
          	js(RN) ==> 原生(iOS)
          		1:把一次命令存入消息对象中  _queue
          		2:当原生调用RN时 
          			1:执行这次(native==>js)命令
          			2:会将消息队列中的命令 通过WS  发送到原生
          			3:执行原生对应方法
          疑问
          	如果某段时间内 _queue有命令,但是无(native=>js)命令。那不是_queue队列消息不是无法触发
          	
          	有兴趣可以查看
          		ios / RCTTiming.m  ==> JSTimers
          	会保持一定的回调周期
          			
          
        • [5] 发送事件给原生

          http://localhost:8081/debugger-ui/debuggerWorker.js
          	57 行
          http://localhost:8081/debugger-ui/
          	122 行 Ws 发送
          	/**
          		"{"replyID":10483,"result":"[[43,25,5,1],[19,1,3,1],[[],[72],[8,3,{\"type\":\"frames\",\"frames\":[0,0.008888888888888889,0.035555555555555556,0.08000000000000002,0.14222222222222222,0.22222222222222227,0.3200000000000001,0.4355555555555557,0.5644444444444444,0.6799999999999999,0.7777777777777777,0.8577777777777778,0.9199999999999999,0.9644444444444443,0.991111111111111,1,1],\"toValue\":1,\"iterations\":1},4907],[\"朱子豪\",[111,222]]],2451]"}"
          	*/
          	ws.send(JSON.stringify(message.data));
          
      • Native 接受JS消息

        • [1] node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m

          message 
          ==js 发送的对像  
          "{"replyID":10483,"result":"[[43,25,5,1],[19,1,3,1],[[],[72],[8,3,{\"type\":\"frames\",\"frames\":[0,0.008888888888888889,0.035555555555555556,0.08000000000000002,0.14222222222222222,0.22222222222222227,0.3200000000000001,0.4355555555555557,0.5644444444444444,0.6799999999999999,0.7777777777777777,0.8577777777777778,0.9199999999999999,0.9644444444444443,0.991111111111111,1,1],\"toValue\":1,\"iterations\":1},4907],[\"朱子豪\",[111,222]]],2451]"}"
          
          - (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
          {
            NSError *error = nil;
            NSDictionary<NSString *, id> *reply = RCTJSONParse(message, &error);
            NSNumber *messageID = reply[@"replyID"];
            //处理消息的回调方法
            RCTWSMessageCallback callback = _callbacks[messageID];
            if (callback) {
              callback(error, reply);
              [_callbacks removeObjectForKey:messageID];
            }
          }
          
        • [2] node_modules/react-native/React/CxxBridge/RCTObjcExecutor.mm

          54行
           m_jsThread->runOnQueue([this, json]{
          	m_delegate->callNativeModules(*this, convertIdToFollyDynamic(json), true);
          });
          
        • [3] node_modules/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp

          [
          	[43,25,5,1]
          	[19,1,3,1],
          	[[],[92],[xx],["朱子豪",[11,22]]]
          ]
          ==>
           [43,19,[]]
           [19 1 [92]]
           [5,3,[xx]]
           [1,1,["朱子豪",[11,22]]]
          
          ===>
          [1,1,["朱子豪",[11,22]]] =====> [0]为模块标识  [1]为方法标识  [2]为方法调用参数
          
          
          47行
          for (auto& call : parseMethodCalls(std::move(calls))) {
          	m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
          }
          
        • [4] node_modules/react-native/ReactCommon/cxxreact/ModuleRegistry.cpp

          void ModuleRegistry::callNativeMethod(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params, int callId) {
            if (moduleId >= modules_.size()) {
              throw std::runtime_error(
                folly::to<std::string>("moduleId ", moduleId, " out of range [0..", modules_.size(), ")"));
            }
            //[1,1,["朱子豪",[11,22]]] =====> [0]为模块标识  [1]为方法标识  [2]为方法调用参数
            // moduleId 查找RCTNativeModule模块  mthodID 方法标识 params参数
            modules_[moduleId]->invoke(methodId, std::move(params), callId);
          }
          
        • [5] node_modules/react-native/React/CxxModule/RCTNativeModule.mm

          71 行
          	invokeInner(weakBridge, weakModuleData, methodId, std::move(params));
          86 行
          	static MethodCallResult invokeInner(RCTBridge *bridge, RCTModuleData *moduleData, unsigned int methodId, const folly::dynamic &params) {
          		//找到对应方法
          		method == RCTModuleMethod
          			1: 包含对应方法domeMethod2 的 NSInvocation对象
          			2: 包含你声明的管理对应应用ABCDViewManager 信息
          			3: 方法选择器							
          			
          	  id<RCTBridgeMethod> method = moduleData.methods[methodId];
          	  NSArray *objcParams = convertFollyDynamicToId(params);
          	  @try {
          	    id result = [method invokeWithBridge:bridge module:moduleData.instance arguments:objcParams];
          	    return convertIdToFollyDynamic(result);
          	  }
          	  return folly::none;
          }
          
        • [6] node_modules/react-native/React/Base/RCTModuleMethod.mm

          544行
          	执行 NSInvocation
          	[_invocation invokeWithTarget:module];
          
        • [7] ABCDViewManager.m

          RCT_REMAP_METHOD(domeMethod2, A:(NSString*)name B:(CGSize)size){
          	//调用方法
          }
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值