App Center分发 - iOS 应用内更新

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

备注

使用应用内更新时,需要考虑一些操作:

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

备注

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

重要

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

将应用内更新添加到应用

如果 尚未在应用程序中 配置 SDK,请遵循"入门"部分。

1.添加App Center分发模块

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 的 Project Navigator 中。

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

通过 Swift 程序包管理器

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

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

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

备注

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

  1. 下载作为 zip 文件提供的 APP CENTER SDK 框架。

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

  3. 可有可无为第三方库创建子目录。

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

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

    • 请确保 Project 导航器 (⌘ + 1) 可见。
    • 现在,将 AppCenterAppCenterDistributeAppCenterDistributeResources 从查找器中拖放 (供应商 文件夹内的 Project 导航器中) 。 启动 SDK 需要 AppCenter。 请确保将其添加到项目中,否则其他模块将无法运行,并且你的项目不会成功编译。
    • 随即出现一个对话框,确保已选中应用目标。 然后单击“完成”。

2.开始App Center分发

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

2.1 为 App Center Distribute 添加导入

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

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

2.2 添加 start:withServices: 方法

Distribute 添加到 start:withServices: 方法以启动App Center分发服务。

在 方法中的 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>

使用专用通讯组

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

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

备注

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

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

如果用户在专用轨迹上,这意味着身份验证成功后,他们将从他们作为成员的任何专用通讯组获取最新版本。 如果用户在公共轨迹 ,这意味着他们将从任何公共通讯组获取最新版本。

禁用自动更新检查

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

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

如果要手动检查新版本,可以禁用自动更新检查。 为此,在 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;
}

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

// 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分发"

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

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

若要再次App Center分发,请使用同一 API,但作为 YES / true 参数传递。

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

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

备注

此方法只能在启动后使用 Distribute

检查是否已启用 App Center 分发

还可以检查是否已启用 App Center 分发:

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

备注

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

不会在开发过程中初始化 App Center 分发

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

#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 distributed service 分发的版本。 如果已连接调试器或启用了 iOS 引导访问功能,则不会运行该功能。

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

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

  4. 如果应用程序将曲目设置为 "专用",则会打开一个浏览器来对用户进行身份验证并启用应用内更新。 只要身份验证信息保持有效,则浏览器将不会重新打开,即使在稍后切换回公共轨并再次返回到私用也是如此。 如果浏览器身份验证成功,则会将用户重定向回应用程序。 如果轨道为公用 (默认) ,则下一步将直接发生。

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

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

提示

如果第二次上传相同的 ipa,则 会显示该对话框,因为二进制文件是相同的。 如果使用相同的版本属性上传 版本,则会显示 "更新" 对话框。 这是因为它是一个 不同 的二进制文件。

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

需要将使用 App Center) SDK 的 "分发" 模块的 "发布版本" (上载到 App Center 门户,以便测试应用内更新,每次增加版本号。

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

提示

请查看有关如何 使用 App Center 分布 的信息,以获取有关 通讯组 等的更多详细信息。尽管可以使用 App Center 分发来分发新版本的应用程序而无需添加任何代码,但在应用程序代码中添加 App Center 分发将为测试人员和用户提供更无缝的体验,因为他们会获得应用程序内更新体验。

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

App Center SDK 使用 swizzling 通过自行转发某些应用程序委托的方法调用来改善其集成。 方法 swizzling 是在运行时更改方法实现的一种方法。 如果出于任何原因而不想使用 swizzling (例如,由于特定策略) ,则可以按照以下步骤为所有 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)
}