返回博客首页
← 所有文章

使用 fastlane 自动化 NativeScript 应用部署

2019 年 10 月 15 日 — 作者 Tiago Alves

如果要我指出 NativeScript 开发者激动人心的生活中最不愉快的一项任务,我会说:部署!哦,我多么讨厌它们……

从苹果的配置文件地狱到不断变化的 Google Play Console,部署应用程序总是让人感觉无聊、繁琐,纯粹是浪费时间,你本来可以用来为你的精彩应用程序开发精彩的功能。在项目的生命周期中,一个应用程序可以部署数十次(如果不是数百次!),包括测试版本、测试版、错误修复和新功能。如果有一种方法可以使部署自动化,以便我们可以随时将应用程序的最新版本交付到我们的队友和用户手中,那岂不是太好了吗?好吧……有了 fastlane,现在可以实现了。

fastlane 是一个用于自动执行 iOS 和 Android 应用程序部署和发布的工具。通过正确的配置,它可以用来自动化 NativeScript 部署。正如你从这篇文章的篇幅中所看到的,设置它并不简单……但是,如果你的项目持续时间足够长,它将为你节省大量时间。

我们将介绍配置 fastlane 所需的步骤,并解释每个步骤,这样你就知道如何根据自己的项目进行调整。这篇文章是我经过几个小时的实验得出的,最终得到了一种对我的项目有意义的配置,并在一定程度上关注了在开发团队中管理秘密。再次强调,请随意根据自己的项目和组织进行调整。

免责声明:在本文中,我们假设你已经为 iOSAndroid 都完成了部署设置。我们不会展示如何部署应用程序,而是展示如何自动化这些部署。

例如,我们将创建一个 fastlane 配置,用于一个名为 HubbyChef 的演示项目。

fastlane 入门

我们将从安装 fastlane 开始,可以使用以下命令完成安装

brew cask install fastlane

有关更多安装选项和故障排除,请查看 fastlane 文档

我们不能使用 fastlane 命令 fastlane init 来开始,因为 NativeScript 项目文件夹结构与“正常”原生应用程序不同。相反,我们将手动创建和编辑配置文件。

Fastfile (fastlane/Fastfile)

创建文件夹 fastlane/,并在其中创建文件 Fastfile

mkdir fastlane
touch fastlane/Fastfile

Fastfilefastlane 的主配置文件。在这里,我们将添加我们的 lane。你可以将 lane 视为一组任务。Lane 包括 操作 和其他 lane。你也可以将 lane 分组到 platform 下。

让我们看看如何通过为 Fastfile 创建顶部结构来实现这一点

fastlane_version '2.131.0'

desc 'test lane'
lane :test do
  print "TEST SUCCESSFUL!"
end

platform :ios do

 desc 'Fetch certificates and provisioning profiles'
 lane :certificates do
 end

 desc 'Build the iOS application.'
 lane :build do
 end

 desc 'Ship to Testflight.'
 lane :beta do
 end

end

platform :android do

 desc 'Build the Android application.'
 lane :build do
 end

 desc 'Ship to Playstore Alpha track.'
 lane :alpha do
 end

end

第一行 (fastlane_version '<x>') 将确保你的队友没有使用过时的 fastlane 版本。然后,我们创建了一个测试 lane test,只是为了看看 fastlane 是否正常工作。你可以使用命令 fastlane test 进行测试。它应该在控制台中打印出 TEST SUCCESSFUL!

然后,我们添加了两个 platformiosandroid。对于 ios 平台,我们将使用 lane certificatesbuildbeta。对于 android,将使用 lane buildalpha。每个 lane 上面的 desc 描述了它们将执行的操作。我们将在稍后使用 fastlane <platform> <lane> 调用这些 lane,例如 fastlane ios build

运行 fastlane lanes 将显示所有可用 lane 的摘要

fastlane lanes result

Appfile (./fastlane/Appfile)

fastlane 文件夹内创建 Appfile。此文件将存储有关应用程序的信息,如下所示

app_identifier "dev.tiagoalves.hubbychef"
apple_id "[email protected]"
team_id "xxxxxxxxx"

.env.default (./.env.default)

将密码和 API 密钥等秘密直接存储在 fastlane 配置文件中并不安全,因为这些文件是项目的一部分,应该与代码一起推送到版本控制中。相反,我们将使用 dotenv 并将所有敏感信息存储在 .env.default 文件中。只要不要忘记 .gitignore 它。

此文件包含一组键值对,例如

MATCH_PASSWORD="xxxxxxxxx"

我们可以在 Fastfile 中使用 ENV["MATCH_PASSWORD"] 来使用此值,但有时操作会在后台使用这些值。

iOS

现在我们将构建我们的 iOS 配置,从最难的部分开始:代码签名。

代码签名

请允许我推荐 match 方法。你可以在这里 阅读有关此概念的所有内容,但简而言之,match 将为你执行以下操作

  • 自动生成必要的证书和配置文件(无需访问 Apple 开发者帐户页面);
  • 将证书和配置文件存储在存储库中(Git 或 Google 云存储)。所有文件都将被加密,作为额外的安全层;
  • 在新的机器上部署或为新的团队成员进行入职更轻松。match 将在构建过程中负责安装所有内容;
  • fastlane 构建集成;

你可以在 官方文档 中阅读有关 match 的所有内容。在这里,我们将展示让它工作的基本步骤。

提示:match 文档建议创建 “一个新的共享 Apple 开发者门户帐户,类似于 [email protected]。这将使团队成员之间共享访问权限变得更加容易。

1) 安装 match

运行以下命令

fastlane match init

此命令将询问证书和配置文件的存储方法。我建议使用 GIT 并为证书创建一个新的私有存储库(例如 https://github.com/tralves/hubbychef-certs)。该命令将创建文件 fastlane/Matchfile

2) 配置 match

使用你的项目和 Apple 帐户信息编辑文件 fastlane/Matchfile。这是我的 Matchfile 的样子

git_url("https://github.com/tralves/hubbychef-certs")

storage_mode("git")

type("development") # The default type

app_identifier("dev.tiagoalves.hubbychef")
username("[email protected]") # Your Apple Developer Portal username

team_id('xxxxxxxxxx')
team_name('Tiago Alves')

将存储库加密密码添加到 .env.default,这样你就不必每次部署时都提供密码。

MATCH_PASSWORD="xxxxxxxxx"

3) 生成证书和配置文件

你现在可以使用 match 生成新的证书和配置文件。

提示:在执行此步骤之前,请确保已从你机器的“钥匙串访问”中删除与该帐户关联的所有 Apple 开发者证书。match 将创建并安装新的证书,这些证书可能与现有证书冲突。

为此,请运行

match development
match appstore

这将创建开发和分发证书以及它们各自的配置文件。它还将在你的机器上安装它们。如果一切顺利,你现在就可以在 Xcode 中打开项目并使用新的配置文件。你还可以看到这些文件已提交到之前创建的 GIT 存储库中。就像变魔术一样!

4) 配置 certificates lane

现在,你可以在 Fastfile 中配置 certificates lane

desc 'Fetch certificates and provisioning profiles'
lane :certificates do
    match(type: 'development')
    match(type: "appstore")
    # match(type: "adhoc")
end

使用此 lane,你可以使用 fastlane ios certificates 安装所有证书。

构建步骤

有了所有证书和配置文件,我们现在可以着手构建步骤。在这里,我们将创建一个使用分发配置文件签名的 .ipa,稍后可以将其发布到 TestFlight 或 App Store。这是我的 ios build lane 的样子

desc 'Build the iOS application.'
lane :build do
    sh("tns", "prepare", "ios", "--release", "--clean", "--env.production")

    match(type: "appstore")

    build_app(
      scheme: "HubbyChef",
      workspace: './platforms/ios/HubbyChef.xcworkspace',
      export_method: "app-store"
    )
end

lane 中的第一个操作运行命令 tns prepare ios --release --clean --env.production,这是我们在手动部署中键入的命令。

第二个操作 match(type: "appstore") 确保安装分发证书和配置文件,并将其设置为在下一个操作中使用。

最后,build_app 操作 编译并签名 .ipa。请注意操作中的参数

  • scheme:构建方案,如 Xcode 顶部的栏中所示,通常是应用程序的名称:xcode scheme
  • workspace:指向项目 .xcworkspace 文件的路径;
  • export_method:导出存档的方法。在本例中,我们想要 app-store

此时,我们可以使用以下命令生成已签名的 .ipa

fastlane ios build

如果一切顺利,你应该在项目根文件夹中看到 .ipa

发布到 TestFlight

最后一步是将 .ipa 发布到 TestFlight。查看 ios beta lane

desc 'Ship to Testflight.'
lane :beta do
    build

    changelog_from_git_commits

    upload_to_testflight(
      beta_app_feedback_email: "[email protected]",
      beta_app_description: "App for Hubbies trying to learn how to cook.",
      demo_account_required: false,
      distribute_external: true,
      groups: ["beta testers"],
      notify_external_testers: true,
      beta_app_review_info: {
        contact_email: "[email protected]",
        contact_first_name: "Tiago",
        contact_last_name: "Alves",
        contact_phone: "+351 9xxxxxxxx",
        demo_account_name: "",
        demo_account_password: "",
        notes: "<3 Thank you for reviewing!"
      },
    )
end

lane 从调用我们之前定义的 build lane 开始,这样我们始终可以有一个最新构建的应用程序发送到 TestFlight。

然后,我喜欢使用 操作 changelog_from_git_commits。默认情况下,此操作会获取自上次 GIT 标签以来的所有提交消息,并将它们用作提交应用程序到 TestFlight 时使用的变更日志。这样,你的测试人员就会知道每个版本的新功能,而你无需为此做任何事情(除了编写正确的提交消息……)。

最后一个操作 uploadtotestflight

  1. .ipa 上传到 App Store Connect;
  2. 等待应用程序处理;
  3. 将构建添加到 TestFlight;
  4. 分配给所需的测试组(在本例中为“测试人员”组);
  5. 提交应用程序以供审核;

如果你曾经手动执行过此过程,你就会识别出此操作中的参数与你必须反复填写的表单字段相对应。有了此配置,你只需执行以下操作

fastlane ios beta

你还可以使用 fastlane 将应用程序提交到 App Store,使用操作 upload_to_app_store。你可以在 这里 阅读有关它的所有信息。我在本教程中没有创建该 lane,因为我自己没有尝试过,我更愿意对这一步有更多控制。不过,它应该与使用 upload_to_testflight 很相似。

Android

我们才完成了一半!是时候创建 fastlane Android 配置了。

代码签名

你可能已经拥有项目的 .keystore 文件。如果没有,请查看 这里 如何创建它。

我们将 keystore 放在 certs/hubby-chef-prod.keystore 中,并将它的秘密信息添加到 .env.default

KEYSTORE_PASSWORD="xxxxxxxxxxxxx"
KEYSTORE_ALIAS="dist"
KEYSTORE_ALIAS_PASSWORD="xxxxxxxxxx"

构建步骤

要构建 Android 应用程序,需要一个 lane 来运行 tns 命令以创建签名的生产版本

desc 'Build the Android application.'
  lane :build do
    sh("tns", "build", "android", "--release", "--clean", "--env.production",
        "--key-store-path", "../certs/hubby-chef-prod.keystore",
        "--key-store-password", ENV["KEYSTORE_PASSWORD"],
        "--key-store-alias", ENV["KEYSTORE_ALIAS"],
        "--key-store-alias-password", ENV["KEYSTORE_ALIAS_PASSWORD"]
      )
end

我们完成了!你现在可以运行 fastlane android build,最后,你应该在 platforms/android/app/build/outputs/apk/release/ 下看到 app-release.apk

发布到 Play Store alpha 轨道

我们需要设置一个 Google Developers 服务帐户。为此,请按照以下步骤操作(或查看 fastlane 文档

  • 打开 Google Play Console;
  • 单击“设置”菜单项,然后单击“API 访问”;
  • 单击“创建服务帐户”按钮;
  • 在对话框中,单击“Google Developers Console”链接,这将打开一个新的标签/窗口:;
  • 点击 Google Developers Console 顶部的“创建服务帐户”按钮;
  • 提供一个服务帐户名称(例如:hubbychef-manager);
  • 点击“创建”;
  • 点击“选择角色”,然后选择“服务帐户” > “服务帐户用户”;
  • 点击“继续”;
  • 点击“创建密钥”;
  • 选中“提供新的私钥”复选框;
  • 确保选择“JSON”作为“密钥类型”;
  • 一个 JSON 文件将被下载;
  • 点击新添加的服务帐户的“授予访问权限”;
  • 从“角色”下拉列表中选择“版本经理”(或“项目负责人”);
  • 点击“添加用户”以关闭对话框;

然后,将 JSON 文件内容复制到 .env.default 中,如下所示

PLAYSTORE_JSON_KEY_DATA='
{
  "type": "service_account",
  "project_id": "api-642090...",
  "private_key_id": "11d039fd....",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMI...",
  "client_email": "hubbychef-manager@api-6420905...",
  "client_id": "114219...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis...",
  "client_x509_cert_url": "https://www.googleapis.com/..."
}

现在,我们可以在 Fastfile 中创建 lane

desc 'Ship to Playstore Alpha.'
  lane :alpha do
    build

    changelog_from_git_commits

    upload_to_play_store(
      track: 'alpha',
      track_promote_to: 'alpha',
      json_key_data: ENV["PLAYSTORE_JSON_KEY_DATA"],
      apk: './platforms/android/app/build/outputs/apk/release/app-release.apk'
    )
end

与 iOS 一样,我们从调用 build lane 开始。同样,我们将使用 changelog_from_git_commits 来生成变更日志。

然后,构建将在 upload_to_play_store 操作中发布。在这里,我们将构建发送到“Alpha”轨道,但你可以将其发送到 Beta 或生产轨道。查看 upload_to_play_store 的文档 以获取更多详细信息。

工作流程

请允许我再补充说明一下我使用 fastlane 进行部署工作流程。以下是我部署新版本时采取的步骤

1) 在 package.json 中增加版本号。

不过,增加版本号存在一个问题:即使你只是部署到 Testflight,Apple 也要花数小时甚至数天的时间来审核你的应用程序。我的另一种选择是使用 这个 NativeScript 插件,它允许你将 versionNumber 参数添加到 package.json 中。这个数字将是 iOS 上的版本号。如果你只增加这个值,你的应用程序将立即被批准进行测试。这个插件还确保你获得 Android 上的递增 versionCode

警告:fastlane 操作 increment_build_number 无法与 NativeScript 应用程序生成流程良好配合。

2) 运行 fastlane 命令

fastlane ios beta
fastlane android alpha

3) 创建一个 git 标签

这将确保操作 changelog_from_git_commits 仅在下次部署时获取正确的提交。

总而言之...

fastlane 是一款很棒的工具!在这篇文章中,我们只是触及了 fastlane 可以为你做些什么的皮毛。如果你想将某些内容附加到构建流程,很有可能存在一个 操作 来实现它。我说的是诸如集成自动化测试、截取屏幕截图、Slack 机器人/报告、各种 CI 集成等等。

我知道所有这些工作看起来很繁琐,但与我最初摸索这些内容相比,这只是一小部分时间!它一定会为你节省时间和精力。部署将会变得轻而易举... 你最终会更频繁地进行部署,从而使你的用户、队友、QA 人员和老板更快乐。享受吧!