React-Native开发十 react-navigation开发中的一些常见的坑

1 前言

都说RN开发效率高,一次学习随处编写。真的用RN开发了一个APP才知道,RN中坑真是太多,特别是很多坑只有在生产模式下才会出现,在平常的debug模式下,APP运行好好的,但是你一旦打正式包,就会发现各种报错,各种崩溃,如果在Android平台下,各种兼容性,各种奇葩的问题,加上js本身是动态语言,很多错误又无法在编译期间检查出来。因此用RN开发APP,在调试bug阶段消耗的时间和精力一点也不必开发的时间少。
下面说一说RN开发过程中的几个巨大的坑

2 常见的一些开发的坑

1 debug模式ok,但是生产环境打包出现了异常ReactNativeJS: undefined is not an object

08-20 20:03:55.491 2028-2050/com.github E/ReactNativeJS: undefined is not an object (evaluating 'a.View.propTypes.style')
08-20 20:03:55.494 2028-2050/com.github E/ReactNativeJS: Module AppRegistry is not a registered callable module (calling runApplication)

    --------- beginning of crash
08-20 20:03:55.498 2028-2051/com.github E/AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
    Process: com.github, PID: 2028
    com.facebook.react.common.JavascriptException: undefined is not an object (evaluating 'a.View.propTypes.style'), stack:
    <unknown>@453:1186
    d@2:768
    n@2:409
    t@2:262
    <unknown>@435:301
    d@2:768
    n@2:409
    t@2:262
    <unknown>@425:191
    d@2:768
    n@2:409
    t@2:262
    <unknown>@307:191
    d@2:768
    n@2:409
    t@2:262
    <unknown>@306:32
    d@2:768
    n@2:409
    t@2:262
    <unknown>@12:42
    d@2:768
    n@2:339
    t@2:262
    global code@547:8

        at com.facebook.react.modules.core.ExceptionsManagerModule.showOrThrowError(ExceptionsManagerModule.java:54)
        at com.facebook.react.modules.core.ExceptionsManagerModule.reportFatalException(ExceptionsManagerModule.java:38)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:160)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
        at android.os.Looper.loop(Looper.java:164)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:192)
        at java.lang.Thread.run(Thread.java:764)
08-20 20:03:55.580 2028-2050/com.github E/ReactNativeJS: Module AppRegistry is not a registered callable module (calling unmountApplicationComponentAtRootTag)

这里写图片描述

这个错误很悲催的是,在debug模式下是不会出现的,但是一旦在生成环境,在Android平台下就会出现。
出现这个错误后,一定要详细分析日志,详细分析日志,日志。。。
这里我把关键日志贴出来了undefined is not an object (evaluating ‘a.View.propTypes.style’)。现实的情况下你不一定会注意到这句话,这句话的意思是a.View.propTypes.style不是一个对象。怎么理解呢?google发现,是你js代码中propTypes使用方式错误了,网上很多资料提醒你,要导入import {PropTypes} from “prop-types”;之类的。但是我相信开发者一般不会犯这个错误。那么真实的错误是什么呢?真实的错误是代码中使用了View.propTypes.style来对某个属性的类型进行声明了。例如我犯错的代码如下:

    //设置属性约束
    static propTypes = {
        style:View.propTypes.style,
        title:PropTypes.string,
        titleView:PropTypes.element,
        hide:PropTypes.bool,
        leftView:PropTypes.element,
        rightView:PropTypes.element,
        statusBar:PropTypes.shape(StatusBarShape),
    };

可以看到style的属性约束和其他的属性约束不一样,由于js动态语言特性,不会报错。所以编译是没问题的。正确修改如下:

    //设置属性约束
    static propTypes = {
        title:PropTypes.string,
        titleView:PropTypes.element,
        hide:PropTypes.bool,
        leftView:PropTypes.element,
        rightView:PropTypes.element,
        statusBar:PropTypes.shape(StatusBarShape),
    };

我直接去掉style的属性约束

这个bug坑爹的地方有以下两点
1 debug模式下,该bug不会出现的,导致无法定位和调试。
2 js是动态语言,这种类型的错误编译器也无法检测到,不会上报出来,导致只有在打release包之后才会出现,而且一出现就是崩溃。

2 生产环境Error while updating property ‘colors’ of a view managed by: AndroidSwipeRefreshLayout 错误
这个错误的崩溃信息如下:

08-20 20:54:36.105 3883-3883/com.github E/unknown:ViewManager: Error while updating prop colors
    java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:80)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:129)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:48)
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32)
        at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:232)
        at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:152)
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:815)
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:928)
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:46)
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:988)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
        at android.view.Choreographer.doCallbacks(Choreographer.java:723)
        at android.view.Choreographer.doFrame(Choreographer.java:655)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Double.intValue()' on a null object reference
        at com.facebook.react.bridge.ReadableNativeArray.getInt(ReadableNativeArray.java:124)
        at com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager.setColors(SwipeRefreshLayoutManager.java:58)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:80) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:129) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:48) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:232) 
        at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:152) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:815) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:928) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:46) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:988) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:789) 
        at android.os.Handler.dispatchMessage(Handler.java:98) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
08-20 20:54:36.106 3883-3883/com.github E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.github, PID: 3883
    java.lang.RuntimeException: com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'colors' of a view managed by: AndroidSwipeRefreshLayout
        at com.facebook.react.bridge.ReactContext.handleException(ReactContext.java:311)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:31)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909)
        at android.view.Choreographer.doCallbacks(Choreographer.java:723)
        at android.view.Choreographer.doFrame(Choreographer.java:655)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'colors' of a view managed by: AndroidSwipeRefreshLayout
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:92)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:129)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:48)
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32)
        at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:232)
        at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:152)
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:815)
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:928)
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:46)
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:988)
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:789) 
        at android.os.Handler.dispatchMessage(Handler.java:98) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:80)
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:129) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:48) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:232) 
        at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:152) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:815) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:928) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:46) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:988) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:789) 
        at android.os.Handler.dispatchMessage(Handler.java:98) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Double.intValue()' on a null object reference
        at com.facebook.react.bridge.ReadableNativeArray.getInt(ReadableNativeArray.java:124)
        at com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager.setColors(SwipeRefreshLayoutManager.java:58)
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.facebook.react.uimanager.ViewManagersPropertyCache$PropSetter.updateViewProp(ViewManagersPropertyCache.java:80) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater$FallbackViewManagerSetter.setProperty(ViewManagerPropertyUpdater.java:129) 
        at com.facebook.react.uimanager.ViewManagerPropertyUpdater.updateProps(ViewManagerPropertyUpdater.java:48) 
        at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:32) 
        at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:232) 
        at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:152) 
        at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:815) 
        at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:928) 
        at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:46) 
        at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:988) 
        at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29) 
        at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134) 
        at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105) 
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:909) 
        at android.view.Choreographer.doCallbacks(Choreographer.java:723) 
        at android.view.Choreographer.doFrame(Choreographer.java:655) 
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 
        at android.os.Handler.handleCallback(Handler.java:789) 
        at android.os.Handler.dispatchMessage(Handler.java:98) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
08-20 20:54:36.119 3883-3886/com.github I/zygote: Do partial code cache collection, code=30KB, data=23KB
08-20 20:54:36.120 3883-3886/com.github I/zygote: After code cache collection, code=30KB, data=23KB
    Increasing code cache capacity to 128KB

这个错误初看起来是Android平台AndroidSwipeRefreshLayout的问题,但是我们知道RN都是将组件映射到原生控件的。因此要定位这个问题,你必须得知道什么控件会映射为AndroidSwipeRefreshLayout控件。
这里可以直接告诉你是RefreshControl,如果你不知道的话,那就只有一步一步的定位吧,对执行的代码加打点,一点一点的定位。
我们仔细看日志,发现是和colors有关系,那么检查代码中所有使用RefreshControl有关colors的地方吧,终于我发现了疑似出问题的地方

                    refreshControl={
                        <RefreshControl
                            //android
                            colors={[this.props.theme.colorPrimary]}
                            //ios
                            tintColor={this.props.theme.colorPrimary}
                            //ios
                            title="Loading"
                            titleColor={this.props.theme.colorPrimary}
                            refreshing={this.state.refreshing}
                            onRefresh={() => this.loadPopularData()}
                        />
                    }

我们设置了Android平台下进度条颜色值,这里也是按照官方的使用说明设置成了一个数组。
这里写图片描述

那么为什么会报错呢,而且只是在release包中会报错呢?
答案就是this.props.theme.colorPrimary可能为null。如果为null,就会报错,并且这个报错只会在release中会出现。
所以解决办法也很简单,确保传入的值不会为null即可
坑爹的点
1 RefreshControl文档中未说明colors的属性要求的值不能为null
2 RN中对debug和release模式下处理的机制不一样,导致很多错误在release才会出现

先暂时写这两个坑吧,话说定位这两个错误真的花费了不少时间。后续有坑再继续补上!

3 总结

最后说一点RN开发的“忠告”
1 RN开发中不要太依赖debug模式,特别是Android平台,要不然你就等着哭吧
2 JS是动态类型语言,很多类型及值在编译器中不检查,如果依赖类型及特殊值的,一定要养成良好的编程习惯,自己提早解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值