记一次 RN 升级(0.49.5->0.56.0)

作者: 哪吒闹海全靠浪 | 来源:发表于2018-09-28 15:57 被阅读104次

    一、前言

    首先我们可以在官方文档里查到RN升级的文档Upgrading to new React Native versions
    文中介绍了两种办法:

    1.通过react-native-git-upgrade

    因为这个方法是一键式升级,所以它会改变项目中的iOSAndroid文件,由于我们的项目是混合型的,这样严重破坏了客户端的代码,会让解决冲突变得十分困难,不推荐。

    2.通过修改package.jsonreact-native的版本号来升级

    这个方案只牵涉到前端,破坏性小,还可以通过rn-diff来查看到升级的一些文件改变,通常react-native的升级和react的升级是绑定的,我们就可以通过rn-diff找到相应的版本号,接下来我们就用这种办法来进行升级。

    二、踏坑

    1.修改package.json

    "react": "16.4.1",
    "react-native": "0.56.0",
    
    npm i
    

    2.运行iOS的pod:update

    发现pod.file中为了兼容scrollView的一段代码已无用,故删除。

    3.执行react-native run-ios

    错误信息:

    Failing run on IOS and Android because a syntax error in `local-cli`
    

    解决:
    需要升级 node,版本大于8.3

    sudo npm cache clean -f && sudo npm install -g n install "n" && sudo n stable
    

    4.启动后的红屏

    错误信息1:

    Unable to resolve module AccessibilityInfo from XXX
    

    解决:
    清除缓存

    npm run reset  
    相当于 
    watchman watch-del-all && rm -rf node_modules && npm install && npm start --reset-cache
    

    这里还需要提到一点,在修复过程中,经常发现改动了代码但没生效,这时候需要重启服务试试

    npm start --reset-cache
    

    错误信息2:

    Using the export keyword between a decorator and a class is not allowed
    

    解决:

    将
    @dec1
    @dec2({
      option1: "foo" 
    })
    export class C {
    } 
    改为
    export
    @dec1
    @dec2({
      option1: "foo" 
    })
    class C {
    } 
    

    错误信息3:

    Cannot read property 'bindings' of null at Scope.moveBindingTo
    

    错误信息4:

    Property right of AssignmentExpression expected node to be of a type ["Expression"] but instead got null
    

    解决:
    3和4都是由于在0.56版本,RN需要使用babel7+

    package.json
     "dependencies": {
        "react": "16.4.1",
        "react-native": "0.56.0",
        "@babel/core": "7.0.0-beta.47",
        "@babel/plugin-proposal-decorators": "7.0.0-beta.47",
        "@babel/plugin-transform-classes": "7.0.0-beta.47",
        "@babel/register": "7.0.0-beta.47",
      }
      "devDependencies": {
        "babel-jest": "23.4.0",
        "babel-preset-react-native": "^5",
        "jest": "23.4.1",
        "react-test-renderer": "16.4.1"
      }
    .babelrc
    {
        "presets": ["react-native"],
        "plugins": [
            ["@babel/plugin-proposal-decorators", { "legacy": true }]
        ]
    }
    

    5.第三方库错误

    react-native-scrollable-tab-view

    错误信息:

    A trailing comma is not permitted after the rest element
    

    解决:
    由于此库已无人维护,所以把源码放到本地维护,去除错误提示代码中的几处逗号即可

    react-native-modal

    错误信息:

    bundling failed: Error: We don't know what to do with this node type. We were previously a Statement but we can't fit in here?
    

    解决:
    升级库

    "react-native-modal": "^6.5.0"
    

    react-native-svg-uri

    错误信息:

    element type is invalid expected a string (for built-in components) or a class/function check 
    

    解决:
    升级库

    "react-native-svg": "^6.5.2",
    "react-native-svg-uri": "^1.2.3"
    

    react-native-root-siblings

    错误信息:

    Exporting local "_default", which is not declared.
    

    解决:
    由于此库近半年无人维护,所以把源码放到本地维护

    export default class {
    改为
    export default class xxx { 
    

    6.RN内部组件的调整

    Text/TextInput

    错误信息:

    Text.prototype.render undefined
    

    解决:

    Text.prototype.render
    改为
    Text.render
    

    create-react-class

    错误信息:

    Module create-react-class does not exist in the Haste module map
    

    解决:
    由于把第三方库引入本地,代码老旧,新版已不支持create-react-class的方式,所以逐个改造为es6的语法

    7.Android上的修改

    解决完上面的问题,在iOS上就可以正常的跑起来了,但在Androidbuild都过不了。
    想到客户端同学之前提到的一个坑:

     //解决同一个库依赖不同的版本 例如react-native 有0.49.5 有的是+ 统一成0.49.5
        subprojects {
            project.configurations.all {
                resolutionStrategy.eachDependency { details ->
                    if (details.requested.group == 'com.facebook.react'
                        && details.requested.name.contains('react-native')) {
                        details.useVersion "0.49.5"
                    }
                    if (details.requested.group == 'com.airbnb.android'
                            && details.requested.name.contains('lottie')) {
                        details.useVersion "2.5.0"
                    }
                }
            }
        }
    

    他们需要把依赖的库统一版本,于是把上述的0.49.5改为0.56.0

     //解决同一个库依赖不同的版本 例如react-native 有0.56.0 有的是+ 统一成0.56.0
        subprojects {
            project.configurations.all {
                resolutionStrategy.eachDependency { details ->
                    if (details.requested.group == 'com.facebook.react'
                        && details.requested.name.contains('react-native')) {
                        details.useVersion "0.56.0"
                    }
                    if (details.requested.group == 'com.airbnb.android'
                            && details.requested.name.contains('lottie')) {
                        details.useVersion "2.5.0"
                    }
                }
            }
        }
    

    重新build,成功了,但启动后马上Crash,打开AndroidStudio发现有错误信息:


    解决:将这些项目android文件下的 ***.iml 文件删掉,重新编译
    错误信息没有了,但启动依旧Crash,这时候和客户端同学沟通可能是so库的问题,于是替换了so库(这里有一个小技巧,要获得一个新版本的so库,可以通过创建一个新版本的Demo,然后从中获取),依旧出错,但错误信息变了:
    java.lang.NoClassDefFoundError: Failed resolution of: Lcom/facebook/common/soloader/SoLoaderShim;
    

    通过Google大致猜测是gif库出了问题

     //fresco
        compile "com.facebook.fresco:animated-gif:$rootProject.ext.frescoVersion"
        compile "com.facebook.fresco:fresco:$rootProject.ext.frescoVersion"
    

    官网的升级日志中查到

    Update Fresco to v1.9.0, okhttp3 to v3.10.0
    

    于是把版本改为1.9.0,重新编译运行,一切正常。

    8.Android Jenkins 打包失败

    错误信息:


    解决:
    这个问题相当奇葩,几乎找不到思路,试过删除目录,再拉代码、拉库都无效,最后是在react-native bundle命令加中增加一个--reset-cache参数,清除打包的缓存文件,终于可以了。

    9.Android Code-Push错误

    错误信息(issue):

    facebook::react::Recoverable: Could not open file ReactNativeDevBundle.js: No such file or directory
    

    解决:
    暂时还未解决,code-push的代码中可以看到一段注释说明解决代码的片段,但实际仍未解决,不过好在只出现在本地开发模式,这个还需继续跟进。

    三、总结

    1.看升级日志

    升级前,建议看一遍官方的升级日志,这样可以对碰到的问题有预期和解决方向。

    2.勤升级

    有精力的话,建议更勤快的升级,这样每次升级带来的问题不会那么多,而且通过特定版本的升级日志通常就能定位问题。像这次跨多版本的升级,中间涉及的错误修复可能需要你仔细阅读多个版本的升级日志,困难度增大不少。

    3.谨慎选择第三方库

    对于第三方库,除了高star,还要注意它的更新频率。
    如果在更新时碰到第三方库出错并很长时间都无人维护了,可通过下面几种办法解决:

    • Fork一份,修改代码,自己发npm或者引用fork地址;
    • 本地新建一个组件,利用继承的方式,修改源码,引用本地的新组件;
    • 把GitHub上的代码直接放在本地维护。

    相关文章

      网友评论

      • 哪吒闹海全靠浪:补充:Text组件被重写,android修复了不少bug,增强了不少能力,但iOS上反倒是不支持原来nest图片的方式了,目前iOS上要实现图文混排似乎很困难。

      本文标题:记一次 RN 升级(0.49.5->0.56.0)

      本文链接:https://www.haomeiwen.com/subject/wruuoftx.html