React Navtive App 自动打包实践指南

1,452 阅读9分钟
原文链接: zhaozhiming.github.io

React Native 创建项目有 2 种方式,一种是通过 Expo 框架创建,这种项目可以通过 Expo 提供的命令进行打包;另外一种是通过 React Native 原生命令生成的项目,需要使用 GradleXcode 这些原生工具打包,虽然麻烦了一些,但是灵活性更高,今天讨论的自动打包主要是基于后者。

打包流程

这是自动打包程序的流程图,概述了从我们提交代码到收到通知这一过程。

  • 提交代码:将要发布的代码提交到代码库,这里我们假设使用 gitlab 来做为我们代码管理的平台。
  • 持续集成:将新代码合并到代码库后执行的一系列操作,多用来做静态检查、单元测试等,可以尽早发现集成过程中的问题,这里我们用持续集成来自动打包。
  • 上传 App:将打好的 App 文件上传到分发平台,这里我们选择蒲公英,它是国内提供手机应用内测服务较好的供应商。
  • 消息通知:当所有东西都完成后,我们需要及时通知到相关人员,结合笔者平时工作用的聊天工具钉钉,我们可以使用钉钉的自定义机器人来发送消息。

PS:在持续集成的过程中,我们根据不同的设备使用了不同的打包策略,Android 使用 Docker + Gradle 的方式,而 iOS 因为强依赖于 Mac 的系统和环境,所以需要单独一台 Mac 机器来做打包机器,详细的打包过程将在下面介绍。

工具集

打包过程涉及的工具简单介绍一下:

  • gitlab:代码托管平台,类似 github,但可以支持免费内部部署服务,是大部分公司使用的内部代码托管平台。
  • gitlab-ci:市面上有很多持续集成的框架,但如果是用 gitlab 来做代码管理的话,使用 gitlab-ci 无疑是最简单的持续集成方式。
  • Docker:容器管理工具,可以和大部分持续集成工具集成,使用 Docker 来做持续集成是一种趋势。
  • 蒲公英:国内做的比较好的手机内测服务平台,在上面上传 App 后用户就可以进行 App 测试,它对应的竞品是 Fir.im
  • Mac 机器:这里需要借助 Mac 的机器来执行 iOS App 的打包程序,可以是任意苹果公司的机器,比如 Mac mini、MacBook air/pro 等。
  • 钉钉:阿里推出的企业聊天工具,它支持自定义聊天机器人,方便我们定制自动发送消息的功能。

Android 打包

React Native 工程下面有个android目录,里面放置的是 Android 的原生代码,手动打包只需要在该目录下执行gradlew assembleRelease命令即可。

但如果要实现自动打包,则需要先做以下准备。

Docker 镜像

首先要准备一个 Docker 镜像,这个镜像需要可以同时运行 Android 和 React Native 环境,那么问题就来了,我们是要在 React Native 环境的镜像上添加 Android 呢,还是在 Android 环境的镜像上添加 React Native 呢?

运行 Android 需要安装 JDK(Java SE Development Kit)和 Android SDK 等,而运行 React Native 环境只需要安装 Node.js 就可以了,相对于 Android 环境比较简单,所以我们可以找一个 Android 环境的镜像,然后在这个镜像的基础上安装 Node.js。

Docker 镜像可以上 Docker Hub 上查找,如果没有找到合适的,也可以用这个的 Dockerfile 来创建。

在本地创建完 Docker 镜像后记得将镜像上传到 Docker Hub,以便下面的步骤可以使用。

gitlab-ci 配置

接下来我们可以在 gitlab-ci 上配置自动打包的任务了,首先需要在项目中添加一个.gitlab-ci.yml文件,这个文件是用来配置 gitlab-ci 持续集成任务,下面是自动打包任务的示例:

gitlab-ci.yml
1
2
3
4
5
6
7
deploy_android: // 任务名称
  stage: deploy
  image: your_docker_react_native_android_image_name // 上面的 Docker 镜像名称
  only:
    - staging // 指定某个分支有代码进入时执行
  script:
    - some scripts // 自动打包命令

配置完成后,只要代码库中的staging分支有新代码进入,gitlab-ci 就会开始执行自动打包任务,步骤如下:

  • 下载 Docker 镜像(有则跳过这一步)
  • 使用 Docker 镜像创建容器实例
  • 拉取项目最新代码
  • 执行任务中的script命令

关于.gitlab-ci.yml文件的更多信息可以参考这里

打包

在上面的自动打包任务的示例代码中,script属性用来配置任务的执行命令,Android 的打包任务比较简单,首先是安装依赖包,然后执行gradle命令就可以了,下面是script的示例脚本:

gitlab-ci.yml
1
2
3
  script:
    - npm install // 安装依赖包
    - cd android && ./gradlew assembleRelease // 进入 android 目录并执行打包命令

上传 App

打包命令执行完成后,会在工程目录下生成一个apk文件,我们需要找到这个文件并上传到蒲公英分发平台,这样其他人才能下载这个 App。

其实 apk 文件也可以放在 gitlab-ci 上,然后让用户通过 gitlab 的链接来下载,但是 gitlab 的权限管理比较严格,每个要下载 App 的人都必须在 gitlab 上授权,这样会比较麻烦,所以我们还是用蒲公英这个分发平台比较好。

蒲公英提供了上传 App 的 API,调用这个 API 需要提供用户的uKeyapi_key,这 2 个 key 在蒲公英的账号设置中可以找到。

一般使用curl命令调用这个 API 就可以了,打包后的 Android apk 文件会在android/app/build/outputs/apk/release/这个目录下找到。所以我们任务中的script属性可以加上上传的命令:

gitlab-ci.yml
1
2
3
4
  script:
    - npm install // 安装依赖包
    - cd android && ./gradlew assembleRelease // 进入 android 目录并执行打包命令
    - curl -F "file=@android/app/build/outputs/apk/release/app-release.apk" -F "uKey=yourUkey" -F "_api_key=yourApiKey" https://qiniu-storage.pgyer.com/apiv1/app/upload // 上传 App

上传 App 成功后,App 会上传到你的蒲公英账号下面(因为是通过你的账号的 key 来创建的),把下载链接发给用户,用户就可以直接下载 App 了。

打包成功通知

最后一步是提醒相关人员 App 已经打包完成,这里我们利用了钉钉自定义机器人 功能。

首先在钉钉的工作群里添加一个自定义机器人,然后获取到机器人的Hook 地址,最后再用curl命令调用这个地址就可以发消息了,我们再将这一步添加到script属性中:

gitlab-ci.yml
1
2
3
4
5
  script:
    - npm install // 安装依赖包
    - cd android && ./gradlew assembleRelease // 进入 android 目录并执行打包命令
    - curl -F "file=@android/app/build/outputs/apk/release/app-release.apk" -F "uKey=yourUkey" -F "_api_key=yourApiKey" https://qiniu-storage.pgyer.com/apiv1/app/upload // 上传 App
    - curl 机器人地址 -XPOST -H 'content-type:application/json' -d '{"msgtype":"text","text":{"content":"@13912345678 Android 打包完成,下载地址:https://www.pgyer.com/xxxx"},"at":{"atMobiles":["13912345678"],"isAtAll":false}}' // 利用钉钉机器人通知群里的某人

iOS 打包

iOS 打包的原理和 Android 的差不多,不同的是需要一台 Mac 操作系统的机器来执行,因为需要用到Xcode来打包。

环境准备

准备好一台 Mac 机器后,我们需要将其集成到 gitlab-ci 来作为执行任务的 Runner,安装步骤可以参照 gitlab 的官方指南:

完成后可以在 gitlab 的 Runners 界面看到多了一台 Runner 机器。

我们可以为其添加 tag 以便执行 iOS 打包任务时可以指定这一台 Runner 来执行。

gitlab-ci.yml
1
2
3
4
5
6
7
8
deploy_ios: // 任务名称
  stage: deploy
  only:
    - staging // 指定某个分支有代码进入时执行
  tags:
    - ios  // 通过 tags 指定 Runner
  script:
    - some scripts // 自动打包命令

打包

iOS 的手动打包一般是通过苹果的专用 IDE Xcode来完成,操作步骤是:

  • 点击Product菜单的Archive命令完成 App 的归档
  • 再通过Export命令导出 App 的ipa文件

如果要自动打包,我们就不可能像手动打包一样打开Xcode了,因为 gitlab-ci 不提供 Runner 的 GUI 界面,但我们可以使用Xcode提供的命令行工具xcodebuild来进行打包。

新建一个脚本来编写打包命令,如下所示:

build_ios.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建打包 build 目录
mkdir -p ios/build
# 删除之前的打包文件及目录
rm -rf ios/build/archive.xcarchive ios/build/ipa-*

# 打包 app
xcodebuild -scheme project_name -workspace ./ios/project_name.xcworkspace -configuration Release clean build archive -derivedDataPath "./ios/build" -archivePath "./ios/build/archive.xcarchive" -quiet

xcodebuild -exportArchive \
    -archivePath ./ios/build/archive.xcarchive \
    -exportPath ./ios/build/ipa-ad-hoc \
    -exportOptionsPlist ./ci/ad-hoc.plist \
    -allowProvisioningUpdates

注意:

  • project_name需要改成真正的 App 名称。
  • 构建参数-quiet 表示打包过程中减少打印信息,如果不加这个参数,会导致 gitlab-ci 任务上的日志信息过多而失败。
  • ad-hoc.plist 文件可以在手动打包的导出文件夹中找到,原来的名字是ExportOptions.plist,可以根据 App 的类型重命名为ad-hoc.plistad-store.plist

脚本写完后,将打包脚本添加到自动打包的任务中:

gitlab-ci.yml
1
2
3
  script:
    - npm install // 安装依赖包
    - ./build_ios.sh // iOS 打包

上传 App

上传 App 和 Android 类似,只是文件的地址要换一下,iOS 生成的 ipa 文件路径是ios/build/ipa-ad-hoc/app.ipa

gitlab-ci.yml
1
2
3
4
  script:
    - npm install // 安装依赖包
    - ./build_ios.sh // iOS 打包
    - curl -F "file=@ios/build/ipa-ad-hoc/app-release.ipa" -F "uKey=yourUkey" -F "_api_key=yourApiKey" https://qiniu-storage.pgyer.com/apiv1/app/upload // 上传 App

注意:苹果的ipa文件不像 Android 的apk文件一样可以直接在手机设备上安装,所以特别需要蒲公英这样的平台来进行分发。

打包成功通知

通知功能与 Android 相同,这里就不重复介绍了。

总结

文章简单介绍了 React Native 的自动打包流程,这个流程是基于笔者的工作开发环境:gitlab + 蒲公英 + 钉钉,但其实这几个部分都是可以替换的,比如用Jenkins代替 gitlab-ci,用fir.im代替蒲公英,用 Slack或者邮件代替钉钉等,读者可以根据自己的工作环境自行替换,也欢迎留言共同讨论交流。