Taro 中的 React Native 开发总结
Taro 中的 React Native 开发总结

Taro 中的 React Native 开发总结

tags
Taro
Android
iOS
ReactNative
React
JavaScript
date
Aug 5, 2020
source
status

notion image
notion 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文件后再重试
  • iOS Debug 构建流程:
      1. npm run dev:rn
      1. 在Xcode中导入project/ios/编译后的ios项目目录
      1. 在Xcode左上角菜单栏preference -> accounts -> 添加Apple ID开发账号 -> 主界面选择模拟器 -> 构建运行
  • iOS APP内呼出开发控制菜单:command + control + Z,或者顶部菜单栏:设备(Device)-> 摇一摇(Shake)
  • iOS 构建成功后无法在模拟器中启动APP:检查Xcode设置中开发者账号是否需要重新登录验证。
  • iOSpod install构建错误:
    • CocoaPods could not find compatible versions for pod "Folly": In snapshot (Podfile.lock):
      删除project/ios/Podfile.lock文件后重新运行pod install
  • iOS真机调试:参考连接
    • 将手机连接电脑,配置打包签名为Automatically,Team选择个人开发者账户,Bundle Identifier会联网检查,如果不处在同一Team下进行开发,则需要修改为不重复的包名。运行终端模拟器选择刚才连接的手机,点击运行将自动安装到手机上,第一次安装后需要到设置中开启信任模式,否则iOS将禁止调试app运行。运行后的app摇一摇可以呼出控制菜单,如果想要连上React Native Debugger.exe,需要开启Debug JS Remotely,并通过WiFi连接到和电脑的同一局域网,并设置连接地址IP等操作。
notion image
  • 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不适用需要加上判断

标签

  • 任何标签都是大写字母开头,否则RN报红屏错误。
  • 所有文本都需要使用<Text></Text>标签包裹,否则RN红屏闪退,且colorfont-size等文本属性只针对<Text>标签生效。
  • RN限制文本行数:
<Text numberOfLines={1} />
  • 给组件设置引用,可以通过引用调用组件内部方法:
this.Modal && this.Modal.show()

...

{isShow && (
  <Block>
    <Image />
  </Block>
)}
<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' && (
  <RnImage ref={(c) => this.RnImage = c} source={{uri: data}} />
)}
  • 点击事件等事件传递,需要使用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"}}>
  文本
</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>标签上。
      1. 检查<Text>是否有宽度。
      1. 检查<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,具体路径需要根据包名而定。
      1. 选择插件时在Readme中,注意插件有没有对RN版本有要求,根据RN版本下载,最好选择都支持IOS/Android
path: "/data/user/0/com.package.project/cache/1594624681380.JPEG"
DecodeUtil.java:图片转换为Bitmap格式,原插件会在转换为YUV格式,提高二维码识别速度。但是getYUV420sp()在转换中抛出异常,找不到错误位置,判断是数组越界,换为直接使用Bitmap格式。
  • CameraRoll RN原生组件,CameraRoll模块提供了访问/保存本地相册的功能。
  • 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原生代码二改

//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中文输入法:
// package-edit:修复中文输入法 RN 0.57版本
if (_onChange && backedTextInputView.markedTextRange == nil) {
  _onChange(@{
     @"text": self.attributedText.string,
     @"target": self.reactTag,
     @"eventCount": @(_nativeEventCount),
  });
}
参考链接

Loading Comments...