问题1

问题描述:TextInput组件在页面底部时,弹出键盘时遮挡TextInput组件,用户无法正常输入内容
分析解决:弹出键盘浮在页面布局之上占用了一部分布局控件,可以监听键盘的弹出和隐藏事件,实现动态调整页面布局。

//页面装载时
componentWillMount() {//监听键盘弹出事件this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShowHandler.bind(this));//监听键盘隐藏事件this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHideHandler.bind(this));
}//页面移除时
componentWillUnmount() {//卸载键盘弹出事件监听if (this.keyboardDidShowListener != null) {this.keyboardDidShowListener.remove();}//卸载键盘隐藏事件监听if (this.keyboardDidHideListener != null) {this.keyboardDidHideListener.remove();}
}
//自定义键盘事件处理
//键盘弹出事件响应
keyboardDidShowHandler(event) {this.setState({keyboardShow: true});console.log(event.endCoordinates.height);
}//键盘隐藏事件响应
keyboardDidHideHandler(event) {this.setState({keyboardShow: false});
}//强制隐藏键盘
dissmissKeyboard() {Keyboard.dismiss();console.log("输入框当前焦点状态:" + this.refs.bottomInput.isFocused());
}

在render()方法中,通过keyboardShow实现动态布局

{this.state.keyboardShow ? null :<Image style={styles.devImg}source={require('../../../res/img/device/dev_solar_add.png')}/>
}
<Text style={this.state.keyboardShow ? [styles.textTipMain,  {marginBottom:autoHeight(19)}] :styles.textTipMain}>{getString('solar_connect_input_model')}</Text>

问题2

问题描述:在某些情景下需要监听当前页面的物理返回键,例如双击back退出应用,或者某一页按下back键返回特定页面
分析解决:RN中的页面是通过组件的方式实现的,各页面之间的通过路由的方式连接起来,单纯在当前页面监听hardwareBackPress事件,不止会监听到当前页面的物理返回键事件,也会监听到该页面所有上层页面的物理返回键事件。
网上有很多说的是通过路由长度navigator.getCurrentRoutes().length 判断当前所在页面,尝试多次无果,之后找到了新版本react-navigation的当前页面物理返回键监听的正确方式:

class ScreenWithCustomBackBehavior extends Component {componentDidMount() {BackHandler.addEventListener('hardwareBackPress',this.onBackButtonPressAndroid);}componentWillUnmount() {BackHandler.removeEventListener('hardwareBackPress',this.onBackButtonPressAndroid);}onBackButtonPressAndroid = () => {if (this.props.navigation.isFocused()) {if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {//最近2秒内按过back键,可以退出应用。return false;}this.lastBackPressed = Date.now();ToastAndroid.show('再按一次退出应用', ToastAndroid.SHORT);return true;}}
}

有些版本在componentWillUnmount里执行removeEventListener并没有用,还是会监听到,所以这个时候可以换一种写法:

componentDidMount() {this.backHandler = BackHandler.addEventListener('hardwareBackPress',this.onBackButtonPressAndroid);
}componentWillUnmount() {this.backHandler&&this.backHandler.remove();
}

问题3

问题描述:RN里边多语言适配一般用react-native-i18n第三方多语言库,具体使用参考https://github.com/AlexanderZaytsev/react-native-i18n,App多语言通常有一个需求就是切换语言,如果没有杀死应用进程,切换系统语言之后,App仍然后展示切换之前的语言。
分析解决:切换系统语言之后,App仍然显示为切换之前的语言,很可能是当前语言设置没有生效或者是没有进行语言的重新获取。通过原生方式监听切换系统语言的广播并发送消息给RN,然后再RN应用入口处接收系统语言切换的消息,并设置当前语言为切换后的系统语言:

//原生系统语言切换广播监听
public class LocalReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
reactContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("local_changed",null);}}
}

RN入口接收消息

componentWillMount() {console.log('---componentWillMount---');
this.subLocalChangedListener = DeviceEventEmitter.addListener("local_changed", () => {//每次进入应用前台检查语言if (ObjectUtil.isEmpty(I18n.locale)) {getLanguages().then(languages => {console.log('当前语言' + languages);if (languages.toString().match(I18nUtils.ZH)) {I18n.locale = I18nUtils.ZH;} else {I18n.locale = I18nUtils.EN;}}).catch((error) => {console.log("获取语言失败" + error);});}});
}componentWillUnmount() {console.log('---componentWillUnmount---');
this.susubLocalChangedListener .remove();
}

问题4

问题描述:手势滑动事件处理粒度太粗,导致部分手机上当前页面点击事件无法响应
分析解决:在处理首页预留空间滑动事件时,在onStartShouldSetPanResponder事件时就成为事件的响应者,导致该组件成为所有触摸事件(包括点击事件)的响应者,而该组件又不能很好的处理自己所需触摸事件之外的其他事件,默认是不做任何响应,这就导致了页面点击事件无响应。详细分析RN里边触摸事件的分发处理机制,逐步细化处理触摸事件的响应,不要在一开始就响应,当满足特定需求之后,例如滑动时滑动长度超过特定长度之后再处理,这样既不会影响其他组件的默认事件处理机制,也能够处理特定情况的手势事件。

componentWillMount() {this._panResponder = PanResponder.create({// 要求成为响应者:onStartShouldSetPanResponder: (evt, gestureState) => false,onStartShouldSetPanResponderCapture: (evt, gestureState) => false,onMoveShouldSetPanResponder: (evt, gestureState) => false,onMoveShouldSetPanResponderCapture: (evt, gestureState) => {if (Math.abs(gestureState.dx) < this.thresholdMin && Math.abs(gestureState.dy) < this.thresholdMin) {return false;}else{if ((this.show && gestureState.dy < 0) || (!this.show && gestureState.dy > 0)) {return true;} else {return false;}}},onPanResponderGrant: (evt, gestureState) => {// 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!console.log('onPanResponderGrant');// gestureState.{x,y} 现在会被设置为0},onPanResponderMove: (evt, gestureState) => {// 最近一次的移动距离为gestureState.move{X,Y}console.log('onPanResponderMove');// 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}if ((this.show && gestureState.dy < 0) || (!this.show && gestureState.dy > 0)) {}}},onPanResponderTerminationRequest: (evt, gestureState) => true,onPanResponderRelease: (evt, gestureState) => {// 用户放开了所有的触摸点,且此时视图已经成为了响应者。console.log('onPanResponderRelease');// 一般来说这意味着一个手势操作已经成功完},onPanResponderTerminate: (evt, gestureState) => {// 另一个组件已经成为了新的响应者,所以当前手势将被取消。console.log('onPanResponderTerminate');},onShouldBlockNativeResponder: (evt, gestureState) => {// 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者// 默认返回true。目前暂时只支持android。return true;},});
}

问题5

问题描述:FlatList列表加载圈莫名消失,场景:网络慢时导致首页获取不到设备列表,首页为空,不能下拉刷新。
分析解决:这个问题真的是莫名其妙,我第一感觉是怀疑逻辑处理不严谨,开始按照网络请求-正常-异常展示各种情况梳理,顺便整理了下逻辑,没有问题,就把它定义为莫名消失了。记得刚开始简单列表demo的时候就不存在这个问题,和demo对比,转换网络请求的方式,就差把demo代码全部替换过来了。正常逻辑怎么也想不到,把布局调整成最简单的了,终于在网络请求失败时加载圈也不会消失了,那么问题就是出在布局上,也不是布局有误,就是给FlatList的父布局设置了FlexBox布局的属性就出现这个问题了,如下:

container: {flex: 1,justifyContent: 'center',alignItems: 'center',alignSelf: 'center',
}

去掉这三个属性,如下,其他代码逻辑复原,问题解决了。

container: {flex: 1,
}

问题6

问题描述:高版本手机通知栏小图标处理,在部分5.0或7.0手机的消息通知栏不仅会显示消息图标,还会显示一个非常小的应用通知图标,和其他应用对比发现默认显示效果不明显
分析解决:在部分高版本手机上,如果没有设置应用通知图标,系统会默认用应用的icon缩略一个小的通知图标(图标有颜色的部分会填充为白色,导致显示不出来),除非自己指定通知小图标。
找UI出了一个透明背景的icon(因为有颜色的部分会填充为白色,影响图标原有显示效果),指定为通知小图标,这样通知小图标就能显示出正常效果。

问题7

问题描述:编译版本不一致,例如targetSdk,google-supprot,firebase等版本不统一导致编译不通过问题

报错1:Error:Execution failed for task ‘:app:transformClassesWithDexForDebug’.
com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException:
报错2:Program type already present: android.support.v4.app.INotificationSideChannel
报错3:com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details
报错4:unable to find attribute android:fontVariationSettings and android:ttcIndex
报错5:java.util.zip.ZipException: duplicate entry
报错6:Android dependency ‘com.google.android.gms:play-services-basement’ has different version for the compile (16.0.1) and runtime (16.1.0) classpath. You should manually set the same version via DependencyResolution

分析解决:针对以上系列问题,花费了两天半时间,一直在排查这一系列问题,网上搜出的解决方案五花八门,但是都没有完全解决。之后回归问题初始是由于版本冲突/重复依赖第三方包导致的重复依赖或者依赖冲突。从第三方包依赖冲突入手,最容易出现依赖冲突的就是com.android.support组和com.google.firebase组下的包,参考Stack Overflow论坛里解决com.android.support包依赖冲突的解决方法,在project的build.gradle里配置com.android.support的统一版本,同时配置com.google.firebase和com.google.android.gms的同一版本,终于编译通过了。

allprojects {repositories {...}maven {url 'https://maven.google.com/'name 'Google'}configurations.all {resolutionStrategy.eachDependency { DependencyResolveDetails details ->def requested = details.requestedif (requested.group == 'com.google.android.gms') {details.useVersion '12.0.1'}if (requested.group == 'com.google.firebase') {details.useVersion '12.0.1'}}}}subprojects {project.configurations.all {resolutionStrategy.eachDependency { details ->if (details.requested.group == 'com.android.support'&& !details.requested.name.contains('multidex') ) {details.useVersion "26.1.0"}}}}
}

问题8

问题描述:app启动后,先出现白色页面2.5S~3S再出现启动页
分析解决:白屏为js文件解析阶段,将此时的白屏用启动页替换,到真正启动页停留时间完毕,跳转到主页。冷启动时间比热启动时间长,所以白屏时间也相对较长。
参考:React Native Android启动屏,启动白屏,闪现白屏
也可以直接使用第三方库react-native-splash-screen,原理一样

问题9

问题描述:文字过长添加省略号,最大长度阈值需要区分中英文,但中文和英文可容纳字符个数不同,在中英文混合的情况下如何动态控制可显示文字的长度
分析解决:在指定长度的区域内显示文字,超过可容纳长度用省略号表示,中文和英文可容纳字符个数不同,一个中文占两个英文长度,以中文文字可显示标准为例,为了更好的显示效果,就需要动态转换可显示中文文字个数,例如“你hhh好kk啊”转换为中文标准长度就是5.5个,提供可显示中文长度的最大值,截取可显示文字即可。

static CutStr(str, len){if (str.replace(/[^\x00-\xff]/g, "**").length <= 2 * len) {return str;}let char_length = 0;for (let i = 0; i < str.length; i++){let son_str = str.charAt(i);encodeURI(son_str).length > 2 ? char_length += 1 : char_length += 0.5;if (char_length >= len){let sub_len = char_length == len ? i+1 : i;return str.substr(0, sub_len) + '...';break;}}
}

问题10

问题描述:网络稳定的情况下,不能确保mqtt消息的正常接收,mqtt消息心跳检测,重连机制
分析解决:在物联网应用里,消息传输通常使用mqtt协议,MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。确保消息的正常接收就需要保证客户端和服务器的连接,通过重连机制和心跳检测来确保连接的可靠性。

重连机制:客户端和服务器mqtt建立连接失败/断开连接了则开启重连模式;三秒后进行一次重连,重连时首先检查网络是否正常,其次判断mqtt连接是否已经建立,如果没有建立连接才进行连接请求;当连接建立成功时,关闭重连循环,并开始消息订阅。
心跳检测:在RN的Android系统下,后台任务可以通过HeadlessJS 来实现,react-native-background-job就是基于HeadlessJS 实现的用来处理后台程序的第三方库,这里使用第三方库react-native-background-job做辅助,在应用切换到后台时,通过循环处理后台任务来确保连接不被断开,当应用再次回到前台时取消后台任务的执行。

//注册后台任务
BackgroundJob.register({jobKey: GlobalConstant.REGULAR_JOB_KEY,job: () => console.log("Running in background")
});//前后台切换
handleAppStateChange(appState) {console.log('当前状态为:' + appState);if (appState === 'active') {//回到前台BackgroundJob.cancel({jobKey: GlobalConstant.REGULAR_JOB_KEY});}else if(appState == 'background'){//后台运行,触发执行BackgroundJob.schedule({jobKey: GlobalConstant.REGULAR_JOB_KEY,period: 2000,exact: true});}
}

问题11

问题描述:Android9.0网络请求都是失败
分析解决: Android9 开始,也会默认阻止 http 请求,督促开发者使用https请求。

方法一:APP网络请求更改为HTTPS(推荐);
方法二:targetSdkVersion 降到27及以下;
方法三:在 res 下新增一个 xml 目录,然后创建一个名为:network_security_config.xml 文件(名字自己取) ,内容如下,大概意思就是允许开启http请求

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>

在项目的AndroidManifest.xml文件下的application标签增加以下属性,应用以上配置。

<application...android:networkSecurityConfig="@xml/network_security_config"...>
</application>

问题12

问题描述:github下载代码报错

fatal: unable to access ‘https://github.com/youyanping/react-native-project.git/’: Failed to connect to 127.0.0.1 port 1080: Connection refused

分析解决

git config --global http.proxy 查询到当前设置了代理,所以我取消这个设置,
git config --global --unset http.proxy 再查询,已经没有了代理,然后再clone,成功了!

问题13

问题描述:四指触控的报错

enabled a touch event which was not counted in ‘tracedeTouchCount’

分析解决:网上人说是ReactNative 框架本身的bug,可以通过修改RN的源码解决,之后没改源码,打包成正式apk就不会有这个问题了。

RN项目问题总结梳理相关推荐

  1. 复盘离线电商数仓3.0项目–数据开发梳理

    复盘离线电商数仓项目–数据开发梳理 业务数据 数仓分层 ods层到ads层的开发 开源BI工具Superset ODS层业务数据&日志数据 ods层业务数据 使用Sqoop脚本从Mysql数据 ...

  2. 解决 'config.h' file not found。升级xcode 新版本导致旧的RN项目打开报错 解决方法。...

    2019独角兽企业重金招聘Python工程师标准>>> 电脑升级了最新的 macOS Mojave 和最新的 XCode 10,升级之后解决出现以前旧版本的RN项目打不开. 解决方法 ...

  3. RN学习笔记02:利用WebStorm创建RN项目

    RN学习笔记02:利用WebStorm创建RN项目 在RN学习笔记01里,安装了node.js与react-native-cli,而且配置了环境变量. 在命令行环境,利用react-native in ...

  4. 我的第一个 RN 项目-趣闻

    代码地址如下: http://www.demodashi.com/demo/13486.html 项目预览 IOS: Android: 扫描体验: 或者点我 整体功能跟之前小程序和 Android 项 ...

  5. ReactNative入门(一)——环境搭建及第一个RN项目—HelloWorld

    ReactNative入门--本篇以及接下来的几篇有关RN的文章,是默认你对前端相关知识如Node,React,以及原生移动端Android可以熟练使用的情况下(最起码达到了解会用的程度)为前提的!不 ...

  6. RN入门基础1:第一个RN项目-hello World

    1.新建工程,用webStorm创建一个react native项目 首先打开package.json, 因为webstorm会创建rn项目时会下载最新的react-native,所以运行程序到模拟器 ...

  7. rn项目 假如cocoapods_RN在mac os上面的项目创建以及Android/IOS模拟运行

    最近捯饬了RN. 第一步,创建项目 react-native init demo 第二步,如果遇到Installing required CocoaPods dependencies卡顿,停下当面执行 ...

  8. RN项目安卓真机调试步骤

    RN项目安卓真机调试步骤 1.adb(Android Debug Bridge)工具安装: 打开终端,入当前用户的home目录,默认就是,不是的话执行命令:cd ~ 或 cd /Users/YourM ...

  9. 简历中项目部分内容梳理

    简历中项目部分内容梳理 摘要 基于检索的肺结节分类算法 基于GNN特征融合的肺结节分类方法 WEB开发 比赛 web服务器 为什么要用协程? 项目难点是哪些? 怎么实现同步的写法实现异步性能的呢? 有 ...

最新文章

  1. 解析 Callable Runnable Future 使用和原理
  2. oracle 数据导入导出
  3. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”
  4. 为什么说语言是思维的最有效的工具
  5. RUNOOB python练习题2
  6. 《TCP/IP详解》学习笔记(四):ICMP 协议、ping 和 Traceroute
  7. long在python中的意思_Python如何管理int和long?
  8. unity5 静态和动态cubmap
  9. 明明白白你的Linux服务器——网络篇(2)
  10. 最简单的基于FFmpeg的内存读写的例子:内存播放器
  11. UIApplication
  12. UG NX 12 视图操作
  13. java log4j日志级别配置详解
  14. ununtu18.0安装搜狗输入法
  15. 宏碁传奇14 Swift 指纹模块失效解决
  16. 飞将军李广自杀:性格能力注定悲剧!(
  17. 常见时序算法集合【资源整理】
  18. codelite开发php,C++跨平台开发环境(CodeLite)
  19. 滑铁卢大学 S. Keshav 教授:高效阅读科研论文的方法
  20. 送您一份《学编程笔记本电脑选购指南》,建议收藏!

热门文章

  1. 2020最受欢迎的7个vue管理后台框架
  2. 常用目录加密的朋友请看:千万别用《高强度文件夹加密大师》这个软件。
  3. 如何将echarts图标的显示/隐藏按钮改成圆形
  4. 403 - 禁止访问: 访问被拒绝。
  5. 如何找回丢失的硬盘分区表?
  6. SpringBoot整合RabbitMQ 消息可靠投递、手动ack、延迟队列、死信队列、消息幂等性保障、消息积压
  7. 番茄时间--2018年1月27日
  8. 2D横版跳跃游戏第三节
  9. 使用阿里云Windows云服务器用公网ip访问Django制作的网页(不涉及IIS)
  10. MyBatis-Plus 看这一篇就够了!