美文网首页
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