构建

image

image

  • RN编译不监听修改是代码有错

  • RN编译后的代码文件位于project/rn_temp/下(RN编译后的源码可作参考)。

  • 小程序编译后的代码文件位于project/dist/weapp/下。

  • 进行RN的编译时,确保React Native Debugger.exe程序在运行,用于传输js数据。不开启则代码改动不会生效。

  • 编译小程序:npm run dev:weapp重新编译小程序后,Taro不会编译sitemap文件,微信开发工具会报找不到sitemap文件的错误,需要手动将src文件夹内的sitemap放入dist小程序编译根目录中。

  • 编译RN:npm run dev:rn,编译完成后会开启一个node命令行窗口,通过8081端口用于传输JS代码,此时应该确保React Native Debugger.exe程序在运行。

  • 打包RN(debug):flush-android-debug.batreact-native run-andoridnpx react-native run-android

  • 打包RN(release):flush-android-release.batreact-native run-andorid --variant=releasenpx react-native run-android --variant=release 需要卸载原模拟器里的debug版本,否则自动安装不上,或者可以去project/android/app/build/outputs/apk/release/目录里拿出APK手动拖到模拟器窗口里或者放到真机上安装。

  • 打包debug版的APK安装后,进行调试前需要按下Ctrl+M,点击Debug JS Remotely开启远程JS调试,用于接收React Native Debugger.exe传输过来的,编译后的JS代码。不开启则代码改动不会生效。

  • 确保以上操作都正确,如果还是没更新代码或者连接React Native Debugger.exe的话,去开启模拟器的WIFI。

  • 打包本地图片,新增本地图片时或者初次打包release时需要(确保assets目录存在,不存在则新建文件夹,敲命令前先编译RN):

    react-native bundle --platform android --dev false --entry-file rn_temp/index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
    

    运行完毕后需要进入android/app/src/main/res/目录内删除svg格式图片,否则APK打包报错

  • 使用他人的node_modules包(尤其是不同系统平台的),在使用npm命令前可能需要重置node-sass包:npm rebuild node-sass

以上命令都在项目根目录运行

  • iOS Debug 构建需要另外在project/ios/目录下安装pod install(每次插件更新都要运行pod install)

pod install报插件红字错误的话,删除Podfile.lock文件后再重试

  • Xcode构建崩溃:顶部菜单栏->Product->Clean Build Folder 清空构建缓存

代码

  • this.setState()是异步执行的,可以通过回调参数来保证已经set完毕:

    this.setState({
      a: 'a'
    }, () => {
      console.log(this.state.a)
    })
    
  • Taro判断小程序平台和RN平台表达式:

    process.env.TARO_ENV === 'rn'
    process.env.TARO_ENV === 'weapp'
    
  • RN判断Android平台和iOS平台表达式(需导包):

    import {Platform} from 'react-native'
    
    ...
    
    Platform.OS === 'android'
    Platform.OS === 'ios'
    
  • 只有页面才有componentDidShow生命周期方法,组件是没有的。可以在页面里的componentDidShow方法中,通过持有组件引用来调用组件内方法,来达到componentDidShow的效果。

  • Taro中的props的值是不能改变的需要转换成state来改变:

    static defaultProps = {
      show: false
    }
    state = {
      sShow: false
    }
    constructor(props) {
      super(props);
      this.state.sShow = props.show;
    }
    
    ...
    
    
  • Taro中的e.stopPropagation();冒泡处理在RN不适用需要加上判断

  • JS在遍历中的同时删除数组元素:解决办法

标签

  • 任何标签都是大写字母开头,否则RN报红屏错误。

  • 所有文本都需要使用<Text></Text>标签包裹,否则RN红屏闪退,且colorfont-size等文本属性只针对<Text>标签生效。

  • RN限制文本行数:

    <Text numberOfLines={1} />
    
  • 给组件设置引用,可以通过引用调用组件内部方法:

    this.Modal && this.Modal.show()
    
    ...
    
    <Modal ref={(c) => this.Modal = c}>
    

    调用前需要判断组件是否已经渲染完毕,否则会报undefined

  • 当导入的RN组件与Taro组件重名时,可以起一个别名一起使用:

    import {Image} from '@tarojs/components'
    import {Image as RnImage} from 'react-native'
    
  • 视图渲染中所用用到RN相关组件的地方都需要加平台判断,组件引用时也需要加平台判断,否则小程序编译会报缺少npm包AccessibilityInfo,开始安装...:(import则会在编译时自动忽略不属于当前平台的组件)

    import {Image as RnImage} from 'react-native'
    
    ...
    
    componentDidMount = () => {
      if (process.env.TARO_ENV === 'rn') {
        this.RnImage.getSize()
      }
    }
    
    ...
    {process.env.TARO_ENV === 'rn' && (
      <Block>
        <RnImage
          ref={(c) => this.RnImage = c}
          source={{uri: data}}
        />
      </Block>
    )}
    
  • 点击事件等事件传递,需要使用bind()方法:

    onClickItem = (a, b, c, event) => {
      ...
    }
    
    ...
    
    <View onClick={this.onClickItem.bind(this, a, b, c)} />
    

    onClick中的this参数一定要写在首位,后面按照方法参数顺序排列。方法中的event对应标签中的this,用来传递事件对象,要放在末尾。不再使用小程序的data-*方式传参

  • 不能在<Image></Image>标签内写子布局,且<Image />标签无法直接设置点击事件,需要使用<View></View>标签包裹起来,然后给<View />标签点击事件。

  • <View />标签只包裹<Image />时,需要给定和<Image />标签一样的宽高值,否则会导致弹性布局的垂直居中属性无效。

  • ( )中只有一个组件标签时,需要使用<Block></Block>将标签包裹起来,否则会有语法错误,需要导包:

    import {Block, Image} from '@tarojs/components'
    
    ...
    
    {isShow && (
      <Block>
        <Image />
      </Block>
    )}
    
  • Taro自带的<Image />组件在RN里会有圆角问题,必要时可使用RN的<Image />组件:

    import {Block, Image} from '@tarojs/components'
    import {Image as RnImage} from 'react-native'
    
    ...
    
    {process.env.TARO_ENV != 'rn' ? (
      <Block>
        <Image
          className="img"
          src={'https://avatar.png'}
        />
      </Block>
    ) : (
      <Block>
        <RnImage
          className="img"
          source={{uri: 'https://avatar.png'}}
        />
      </Block>
    )}
    
    ...
    
    .img {
      width: 100px;
      height: 100px;
      border-radius: 100px;
    }
    

    RN的组件在用法上完全和RN原生用法一致

  • 在RN上使用Taro的<Image />组件时,必须设置固定宽高,否则第一次进入APP时将不会显示,且不能带有mode属性。

  • iOS文本下划线颜色设置:

    <Text style={{textDecorationColor: "white"}} className="integral-rule-txt">文本</Text>
    

样式

  • 优先使用flex布局

  • 行内样式必须加{ }包裹,否则不生效(RN需要{{ }}):

    <View style={'height: 100rpx'}>
    
  • Taro只会对写在CSS文件里的px单位自动做缩放,不会对行内样式中的px单位自动做缩放。

  • 在行内样式中,小程序平台需要使用rpx来保证小程序各尺寸缩放,RN平台则不需要写单位(RN行内样式单位默认为点(point)),小程序的rpx和RN的点(point)比例为2倍,css文件中的px是行内样式中点(point)的2倍:

    <View style={process.env.TARO_ENV === 'rn' 
      ? {height: 100} 
      : 'height: 200rpx;'
    }>
    
  • 很多CSS样式在RN上不支持,有些可能会导致闪退,在CSS上做平台判断:

    /* #ifdef rn */
    ...
    /* #endif */
    
    ...
    
    /* #ifndef rn */
    ...
    /* #endif */
    
  • RNposition样式只支持relativeabsolute,不支持blockfixed等(会闪退)。

  • border-radius不支持百分比。圆头像图片框圆角值需要设置成宽高值的一半,过大或过小都会在ios上导致变形。

  • display: flex;小程序默认方向为水平,RN默认方向为竖直。

  • iOS中border-bottom样式失效修复:不能直接在<Text>上加border-bottom样式,需要在外面套一层<View>,给<View>border-bottomborder-radius同理,<Text>只适用文本相关样式,文本无关样式需要给<View>加上并包裹<Text>达到效果。

  • text-align: center;不生效:1.检查样式是否已设置在<Text>标签上。2.检查<Text>是否有宽度。3.检查<Text>的父组件是否已设置display: flex;

插件

  • 安装流程

    下载插件:  npm install <插件名>@<版本号>  --save
    示例:npm install react-native-image-crop-picker@0.23.1 --save
    
    React Native 0.60.x之前的版本需要手动link,
    链接到RN项目:react-native link <插件名>
    示例:react-native link react-native-image-crop-picker
    
    iOS端则需要进入/ios目录中运行一遍命令:pod install
    

    以上命令都在项目根目录运行

  • 提示

    1. 有一些RN插件会使用androidX包导入,比如react-native-view-shot插件,因为RN现在版本较低需要修改导入包路径为android.support.xxx,具体路径需要根据包名而定。

    2. 选择插件时在Readme中,注意插件有没有对RN版本有要求,根据RN版本下载,最好选择都支持IOS/Android

      react-nativereact-native-image-resizer
      ≤ 0.601.1.0
      0.611.2.0
  • react-native-image-crop-picker

    react-native-image-crop-picker是一款注重剪裁,相册单选、多选的第三方框架。

    1. github :react-native-image-crop-picker
    2. 相关链接 https://www.jianshu.com/p/8420b08062c7
  • react-native-image-resizer

    图片压缩插件

    1. github : react-native-image-resizer
    2. 相关链接: https://translate.google.cn/
  • react-native-view-shot

    截图插件

    1. github : react-native-view-shot

    2. 相关链接: https://www.cnblogs.com/jackson-yqj/p/9550652.html
      https://www.jianshu.com/p/bd15516a4ae1

  • react-native-smart-barcode

    app扫描二维码插件

    1. github: react-native-smart-barcode

    2. 相关链接:https://juejin.im/post/5ce374b36fb9a07edd29e623

    3. 插件使用的二维码库:ZXing

    4. 获取图片本地路径识别二维码:

      i. 调用的android目录下的RCTCaptureModule.java中DecodeFromPath() 方法

      图片路径为:

      path: "/data/user/0/com.package.project/cache/1594624681380.JPEG"
      

      ii. DecodeUtil.java

      图片转换为Bitmap格式,原插件会在转换为YUV格式,提高二维码识别速度。但是getYUV420sp()在转换中抛出异常,找不到错误位置,判断是数组越界。换为直接使用Bitmap格式。

  • CameraRoll
    RN原生组件,CameraRoll模块提供了访问/保存本地相册的功能。

  • PermissionsAndroid

    Android获取权限,Android6.0以上的设备需要动态申请权限。

    相关链接: https://juejin.im/post/5a0c51d3f265da431e164df9

  • react-native-webview

    低版本RN自带的WebView插件,高版本已分离,需要手动npm install。
    已针对ios进行修改:react-native-webview的ios端实现禁止在注入js内使用window.postMessage()方法,所以在project/node_modules/react-native/React/Views/RCTWebView.m中进行了修改:

    BOOL postMessageIsNative = [
      [webView stringByEvaluatingJavaScriptFromString:testPostMessageNative]
      isEqualToString:@"true"
    ];
    // package-edit:解除webview内嵌js中window.postMessage
    //if (!postMessageIsNative) {
    //  RCTLogError(@"Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
    //}
    // package-edit:解除webview内嵌js中window.postMessage
    #endif
    

ReactNative-iOS原生代码二次修改

  • 修复ios输入法遮挡问题:参考链接

  • Xcode11以上编译报错:Unknown argument type ‘attribute’ in method -[RCTAppState getCurrentAppState:error:]. Extend RCTConvert to support this type.

    //project/node_modules/react-native/React/Base/RCTModuleMethod.mm
    static BOOL RCTParseUnused(const char **input)
    {
      return RCTReadString(input, "__unused") ||
             // package-edit:Xcode11以上编译报错修复
             RCTReadString(input, "__attribute__((__unused__))") ||
             // package-edit:Xcode11以上编译报错修复
             RCTReadString(input, "__attribute__((unused))");
    }
    
  • 修复ios中文输入法(已在0.57node包中修改,搜索注释package-edit可找到):参考链接

    // package-edit:修复中文输入法 RN 0.57版本
    if (_onChange && backedTextInputView.markedTextRange == nil) {
      _onChange(@{
         @"text": self.attributedText.string,
         @"target": self.reactTag,
         @"eventCount": @(_nativeEventCount),
      });
    }