美文网首页
ReactNative原生集成-iOS

ReactNative原生集成-iOS

作者: 玄策 | 来源:发表于2017-12-26 17:22 被阅读38次

目录

  • 1)搭建-原生集成rn
  • 2)demo
  • 3)访问原生侧常量
  • 4)访问原生侧方法
    • 4.1)void无返回
    • 4.2)有返回回调
  • 5)原生启动RN并获取ViewController传递的数据
  • 6)原生发送通知给RN

1)搭建-原生集成rn

  • react-native init 工程名
  • copy原iOS工程至Rn工程/ios中
  • 进入ios目录,配置CocoaPods依赖
    ~/ios/
pod init
  • 修改生成的Podfile文件
    ~/ios/Podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'studyRn_Native_iOS' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for studyRn_Native_iOS

  # 'node_modules'目录一般位于根目录中
  # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
  pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    #'CxxBridge', # 如果RN版本 >= 0.45则加入此行
    'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket', # 这个模块是用于调试功能的
    # 在这里继续添加你所需要的RN模块================
  ]
  # 如果你的RN版本 >= 0.42.0,则加入下面这行
  pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"

   # 如果RN版本 >= 0.45则加入下面三个第三方编译依赖
  #pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  #pod 'GLog', :podspec => '../node_modules/react-native/third-party-podspecs/GLog.podspec'
  #pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end
  • 安装pod包
    ~/ios/
pod install
pod安装完成
  • 打开studyRn_Native_iOS.xcworkspace进入xcode


    打开xcode
  • 在ViewController中导入头文件,并修改入口代码

#import "ViewController.h"
#import <React/RCTRootView.h>

@interface ViewController ()

@end

@implementation ViewController

- (IBAction)onClick:(id)sender {
    //如果这样写 需要RN侧有 index.js的入口文件
    //    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    //如果这样写 需要RN侧有 index.ios.js的入口文件
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.127:8081/index.ios.bundle"];
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
                         moduleName        : @"FirstReactComponent"
                         initialProperties :
                    @{
                       @"scores" : @[
                               @{
                                   @"name" : @"Alex",
                                   @"value": @"42"
                                   },
                               @{
                                   @"name" : @"Joel",
                                   @"value": @"10"
                                   }
                               ]
                       }
                          launchOptions    : nil];
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    [self presentViewController:vc animated:YES completion:nil];
}
  • 新建RN-Component
export default class FirstReactComponent extends Component {
  render() {
    const data = this.props.scores;
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          大家好,我是React界面
        </Text>
        {
            data.map(function(item,index){
                return (
                 <Text style={styles.welcome} key={index}>
                  大家好,我是{item.name},我今年{item.value}岁
                </Text>
                )
            })
        }
      </View>
    );
  }
}
  • 在RN的入口文件处注册此Component,注意:所有暴露给原生的Component都需要在入口文件处注册。
    ~/index.ios.js
import FirstReactComponent from './src/FirstReactComponent';
...
//暴露给原生使用
AppRegistry.registerComponent('FirstReactComponent', () => FirstReactComponent);
  • 打开Packager服务
    ~/工程根目录
npm start
RN集成iOS
  • 生产打release包
  //release包流程
  //第一步 新建release_ios文件夹 然后
  //react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
  //第二步 将assets和main.jsbundle拖进xcode [create floder references即可]
  
  //为了方便使用,也可以把打包命令写到npm script中
  //package.json中  "bundle-ios":"node node_modules/react-native/local-cli/cli.js bundle --entry-file index.ios.js  --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/"
  //运行命令直接打包 npm run bundle-ios
  
  //最后
  //    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

2)demo

ios屏幕快照
RN屏幕快照
demo
  • 新建原生桥接模块MyNativeBridgeModule
//  MyNativeBridgeModule.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface MyNativeBridgeModule : NSObject<RCTBridgeModule>

@end
//  MyNativeBridgeModule.m
#import "MyNativeBridgeModule.h"

@implementation MyNativeBridgeModule

RCT_EXPORT_MODULE();

-(NSDictionary *)constantsToExport
{
    return @{
             @"Native_Constants_A": @"原生常量A",
             @"Native_Constants_B": @"原生常量B",
            };
}

RCT_EXPORT_METHOD(NATIVE_sendDataToNative:(NSString *)str){
    NSLog(@"收到RN侧的str数据:%@",str);
}

RCT_EXPORT_METHOD(NATIVE_sendDataToNativeCallback:(NSDictionary *)dict callback:(RCTResponseSenderBlock)callback){
    for (NSString *key in dict) {
        NSLog(@"收到RN侧的dict数据: key= %@, value= %@", key,dict[key]);
    }
    NSString *str = @"数据已收到,且被我改变啦";
    callback(@[[NSNull null],str]);
}

@end
  • RN侧文件
export default class  FirstReactComponent_Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name:'大家好,我是React界面'
    };
  }
  _sendDataToNative=()=>{
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNative('我是来自RN的数据');
  };
  _sendDataToNativeCallback=()=>{
    const params = {
      '姓名':'杰洛特',
      '性别':'男',
    }
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNativeCallback(
      params,
      (error,result)=>{
        this.setState({
          name:result
        })
      }
      )
  };

  render() {
    const data = this.props.scores;
    const Native_Constants_A = NativeModules.MyNativeBridgeModule.Native_Constants_A;
    return (
      <View style={styles.container}>
        {
            data.map(function(item,index){
                return (
                 <Text style={styles.welcome} key={index}>
                    我是Intent数据:{item.name},{item.value}岁
                </Text>
                )
            })
        }
        <Text style={styles.welcome}>
              {Native_Constants_A}
        </Text>
        <TouchableOpacity onPress={this._sendDataToNative} style={styles.button}>
          <Text style={styles.instructions}>
            点击发送数据给原生
          </Text>
        </TouchableOpacity>
        <Text style={styles.welcome}>
          {this.state.name}
        </Text>
       <TouchableOpacity onPress={this._sendDataToNativeCallback} style={styles.button}>
          <Text style={styles.instructions}>
            点击发送数据给原生,并回调修改
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
}
//暴露给原生使用
AppRegistry.registerComponent('FirstReactComponent', () => FirstReactComponent);

3)访问原生侧常量

在MyNativeBridgeModule中

-(NSDictionary *)constantsToExport
{
    return @{
             @"Native_Constants_A": @"原生常量A",
             @"Native_Constants_B": @"原生常量B",
            };
}

RN侧只需调用即可

const Native_Constants_A = NativeModules.MyNativeBridgeModule.Native_Constants_A;

4)访问原生侧方法

  • 4.1)void无返回
RCT_EXPORT_METHOD(NATIVE_sendDataToNative:(NSString *)str){
    NSLog(@"收到RN侧的str数据:%@",str);
}
  _sendDataToNative=()=>{
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNative('我是来自RN的数据');
  };
  • 4.2)有返回回调
RCT_EXPORT_METHOD(NATIVE_sendDataToNativeCallback:(NSDictionary *)dict callback:(RCTResponseSenderBlock)callback){
    for (NSString *key in dict) {
        NSLog(@"收到RN侧的dict数据: key= %@, value= %@", key,dict[key]);
    }
    NSString *str = @"数据已收到,且被我改变啦";
    callback(@[[NSNull null],str]);
}
  _sendDataToNativeCallback=()=>{
    const params = {
      '姓名':'杰洛特',
      '性别':'男',
    }
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNativeCallback(
      params,
      (error,result)=>{
        this.setState({
          name:result
        })
      }
      )
  };

5)原生启动RN并获取ViewController传递的数据

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //如果这样写 需要RN侧有 index.js的入口文件
    //    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    //如果这样写 需要RN侧有 index.ios.js的入口文件
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.127:8081/index.ios.bundle"];
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
                         moduleName        : @"FirstReactComponent"
                         initialProperties :
     @{
       @"datas" : @[
               @{
                   @"name" : @"Alex",
                   @"value": @"42"
                   },
               @{
                   @"name" : @"Joel",
                   @"value": @"10"
                   }
               ]
       }
                       launchOptions    : nil];
    self.view = rootView;
}
const data = this.props.datas;

6)原生发送通知给RN

~ NativeBridge.h

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

//继承了RCTEventEmitter这个类,用来发送通知的
@interface NativeBridge  : RCTEventEmitter<RCTBridgeModule>

@end

~ NativeBridge.m

@implementation NativeBridge

RCT_EXPORT_MODULE();

//实现suppportEvents方法
- (NSArray<NSString *> *)supportedEvents
{
  return @[@"Native_PushTo_RN_AliPayBoardcast"];
}

//设置发送事件通知给RN侧,通知规约为 "Native_PushTo_RN_AliPayBoardcast"
- (void)AliPayBoardcastReceived:(NSNotification *)notification
{
  [self sendEventWithName:@"Native_PushTo_RN_AliPayBoardcast" body:notification.object];
}
  • 本例中实现调用支付宝支付,支付宝回调给AppDelegate
    新增单例方法,注册native本地通知,当AppDelegate接收到支付宝的回调时,发送通知给本地通知,由本地通知调用方法通知RN侧
    ~ NativeBridge.m
+ (id)allocWithZone:(NSZone *)zone {
  static NativeBridge *pushManager = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    pushManager = [super allocWithZone:zone];
    //注册通知alipay支付宝回调
    [[NSNotificationCenter defaultCenter] addObserver:pushManager selector:@selector(AliPayBoardcastReceived:) name:@"AliPayBoardcast" object:nil];
  });
  return pushManager;
}

~AppDelegate.m

// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
  if ([url.host isEqualToString:@"safepay"]) {
    // 支付跳转支付宝钱包进行支付,处理支付结果
    [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
      NSLog(@"result = %@",resultDic);
      [[NSNotificationCenter defaultCenter] postNotificationName:@"AliPayBoardcast" object:resultDic];
    }];
    return YES;
  }
}

参考资料

官网


相关文章

网友评论

      本文标题:ReactNative原生集成-iOS

      本文链接:https://www.haomeiwen.com/subject/ygmdgxtx.html