- 原文地址:React Native Bridge for iOS and Android
- 原文作者:Abhishek Nalwaya
- 译文出自:掘金翻译计划
- 本文永久链接:github.com/xitu/gold-m…
- 译者:MeandNi
- 校对者:lsvih
React Native 流行的最大原因之一是我们可以在 Native 语言和 JavaScript 代码之间建立桥梁。这意味着我们可以复用在 iOS 和 Android 中创建的所有可重用库。
要创建一个商业级的应用程序,您需要使用 Native Bridge。React Native 可以同时在 iOS 和 Android 上运行,但关于它如何跨平台的文章教程非常少。在本文中,我们将创建一个 Native Bridge,以便从 JavaScript 访问 Swift 和 Java 类。
文本是此系列的第一部分,第二部分可以在 Native Bridge of UI component 中找到 这里。
代码可以在这里找到 -> github.com/nalwayaabhi…
创建一个 LightApp(手电筒)
为了更好地理解 Native Module,我们将使用 react-native CLI 创建一个简单的 LightApp 示例。
$ react-native init LightApp
$ cd LightApp
接下来,我们将在 Swift 和 Java 中创建一个 Bulb
类,稍后将在 React 组件中使用它。这是一个跨平台的示例,相同的 React 代码将同时适用于iOS和Android。
现在我们已经创建了项目的基本框架,接下来我们将本文分为两部分:
第一节 — 与原生 iOS 通信
第二节 — 与原生 Android 通信
第一节 — 与原生 iOS 通信
在本节中,我们将重点关注 iOS,了解如何在 Swift/Objective C 和 React 组件间建立桥梁。有以下三个步骤:
步骤 1) 创建一个 Bulb 类 并且完整初步通信
步骤 2) 理解 GCD Queue 并且解决出现的警告
步骤 3) 从 Swift 和 Callbacks 访问 JavaScript 中的变量
步骤 1) 创建一个 Bulb 类 并且完成初步通信
首先,我们将在 swift 中创建一个 Bulb 类,它将具有一个静态类变量 isOn
和一些其他函数。然后我们将从 Javascript 访问这个 swift 类。让我们首先在 ios 文件夹中打开 LightApp.xcodeproj 文件。此时 Xcode 应该会被打开。
在 Xcode 中打开项目后,创建一个新的 Swift文件 Bulb.swift,如下所示:
我们还要点击 Create Bridging Header,创建一个文件 LightApp-Bridging-Header.h
它将有助于 Swift 和 Objective C 代码之间的通信。请记住,在项目中,我们只有一个 Bridge Header 文件。因此,如果我们添加新文件,我们可以重用此文件。
将以下代码加入 -Bridging-Header.h
文件:
#import "React/RCTBridgeModule.h"
RCTBridgeModul 将提供一个接口,用于注册 Bridge 模块。
接下来将以下代码输入 Bulb.swift
:
import Foundation
@objc(Bulb)
class Bulb: NSObject {
@objc
static var isOn = false
@objc
func turnOn() {
Bulb.isOn = true
print("Bulb is now ON")
}
}
我们创建了 Bulb
类,它继承自 NSObject。大多数 Objective-C 类的根类是 NSObject,子类从该类继承运行时系统的基本接口,因此它们有与 Objective-C 对象相同的能力。我们在函数和类之前使用了 @objc,这将使那个类,方法或对象可用于 Objective C。
@objc 注解使您的 Swift API 在 Objective-C 和 Objective-C 运行时可用。
现在选择 File -> New -> File 创建一个新文件,然后选择 Objective-C 文件,然后将该文件命名为 Bulb.m 并添加以下代码:
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(Bulb, NSObject)
RCT_EXTERN_METHOD(turnOn)
@end
除非显式地指定,否则 React Native 不会将任何 Bulb 中的函数暴露给 React JavaScript。为此,我们使用了 RCT_EXPORT_METHOD() 宏。所以我们已经暴露了 Bulb 类和 turnOn 函数给了我们的 Javascript 代码。由于 Swift 对象被转换为了 Javascript 对象,因此其中一定存在一种对应关系。RCT_EXPORT_METHOD 支持所有标准 JSON 对象类型:
- NSString 对应 string
- NSInteger、float、double、CGFloat、NSNumber 对应 number
- BOOL 对应 boolean
- NSArray 对应 array
- NSDictionary 对应 包含此列表中的字符串键和任何类型的值的对象
- RCTResponseSenderBlock 对应 function
现在让我们更新 JavaScript 代码并从我们的 React 组件访问这个 Bulb 类。为此,请打开 App.js 并更新为以下代码:
import React, {Component} from 'react';
import {StyleSheet, Text, View, NativeModules, Button} from 'react-native';
export default class App extends Component{
turnOn = () => {
NativeModules.Bulb.turnOn();
}
render() {
return (
<View style={styles.container}> <Text style={styles.welcome}>Welcome to Light App!!</Text> <Button onPress={this.turnOn} title="Turn ON " color="#FF6347" /> </View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
现在运行iOS模拟器:
现在打开 Xcode 控制台查看日志,我们可以看到从 JavaScript 代码调用 Swift turnOn 方法。(因为我们已经看到了方法中执行的日志)
步骤 2) 理解 GCD Queue并且解决出现的警告
现在让我们修复模拟器底部和浏览器控制台中显示的警告:
Bulb 模块需要主队列设置,因为它覆盖 init
但 没有实现 requiresMainQueueSetup
。在以后的版本中,React Native 将默认初始化后台线程上的所有原生模块,除非明确选择不需要。
为了更好地理解,让我们了解 React Native 运行的所有线程:
- Main thread:UI 渲染执行的线程
- Shadow queue:布局发生的地方
- JavaScript thread:JS 代码实际执行的地方
除非另有说明,否则每个原生模块都有自己的 GCD 队列。 现在,由于这个原生模块将在不同的线程上运行,并且我们的主线程依赖于它,它会显示此警告。 要使此代码在 MainQueue 上运行,请打开 Bulb.swift 并添加此函数。
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
您可以明确提及 return false 以让它在单独的线程中运行。
步骤 3) 从Swift和Callbacks访问JavaScript中的变量
现在让我们将 Bulb 的开关(ON 或 OFF)值添加到 React 屏幕。为此,我们将 getStatus 函数添加到 Bulb.swift 并从 JavaScript 代码调用该方法。 我们将创建此方法作为回调。
React Native 桥是异步的,因此将结果传递给 JavaScript 的唯一方法是使用回调或触发事件
让我们用粗体更新 Bulb.swift 中的代码:
@objc(Bulb)
class Bulb: NSObject {
@objc
static var isOn = false
@objc
func turnOn() {
Bulb.isOn = true
print("Bulb is now ON")
}
@objc
func turnOff() {
Bulb.isOn = false
print("Bulb is now OFF")
}
@objc
func getStatus(_ callback: RCTResponseSenderBlock) {
callback([NSNull(), Bulb.isOn])
}
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
}
getStatus() 方法接收一个我们将从您的 JavaScript 代码传递的回调参数。我们用值数组调用了回调函数,这些函数将暴露在 JavaScript 中。我们已经将 NSNull() 作为第一个元素传递,我们将其视为回调中的错误。
我们需要将这个 Swift 方法暴露给 JavaScript,所以添加下方的粗体行代码到 Bulb.m 中:
@interface RCT_EXTERN_MODULE(Bulb, NSObject)
RCT_EXTERN_METHOD(turnOn)
RCT_EXTERN_METHOD(turnOff)
RCT_EXTERN_METHOD(getStatus: (RCTResponseSenderBlock)callback)
@end
我们已将 (RCTResponseSenderBlock)callback 暴露为函数 getStatus 的参数
然后最后更新React代码:
import React, {Component} from 'react';
import {StyleSheet, Text, View, NativeModules, Button} from 'react-native';
export default class App extends Component{
constructor(props) {
super(props);
this.state = { isOn: false };
this.updateStatus();
}
turnOn = () => {
NativeModules.Bulb.turnOn();
this.updateStatus()
}
turnOff = () => {
NativeModules.Bulb.turnOff();
this.updateStatus()
}
updateStatus = () => {
NativeModules.Bulb.getStatus( (error, isOn)=>{
this.setState({ isOn: isOn});
})
}
render() {
return (
<View style={styles.container}> <Text style={styles.welcome}>Welcome to Light App!!</Text> <Text> Bulb is {this.state.isOn ? "ON": "OFF"}</Text> {!this.state.isOn ? <Button onPress={this.turnOn} title="Turn ON " color="#FF6347" /> : <Button onPress={this.turnOff} title="Turn OFF " color="#FF6347" /> } </View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
重新变异代码并运行应用程序,您可以看到 Bulb Status 的值,当您单击 Turn ON 时,它将显示 Bulb 为 ON
请记住重新编译代码而不是刷新,因为我们更改了原生代码。
Section 2 — Native Bridge in Android
在本节中,我们将使用与 iOS 相同的 Javascript 代码,它同样可以应用在 Android 中。这次我们将在 Java 中创建 Bulb 类并将相同的函数 turnOn, TurnOff 和 getStatus 暴露给 Javascript。
打开 Android Studio 并单击 打开现有的 Android Studio 项目,然后在 LightApp 中选择 android 文件夹。下载所有 gradle 依赖项后,创建一个 Java 类 Bulb.java,如下所示:
并将 Bulb.java 中代码更新为:
package com.lightapp;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
public class Bulb extends ReactContextBaseJavaModule {
private static Boolean isOn = false;
public Bulb(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
public void getStatus( Callback successCallback) {
successCallback.invoke(null, isOn);
}
@ReactMethod
public void turnOn() {
isOn = true;
System.out.println("Bulb is turn ON");
}
@ReactMethod
public void turnOff() {
isOn = false;
System.out.println("Bulb is turn OFF");
}
@Override
public String getName() {
return "Bulb";
}
}
我们创建了一个 Bulb Java 类,它继承自 ReactContextBaseJavaModule 。 ReactContextBaseJavaModule 要求一定要实现名一个为 getName 的函数。此方法的作用是返回在 JavaScript 中表示此类的 NativeModule 的字符串名称。所以在这里我们将调用 Bulb ,以便我们可以通过 JavaScript 中的 React.NativeModules.Bulb 来访问它。我们可以使用其它不同的名称代替 Bulb。
并非所有函数都显式地暴露给 Javascript,要向 JavaScript 公开函数,必须使用 @ReactMethod 注解 Java 方法。桥接方法的返回类型始终为 void。
我们还创建了一个 getStatu 函数,它具有参数作为回调,它返回一个 callback 并传递静态变量 isOn 的值。
下一步是注册模块,如果模块未注册,则无法从 JavaScript 获得。通过单击菜单”文件” ->“新建” -> “Java 类”并将文件名设置为 BulbPackage 来创建文件,然后单击“确定”。然后将以下代码添加到 BulbPackage.java
package com.lightapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BulbPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new Bulb(reactContext));
return modules;
}
}
我们需要覆盖 createNativeModules 函数并将 Bulb 对象添加到 modules 数组中。如果这里没有添加,那么它将无法在 JavaScript 中使用。
需要在 MainApplication.java 文件的 getPackages 方法中提供 BulbPackage 包。此文件存在于 react-native 应用程序目录中的 android 文件夹下。在 android/app/src/main/java/com/LightApp/MainApplication.java 中更新以下代码
public class MainApplication extends Application implements ReactApplication {
...
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new BulbPackage()
);
}
....
}
我们不需要更改在 iOS 中编写的任何 JavaScript 代码,因为我们已经暴露了相同的类名和函数。如果您已跳过 iOS 部分,则需要从 App.js 复制 React Javascript 代码。
现在通过 Android Studio 或 react-native run-android 运行 App:
哇唔!我们可以在屏幕上看到 Bulb 状态,并可以从按钮切换 ON 或 OFF。最棒的是我们创建了一个跨平台的应用。
如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。
今天的文章[译] React Native 与 iOS 和 Android 通信分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18593.html