返回博客首页
← 所有文章

使用 NativeScript AppSync 实时更新您的 iOS 和 Android 应用

2019 年 8 月 1 日 — 作者:TJ VanToll

最近发布的 NativeScript 6.0 版本中,我们宣布了一项名为NativeScript AppSync的新 Beta 服务,该服务允许您更新使用 NativeScript 构建的 iOS 和 Android 应用,无需使用 App Store 或 Google Play。

如果您还没有看到此功能的实际应用,则可以观看最近NativeScript 6.0 发布网络研讨会中的这段 7 分钟的片段来快速了解。


在本文中,我想超越基本的演示,并回答一些关于使用此服务的一些常见问题。例如,您首先为什么要这样做,以及 Apple 是否允许我在我的应用中启用此功能?

为什么要使用它?

每个更新过 Android 或 iOS 应用的人都讨厌这个过程。每次更新都涉及许多手动步骤,例如创建新的发布版本、更改版本号等一系列配置、编写发行说明,以及在 iOS 上等待审核才能发布更新。

而且问题不仅仅限于开发人员的生产力。假设您在生产应用中发现了一个错误,该错误正在给您的业务造成经济损失。要使用正常的部署流程修复该错误,您必须:手动创建应用的发布版本,将该版本上传到商店,等待批准(在 iOS 上),然后等待用户在他们的设备上下载并安装该更新。

此过程很容易花费几天时间,在此期间,您的业务正在损失金钱,并且您的用户会因您的应用存在错误而感到沮丧。使用 NativeScript AppSync,您可以大大加快更新过程。

AppSync 如何工作?

AppSync 服务有几个不同的组件,我认为单独解释它们是展示服务整体工作原理的最佳方式。

AppSync CLI

AppSync 服务有其自己的命令行界面,您可以使用npm install -g nativescript-app-sync-cli进行安装。安装后,您将在终端上获得一个新的nativescript-app-sync命令,您可以使用它与 AppSync 服务器进行交互。terminal

CLI 允许您注册 AppSync 服务,添加您希望使用该服务的应用,上传这些应用的代码更新等等。

AppSync 服务器

NativeScript AppSync 服务器提供了一个前端,用于查看连接您的应用程序代码与 AppSync 服务器所需的访问密钥和部署密钥。server

当您通过 AppSync CLI 上传更新时,服务器还会保存您的应用更新(即您的实际应用文件)。

AppSync 插件

拼图的最后一块是AppSync 插件,您可以使用tns plugin add将其安装到任何 NativeScript 应用中。

tns plugin add nativescript-app-sync

安装插件后,您需要使用以下代码在应用中添加对 AppSync 插件的sync()方法的调用。

import { AppSync } from "nativescript-app-sync";

AppSync.sync({
  deploymentKey: "..."
});

AppSync.sync()方法调用 AppSync 服务器以检查您的应用是否有任何新的更新可用。如果找到更新,则插件方法会静默地在后台下载该更新,并在用户下次重新启动应用时应用该更新。

我应该如何在真实的应用中使用它?

从技术上讲,您可以在应用中的任何位置调用AppSync.sync(),并且可以根据需要调用任意次数。但是,最常见的方法是将以下代码片段放在您的app.js文件中(对于 NativeScript Core 和 NativeScript-Vue),或放在您的main.ts文件中(对于 NativeScript Angular)。

import * as application from "tns-core-modules/application";
import { AppSync } from "nativescript-app-sync";

application.on(application.resumeEvent, () => {
  AppSync.sync(...);
});

此代码将事件处理程序附加到您的 NativeScript 应用的resume事件,NativeScript 在每次用户恢复您的应用时都会触发该事件。

注意:当用户启动您的应用或从设备上的其他应用切换到您的应用时,会发生resume事件。

需要注意的是,AppSync.sync()仅确定更新是否可用,如果可用,则在后台下载该更新。sync()方法实际上不会应用更新——毕竟,需要更改的是应用的源代码本身,而这在应用运行时是无法做到的。

话虽如此,您可以使用一些选项来确认您的应用程序同步工作方式。

我应该使用哪些选项?

AppSync 插件的sync()方法允许您以多种不同的方式配置应用程序同步的工作方式。以下是可用的一些选项及其默认值的快速浏览。

import { AppSync, InstallMode, SyncStatus } from "nativescript-app-sync";
import { isIOS } from "tns-core-modules/platform";

AppSync.sync({

  deploymentKey: isIOS ? "your-ios-deployment-key" : "your-android-deployment-key",

  installMode: InstallMode.ON_NEXT_RESTART,

  mandatoryInstallMode: isIOS ? InstallMode.ON_NEXT_RESUME : InstallMode.IMMEDIATE,

  updateDialog: {
    updateTitle: "Please restart the app",
    optionalUpdateMessage: "Optional update msg",
    mandatoryUpdateMessage: "Mandatory update msg",
    optionalIgnoreButtonLabel: "Later",
    mandatoryContinueButtonLabel: isIOS ? "Exit now" : "Restart now",
    appendReleaseDescription: true
  }
});

以下是一些关于每个选项如何工作的更多信息。

  • deploymentKeydeploymentKey是必需的,因为它将您的应用程序代码连接到 AppSync 服务器。iOS 和 Android 将具有不同的密钥,因此示例代码包含一个三元检查,允许您粘贴两个值。

  • installMode:默认情况下,AppSync 仅在用户重新启动应用时安装更新。但是,AppSync 确实具有立即应用更新的功能,如果您将installMode设置为InstallMode.IMMEDIATE,则会立即应用更新。但这有一个很大的警告:InstallMode.IMMEDIATE会显示安装提示(请参见下面的图片),而 Apple 不允许通过 App Store 分发的 iOS 应用这样做。因此,仅当您构建企业分发的 iOS 应用时,才在 iOS 上设置InstallMode.IMMEDIATE

  • mandatoryInstallMode:当您通过 AppSync CLI(nativescript-app-sync release)发布 AppSync 更新时,您可以选择使用--mandatory标志将该版本指定为强制版本。mandatoryInstallMode选项使您能够立即安装标记为强制的更新,同时允许非强制更新等到下次应用重新启动时再安装。再次强调,不要对通过 App Store 分发的 iOS 应用使用立即发布。

  • updateDialog:AppSync 插件有一个内置机制,用于在使用InstallMode.IMMEDIATE时显示一个对话框,通知用户有关更新的信息。下面的 GIF 演示了 Android 和 iOS 上的对话框。在 Android 上,插件能够立即使用新的更改重新启动您的应用。在 iOS 上,应用不允许自行重新启动,因此插件对话框改为指示用户手动重新启动应用。(大概是因为用户体验不佳,所以 Apple 不希望您对通过 App Store 分发的应用使用这种工作流程。)

appsync-androidappsync-ios

AppSync 插件的sync()方法还接受一个回调函数作为第二个参数,该函数报告sync()方法的进度。以下是其在实际应用中的样子。

import * as application from "tns-core-modules/application";
import { AppSync, SyncStatus } from "nativescript-app-sync";

application.on(application.resumeEvent, () => {
  AppSync.sync({
    ...
  }, (syncStatus: syncStatus) => {
    if (syncStatus === SyncStatus.UP_TO_DATE) {
      console.log("No pending updates; you’re running the latest version.");
    } else if (syncStatus === SyncStatus.UPDATE_INSTALLED) {
      console.log("Update found and installed. It will be activated upon next cold reboot");
    }
  });
});

您可能会发现此回调在调试或排查生产应用问题时很有用。

Apple 是否允许我这样做?

让我们从这个问题的简单部分开始。如果您使用企业开发证书开发 iOS 应用,则可以根据自己的意愿推送更新,并根据自己的意愿通知用户这些更新;Apple 实际上只关心通过 App Store 分发的应用。

对于 App Store,Apple 制定了此准则

应用可以包含或运行未嵌入二进制文件中的代码(例如基于 HTML5 的游戏、机器人等),只要代码分发不是应用的主要目的,代码不在商店或类似商店的界面中提供,并且只要软件 (1) 是免费的或使用应用内购买购买的;…

完整文本中有很多法律术语,但关键部分是这个。

应用可以包含或运行未嵌入二进制文件中的代码,只要代码分发不是应用的主要目的。

基本上,只要您的应用不是将代码分发作为应用本身的功能,并且只要您不滥用 AppSync 从根本上更改应用的目的(例如突然将您的日历应用变成赌博应用),您就可以放心使用。

值得注意的是,NativeScript AppSync 基于 Microsoft 的 CodePush 项目,该项目已被数千名开发人员用于部署和更新 iOS 应用程序。

注意:Apple 已明确表示他们不希望您的应用向用户显示更新对话框,因此,再次强调,请确保您不要在通过 App Store 分发的 iOS 应用上使用InstallMode.IMMEDIATE

AppSync 还能做什么?

您可能希望将许多其他 AppSync 功能整合到您的开发工作流程中。

例如,AppSync CLI 和服务器能够分别处理暂存和生产版本,使您能够在将更新发送给生产用户之前在本地测试更新。

此外,AppSync CLI 和服务器都提供了部署历史记录数据,包括您推送出的更新的确切用户数量。如果出现问题,您甚至可以使用nativescript-app-sync rollback回滚更新。

$ nativescript-app-sync deployment history ACMEAndroid Staging
┌───────┬──────────────┬─────────────┬───────────┬─────────────┬───────────────────────┐
│ Label │ Release Time │ App Version │ Mandatory │ Description │ Install Metrics       │
├───────┼──────────────┼─────────────┼───────────┼─────────────┼───────────────────────┤
│ v1    │ 2 hours ago  │ 1.0         │ No        │             │ Active: 100% (1 of 1) │
│       │              │             │           │             │ Total: 1              │
└───────┴──────────────┴─────────────┴───────────┴─────────────┴───────────────────────┘

如您所见,AppSync 可以提供很多功能来改进您的开发工作流程,并帮助您更快地将修复程序交付给用户。有关更多详细信息,请参阅NativeScript 市场上的 AppSync 插件文档,如果您对使用插件有任何其他疑问,请随时在评论中提出。