ZHANGYU.dev

October 14, 2023

fastlane自动化打包React Native笔记

Others3.9 min to read

fastlane

fastlane是使用Ruby写的一套自动化打包IOS和Android应用的工具,提供了很多插件化操作,包括证书管理,上传商店。

由于它只是一套自动化打包工具,所以想要部署还是需要使用Github Actions这种CI平台的。

需要提前需要安装好ruby环境,macOS自带ruby,如果没有,可以使用rbenv来管理。

安装fastlane

setup

xcode-select --install

安装

brew install fastlane

初始化fastlane

项目根目录执行

fastlane init

项目下会创建fastlane文件夹和Gemfile文件

├── Gemfile
└── fastlane
    ├── Appfile
    └── Fastfile

Appfile是存一些fastlane的变量文件,不过我没有使用这个文件,大部分的值是通过环境变量来拿的。

Fastfile则是主要的执行文件了,里面定一些所谓lane的执行命令。

证书管理

证书管理这一块浪费了我很多时间,可算整好了。

IOS

IOS的证书一直都很麻烦,分为development和上架需要的distribution证书。使用fastlane的match就可以很轻松的管理证书,甚至开发人员根本不需要登陆Xcode的开发者账号,如果有新成员执行一下命令就能安好证书了。

match可以将证书存放在一个私有的git仓库中,然后开发者只需要执行命令,就可以将证书安装到本地了,这样共用同一个证书,避免申请多个证书。

同时它推荐创建一个新的开发者账号作为公用账号,并申请一个App Store Connect API

截屏2021-11-05 下午9.01.34

首先使用新的开发者账号来配置match,输入一个私有的git仓库地址用来存放证书。

fastlane match init

现在会增加一个Matchfile在fastlane文件夹,里面则是match的配置。

如果你想将证书放在不同的分支,可以在Matchfile文件中加上你自定义的分支名称

git_branch("fastlane_certificates")

还需要申请一个Github Token,用于后续的仓库访问。

将Token转为base64。

echo -n your_github_username:your_personal_access_token | base64

写入Matchfile文件

git_basic_authorization("xxxxxxxxx")

app identifier写入Matchfile,如果有多个,可以写为一个数组。

app_identifier("com.xxx.xxx")

如果想要撤销掉之前发放的所有证书,可以执行

fastlane match nuke development
fastlane match nuke distribution

创建新证书

执行过程中会输入Apple ID,同时会设定一个访问密码。

fastlane match appstore
fastlane match development

速度会有一些慢,建议代理加速,执行完后看Github仓库里会有对应的证书文件。

增加Matchfile的配置

clone_branch_directly(true)
shallow_clone(true) // 加速clone

readonly(true) // 不会生成新证书

之前有说申请一个App Store Connect API,现在将它配置上。

fastlane目录下创建一个api-key.json文件

{
  "key_id": "xxx",
  "issuer_id": "xxx",
  "key_content": "-----BEGIN PRIVATE KEY-----\nxxxxxxx\n-----END PRIVATE KEY-----"
}

增加Matchfile配置

api_key_path("fastlane/api-key.json")	

Android

Android证书比较简单,但是没有提供插件来处理,我的方法是将证书转为base64,在CI过程中把它转完文件写入。

转base64

base64 -i xxx.keystore > key

自动化打包

IOS

fastlane ios deploy

platform :ios do
  lane :deploy do

    # React Native对应项目的配置和名称
    XCODE_PROJECT = './ios/rnapp.xcodeproj'
    XCODE_WORKSPACE = './ios/rnapp.xcworkspace'
    PLIST_PATH = "./rnapp/Info.plist"
    SCHEME = 'rnapp'

    setup_ci
    
    if is_ci
      unlock_keychain(
      	path: "fastlane_tmp_keychain",
      	password: "",
      	set_default: true
    	)
    end

    increment_build_number(xcodeproj: XCODE_PROJECT)

    match(type: "appstore")

    # 需要先关闭自动签名
    update_code_signing_settings(
      use_automatic_signing: false,
      path: XCODE_PROJECT
    )

    build_ios_app(
      workspace: XCODE_WORKSPACE,
      scheme: SCHEME,
      clean: true,
      export_method: "app-store"
    )

    update_code_signing_settings(
      use_automatic_signing: true,
      path: XCODE_PROJECT
    )

    upload_to_testflight
  end
end

安装证书到新开发的机器

fastlane certificates

lane :certificates do

  match(
    type: "development",
    force_for_new_devices: true,
    readonly: true
  )

  match(
    type: "appstore",
    readonly: true
  )
end

Android

fastlane android deploy

require 'base64'

platform :android do
	lane :deploy do |options|
	  setup_ci

          puts "env file path: #{ENV['ENVFILE']}"
		      # 把之前base64的Android证书写入
          if !ENV["ANDROID_KEY_STORE"].empty?
            File.open("../android/app/rnapp-release-key.keystore", 'wb') do |file|
              file.write(Base64.decode64(ENV["ANDROID_KEY_STORE"]))
            end
          end
          gradle(task: 'clean', project_dir: 'android/')
      
          gradle(task: 'app:assemble',  build_type: 'Release', project_dir: 'android/')
	end
end

关于环境变量问题

如果使用了react-native-config这样的包来管理环境变量,就需要额外的配置了。

require 'dotenv'

projectPath = File.join(Dir.pwd,"..")

before_all do |lane, options|
  filePath = "../.env.#{options[:env]}"
  Dotenv.load filePath
  ENV["ENVFILE"] = filePath
end

# Android读不到相对路径,不知道为什么
platform :android do
	...
  ENV["ENVFILE"] = File.join(projectPath, ".env.#{options[:env]}")
	...
end

执行命令

fastlane ios deploy env:dev	

就能够读取.env.dev这个环境


废了老大时间来做这个不属于前端的活路,真是累死我了,简单做个笔记,再也不想整这个了。