React Native (11)引入原生模塊& UI

本文章主要介紹如何在 React Native中使用原生模塊、以及在ReactNative 中如何使用原生UI 作為 Component;

項(xiàng)目中用到的源碼 ReactNative_demo

1.打包JSbundle

進(jìn)行編譯,離線打包資源。命令如下:

react-native bundle 
    --entry-file index.js    //entry-file,ios或者android入口的js名稱,比如index.js
    --platform ios    //platform ,平臺(tái)名稱(ios或者android)
    --dev false    //設(shè)置為false時(shí)會(huì)對(duì)JavaScript代碼進(jìn)行優(yōu)化處理 
    --bundle-output ./ios/bundle/index.ios.jsbundle    //生成的jsbundle文件的名稱
    --assets-dest ./ios/bundle    //圖片以及其他資源存放的目錄,比如./ios/bundle

為了方便操作,在package.json中添加編譯命令(node node_modules/react-native/local-cli/cli.js為腳本,固定寫就行)
提前在項(xiàng)目根目錄的 iOS 目錄下新建好 bundle文件夾

"scripts": {
    此處省略其它配置....
    "bundle-ios" : "node node_modules/react-native/local-cli/cli.js bundle --entry-file index.js  --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./output/bundle"
  },

執(zhí)行命令

yarn bundle-ios

最后輸出jsbundle圖片資源文件

image.png

2. RN橋接原生模塊

定義一個(gè)ConnectTool 的類,提供給React Native調(diào)用,首先這個(gè)類需要遵守 <RCTBridgeModule>協(xié)議;
RCT_EXPORT_MODULE(); 默認(rèn)導(dǎo)出以該類名為名字的原生模塊;

    1. 導(dǎo)出一個(gè)異步方法
RCT_EXPORT_METHOD(openView:(NSDictionary*)params){
  // 因?yàn)槭秋@示頁(yè)面,所以讓原生接口運(yùn)行在主線程
     NSLog(@"start openView:");
     dispatch_async(dispatch_get_main_queue(), ^{
          sleep(3.0);
         // 在這里可以寫需要原生處理的UI或者邏輯
         NSLog(@"end openView = %@", params);
     });
}
    1. 導(dǎo)出一個(gè)支持Promise的方法
RCT_EXPORT_METHOD(request2:(NSDictionary *)params success:(RCTPromiseResolveBlock)success failed:(RCTPromiseRejectBlock)failed){
  
 
  NSMutableDictionary *paramsMutable = @{@"result":@"success"}.mutableCopy;
  
  /// 這里模擬一個(gè)網(wǎng)絡(luò)請(qǐng)求 成功/失敗的情況
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  __weak typeof(self) weakSelf = self;
  dispatch_async(queue, ^{
    [paramsMutable setValue:@(1) forKey:@"success"];
    sleep(1.0); //模擬網(wǎng)絡(luò)請(qǐng)求
    if ((weakSelf.value % 2 == 0) && success != NULL) {
        success(paramsMutable);
     
    } else {
      NSError *error = [NSError errorWithDomain:@"我是Promise回調(diào)錯(cuò)誤信息..." code:101 userInfo:nil];
      failed( @"-1",@"failed ",error);
    }
    weakSelf.value++;
  });
}

    1. 導(dǎo)出一個(gè)同步方法
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSArray *,testSyncFunc:(NSString *)name)
{
  NSMutableArray *events = @[@"value1",@"value2",@"value3",@"value4",@"value5"].mutableCopy;
  [events insertObject:name atIndex:0];
  return events.copy;
}

    1. 導(dǎo)出一個(gè)常量方法
-(NSDictionary *)constDict{
  return @{@"key1":@"value1",
           @"key2":@"value2",
           @"key3":@"value3",
  };
}
在 React Native 的調(diào)用方法

提供一個(gè)文件封裝原生模塊 ,文件名文NativeIOSModule;

/// 把這個(gè)原生模塊封裝起來(lái)exprot 導(dǎo)出(文件名為NativeIOSModule)
import {NativeModules} from 'react-native';
export default  NativeModules.ConnectTools;

調(diào)用地方

import ConnectTools from '../Native/NativeIOSModule';

省略...
render(){
return(
     <View>
        <TouchableHighlight  onPress={()=>this.onPress()}>
        <Text style={{color: 'red',fontSize:34,fontWeight:'bold'}}>{this.props.titleName}</Text>
        </TouchableHighlight>
    </View> 
)
}
async onPress(state) {
        let value = {'title':'pengchao'};

        //func1  (異步方法 無(wú)回調(diào))
        ConnectTools.openView(value);

        // func2  (Promise 方法)
        ConnectTools.request2(value).then((result)=>{
            console.log('success'+ JSON.stringify(result));
        },(code,message,error)=>{
            console.log(code + message + error);
            //coder \ message\ error ,只收到了 code == 'failed'
        });

        ///func3 同步方法
        let value2 = ConnectTools.testSyncFunc('value4');   
        alert(JSON.stringify(value2));
        
        //func4 
        ConnectTools.request("deviceName", function(error,result1,result2){
             console.log(error);
             console.log(result1);
             console.log(result2);
         });
    }

方法1 調(diào)用結(jié)果


image.png

方法2 調(diào)用結(jié)果


IMG_4867 2.jpg

方法3 調(diào)用結(jié)果
略...

方法4 調(diào)用結(jié)果
略...

2. RN橋接原生UI

橋接原生的UI ,需要實(shí)現(xiàn)兩個(gè)對(duì)象,一個(gè)是自定義的View 和繼承于RCTViewManager的子類 ;

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h>
#import "CustomButton.h"

/// 自定義VIew
@interface CustomButton : UIView
@property (nonatomic,copy) NSString *mapData;//RN 組件傳來(lái)的屬性
@property (nonatomic,copy) RCTBubblingEventBlock onButtonClick; //回調(diào)方法
@end

/// Bridger
@interface CustomButtonView : RCTViewManager
@property (nonatomic) CustomButton *customBtn;
@end
#import "CustomButton.h"
@interface CustomButton()
@property (nonatomic,strong) UIButton *leftButton;
@property (nonatomic,strong) UIImageView  *rightImage;
@property (nonatomic,assign) NSUInteger value;
@end
@implementation CustomButton

- (instancetype)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    [self setupUI];
    self.value = 0;
  }
  return self;
}

- (void)setupUI {
  /// 自定義UI的布局 & 初始化
  self.leftButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
  [self.leftButton setTitle:@"custom" forState:UIControlStateNormal];
  [self.leftButton.titleLabel setFont:[UIFont systemFontOfSize:14]];
  [self.leftButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
  self.rightImage = [[UIImageView alloc]initWithFrame:CGRectMake(60, 0, 40, 40)];
  self.rightImage.image =[UIImage imageNamed:@"test_icon"];
  /// 事件
  [self.leftButton addTarget:self action:@selector(clickFunc:) forControlEvents:UIControlEventTouchUpInside];
  [self addSubview:self.leftButton];
  [self addSubview:self.rightImage];
}

/// 響應(yīng)點(diǎn)擊事件
- (void)clickFunc:(UIButton *)sender {
  NSLog(@"clickFunc");
  self.value ++;
  // @{@"key":@(self.value) 這里表示需要回傳給外部的值
  self.onButtonClick(@{@"key":@(self.value)});
}

/// RN 部分的屬性被賦值后會(huì)自動(dòng)調(diào)用這個(gè)方法傳參
-(void)setTitleName:(NSString *)titleName{
  if (titleName) {
    [self.leftButton setTitle:titleName forState:UIControlStateNormal];
  }
  [self layoutSubviews];
}

/// 自定義一些其它參數(shù)的邏輯
- (void)setMapData:(NSString *)mapData {
  NSLog(@"%@",mapData);
}
@end

@implementation CustomButtonView
RCT_EXPORT_MODULE();
// props 參數(shù) (定義的參數(shù)要在相應(yīng)的view實(shí)現(xiàn)方法)
RCT_EXPORT_VIEW_PROPERTY(titleName, NSString)

// 字典類型 ,參數(shù)名 mapData
RCT_EXPORT_VIEW_PROPERTY(mapData, NSDictionary)

// 點(diǎn)擊事件
RCT_EXPORT_VIEW_PROPERTY(onButtonClick, RCTBubblingEventBlock)

// 自定義數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)json
RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, CustomButtonView){
}

- (UIView *)view
{
  /// frame不設(shè)置也行,反正都會(huì)被覆蓋
  if (!_customBtn) {
    _customBtn = [[CustomButton alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
  }
  return _customBtn;
}

注意事項(xiàng):
RCT_EXPORT_VIEW_PROPERTY()自定義的屬性,需要在自定義View內(nèi)部實(shí)現(xiàn),不然會(huì)出現(xiàn)找不到該方法的報(bào)錯(cuò)導(dǎo)致崩潰

//導(dǎo)出原生view 模塊
import React, { Component } from 'react';
import { requireNativeComponent } from 'react-native';
var CustomButtonView  = requireNativeComponent('CustomButtonView');
export default class CustomNativeButton extends Component {
  render() {
    return (
      <CustomButtonView {...this.props}></CustomButtonView>
    );
  }
}

調(diào)用

/// 導(dǎo)入
import CustomNativeButton from './UI/CustomNativeButton'
/// 調(diào)用
<CustomNativeButton 
          titleName = 'CustomNativeButton'
           onButtonClick={(result)=>{
            console.log("xxxx" + result.key);
          }}  
          mapData = {{mapKey:"mapValue"}}
          style={{width: 300, height:100,flex:1}} >
</CustomNativeButton>

React Native中的調(diào)用

效果圖如下(這里只是舉個(gè)例子,樣式寫的比較垃圾):


原生view在RN中展示.jpg

3. RN動(dòng)態(tài)更新

  1. React Native 中文網(wǎng)的 Pushy
  2. 微軟的 CodePush
  3. 搭建私服的 code-push-server。

3. RN圖片資源本地化

4. RN發(fā)起網(wǎng)絡(luò)請(qǐng)求 Get、Post

參考鏈接 React-Native JS 加載原生組件(iOS)
參考鏈接 詳解RN導(dǎo)出Native Module原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容