App Center Distribute - iOS 应用内更新

重要

Visual Studio App Center 计划于 2025 年 3 月 31 日停用。 虽然可以继续使用 Visual Studio App Center,直到它完全停用,但你可以考虑迁移到几个建议的替代方法。

详细了解支持时间线和替代方法。

当你通过 App Center 分发应用时,App Center 分发将允许用户安装新版本的应用。 新版本的应用可用后,SDK 将向用户显示一个更新对话框,以下载或推迟新版本。 选择更新后,SDK 将开始更新应用程序。

注意

使用应用内更新时,需要考虑以下几点:

  1. 如果你已在App Store中发布了应用,则将禁用应用内更新。
  2. 如果运行的是自动 UI 测试,则启用的应用内更新将阻止自动化 UI 测试,因为它们将尝试对 App Center 后端进行身份验证。 建议不要为 UI 测试目标启用 App Center Distribute。

注意

4.0.0 App Center 版本中引入了中断性变更。 按照 迁移到 App Center SDK 4.0.0 及更高 版本部分从早期版本迁移 App Center。

重要

App Center SDK 不支持 iOS 13 中引入的多个窗口应用。

将应用内更新添加到应用

如果尚未在应用程序中配置 SDK,请按照 入门 部分进行操作。

1.添加 App Center Distribute 模块

App Center SDK 采用模块化方法设计,只需集成感兴趣的服务的模块。

通过 Cocoapods 集成

如果要通过 Cocoapods 将 App Center 集成到应用中,请将以下依赖项添加到 podfile 并运行 pod install

pod 'AppCenter/Distribute'

通过 Carthage 集成

  1. 将以下依赖项添加到 , Cartfile 以包括 App Center Distribute。

    # Use the following line to get the latest version of App Center
    github "microsoft/appcenter-sdk-apple"
    
    # Use the following line to get the specific version of App Center
    github "microsoft/appcenter-sdk-apple" ~> X.X.X
    
  2. 运行 carthage update

  3. 打开应用程序目标的“ 常规 设置”选项卡。将 AppCenterDistribute.framework 文件从 Carthage/Build/iOS 文件夹拖放到 XCode 中的 “链接框架和库” 部分。

  4. AppCenterDistributeResources.bundleAppCenterDistribute.framework 拖放到 XCode 的项目导航器中。

  5. 将显示一个对话框,确保已选中你的应用目标。 然后单击“完成”。

通过 Swift 包管理器集成

  1. 在“Xcode”菜单中,单击“ 文件 > ”“Swift 包 > ”“添加包依赖项”。
  2. 在出现的对话框中,输入存储库 URL: https://github.com/microsoft/appcenter-sdk-apple.git
  3. “版本”中,选择“ 下一个主要 版本”并采用默认选项。
  4. 在“包产品”列中选择“AppCenterDistribute”。

通过将二进制文件复制到项目中进行集成

如果不想使用 Cocoapods,可以通过将二进制文件复制到项目中来集成模块。 请遵循以下步骤进行配置:

注意

App Center SDK 支持使用 XCframework。 如果要将 XCframeworks 集成到项目中,请从发布页下载 AppCenter-SDK-Apple-XCFramework.zip 并将其解压缩。 生成的文件夹内容不是特定于平台的,而是包含每个模块的 XCframeworks。 可以像通常的框架一样集成它们,如下所述。

  1. 下载以 zip 文件的形式提供的 App Center SDK 框架。

  2. 解压缩该文件,你将看到一个名为 AppCenter-SDK-Apple/iOS 的文件夹,其中包含每个 App Center 服务的不同框架。 项目中需要调用 AppCenter 的框架,因为它包含在不同模块之间共享的代码。

  3. [可选]为第三方库创建子目录。

    • 最佳做法是,第三方库通常位于子目录内,通常称为 Vendor。 如果项目未使用库的子目录进行组织,请立即创建 Vendor 子目录。
    • 在 Xcode 项目中创建名为 Vendor 的组,以模拟磁盘上的文件结构。
  4. 打开 Finder,将解压缩的 AppCenter-SDK-Apple/iOS 文件夹复制到项目文件夹中,该文件夹位于所需位置。

  5. 将 SDK 框架添加到 Xcode 中的项目:

    • 确保项目导航器 (⌘+1) 可见。
    • 现在,将 Finder 中的 AppCenter.frameworkAppCenterDistribute.frameworkAppCenterDistributeResources.bundle (供应商文件夹中) 的 AppCenter.framework 和 AppCenterDistributeResources.bundle 拖放到 Xcode 的 Project Navigator 中。 启动 SDK 需要 AppCenter.framework。 请确保已将其添加到项目中,否则其他模块将不起作用,并且无法成功编译项目。
    • 将显示一个对话框,确保已选中你的应用目标。 然后单击“完成”。

2. 启动 App Center 分发

App Center 仅使用在应用程序中调用的特定模块。 启动 SDK 时,必须显式调用其中每个。

2.1 添加 App Center Distribute 的导入

在 Objective-C 中打开项目的 AppDelegate.m 文件,在 Swift 中打开 AppDelegate.swift 文件,并添加以下 import 语句:

@import AppCenter;
@import AppCenterDistribute;
import AppCenter
import AppCenterDistribute

2.2 添加 start:withServices: 方法

将 添加到 Distributestart:withServices: 方法以启动 App Center Distribute 服务。

插入以下行以在方法中用于 Objective-C 的项目 AppDelegate.m 类或适用于 Swift 的 AppDelegate.swift 类中 didFinishLaunchingWithOptions 启动 SDK。

[MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACDistribute class]]];
AppCenter.start(withAppSecret: "{Your App Secret}", services: [Distribute.self])

确保已将上述代码示例中的 替换为 {Your App Secret} 应用机密。 如果尚未在应用程序中配置 SDK,检查入门部分。

2.3 修改项目的 Info.plist

  1. 在项目的 Info.plist 文件中,单击顶部“信息属性列表”旁边的“+”按钮,为 URL types 添加新键。 如果 Xcode 将 Info.plist 显示为源代码,请参阅下面的提示。
  2. 将键类型更改为 Array。
  3. 将新条目添加到数组 (Item 0) ,并将类型更改为 Dictionary。
  4. 在 下 Item 0,添加一个 URL Schemes 键并将类型更改为 Array。
  5. 在密钥下 URL Schemes , (Item 0) 添加新条目。
  6. 在 下 URL Schemes>Item 0,将值更改为 appcenter-{APP_SECRET} ,并将 替换为 {APP_SECRET} 应用的应用机密。

提示

如果要验证是否正确修改了 Info.plist,请将其作为源代码打开。 它应包含以下带有应用机密的条目, {APP_SECRET}而不是 :

<key>CFBundleURLTypes</key>
<array>
  <dict>
  	<key>CFBundleURLSchemes</key>
  	<array>
  		<string>appcenter-{APP_SECRET}</string>
  	</array>
  </dict>
</array>

使用专用通讯组

默认情况下,分发使用公共通讯组。 如果要使用专用通讯组,则需要通过 updateTrack 属性显式设置它。

MSACDistribute.updateTrack = MSACUpdateTrackPrivate;
Distribute.updateTrack = .private

注意

默认值为 UpdateTrack.public。 此属性只能在方法调用之前 AppCenter.start 更新。 当应用程序进程重启时,不会保留对更新跟踪的更改,因此,如果 属性在调用之前 AppCenter.start 并不总是更新的,则默认情况下,该属性将是公开的。

在此调用后,将打开一个浏览器窗口来对用户进行身份验证。 所有后续更新检查都将在专用轨道上获取最新版本。

如果用户处于 专用通道上,这意味着身份验证成功后,他们将从其所属的任何专用通讯组获取最新版本。 如果用户处于 公共轨道上,则意味着他们将从任何公共通讯组获取最新版本。

禁用更新的自动检查

默认情况下,SDK 会自动检查新版本:

  • 应用程序启动时。
  • 当应用程序进入后台时,然后再次进入前台。
  • 启用分发模块(如果之前已禁用)。

如果要手动检查新版本,可以禁用自动检查进行更新。 为此,请在 SDK 启动之前调用以下方法:

[MSACDistribute disableAutomaticCheckForUpdate];
Distribute.disableAutomaticCheckForUpdate()

注意

必须在方法调用之前 AppCenter.start 调用此方法。

然后, checkForUpdate 可以使用下一部分所述的 API。

手动检查更新

[MSACDistribute checkForUpdate];
Distribute.checkForUpdate()

这会向 App Center 发送请求,并在有新版本可用时显示更新对话框。

注意

即使启用了自动更新,更新调用的手动检查也有效。 如果正在执行另一个检查,则忽略更新的手动检查。 如果用户已推迟更新 (,则不会处理更新的手动检查,除非最新版本是) 的必需更新。

自定义或本地化应用内更新对话框

1. 自定义或本地化文本

如果要本地化更新对话框中显示的文本,可以轻松提供自己的资源字符串。 查看 此字符串文件。 使用相同的字符串名称/键,并在你自己的应用字符串文件中指定要反映在对话框中的本地化值。

2.自定义更新对话框

可以通过实现 DistributeDelegate 协议自定义默认更新对话框的外观。 在启动 SDK 之前,需要注册委托,如以下示例所示:

[MSACDistribute setDelegate:self];
Distribute.delegate = self;

下面是将 SDK 对话框替换为自定义对话框的委托实现示例:

- (BOOL)distribute:(MSACDistribute *)distribute releaseAvailableWithDetails:(MSACReleaseDetails *)details {

  // Your code to present your UI to the user, e.g. an UIAlertController.
  UIAlertController *alertController = [UIAlertController
      alertControllerWithTitle:@"Update available."
                       message:@"Do you want to update?"
                preferredStyle:UIAlertControllerStyleAlert];

  [alertController
      addAction:[UIAlertAction actionWithTitle:@"Update"
                                         style:UIAlertActionStyleCancel
                                       handler:^(UIAlertAction *action) {
                                         [MSACDistribute notifyUpdateAction:MSACUpdateActionUpdate];
                                       }]];

  [alertController
      addAction:[UIAlertAction actionWithTitle:@"Postpone"
                                         style:UIAlertActionStyleDefault
                                       handler:^(UIAlertAction *action) {
                                         [MSACDistribute notifyUpdateAction:MSACUpdateActionPostpone];
                                       }]];

  // Show the alert controller.
  [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  return YES;
}
func distribute(_ distribute: Distribute, releaseAvailableWith details: ReleaseDetails) -> Bool {

  // Your code to present your UI to the user, e.g. an UIAlertController.
  let alertController = UIAlertController(title: "Update available.",
                                        message: "Do you want to update?",
                                 preferredStyle:.alert)

  alertController.addAction(UIAlertAction(title: "Update", style: .cancel) {_ in
    Distribute.notify(.update)
  })

  alertController.addAction(UIAlertAction(title: "Postpone", style: .default) {_ in
    Distribute.notify(.postpone)
  })

  // Show the alert controller.
  self.window?.rootViewController?.present(alertController, animated: true)
  return true;
}

如果你在上述方法中返回 YES/true ,你的应用应获取用户的选择,并使用以下 API 向 SDK 发送结果消息。

// Depending on the user's choice, call notifyUpdateAction: with the right value.
[MSACDistribute notifyUpdateAction:MSACUpdateActionUpdate];
[MSACDistribute notifyUpdateAction:MSACUpdateActionPostpone];
// Depending on the user's choice, call notify() with the right value.
Distribute.notify(.update);
Distribute.notify(.postpone);

如果不调用上述方法,每当应用进入前台时, releaseAvailableWithDetails:-method 都将重复。

3.如果未找到更新,则执行代码

如果 SDK 检查更新,但找不到比当前使用的 distributeNoReleaseAvailable: 更新,则会调用来自 MSACDistributeDelegate 委托回调的 。 这样,就可以在此类方案中执行自定义代码。

以下示例演示如何在找不到任何更新时显示警报 UI:

- (void)distributeNoReleaseAvailable:(MSACDistribute *)distribute {
  UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
                                                                 message:NSLocalizedString(@"No updates available", nil)
                                                          preferredStyle:UIAlertControllerStyleAlert];
  [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:nil]];
  [self.window.rootViewController presentViewController:alert animated:YES completion:nil];
}
  func distributeNoReleaseAvailable(_ distribute: Distribute) {
    let alert = UIAlertController(title: nil, message: "No updates available", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
    self.window?.rootViewController?.present(alert, animated: true)
  }

在运行时启用或禁用 App Center Distribute

可以在运行时启用和禁用 App Center Distribute。 如果禁用它,SDK 不会提供任何应用内更新功能,但你仍然可以在 App Center 门户中使用分发服务。

[MSACDistribute setEnabled:NO];
Distribute.enabled = false

若要再次启用 App Center Distribute,请使用同一 API,但将 作为参数传递 YES/true

[MSACDistribute setEnabled:YES];
Distribute.enabled = true

在应用程序启动时,状态将保留在设备的存储中。

注意

只有在启动之后 Distribute 才能使用此方法。

检查是否启用了 App Center 分发

如果启用或未启用 App Center Distribute,还可以检查:

BOOL enabled = [MSACDistribute isEnabled];
var enabled = Distribute.enabled

注意

此方法只能在启动后 Distribute 使用,它将始终在启动之前返回 false

在开发期间不初始化 App Center Distribute

如果处于专用模式,App Center Distribute 将在应用程序启动时打开其 UI/浏览器。 虽然这是最终用户的预期行为,但它可能会在应用程序的开发阶段对你造成干扰。 不建议为DEBUG配置初始化Distribute

#if DEBUG
    [MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACAnalytics class], [MSACCrashes class]]];
#else
    [MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACAnalytics class], [MSACCrashes class], [MSACDistribute class]]];
#endif
#if DEBUG
    AppCenter.start(withAppSecret: "{Your App Secret}", services: [Analytics.self, Crashes.self])
#else
    AppCenter.start(withAppSecret: "{Your App Secret}", services: [Analytics.self, Crashes.self, Distribute.self])
#endif

在应用程序关闭进行更新之前立即执行清理

DistributeDelegate实现 协议并注册委托,如以下示例所示:

[MSACDistribute setDelegate:self];
Distribute.delegate = self;

distributeWillExitApp: 应用终止更新安装之前,将立即调用 委托方法:

- (void)distributeWillExitApp:(MSACDistribute *)distribute {
  // Perform the required clean up here.
}
func distributeWillExitApp(_ distribute: Distribute) {
  // Perform the required clean up here.
}

应用内更新的工作原理是什么?

注意

若要运行应用内更新,应从链接下载应用内部版本。 如果从 IDE 安装或手动安装,它将不起作用。

应用内更新功能的工作原理如下:

  1. 此功能仅适用于使用 App Center Distribute 服务分发的版本。 当附加调试器或打开 iOS 引导访问功能时,它将不起作用。

  2. 集成 SDK 后,生成应用的发布版本并将其上传到 App Center,该通讯组中的用户将收到有关新版本的电子邮件通知。

  3. 当每个用户在其电子邮件中打开链接时,该应用程序将安装在其设备上。 请务必使用电子邮件链接安装应用 - App Center Distribute 不支持从其他源安装的应用 (应用内更新,例如从电子邮件附件) 下载应用。 从链接下载应用程序时,SDK 会将 cookie 中的重要信息保存到检查以供以后更新,否则 SDK 没有该密钥信息。

  4. 如果应用程序将跟踪设置为专用,浏览器将打开以对用户进行身份验证并启用应用内更新。 只要身份验证信息保持有效,浏览器就不会再次打开,即使稍后切换回公共轨道并再次切换回专用。 如果浏览器身份验证成功,用户会自动重定向回应用程序。 如果曲目是公共 (这是默认) ,则直接执行下一步。

    • 在 iOS 9 和 10 上,将在应用中打开 的 SFSafariViewController 实例,以对用户进行身份验证。 身份验证成功后,它将自动关闭。
    • 在 iOS 11 上,用户体验类似于 iOS 9 和 iOS 10,但 iOS 11 将要求用户提供访问登录信息的权限。 这是一个系统级对话框,无法对其进行自定义。 如果用户取消对话框,他们可以继续使用他们正在测试的版本,但不会获得应用内更新。 下次启动应用时,系统会要求他们再次访问登录信息。
  5. 新版本的应用显示应用内更新对话框,要求用户在以下情况更新应用程序:

    • 或 的较高值CFBundleShortVersionString
    • 一个相等值 CFBundleShortVersionString ,但 值 CFBundleVersion较高。
    • 版本相同,但生成唯一标识符不同。

提示

如果再次上传相同的 ipa, 对话框将不会显示 ,因为二进制文件相同。 如果上传具有相同版本属性 的新版本 ,则会显示更新对话框。 原因是它是 不同的 二进制文件。

如何实现测试应用内更新?

需要将发布版本上传到 (,这些版本使用 App Center SDK 的分发模块) 到 App Center Portal 来测试应用内更新,每次都会增加版本号。

  1. 在 App Center 门户中创建应用(如果尚未创建)。
  2. 创建新的通讯组并将其命名,以便可以识别它用于测试应用内更新功能。
  3. 将自己 (或要包含在应用内更新功能测试) 中的所有人员。 为此,请使用新的或丢弃的电子邮件地址,该地址未用于 App Center 上的该应用。 这可确保你的体验接近于真实测试人员的体验。
  4. 创建应用的新内部版本,其中包含 App Center Distribute 并包含如下所述的设置逻辑。 如果组是专用组,在开始使用 updateTrack 属性之前,不要忘记设置专用应用内更新跟踪。
  5. 单击门户中的“ 分发新版本 ”按钮,然后上传应用的内部版本。
  6. 上传完成后,单击“下一步”,然后选择创建为该应用分发的目标通讯组
  7. 查看分发并将生成分发到应用内测试组。
  8. 该组中人员将收到成为应用测试人员的邀请。 接受邀请后,即可从其移动设备从 App Center 门户下载应用。 安装应用内更新后,即可测试应用内更新。
  9. 将版本名称 (应用) CFBundleShortVersionString
  10. 生成应用的发布版本并上传应用的新版本,就像在上一步中所做的那样,并将其分发到前面创建的 通讯组 。 下次启动应用时,将提示通讯组成员输入新版本。

提示

查看有关如何 利用 App Center 分发 的信息,了解有关 通讯组 等的更多详细信息。虽然可以在不添加任何代码的情况下使用 App Center Distribute 来分发应用的新版本,但将 App Center Distribute 添加到应用的代码将为测试人员和用户带来更无缝的体验,因为他们可以获得应用内更新体验。

禁止将应用程序委托的方法调用转发到 App Center 服务

App Center SDK 使用重排通过转发自身的某些应用程序委托方法调用来改进其集成。 方法重排是在运行时更改方法实现的一种方法。 如果出于任何原因不想使用重排 (例如由于特定策略) ,则可以按照以下步骤为所有 App Center 服务禁用此转发:

  1. 打开项目的 Info.plist 文件。
  2. 添加 AppCenterAppDelegateForwarderEnabled 键并将值设置为 0。 这会为所有 App Center 服务禁用应用程序委托转发。
  3. openURL 项目的 AppDelegate 文件中添加回调。
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {

  // Pass the url to MSACDistribute.
  return [MSACDistribute openURL:url];
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {

  // Pass the URL to App Center Distribute.
  return Distribute.open(url)
}