为其他企业创建 App Clips
Create App Clips for other businesses
2020年6月25日
一句话判断
如果你是一家 SaaS 公司(比如点餐系统、停车缴费平台),你可以为你的商户创建带有他们品牌和配置的 App Clips,让他们的客户扫码即用——这是一个全新的 B2B2C 分发模式。
这场 Session 讲了什么
App Clips 通常被认为是一种让用户快速体验你的 App 功能的方式。但 Session 10118 揭示了 App Clips 的另一个重要用途:作为平台型公司为你的企业客户提供的即用型服务。
具体场景是:假设你经营一个点餐平台(类似美团外卖的 SaaS 版),你的商户(餐厅)需要一个点餐入口。传统做法是让商户的用户下载你的 App。但有了 App Clips,你可以为每个商户生成一个专属的 App Clip——餐厅把二维码贴在桌上,顾客扫码就能直接点餐,无需安装任何 App。关键的技术点是:App Clip 的 URL 可以携带商户 ID、桌号等参数,App Clip 启动后直接进入对应的商户页面。
值得深挖的点
多商户的 URL 路由设计
当你为成百上千个商户提供 App Clip 时,URL 路由设计变得关键。你需要一个统一的 URL 模式,通过路径参数来区分不同的商户和场景。比如 https://order.app/restaurant/{id}/table/{number}。AASA 文件只需要配置一次通配符路径,就能覆盖所有商户。
App Clip 的配置分发
你可以为每个商户生成不同的 App Clip Code(二维码),URL 中包含商户特有的参数。当用户扫码时,App Clip 收到 URL 后解析参数,直接加载对应商户的菜单和配置。商户的品牌信息(Logo、颜色)可以存储在你的服务器上,App Clip 启动后动态加载。
代码片段
配置支持多商户的 AASA 文件
场景:在服务器端配置通配的 AASA 文件。
{
"appclips": {
"apps": ["ABCDE12345.com.orderapp.Clip"],
"details": [
{
"appID": "ABCDE12345.com.orderapp.Clip",
"paths": [
"/restaurant/*",
"/order/*",
"/pay/*"
]
}
]
},
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.orderapp"],
"components": [
{ "/": "/restaurant/*" },
{ "/": "/order/*" }
]
}
]
}
}
处理多商户的 URL 路由
场景:App Clip 启动时解析商户信息和参数。
import UIKit
class ClipSceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene,
openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
handleClipURL(url)
}
private func handleClipURL(_ url: URL) {
// URL 格式: https://order.app/restaurant/{id}/table/{number}
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let pathComponents = components.path.components(separatedBy: "/").filter({ !$0.isEmpty }) else {
showError()
return
}
// 解析路径
guard pathComponents.count >= 2,
pathComponents[0] == "restaurant" else {
showError()
return
}
let restaurantId = pathComponents[1]
var tableNumber: String?
// 解析桌号
if pathComponents.count >= 4,
pathComponents[2] == "table" {
tableNumber = pathComponents[3]
}
// 加载商户配置
loadMerchantConfig(restaurantId: restaurantId, tableNumber: tableNumber)
}
private func loadMerchantConfig(restaurantId: String, tableNumber: String?) {
// 从服务器获取商户的品牌配置(Logo、颜色、菜单等)
MerchantService.fetchConfig(restaurantId: restaurantId) { config in
DispatchQueue.main.async {
self.showOrderingView(config: config, tableNumber: tableNumber)
}
}
}
private func showOrderingView(config: MerchantConfig, tableNumber: String?) {
// 直接展示点餐页面,应用商户的品牌样式
let orderingVC = OrderingViewController(
merchantConfig: config,
tableNumber: tableNumber
)
orderingVC.modalPresentationStyle = .fullScreen
window?.rootViewController?.present(orderingVC, animated: true)
}
private func showError() {
// URL 解析失败的处理
}
}
生成商户专属的 App Clip Code
场景:为商户生成可打印的二维码。
import UIKit
class QRCodeGenerator {
// 为特定餐厅的特定桌号生成二维码
static func generateCode(
restaurantId: String,
tableNumber: String? = nil
) -> UIImage? {
var urlString = "https://order.app/restaurant/\(restaurantId)"
if let table = tableNumber {
urlString += "/table/\(table)"
}
guard let url = URL(string: urlString),
let data = urlString.data(using: .ascii) else {
return nil
}
// 使用 CIFilter 生成二维码
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(data, forKey: "inputMessage")
filter?.setValue("M", forKey: "inputCorrectionLevel") // 中等容错
guard let outputImage = filter?.outputImage else { return nil }
// 缩放到合适大小
let transform = CGAffineTransform(scaleX: 10, y: 10)
let scaledImage = outputImage.transformed(by: transform)
return UIImage(ciImage: scaledImage)
}
}
为商户配置 Apple Pay
场景:让每个商户都能通过 App Clip 接收 Apple Pay 支付。
import PassKit
class PaymentHandler: NSObject, PKPaymentAuthorizationViewControllerDelegate {
private var merchantConfig: MerchantConfig?
func startPayment(config: MerchantConfig, amount: Decimal) {
self.merchantConfig = config
// 检查是否支持 Apple Pay
guard PKPaymentAuthorizationViewController.canMakePayments(
usingNetworks: [.visa, .masterCard, .chinaUnionPay]
) else {
showAlternativePayment()
return
}
let request = PKPaymentRequest()
request.merchantIdentifier = "merchant.com.orderapp"
request.supportedNetworks = [.visa, .masterCard, .chinaUnionPay]
request.merchantCapabilities = .capability3DS
// 使用商户的配置
request.paymentSummaryItems = [
PKPaymentSummaryItem(
label: config.name, // 显示商户名称
amount: NSDecimalNumber(decimal: amount)
)
]
// 设置为 App Clip 的即时支付
request.requiredShippingContactFields = [.name, .phone]
guard let vc = PKPaymentAuthorizationViewController(paymentRequest: request) else {
return
}
vc.delegate = self
// 展示支付界面
// present(vc, animated: true)
}
func paymentAuthorizationViewController(
_ controller: PKPaymentAuthorizationViewController,
didAuthorizePayment payment: PKPayment,
handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
// 处理支付
// 将 payment.token 发送到你的支付服务器
// 使用商户的支付配置进行处理
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
}
func paymentAuthorizationViewControllerDidFinish(
_ controller: PKPaymentAuthorizationViewController) {
controller.dismiss(animated: true)
}
private func showAlternativePayment() {
// 如果不支持 Apple Pay,显示其他支付方式
}
}
最佳实践
已有项目:如果你在经营一个面向商户的 SaaS 平台(点餐、停车、预约等),立即评估 App Clips 的集成方案。核心改动是:添加 App Clip target、配置 URL 路由、为每个商户生成专属的 App Clip Code。商户端只需要打印和放置二维码。
新项目:从架构上就把”商户配置化”考虑进去。商户的品牌、菜单、支付方式都应该是动态配置的,而不是硬编码的。App Clip 只是前端的展示层,所有的配置数据来自你的后端 API。
还有什么值得关注
- App Clip 的 10MB 体积限制意味着你不能把所有商户的配置都打包进去,必须通过网络动态加载。
- Apple 提供了 App Clip Code 生成器(Xcode 内置),可以生成带有 Apple Logo 的标准二维码。
- App Clip 支持 NFC 标签触发,适合商户的线下场景(如 NFC 贴纸贴在桌上)。