美文网首页React NativeReact NativeReact Native
React Native 插曲 打离线包和CodePush发布更

React Native 插曲 打离线包和CodePush发布更

作者: 朱_源浩 | 来源:发表于2016-08-19 12:24 被阅读2551次

    用了两天才搞定了这些琐碎的操作,从真机调试到利用CodePush进行热更新。。。知道最后才发现一个血的教训:即使用了CodePush,本地也必须要有一个离线包才行,即本地需要打包一个main.jsbundle放进项目中,才可以成功运行。

    首先,讲React Native的发布更新,这就涉及到React Native的热更新主要是怎么工作的,关键在于bundle的更新
    我们先来看看ReactNative是怎么处理bundle文件(bundle文件用于资源管理)的。可以有如下两种方式:
    1、app发版时,将bundle文件内置到app中,同时将图片和js文件内置到app中(Android和iOS处理的不同)
    2、app在合适的时机,加载服务端最新的bundle文件

    下面一张流程图简单介绍ReactNative的热更新机制:
    (参考自:http://blog.csdn.net/codetomylaw/article/details/52115704

    ReactNative的热更新.png

    一、打离线包(打包bundle文件内置到app中)

    离线包即本地存着一个离线包,保证没有网络的时候程序不会报错。
    1、将js代码打包到jsbundle文件中
    在index.ios.js所在目录下,执行以下命令(文件名自定义,使用codepush的时候最好命名为默认的main.jsbundle):

    //  无图片资源等
    react-native bundle --entry-file index.ios.js --platform ios --bundle-output main.jsbundle
    
    //  有图片资源
    react-native bundle --entry-file index.ios.js --platform ios --bundle-output index.ios.bundle --platform ios --dev false --assets-dest ./  
    
    //  或者放bundle文件夹里(注意要先保证bundle文件夹存在!!!) 
    react-native bundle –entry-file index.ios.js –bundle-output ./bundle/iosBundle/index.ios.jsbundle –platform ios –assets-dest ./bundle/iosBundle –dev false 
    
    /*
    entry-file: RN的入口文件
    bundle-out: 输出bundle文件的输出路径(bundle文件名和oc里面的代码要对应)
    asset-dest:输出的asset资源目录
    */
    
    

    2、添加到项目中。
    在xcode中添加assets【必须用Create folder references的方式,添加完是蓝色文件夹图标】和index.ios.jsbundle(或者main.jsbundle、命名不同)

    网上参考的放bundle文件夹的目录结构和项目结构如下:


    bundle文件夹的目录结构和项目结构(自网上).png

    参考自:https://segmentfault.com/a/1190000004189538

    个人利用第一句命令创建的包,目录如下:


    离线包目录结构.png

    3、修改AppDelegate.m文件(只使用离线包不使用热更新的情况)

    //  URLForResource根据第一步对应的名字对应修改
    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
    

    4、模拟器或者真机调试都没有问题。

    顺带列举下ios打包可能遇到的问题(虽然我都没遇到哈):
    1)离线包如果开启了chrome调试,会访问调试服务器,而且会一直loading出不来。
    2)如果bundle的名字是main.jsbundle,app会一直读取旧的,改名就好了。。。非常奇葩的问题,我重新删了app,clean工程都没用,就是不能用main.jsbundle这个名字。
    3)必须用Create folder references【蓝色文件夹图标】的方式引入图片的assets,否则引用不到图片
    4)执行bundle命令之前,要保证相关的文件夹都存在

    二、使用CodePush实现热更新

    1. 环境准备(Mac)

    1)安装Code-push cli

    $ npm install -g code-push-cli

    2) 注册CodePush账户

    $ code-push register

    执行以上命令将会自动打开如下图所示的注册页面:

    注册页面.png

    可以使用github或者Microsoft帐户注册(本文使用GitHub账户进行注册),注册成功后将会生成如下图所示相应的access token:

    access token.png

    按照提示在终端输入刚生成的access token(会自动登录):

    输入access token.png

    3)添加CodePush应用

    $ code-push app add XXX      //xxx 为你要热部署的app name

    结果如下:


    添加CodePush应用.png

    2. 安装CodePush

    在项目更目录(或者说package.json所在目录)执行以下语句安装CodePush,会自动对应修改package.json内容。

    npm install --save react-native-code-push
    

    效果如下:

    安装CodePush.png

    3. 集成code-push 到工程文件

    CodePush集成到项目中,一般有三种方法:
    RNPM、CocoaPods 、"Manual"

    详细可参考CodePush的Github:
    https://github.com/Microsoft/react-native-code-push

    下文分别对其接入方法进行简单介绍:
    个人感觉按情况分,如果是将React Native集成到原生项目中的项目,因为本身应该有用到cocoaPods,所以推荐使用cocoaPods接入,比较方便简单。
    如果是纯React Native项目,则可以考虑手动接入。

    (因为我测试用的是原生集成项目,所以就使用了cocoaPods)

    方式一:cocoaPods接入

    1)修改Podfile文件:(自己注意路径哈)

    pod 'CodePush', :path => './node_modules/react-native-code-push'
    

    2)执行命令行更新pod:

    pod install 
    //  或者 
    pod install --verbose --no-repo-update
    

    方式二:手动接入

    1)将react-native-code-push文件夹中 CodePush.xcodeproj 直接拉入项目中Libraries中

    CodePush.xcodeproj 拉入项目.png

    2)在Link Binary With Libraries中添加Libraries/CodePush.xcodeproj /Products中的libCodePush.a以及libz.tbd。

    Link Binary With Libraries.png

    3)在Build Settings的Header Search Paths那一项中加入(路径要注意)

    $(SRCROOT)/../node_modules/react-native-code-push

    Header Search Paths.png

    方式三:RNPM接入

    好像是官方推荐使用最简单的方式,不过没有试过哈
    1)安装rnpm

    $ npm -g install rnpm xcode

    2)使用

    $ rpm link

    4. 修改项目配置

    1)在命令行下使用code-push deployment ls <AppName> --displayKeys 查出Staging的值,在info.plist文件中添加CodePushDeploymentKey并且把Staging的值填入。
    2)在Info.plist中将Bundle versions string, short的值修改为1.0.0(或者其它,结构一样为x.x.x,且和之后code push更新的版本要对应)

    info.plist配置.png

    5. 修改OC代码和JS代码

    1)在加载 js bundle的类中 修改代码

    a)首先,引入头文件:

    #import "CodePush.h"
    

    b)然后修改jsCodeLocation值:

    //该文章是讨论在Release下进行相关的操作,如果是debug版本加上如下代码,系统在运行时候会自动切换。
    NSURL *jsCodeLocation;
        
    #ifdef DEBUG
        jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
    #else
        jsCodeLocation = [CodePush bundleURL];
    #endif
    
    //如果本地js离线包不是命名main.jsbundle,需要对CodePush进行相应设置
    jsCodeLocation = [CodePush bundleURLForResource:@"index"];
    
    2)在js文件中(该项目文件是index.ios.js) 修改代码

    a)引入对应头文件

    import codePush from "react-native-code-push";
    

    b)在componentDidMount调用sync方法,当你的App启动的时候会在后台更新

    componentDidMount(){
        codePush.sync();
      }
    

    6. 发布更新

    1)发布更新 (JavaScript-only)

    当你修改js文件的时候,并且想立刻发布。则仅仅需要以下的操作:

    1. 将你修改的js文件(当前文件是index.ios.js)打包为二进制文件,放入指定的地方(当前位置为根目录)。
    react-native bundle --platform ios --entry-file index.ios.js --bundle-output codepush.js --dev false
    
    1. 将二进制文件push到staging 环境中
    code-push release [--deploymentName ] [--description ]  [--mandatory]
    eg:
    code-push release NativeTest codepush.js 1.0.0
    

    // 上面代码运行有问题的话,试试把codepush.js后缀改成codepush.jsbundle。。好像目前版本和我上年底的要求不同了

    2)发布更新 (JavaScript + images)

    1. –assets-dest 就是你放图片的位置(当前仅仅是做测试,实际上最好建个文件夹专门存入相关图片)
    react-native bundle --platform ios --entry-file index.ios.js --bundle-output ./main.jsbundle --assets-dest ./<img 地址>
    // main.jsbundle 为自定义名字的bundle名
    
    1. push bundle文件
    code-push <release/debug> <projectName(与注册的app同名)><bundle文件名> <版本号>
    eg:
    code-push release NativeTest main.jsbundle 1.0.0
    

    到这一步的时候,正常来说,该配置的都配置了,试着更新一个版本push到codepush上,运行下项目,就会出现效果。
    注意:如果出现找不到main.jsbundle的报错,很大的原因就是没有在本地打个离线包,详细参考这篇文章的第一部分。(曾经因为这个原因,我看着报错发呆了好久,上网也找不到任何说法😂)

    Q&A

    1. CodePush更新规则


      CodePush更新规则.png
    2. 更新后都需要重启才能看到最新的变化 再次进入后要等一会。TODO:还要验证后确定稳定时机。
    3. 查看历史上传过的版本:

    code-push deployment history NativeTest Staging

    查看历史上传过的版本.png

    更多的CodePush相关命令推荐参考以下几篇文章:
    Code Push 热更新使用详细说明和教程
    app实现热更新codepush
    以及CodePush的Github:
    https://github.com/Microsoft/react-native-code-push

    相关文章

      网友评论

      • youth杨://如果本地js离线包不是命名main.jsbundle,需要对CodePush进行相应设置
        jsCodeLocation = [CodePush bundleURLForResource:@"index"];
        这段代码会不会把 jsCodeLocation = [CodePush bundleURL];覆盖了然后造成CodePush 不能进行热更新
        _Jason___:@youth杨 我遇到你这样的问题,无论怎么更新,codepush 最后加载的还是本地静态文件,也就是那个 ‘main.jsbundle’ ,最后你怎么解决的呢?
      • 鹏雨燕:@朱_源浩 iOS照你写的可以了,但是有个问题,jsbundle和图片资源太大了,然后安卓这边怎么弄离线包呢,紧急,在线等
      • 大萌哥哥:你好,我按照上面的方法打包生成了jsbundle和assets文件夹,jsbundle拖进项目,assets用Create folder references的方式,运行出来没问题,就是图片都没有加载出来,请问这个问题怎么解决,有点紧急!求助!!!:pray:
      • 我是C:react-native bundle --platform ios --entry-file index.ios.js --bundle-output codepush.js --dev false 为什么输出是个codepush.js js文件
        码农的思念:@我是C 哦哦 估计是他写错了
        我是C:@码农的思念 我的意思是 应该是 .jsbundle ,但是 博主 写的是.js ,不知道为什么
        码农的思念:你写错了,你的指令中--bundle-output codepush.js 当然输出的是这个了,可以这么写
        react-native bundle --entry-file index.ios.js --platform ios --bundle-output main.jsbundle
      • 丐帮头:你好,我这边打包发布上传,但是本地不会更新,求助
        码农的思念:看下你的更新策略
      • 2c20dfb98fbb:codepush relesase ./bundle文件夹(jsbundle和assets(图片资源)),app更新失败,只发布jsbundle的话, 能更新,但app不会显示本地图片。这个是什么问题
        鹏雨燕:把jsbundle和assets文件夹放在同一个文件夹中,然后上传
        朱_源浩:@狍子528 应该是图片要一起打包发布才行的吧,带图片的push我没试过,不好意思啊,查查应该有挺多资料
      • Azen:哇写的好棒好全!你RN文章写这么好我Q3的KPI完成不了了啊😭 赔我奖金啊😭
        朱_源浩:@Azen Q3什么来的。。。我都是研究的时候写的,工作任务来了,之后都没什么时间写啦
      • vincent涵:在命令行我输入 code-push deployment ls <AwesomeProject> --displayKeys
        返回的是下面这些:
        Usage: code-push deployment ls <appName> [options]

        选项:
        --format Output format to display your deployments with ("json" or "table") [string] [默认值: "table"]
        --displayKeys, -k Specifies whether to display the deployment keys [boolean] [默认值: false]

        示例:
        deployment ls MyApp Lists the deployments for app "MyApp" in tabular format
        deployment ls MyApp --format json Lists the deployments for app "MyApp" in JSON format

        是不是哪方面有问题
        朱_源浩:@vincent涵 哈哈哈,加油加油
        vincent涵:@朱_源浩 :+1: 我一定是最近睡得太晚,智商直线下降,今晚早点睡 :joy: ,谢谢啦~
        朱_源浩:@vincent涵 应该是不用<>括号吧,直接 code-push deployment ls 项目名 --displayKeys

      本文标题:React Native 插曲 打离线包和CodePush发布更

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