一、Android 通信
在使用通信时分为自定义控件和功能组件两个部分。但是两者都离不开以下几个类:
- ReactPackage: 总管理包
- ReactContextBaseJavaModule: 管理模块
- SimpleViewManager: 管理控件
1.1 ReactPackage
1.1.1 初始化Package
为了将Android功能接入ReactNative,首先需要定义ReactPackage。实现功能,实现的功能分为ReactModule和ViewManager。
如下面代码: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.Arrays;
import androidx.annotation.NonNull;
public class GAMapPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Arrays.asList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Arrays.asList();
}
}
完成后就做好了接入RN层的功能入口,如果需要手动加入则需要找到Application中添加该功能库。需要注意,上的两个接口函数一定要有返回值,如果返回为null,则无法运行。public class MainApplication extends Application implements ReactApplication {
...
List<ReactPackage> packages = new PackageList(this).getPackages();
...
上面代码会进行对所有添加的package进行初始化操作,而我们要做的就是进入getPackages中,手动添加。package com.facebook.react;
public class PackageList {
...
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig),
new RNCMaskedViewPackage(),
new RNGestureHandlerPackage(),
// 这里添加该功能库即可,如果是使用Library的方式添加,就不需要手动添加
));
}
}
如上,但是要注意,如果是在原有Android项目下添加package就需要手动添加,但是如果使用RN的Library方式添加的话,就不需要进行手动处理操作。另外需要注意最好在自定义添加package的时候,在Application中添加,因为package的创建会在每次编译后重置掉。
1.1.2 package的组成
实现后可以看到两个接口函数:
public List
createNativeModules(@NonNull ReactApplicationContext reactContext)
public ListcreateViewManagers(@NonNull ReactApplicationContext reactContext)
根据函数所需要的泛型不难看出重要的就是NativeModule和ViewManager两个类型。前者用来实现功能方法,后者可以用来实现UI控件。
唯一参数ReactApplicationContext则是该库所在的上下文对象。其内部封装了很多实用的函数,如:getJSModule()、getCurrentActivity(),用来完成js层通信和与主要的activity的沟通功能。
1.1.3 Js 对应 Java 的所有类型映射
JavaScript | Java |
---|---|
Bool | Boolean |
Number | Integer |
Number | Float |
Number | Double |
String | String |
ReadableMap、WritableMap | Object |
ReadableArray、WritableArray | Array |
1.2 ReactModule
1.2.1 初始化ReactModule
这里继承ReactContextBaseJavaModule,该库内部实现NativeModule。public class GAOfflineMapModule extends ReactContextBaseJavaModule {
private ReactApplicationContext context;
public GAOfflineMapModule(@NonNull ReactApplicationContext reactContext) {
// 注意这里需要调用super,将Context传递过去
super(reactContext);
this.context = reactContext;
}
@NonNull
@Override
public String getName() {
// 该Module在js层定义的名称
return "GaoModule";
}
...
}
1.2.2 在JS层找到该库
完成初始化java层库后,就需要在js层找到该库,这样我们就可以完成中间穿透,进行函数调用。import { NativeModules, NativeEventEmitter } from 'react-native';
const { GaoModule } = NativeModules;
export default GaoModule;// 使用该类直接调用java层函数
这样就完成了最简单的双向初始化操作,后面只需要添加指定的函数,就可以进行完整的函数调用、函数回调操作。
1.2.3 从 JS 到 Java
如果需要将函数暴露给JS层,则需要使用注解@ReactMethod...
@ReactMethod
public void test(int a) {
...
}
@ReactMethod
public void test(float a) {
...
}
@ReactMethod
public void test(ReadableArray a, ReadableMap b) {
...
a.getString(0);
a.getInt(1);
b.getString('key');
}
完成函数定义和注解后,就可以在JS层找到该函数了GaoModule.test(1);
GaoModule.test(1.1);
GaoModule.test(['1', 2], { 'key': 'value' });
注意:整个过程在代码编写后需要编译操作,否则会出现意想不到的问题。多 clean 多 rebuild 。
1.2.4 从 JS 到 Java 并回调数据给 JS
数据回调是异步的过程。回调也提供了多种手段。
Callback
重新定义一个函数,并在这个函数最后使用Callback对象进行处理回调方式invoke。import com.facebook.react.bridge.Callback;
...
@ReactMethod
public void test(int a, int b, Callback callback) {
callback.invoke((a + b));
}
上面的invoke函数接收的是多个参数,因此可以在后面继续添加。
然后在Js层可以这么做:GaoModule.test(1, 2, (result) => {
this.setState({ data: result });
});
但是由于多数情况在异步操作随时可能出现异常情况,在异常处理后返回的数据无法在js层正常获取,因此在多数情况下会使用两个Callback来管理回调预测的完整性。// ---------JAVA
import com.facebook.react.bridge.Callback;
...
@ReactMethod
public void test(int a, int b, Callback successCallback, Callback failCallback) {
try {
successCallback.invoke((a + b));
} catch(Exception e) {
failCallback.invoke('err');
}
}
// ----------JS
GaoModule.test(1, 2, (result) => {
this.setState({ data: result });
}, (err) => {
console.log(err)
});
Promise
es6提供了promise来完成异步操作,同样也可以适用于原生调用:import com.facebook.react.bridge.Promise;
...
@ReactMethod
public void test(int a, int b, Promise promise) {
promise.resolve((a + b));
// promise.reject("404", "error");
}
熟悉promise可以知道具有两个回调方式,但是只能使用一种方式来完成回调。GaoModule.test(1, 2)
.then(data => {
this.setState({ data: result });
})
.catch(err => {
console.log(err)
});
相对于Callback,promise更具有完整的异步模式。
1.2.5 从 Java 到 JS
流程如下:
1.注册监听回调
2.监听回调下完成java层内容到js层的所有数据
3.取消注册监听
代码实例
首先在java层需要做一些准备,需要准备emit函数来完成到js层的函数入口。public class GAOfflineMapModule extends ReactContextBaseJavaModule {
private ReactApplicationContext context;
public GAOfflineMapModule(@NonNull ReactApplicationContext reactContext) {
// 注意这里需要调用super,将Context传递过去
super(reactContext);
this.context = reactContext;
}
@NonNull
@Override
public String getName() {
// 该Module在js层定义的名称
return "GaoModule";
}
public void emit(String key, Object value) {
try {
context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(key, value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以看到emit函数所需要的两个参数解释:
key: 监听对象
value: 数据回调,注意格式必须是之前表格的js对应格式。
首先需要找到该监听器对象:import { NativeModules, NativeEventEmitter } from 'react-native';
const { GaoModule } = NativeModules;
const listenerGaoModule = new NativeEventEmitter(ImSdkModule);
GaoModule.listenerGaoModule = listenerGaoModule;
export default GaoModule;
进行注册:import GaoModule from '...';
...
componentDidMount() {
// 注册
this.listener = GaoModule.listener.addListener(key, (value) => {
// 逻辑处理
});
}
componentWillUnmount() {
// 取消注册
GaoModule.listener.removeListener(
this.listener
);
}
1.3 ViewManager
用于完成UI组件部分功能。
说到组件Android就会想到ViewGroup和View,而这里也可以有迹可循。
SimpleViewManager
1.创建java层viewManager
|
看到这里需要如下几个:
泛型UI:表明该viewmanager管理那个控件。
getName:返回该控件在JS端上的命名。
createViewInstance:返回该控件的一个函数,这里返回的类型就是指定的泛型。
2.注册
最后别忘了将这个ViewManager添加到package中:public class DemoPackage implements ReactPackage {
...
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Arrays.asList(new DemoViewManager());
}
}
3.JS层找到该控件
完成java层后,看看js层如何操作:import { requireNativeComponent } from 'react-native';
module.exports = requireNativeComponent('DemoView');
4.设置属性
通过@ReactProp或@ReactPropGroup注解函数来进行属性设置,定义好名称和类型后,就可以直接使用了。public class DemoViewManager extends SimpleViewManager<TextView> {
...
@ReactProp(name = "text")
public void setText(TextView view, String text) {
if (text != null)
view.setText(text);
}
<DemoView
style={{ width: 100, height: 100, backgroundColor: '#0f0' }}
text={'好的'}
/>
当我们在初始化、修改属性时都会调用到java层面上。
5.点击事件
通过一系列的注册来完成该功能:public class DemoViewManager extends SimpleViewManager<TextView> {
...
// @Nullable
// @Override
// public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
// return MapBuilder.<String, Object>builder()
// .put("callback", MapBuilder.of("registrationName", "onCallback"))
// .build();
// }
@Nullable
@Override
public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("callback", MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", "onCallback")))
.build();
}
首先需要注册java层和js层的函数映射及名称,上面的注册前者是java层名称、后者是js层函数名称。上面两个可以使用任意一个,都可以完成注册任务,但是依旧推荐未被注释的方式。
注册好函数后,就可以开始调用并传递参数:@Override
public void onClick(View v) {
Log.e("----->", "click");
WritableMap map = Arguments.createMap();
map.putString("name", "click");
emit("callback", map);
}
public void emit(String key, WritableMap map) {
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(textView.getId(), key, map);
}
注意传递的参数格式,以及最重要的view.getId(),表明这个函数可以在自定义控件中添加,也可以在viewManager中使用,但是一定是指定的view的id。
最后就可以在js层面上使用了:<DemoView
style={{ width: 100, height: 100, backgroundColor: '#0f0' }}
text={text}
onCallback={(data) => {
console.log('-----> callback:', data);
}}
/>
6.refs函数调用
需要注意新老函数的调用区别。
- 新函数
public void receiveCommand(@NonNull TextView root, String commandId, @Nullable ReadableArray args)
只需要在这里处理好 commandId 的功能即可,无需要注册。& js public class DemoViewManager extends SimpleViewManager<TextView> implements View.OnClickListener {
...
@Override
public void receiveCommand(@NonNull TextView root, String commandId, @Nullable ReadableArray args) {
super.receiveCommand(root, commandId, args);
}
import { UIManager, findNodeHandle } from 'react-native';
...
sendCommand = (viewName, funcName, data = []) => {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this),
funcName,
data,
);
};
- 老函数
public Map<String, Integer> getCommandsMap()
public void receiveCommand(@NonNull TextView root, int commandId, @Nullable ReadableArray args)
首先需要通过 getCommandsMap 函数进行注册函数名称和 commandId 进行绑定,然后在 receiveCommand 函数中处理 commandId 的功能即可。
在JS层找到该控件名称、函数名称、需要的参数数组即可。& js public class DemoViewManager extends SimpleViewManager<TextView> implements View.OnClickListener {
...
@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.<String, Integer>builder()
.put("funcName", 1)
.build();
}
@Override
public void receiveCommand(@NonNull TextView root, int commandId, @Nullable ReadableArray args) {
super.receiveCommand(root, commandId, args);
}
import { UIManager, findNodeHandle } from 'react-native';
...
sendCommand = (viewName, funcName, data = []) => {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this),
UIManager.getViewManagerConfig(viewName).Commands[funcName],
data
)
};这里传入的this就是组件的refs,这里在使用sendCommand函数时对自定义控件进行封装后的结果。
ViewGroupManager
与ViewManager的区别就在于 ViewGroupManager 可以对内部组件进行管理,例如地图内部的标记效果。
二、IOS
2.1 Module
2.1.1 RCT_EXPORT_MODULE():创建Module初始化
使用RCT_EXPORT_MODULE()来创建需要的Module,与Android对应。
准备好.h文件,这里的文件名称、类名称都无需在意。#ifndef DemoModule_h
#define DemoModule_h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface DemoModule : NSObject <RCTBridgeModule>
@end
#endif /* DemoModule_h */
在RCT_EXPORT_MODULE()中添加的参数既是定义在JS层中的类名称,注意这里不要加引号,否在在JS层的类名称也会有引号。#import "DemoModule.h"
@implementation DemoModule
RCT_EXPORT_MODULE(DemoModule)
@end
2.1.2 JS中找到该库
需要注意的是使用过程中如果出现问题,请先重新build后在找问题。import { NativeModules } from 'react-native';
const { DemoModule } = NativeModules;
2.1.3 从 JS 到 ios
使用RCT_EXPORT_METHOD()来创建我们需要的功能函数:@implementation DemoModule
RCT_EXPORT_METHOD(test1) {
NSLog(@"-----> test1()");
}
RCT_EXPORT_METHOD(test2:(int)a) {
NSLog(@"-----> test2(%d)", a);
}
整个过程只需要将函数的定义放到该函数中即可。
2.1.4 从 JS 到 ios 并回调数据给 JS
Callback
|
此处代码的js层与android代码一模一样,不同只在于原生@implementation DemoModule
RCT_EXPORT_METHOD(test3:(int)a:(RCTResponseSenderBlock)callback) {
NSLog(@"-----> test3(%d)", a);
callback(@[[NSNumber numberWithInt:a]]);
}
注意返回的是一个NSObject数组,并且内部的每项数据都应该是NSObject类型,因此基本类型int需要进行封箱成对象。
Promise
|
同上,来看看ios如果处理@implementation DemoModule
RCT_EXPORT_METHOD(test4:(int)a:(RCTPromiseResolveBlock)resolve:(RCTPromiseRejectBlock)reject) {
NSLog(@"-----> test4(%d)", a);
if (a == 11) {
resolve(@[[NSNumber numberWithInt:a]]);
} else {
NSError *error = [NSError errorWithDomain:@"Test" code:0 userInfo:nil];
reject(@"CODE", @"MESSAGE", error);
}
}
2.1.5 从 ios 到 JS
通android一样,ios也可以直接访问到Js层面上,方式也有迹可循,在js监听字段,然后ios通过该映射字段进行数据传递。
JS端:import { NativeModules, NativeEventEmitter } from 'react-native';
...
const emitter = new NativeEventEmitter(NativeModules.TestEmitterModule);
// 注册
emitter.addListener('EventName', (name) => {
// 回调
console.log('----->', 'callback:'+name.name);
});
// 模拟发送消息
NativeModules.TestEmitterModule.send('test');
// 取消注册
emitter.remove();
上面的代码大概回顾之前的功能。
1.需要继承RCTEventEmitter。
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface DemoModule : RCTEventEmitter <RCTBridgeModule>
+ (instancetype)instance;
@end
#endif /* DemoModule_h */
2.初始化工作。
...
static DemoModule * _sharedInstance = nil;
+ (instancetype)instance {
return _sharedInstance;
}
- (NSArray<NSString*> *)supportedEvents
{
// 定义的监听字段
return @[@"callback"];
}
- (void)startObserving {
if (_sharedInstance == nil) {
_sharedInstance = self;
}
[super startObserving];
}
- (void)stopObserving {
_sharedInstance = nil;
[super stopObserving];
}
3.编写类似emit的代码作为传递入口。
// 功能回调封装
- (void)emit:(NSString *) key :(NSObject *)value {
[self sendEventWithName:key body:value];
}
RCT_EXPORT_METHOD(send) {
NSLog(@"-----> send()");
[self emit:@"callback" :@{
@"a": @"a",
@"b": [NSNumber numberWithInt:2]
}];
}
4.js层面注册及解绑
2.2 View
2.2.1 RCTViewManager
这里使用通过RCTViewManager来管理ios中的ui控件。
2.2.2 创建自定义View
自定义一个TextView#ifndef DemoView_h
#define DemoView_h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DemoView : UITextView
@end
#endif /* DemoView_h */
然后完成这个View,并且让他实现一个自己的本文设置功能函数:#import "DemoView.h"
@implementation DemoView
// 添加一个设置字符串功能函数
- (void)setTexts:(NSString *)text {
[self setText:text];
}
@end
2.2.3 创建ViewManager
需要继承RCTViewManager:#import <React/RCTViewManager.h>
#import "DemoView.h"
@interface DemoViewManager : RCTViewManager
@end
@implementation DemoViewManager
RCT_EXPORT_MODULE(DemoView)
// RCT_EXPORT_VIEW_PROPERTY(texts, NSString)
// 找到我们定义的UI
- (UIView *)view {
return [[DemoView alloc] init];
}
@end
然后在view函数找返回我们定义的UI控件。
同module一样,通过RCT_EXPORT_MODULE来定义控件在JS层的命名,注意别加引号
2.2.4 JS 中找到该View
官方文档说明:渲染时,请不要忘记拉伸UI即给UI大小,否则将无法在屏幕上看到。import { requireNativeComponent } from 'react-native';
module.exports = requireNativeComponent('DemoView');
...
<Demo.DemoView
ref={(refs) => (this.demoView = refs)}
style={{ width: 100, height: 100, backgroundColor: '#0f0' }}
/>
2.2.5 设置属性
使用RCT_EXPORT_VIEW_PROPERTY()来标注属性命名和属性类型。@implementation DemoViewManager
RCT_EXPORT_MODULE(DemoView)
// 标注属性
RCT_EXPORT_VIEW_PROPERTY(texts, NSString)
然后在控件中定义这个属性#import "DemoView.h"
@implementation DemoView
// 添加一个设置字符串功能函数
- (void)setTexts:(NSString *)text {
[self setText:text];
}
@end
2.2.6 设置函数
添加相应的Delegate协议,这里使用的是UITextView,使用的就是UITextViewDelegate。```
#### 2.2.7 refs函数调用
重要函数有如下几个
* `RCT_EXPORT_MODULE`: 描述当前类为通信类。
* `RCT_EXPORT_METHOD`: 描述该函数为单向通信函数。
* `RCT_REMAP_METHOD`: 解决函数重载问题。
#### 带参数的原生调用
这里在JS端使用类似上面Android端的方式放置代码,来完善ios端的代码。
```java
NativeModules.TestModule.testTwo('a', 'b', 'c');
与Android端一致,需要Module名称,函数名称,参数,及回调。
- 模块名称:
TestModule.m#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface TestModule : NSObject <RCTBridgeModule>
@end
TestModule.mmport "TestModule.h"
@implementation TestModule
// 用于标记为指定RCTBridgeModule协议类
RCT_EXPORT_MODULE();
// 实现函数
RCT_EXPORT_METHOD(testTwo:(NSString*) text1:(NSString*) text2:(NSString*) text3) {
NSLog(@"-----> IOS%@ - %@ - %@", text1, text2, text3);
}
@end
- 模块名称就是实现类名称
- 这里在实现
TestModule
接口后,需要在类中添加RCT_EXPORT_MODULE()
宏。 - 实现的函数必须使用
RCT_EXPORT_METHOD()
来定义。
函数参数:
RCT_EXPORT_METHOD(函数名称:(参数类型)参数名称: (参数类型)参数名称)
这样就完成了单向函数调用,由于调用过程异步,所以回调时也和Android端类似。
原生回调
Callback
使用Callback
完成函数回调。
IOS端:RCT_EXPORT_METHOD(testFour:(NSString*)text:(RCTPromiseResolveBlock)resolve:(RCTPromiseRejectBlock)reject) {
resolve([@"Callback:" stringByAppendingString:text]);
}
JS端:this.test();
...
test = () => {
NativeModules.TestModule.testFour('msg')
.then((msg) => {
console.log('----->', 'over:'+msg);
});
}
// async函数解析与Promise类似
test = async () => {
var a = await NativeModules.TestModule.testFour('msg');
console.log('----->', 'over'+a);
}
上面代码实例看到Callback
的回调方式,但是这种方式必须在JS端触发,才能进行反响回调。
Promise
与Callback
类似,Promise
也具有异步的效果。
Ios端: RCT_EXPORT_METHOD(testFour:(NSString*)text:(RCTPromiseResolveBlock)resolve:(RCTPromiseRejectBlock)reject) {
resolve([@"Callback:" stringByAppendingString:text]);
}
JS端:
NativeModules.TestModule.testThree(test1, test2)
.then((...) => {
...
}).catch(e => {
...
});
但是上面两种方式都无法需要在JS端触发。
RCTEventEmitter
该功能类似广播监听。不同于上面两者函数回调,一次回调,此接口用于多次回调,长期监听。
IOS端:
TestEmitterModule.h@interface TestEmitterModule : RCTEventEmitter <RCTBridgeModule>
- (NSArray<NSString*> *) supportedEvents;
- (void)register: (NSString*)string;
@end
TestEmitterModule.m@implementation TestEmitterModule
RCT_EXPORT_MODULE();
- (NSArray<NSString*> *)supportedEvents {
return @[@"EventName"];
}
// 注册通信
- (void)register: (NSString*) string {
[self sendEventWithName:@"EventName" body:@{@"name": string}];
}
// 发送信息提示回调,这里仅用于测试用
RCT_EXPORT_METHOD(send:(NSString*)text) {
[self register:@"callback"];
}
@end
JS端:import { NativeModules, NativeEventEmitter } from 'react-native';
...
const emitter = new NativeEventEmitter(NativeModules.TestEmitterModule);
// 注册
emitter.addListener('EventName', (name) => {
// 回调
console.log('----->', 'callback:'+name.name);
});
// 模拟发送消息
NativeModules.TestEmitterModule.send('test');
// 取消注册
emitter.remove();
注意,如果在未注册监听的情况下发送消息,则会发送一个警告
Sending XXX with no listeners registered
,告知未找到注册该字段的监听器。
在需要判断该问题时,可以使用startObserving
和stopObserving
方法。@implementation TestEmitterModule
bool hasListener;
RCT_EXPORT_MODULE();
- (NSArray<NSString*> *)supportedEvents {
return @[@"EventName"];
}
- (void)startObserving {
hasListener = YES;
}
- (void)stopObserving {
hasListener = NO;
}
- (void)register: (NSString*) string {
if (hasListener) {
[self sendEventWithName:@"EventName" body:@{@"name": string}];
}
}
类型转换
这里时RCTConvert.h
文件。
https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h
当在定义一组常量时,我们需要对RCTConvert
类进行扩展。
如,需要使用如下:#import <React/RCTConvert.h>
@implementation RCTConvert (AMap3DView)
// 类型
RCT_ENUM_CONVERTER(MAMapType, (@{
@"normal": @(MAMapTypeStandard),
@"satellite": @(MAMapTypeSatellite),
@"night": @(MAMapTypeStandardNight),
@"navi": @(MAMapTypeNavi),
@"bus": @(MAMapTypeBus)
}), MAMapTypeStandard, integerValue);
@end
如上,我们将在JS中需要的字符串,在转换到ios时会自动根据这个内容进行转换到相应枚举类型中。
第一个参数为ios中枚举类型
第二个参数为转换对应表
第三个参数为默认数值
第四个参数为转换器工具
自定义类型
当我们在js层建立一个对象,需要在ios层读取这个对象时,需要对自定义类型进行解析处理,在android中,使用的ReadableMap
、ReadableArray
来解决,在ios上的处理也很像。
当在定义一组常量时,我们需要对RCTConvert
类进行扩展;这里的自定义类型也需要。@implementation RCTConvert (AMap3DView)
...
// 配置自定义对象
+ (LocationStyle *)LocationStyle:(id)json {
LocationStyle * locationStyle = [LocationStyle new];
locationStyle.locationIcon = [UIImage imageNamed:[self NSString:json[@"locationIcon"]]];
locationStyle.strokeColor = [self NSString:json[@"strokeColor"]];
locationStyle.strokeWidth = [self CGFloat:json[@"strokeWidth"]];
locationStyle.showsAccuracyRing = [self BOOL:json[@"showsAccuracyRing"]];
return locationStyle;
}
...
代码中可以看到,这里完成了一个对json格式数据到ios对象数据的转换过程,也是RN在对象转换的一个转换表,所有自定义的对象类型都会像这样进行转换对照。
自定义控件
|
这里创建了一个地图控件管理类,用与管理我们自定义的AMap3DView
。
- 继承
RCTViewManager
- 实现的函数必须使用
RCT_EXPORT_METHOD()
来定义。 - 需要的属性必须使用
RCT_EXPORT_VIEW_PROPERTY()
来定义,前者为属性名称,后面则是属性的类型,如果需要自定义类型,则必须要在RCTConvert
的类中去添加这个自定义类。然后如果我们需要设置这个属性到View中的话,还必须要在自定义的View中添加指定函数设置这个属性。必须以setXxx
格式设置属性函数。- (void)setLocationTypeIos:(MAUserTrackingMode)mode
{
...
} - 最后通过
view()
函数添加这个控件。