大多数浏览器和
Developer App 均支持流媒体播放。
-
实现 App Store Offers
了解如何使用 App Store Connect 通过 App Store Offers 来吸引顾客,以及如何同时运用最新的 StoreKit 功能和 API。探索如何为 Mac App 设置赢回优惠 (重新吸引过往订阅者的全新方式),并生成优惠代码。此外,了解如何在沙盒和 Xcode 中测试优惠,以确保优惠能够顺畅运作。
章节
- 0:00 - Introduction
- 1:32 - Updates to offers
- 4:37 - Introducing win-back offers
- 7:10 - Configure win-back offers
- 16:50 - Support win-back offers
- 28:44 - Streamlined purchasing
资源
- Forum: App Store Distribution & Marketing
- Generating a signature for promotional offers
- Message
- offer
- PurchaseIntent
- Setting up StoreKit Testing in Xcode
- StoreKit views
- Submit feedback
- Supporting subscription offer codes in your app
- Testing win-back offers in Xcode
相关视频
WWDC24
WWDC23
-
下载Array
-
-
4:25 - Present offer code redemption sheet on macOS - SwiftUI API
// Present offer code redemption sheet on macOS - SwiftUI API import SwiftUI import StoreKit struct MyView: View { @State var showOfferCodeRedemption: Bool = false var body: some View { Button("Redeem Code") { showOfferCodeRedemption = true } .offerCodeRedemption(isPresented: $showOfferCodeRedemption) { result in // Handle result } } }
-
20:15 - Choose preferred offer in a SubscriptionStoreView
// Choose preferred offer in a SubscriptionStoreView import SwiftUI import StoreKit struct MyView: View { let groupID: String var body: some View { SubscriptionStoreView(groupID: groupID) .preferredSubscriptionOffer { product, subscription, eligibleOffers in let freeTrialOffer = eligibleOffers .filter { $0.paymentMode == .freeTrial } .max { lhs, rhs in lhs.period.value < rhs.period.value } return freeTrialOffer ?? eligibleOffers.first } } }
-
23:05 - Check subscription entitlement and offer eligibility
// Check subscription entitlement and offer eligibility import StoreKit func shouldShowMerchandising( for groupID: String, productIDs: [Product.ID] ) async throws -> MerchandisingVisibility { // Get subscription status let statuses = try await Product.SubscriptionInfo.status(for: groupID) // Check if the customer is already entitled to the subscription let entitlement = SubscriptionEntitlement(for: statuses) if entitlement.autoRenewalEnabled { return .hidden } // Check for offers to show in merchandising UI let products = try await Product.products(for: productIDs) let isEligibleForIntroOffer = await Product.SubscriptionInfo.isEligibleForIntroOffer(for: groupID) if isEligibleForIntroOffer { let subscriptions = products.map { ($0, $0.subscription?.introductoryOffer) } return .visible(subscriptions) } // Check for eligible win-back offers let purchasedStatus = statuses.first { $0.transaction.unsafePayloadValue.ownershipType == .purchased } let renewalInfo = try purchasedStatus?.renewalInfo.payloadValue let bestWinBackOfferID = renewalInfo?.eligibleWinBackOfferIDs.first // Return the product with the offer if there is one if let bestWinBackOfferID { let subscriptions: [(Product, Product.SubscriptionOffer?)] = products.map { let winBackOffer = $0.subscription?.winBackOffers.first { $0.id == bestWinBackOfferID } return ($0, winBackOffer) } return .visible(subscriptions) } // Only return the product if there is no offer return .visible(products.map { ($0, nil) }) } struct SubscriptionEntitlement { let isEntitled: Bool let autoRenewalEnabled: Bool init(for statuses: [Product.SubscriptionInfo.Status]) { let entitledStatuses = statuses.filter { $0.state == .subscribed || $0.state == .inBillingRetryPeriod || $0.state == .inGracePeriod } isEntitled = !entitledStatuses.isEmpty autoRenewalEnabled = entitledStatuses.contains { $0.renewalInfo.unsafePayloadValue.willAutoRenew } } } enum MerchandisingVisibility { case hidden case visible([(Product, Product.SubscriptionOffer?)]) }
-
25:26 - Add a win-back offer to a purchase
// Add a win-back offer to a purchase import StoreKit func purchase( _ product: Product, with offer: Product.SubscriptionOffer? ) async throws { // Prepare the purchase options var purchaseOptions: Set<Product.PurchaseOption> = [] // Add win-back offer to the purchase if let offer, offer.type == .winBack { purchaseOptions.insert(.winBackOffer(offer)) } // Make the purchase try await product.purchase(options: purchaseOptions) }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。