如何编写重用通用 JavaScript 代码的反应原生“本机模块”(桥)?

Posted

技术标签:

【中文标题】如何编写重用通用 JavaScript 代码的反应原生“本机模块”(桥)?【英文标题】:How to write react native "native module" ( bridge ) that reuses common JavaScript code? 【发布时间】:2017-11-01 15:52:07 【问题描述】:

原生模块如何回调到 javascript 内部桥接方法,然后在内部方法中进行处理,例如将数据解析为 JSON,然后引发 react native 应用接收到的事件?

对于跨平台的桥接模块,我想避免在Objective C 和Java 中重复代码。如果可能的话,我想用 JavaScript 编写跨平台的桥接模块代码,并在 androidios 上重用。

我目前的解决方案:

这行得通。

这将导致对 sendEventWithName 的两次调用:

    使用“_processResponseInJavaScriptMethod”发送EventWithName forwardEventWithName 到 sendEventWithName 到 react native 应用程序。

问题:

有没有办法让原生代码使用 JS 调用同步处理数据,然后使用 sendEventWithName 立即发送结果?

或者是否每个原生 > JS 调用都需要异步 _bridge enqueueJSCall

文件:MyNativeModule.m

// 使用 forwardEventWithName 转发事件 // 普通跨平台JS处理到react native app RCT_EXPORT_METHOD(forwardEventWithName:(NSString*)name 正文:(NSString *)正文) [self sendEventWithName:name body:body]; // 1 - 响应原生应用调用 sendQueryToBluetoothDevice // 2 - 设备在收到响应时调用 commandResponse RCT_EXPORT_METHOD(sendQueryToBluetoothDevice:(NSString*)command [_device sendCommand:command]; // 1 - 从外部蓝牙设备接收 XML 响应 // 2 - 将 XML 发送到内部 JS 方法进行处理 // 3 - 内部 JS 方法使用 forwardEventWithName // 发送事件以响应本机应用程序 - (void) commandResponse:(NSString *) xml [self sendEventWithName:@"_processResponseInJavaScriptMethod" 正文:@@"xml": 配置];

文件:index.js(原生模块)

// 在 Android 和 iOS 原生模块的通用 JS 代码中解析 xml 发射器.addListener("_processResponseInJavaScriptMethod", (e) => 常量体 = parseXml(e.xml); // ??有没有办法直接使用 JS 将事件发送到反应原生应用程序? // Hack - 调用原生方法 forwardEventWithName 到 sendEventWithName 来响应原生应用程序。 /// // 这使得两个 _bridge enqueueJSCall 的 // 1 - 一次调用 sendEventWithName "_myNativeModuleInternalMethod" // 2 - 第二次调用 sendEventWithName "myNativeModuleEvent MyNativeModule.forwardEventWithName( 'myNativeModuleEventResponseReceived', JSON.stringify(body)); )

【问题讨论】:

【参考方案1】:

我建议阅读一下 React Native 中的批处理桥。

原生 -> JS

基本上你可以做的是在 JS 端定义一个带有静态方法的模块,然后你将使用 BatchedBridge (registerCallableModule) 注册 - 这使你可以通过 @ 从本机端直接调用此方法987654323@,您将提供与您的模块和功能分别对应的moduleDotMethod;您还将传递一个唯一(或增量)标识符,稍后您将使用该标识符将响应映射到每个请求。

JS -> 原生

接下来,您将创建一个本地模块,该模块将在 JS 端调用以将数据发送回本机,传递响应数据和标识符,然后您将在本机端处理。

我参与过整个服务层都在 JS 端的项目,并且成功地使用了这种方法。

【讨论】:

谢谢。您能否评论添加到原始问题的“我当前的解决方案:”?本机代码是否有一种方法可以使用 JS 调用同步处理数据,然后使用 sendEventWithName 立即发送结果?还是 RCTBridge().enqueueJSCall 是唯一的方法? 桥上没有任何东西是同步的——最接近同步调用的是在模块上使用constantsToExport,但这些值是在运行时定义的,不能更改。如果你想使用事件调度器,你可以这样做,但这需要你在 JS 端设置一个监听器。 因为没有什么是同步的,听起来我上面发布的“我当前的解决方案:”已经差不多了。对于未来的跨平台可重用性,我可能会考虑将 C++ 包装在 iOS 的 *.mm 文件中,并考虑将 C++ 包装在 Android 的 JNI 中。我一直在为 iOS 和 Android 使用 Qt 5.6,这是一个运行良好的 C++ 环境。【参考方案2】:

不知道Internal bridge module Java Script method 是什么意思,但是JS 代码可以通过方法将数据传递给native,而native 可以通过回调或promise 将数据返回给JS。原生代码也可以向 JS 发送事件。

JS       --->     Native   // Method calls
Native   --->     JS       // Callbacks, Promises, Events

请参阅本机模块文档以获取更多详细信息: - https://facebook.github.io/react-native/docs/native-modules-ios.html - https://facebook.github.io/react-native/docs/native-modules-android.html

【讨论】:

我有本地模块工作。我只是发现自己在 Java 和 Objective C 中复制了可以重复使用的代码。也许我在 beridge 模块的 index.js 中添加了Listener,然后从本机代码接收回调,处理数据,然后发出事件? react-native-fetch-blob 似乎它可能正在做类似的事情? github.com/wkh237/react-native-fetch-blob 如何构建它取决于您自己。你有办法让 native 向 JS 发送信息和 JS 向 native 发送信息。 谢谢。有没有办法让原生代码使用 JS 调用同步处理数据,然后使用 sendEventWithName 立即发送结果? 不行,JS和Native之间不能同步传输数据。

以上是关于如何编写重用通用 JavaScript 代码的反应原生“本机模块”(桥)?的主要内容,如果未能解决你的问题,请参考以下文章

如何编写可重用的 Javascript?

如何在反应中使用自定义可重用组件作为输入字段

如何为 dojox.mobile 视图编写可重用的控制器代码

编写可移植的PHP代码

如何在scala中将withcolumn编写为可重用代码

如何编写在 C++ openmp 上重用线程的代码?