添加 iOS App Clip target

这个指南介绍了如何手动添加另一个使用 Flutter 来渲染的 iOS App Clip target, 并将它集成到您现有的 Flutter 项目或 add-to-app 项目。

This guide describes how to manually add another Flutter-rendering iOS App Clip target to your existing Flutter project or add-to-app project.

如果您有兴趣将 App Clip 自动集成到 iOS 应用中,请参阅功能请求 #65451.

If you are interested in automatically integrating an App Clip into your iOS app, see feature request #65451.

要查看完整可用的示例,请参阅 GitHub 上的 App Clip 示例

To see a working sample, see the App Clip sample on GitHub.

步骤 1 - 打开项目

Step 1 - Open project

打开您的 iOS Xcode 工程,例如您的纯 Flutter 项目中的 ios/Runner.xcworkspace

Open your iOS Xcode project, such as ios/Runner.xcworkspace for full-Flutter apps.

步骤 2 - 添加一个 App Clip 的 target

Step 2 - Add an App Clip target

2.1

点击您项目的 Project Navigator 来显示工程设置。

Click on your project in the Project Navigator to show the project settings.

点击 target 列表底部的 + 来添加一个新的 target。

Press + at the bottom of the target list to add a new target.

2.2

为您的新 target 选择 App Clip 类型。

Select the App Clip type for your new target.

2.3

在对话框为您的新 target 输入详情。

Enter your new target detail in the dialog.

选择 Storyboard 作为界面。

Select Storyboard for Interface.

选择 UIKit App Delegate 作为生命周期。

Select UIKit App Delegate for Life Cycle.

选择与您原来的 target 相同的编程语言。

Select the same language as your original target for Language.

(换句话说,请勿为 Objective-C target 创建 Swift 类型的 App Clip target,反之亦然,以简化设置。)

(In other words, don’t create a Swift App Clip target for an Objective-C main target, and vice versa to simplify the setup.)

2.4

在接下来的对话框中,为新的 target 激活 (activate) 一个新的 scheme。

In the following dialog, activate the new scheme for the new target.

步骤 3 - 移除不需要的文件

Step 3 - Remove unneeded files

3.1

在项目 Project Navigator 的新创建的 App Clip 组中,将除了 Info.plistApp Clip target.entitlements 以外的所有内容删除。

In the Project Navigator, in the newly created App Clip group, delete everything except Info.plist and <app clip target>.entitlements.

移动文件到废纸篓。

Move files to trash.

3.2

如果您不使用 SceneDelegate.swift 文件,移除在 Info.plist 中对应的引用。

If you don’t use the SceneDelegate.swift file, remove the reference to it in the Info.plist.

打开 App Clip 组中的 Info.plist。删除 Application Scene Manifest 字典条目。

Open the Info.plist file in the App Clip group. Delete the entire dictionary entry for Application Scene Manifest.

步骤 4 - 共享构建配置

Step 4 - Share build configurations

对于 add-to-app 项目,此步骤不是必需的,因为 add-to-app 有自己的自定义构建配置和版本。

This step isn’t necessary for add-to-app projects since add-to-app projects have their custom build configurations and versions.

4.1

返回项目设置,现在选择 Project 条目,而不是 Targets 里的任何 target。

Back in the project settings, select the project entry now rather than any targets.

Info 选项卡页中的 Configurations 可扩展组下,展开 DebugProfileRelease 条目。

In the Info tab, under the Configurations expandable group, expand the Debug, Profile, and Release entries.

每一个 App Clip target 的下拉菜单的值都应该与常规应用 target 中的值相同。

For each, select the same value from the drop-down menu for the App Clip target as the entry selected for the normal app target.

这使您的 App Clip target 可以访问 Flutter 的必需构建设置。

This gives your App Clip target access to Flutter’s required build settings.

4.2

在 App Clip 组的 Info.plist 文件中,设置:

In the App Clip group’s Info.plist file, set:

  • Build version string (short) to $(FLUTTER_BUILD_NAME)
  • Bundle version to $(FLUTTER_BUILD_NUMBER)

步骤 5 - 共享代码和资源

Step 5 - Share code and assets

选项 1 - 共享所有东西

Option 1 - Share everything

假设您的目标是在 App Clip 中显示与普通应用相同的 Flutter UI,并共享相同的代码和资源。

Assuming the intent is to show the same Flutter UI in the standard app as in the App Clip, share the same code and assets.

对于以下每一个文件: Main.storyboardAssets.xcassetsLaunchScreen.storyboardGeneratedPluginRegistrant.mAppDelegate.swift,(如果您是 Objective-C 还应该包括 Supporting Files/main.m)选择文件并且在检查器中选择第一个选项卡,并且在 Target Membership 选中 App Clip

For each of the following: Main.storyboard, Assets.xcassets, LaunchScreen.storyboard, GeneratedPluginRegistrant.m, and AppDelegate.swift (and Supporting Files/main.m if using Objective-C), select the file, then in the first tab of the inspector, also include the App Clip target in the Target Membership checkbox group.

选项 2 - 为 App Clip 自定义 Flutter 的启动器

Option 2 - Customize Flutter launch for App Clip

在这个例子中,不需要删除在 步骤 3 中的任何东西。相对的,使用 iOS add-to-app APIs 的模板来自定义 Flutter 启动器。可以参考示例 自定义 Flutter 路由

In this case, do not delete everything listed in Step 3. Instead, use the scaffolding and the iOS add-to-app APIs to perform a custom launch of Flutter. For example to show a custom Flutter route.

步骤 6 - 添加 App Clip 的关联域名

Step 6 - Add App Clip associated domains

这是一个 App Clip 开发的标准步骤。请查看 苹果官方文档

This is a standard step for App Clip development. See the official Apple documentation.

6.1

打开 <app clip target>.entitlements 文件。添加 Associated Domains 数组。添加一行 appclips:<your bundle id> 到数组中。

Open the <app clip target>.entitlements file. Add an Associated Domains Array type. Add a row to the array with appclips:<your bundle id>.

6.2

同样的相关域名权利也需要添加到您的主应用程序中。

The same associated domains entitlement needs to be added to your main app as well.

<app clip target>.entitlements 文件从 App Clip 组复制到主应用程序组,并将其重命名为与主目标相同的名称,例如 Runner.entitlements

Copy the <app clip target>.entitlements file from your App Clip group to your main app group and rename it to the same name as your main target such as Runner.entitlements.

打开文件并删除主应用程序授权文件的 Parent Application Identifiers 条目(将该条目保留为 App Clip 的授权文件)。

Open the file and delete the Parent Application Identifiers entry for the main app’s entitlement file (leave that entry for the App Clip’s entitlement file).

6.3

返回项目设置,选择主应用 target,打开 Build Settings 选项卡。设置 Code Signing Entitlements 的值为主应用创建的第二个授权文件的相对路径。

Back in the project settings, select the main app’s target, open the Build Settings tab. Set the Code Signing Entitlements setting to the relative path of the second entitlements file created for the main app.

步骤 7 - 整合 Flutter

Step 7 - Integrate Flutter

add-to-app 不需要这些步骤。

These steps are not necessary for add-to-app.

7.1

在您的 App Clip 的 target 的项目设置,打开 Build Settings 选项卡。

In your App Clip’s target’s project settings, open the Build Settings tab.

Framework Search Paths 添加两个内容:

For setting Framework Search Paths, add 2 entries:

  • $(inherited)
  • $(PROJECT_DIR)/Flutter

换句话说,与主应用程序 target 的构建设置相同。

In other words, the same as the main app target’s build settings.

7.2

如果是 Swift target,设置 Objective-C Bridging Header 构建配置为 Runner/Runner-Bridging-Header.h

For Swift target, set the Objective-C Bridging Header build setting to Runner/Runner-Bridging-Header.h

换句话说,与主应用程序 target 的构建设置相同。

In other words, the same as the main app target’s build settings.

7.3

现在打开 Build Phases 选项卡。点击 + 并且选择 New Run Script Phase

Now open the Build Phases tab. Press the + sign and select New Run Script Phase.

拖动新的 phase 到 Dependencies phase。

Drag that new phase to below the Dependencies phase.

展开新 phase 并将以下内容添加到脚本:

Expand the new phase and add this line to the script content:

/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build

简单来说,与主应用程序 target 的构建设置相同。

In other words, the same as the main app target’s build phases.

这可以确保在运行 App Clip target 时编译 Flutter 的 Dart 代码。

This ensures that your Flutter Dart code is compiled when running the App Clip target.

7.4

再次点击 + 并且选择 New Run Script Phase。这是最后一个 phase。

Press the + sign and select New Run Script Phase again. Leave it as the last phase.

这次添加如下内容:

This time, add:

/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed_and_thin

简单来说,与主应用程序 target 的构建设置相同。

In other words, the same as the main app target’s build phases.

这将确保您的 Flutter 应用程序和引擎嵌入到 App Clip bundle 中。

This ensures that your Flutter app and engine are embedded into the App Clip bundle.

Step 8 - Disable Bitcode

在 App Clip target 的 Build Settings 选项卡中,将 Enable Bitcode 设置设置为 No。

In the App Clip target’s Build Settings tab, set the Enable Bitcode setting to No.

Step 9 - 整合插件

Step 9 - Integrate plugins

9.1

在您的 Flutter 项目或是 add-to-app 的宿主项目中打开 Podfile 文件。

Open the Podfile for your Flutter project or add-to-app host project.

如果是完整的 Flutter 项目,替换下面这段代码:

For full-Flutter apps, replace the following section:

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

为:

with:

use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

target 'Runner'
target '<name of your App Clip target>'

在文件的开始,需要把 platform :ios, '9.0' 的注释解除,并且为您的 2 个 target 设置最低可运行的 iOS 系统版本。

At the top of the file, also uncomment platform :ios, '9.0' and set the version to the lowest of the 2 target’s iOS Deployment Target.

如果是 add-to-app,紧跟下面的代码:

For add-to-app, add to:

target 'MyApp' do
  install_all_flutter_pods(flutter_application_path)
end

添加:

with:

target 'MyApp' do
  install_all_flutter_pods(flutter_application_path)
end

target '<name of your App Clip target>'
  install_all_flutter_pods(flutter_application_path)
end

9.2

在命令行中,目前工作目录需要是您的 Flutter 项目目录。

From the command line, enter your Flutter project directory.

cd ios

然后运行

then

pod install.

运行

Run

您现在可以在 Xcode 的 scheme 下拉中选择并运行您的 App Clip target 了,选择一个 iOS 14 的设备并点击运行。

You can now run your App Clip target from Xcode by selecting your App Clip target from the scheme drop-down, selecting an iOS 14 device and pressing run.

要从头测试 App Clip 的启动,您也可以查看苹果公司的文档 测试您的 App Clip 的启动体验

To test launching an App Clip from the beginning, also consult Apple’s doc on Testing Your App Clip’s Launch Experience.

调试和热重载

Debugging, hot reload

不幸的是,由于网络权限的原因,flutter attach 无法在 App clip 中自动发现 Flutter 会话。

Unfortunately flutter attach cannot auto-discover the Flutter session in an App Clip due to networking permission restrictions.

为了调试 App clip 并使用诸如热重新加载之类的功能,必须在运行应用后从 Xcode 中的控制台输出中查找 Observatory URI。

In order to debug your App Clip and use functionalities like hot reload, you must look for the Observatory URI from the console output in Xcode after running.

您需要复制粘贴它们到 flutter attach 来连接。

You must then copy paste it back into the flutter attach command to connect.

例如:

Such as

flutter attach --debug-uri <copied URI>