ハイライト
Appleは年額サブスクリプションに、12か月コミットメント付きの月額払いプランを追加しました。ユーザーは月ごとに支払うことで意思決定のハードルを下げられ、開発者は長期サブスクリプション収益を確保できます。StoreKitには表示と購入のための
PricingTermsとbillingPlanTypeAPIが追加され、サーバー側JWSTransactionには履行進捗を追跡するcommitmentInfoフィールドが加わり、App Store Connectの審査提出フローもIAPを他の審査項目とまとめて提出できるようになりました。
主要内容
年額サブスクリプションの価格設定のジレンマ
サブスクリプション事業を行う開発者なら、この難題に出会ったことがあるはずです。年額サブスクリプションを推すと、ユーザーは一括請求額を見て離脱する。月額サブスクリプションを推すと、ユーザーはいつでも解約できるため、LTV(ライフタイムバリュー)を守りにくい。どちらにも利点と欠点があり、中間の選択肢がありませんでした。
AppleはiOS 26.5で公式の解決策を提供しました。12か月コミットメント付きの月額サブスクリプション(Monthly subscriptions with a 12-month commitment)です。ユーザーは毎月少額を支払いますが、契約は12か月ロックされます。開発者は確実な長期収益の見通しを得られ、ユーザーは低い意思決定ハードルで始められます。
このプランはApp Store Connectで直接構成します。1年期間の自動更新サブスクリプションを選び、“monthly with a 12-month commitment availability”で利用可否を設定し、手順に沿って構成を完了します。各請求プランには個別にサブスクリプションオファーを設定できます。たとえば、コミットメントプランのユーザーだけに無料トライアルを提供できます。
(01:53)
StoreKitで新しい請求プランを表示する
構成後、StoreKitは新しいPricingTerms属性を通じて請求プラン情報を公開します。SubscriptionInfo.pricingTermsは、その製品で利用可能なすべての請求プランを含む配列を返します。標準の年額前払いプランのタイプは.upFrontで、月額コミットメントを構成している場合は、配列に.monthlyタイプのオブジェクトが追加されます。
SwiftUIでSubscriptionStoreViewを使う場合、.preferredSubscriptionPricingTerms修飾子で月額コミットメントプランを絞り込み、優先表示できます。
(03:29)
サーバー側でコミットメント期間の進捗を追跡する
ユーザーがサブスクライブした後、サーバーは現在コミットメント期間の何か月目なのか、残り何回の支払いがあるのかを知る必要があります。JWSTransactionとJWSRenewalInfoにはcommitmentInfoフィールドが追加され、現在の期数を表すbillingPeriodNumber、総期数のtotalBillingPeriods、コミットメント終了日時のcommitmentExpiresDateなどが含まれます。
重要な点は、billingPeriodNumberがtotalBillingPeriodsより小さい場合、ユーザーはまだコミットメント期間中だということです。このとき、ユーザーがシステム設定で自動更新をキャンセルしても、Appleはコミットメント期間の終了まで月ごとに課金します。サーバーはユーザーの権利を早期に剥奪してはいけません。
(07:45)
Offer Code Redemption APIのアップグレード
オファーコード引き換えAPIはVerificationResultを返すようになりました。引き換え成功時にはtransactionオブジェクトを直接受け取り、失敗時には具体的なエラー情報を受け取れます。Transaction.updatesに依存して引き換え結果を推測する必要はなくなりました。
SwiftUIでは.offerCodeRedemption修飾子を使い、UIKitではpresentOfferCodeRedeemSheetを使います。Xcode 27のStoreKit Testingは新しい引き換えAPIのテストに対応しています。
(09:58)
App Store Connectの審査提出フローを統一
IAPの審査提出は、In-App Events、カスタムプロダクトページ、プロダクトページ最適化などの他の審査項目と一緒に、1つのSubmissionとしてまとめて提出できるようになりました。提出後は、集中ビューですべての審査項目の状態を確認できます。
App Store Connect APIのreviewSubmissionsエンドポイントは、IAP、サブスクリプション、サブスクリプショングループのリソースに対応するよう拡張されました。古いIAP専用の提出APIは廃止予定であり、新しいreviewSubmissionとreviewSubmissionItemsリソースへの移行が推奨されます。
(10:42)
詳細
StoreKitビューで月額コミットメントプランを表示する
(03:29)
import StoreKit
import SwiftUI
struct SubscriptionStore: View {
var body: some View {
SubscriptionStoreView(groupID: "3F19ED53") {
// Custom marketing content
}
.preferredSubscriptionPricingTerms { _, subscriptionInfo in
subscriptionInfo.pricingTerms.first {
$0.billingPlanType == .monthly
}
}
}
}
重要ポイント:
SubscriptionStoreViewはApp Storeから製品メタデータを自動取得し、各プラットフォームのレイアウトに適応する.preferredSubscriptionPricingTermsはiOS 26.5で追加された修飾子で、優先表示する請求プランを絞り込むために使うsubscriptionInfo.pricingTermsは利用可能なすべての請求プランを返す。.upFrontは常に存在し、.monthlyはコミットメントプランが構成されている場合にだけ現れる- 絞り込みを加えない場合、システムはデフォルトで
.upFrontを表示するため、月額コミットメントの低価格メリットが伝わらない
カスタムストアUIで価格情報を取得して購入する
(04:02)
import StoreKit
var product: Product?
// Fetch and assign product
let pricingTerms = product?.subscription?.pricingTerms
.first(where: { $0.billingPlanType == .monthly })
if let pricingTerms {
let monthlyPrice = pricingTerms.billingDisplayPrice
let totalCommitmentPrice = pricingTerms.commitmentInfo.price
// Display both monthly and total commitment price to the customer
}
let result = try? await product?.purchase(options: [.billingPlanType(.monthly)])
switch result {
// Verify the transaction, give the customer access to
// the purchased content, and then finish the transaction
}
重要ポイント:
billingDisplayPriceはユーザーに表示する月額支払い金額commitmentInfo.priceは12か月の総額であり、UIでは月額と総額を同時に表示するべき- 購入時に
.billingPlanType(.monthly)オプションを渡し、月額コミットメントプランを使うことを指定する - 請求プランのメタデータは、ユーザーの市場のストアで利用可能な場合にだけ返される
サブスクリプション管理Sheet
(05:05)
import SwiftUI
import StoreKit
struct ManageSubscriptionsButton: View {
let subscriptionGroupID: String
@State var presentingManageSubscriptionsSheet: Bool = false
var body: some View {
Button("Manage Subscriptions") {
presentingManageSubscriptionsSheet = true
}
.manageSubscriptionsSheet(
isPresented: $presentingManageSubscriptionsSheet,
subscriptionGroupID: subscriptionGroupID
)
}
}
重要ポイント:
.manageSubscriptionsSheetはSwiftUIでサブスクリプション管理画面を表示する方法- UIKitでは対応する
showManageSubscriptionsAPIを使う - ユーザーは管理画面で残りの支払い期数とコミットメント期間の更新時期を確認できる
- App Storeはコミットメントサブスクリプション向けに新しい管理UIを自動提供する
サーバー側JWSTransactionのコミットメント情報
(07:45)
{
"expiresDate": 1783503660000,
"price": 10990,
"productId": "plus.pro.annual",
"purchaseDate": 1780911660000,
"type": "Auto-Renewable Subscription",
"billingPlanType": "MONTHLY",
"commitmentInfo": {
"billingPeriodNumber": 1,
"totalBillingPeriods": 12,
"commitmentExpiresDate": 1812447660000,
"commitmentPrice": 131880
}
}
重要ポイント:
billingPlanTypeが"MONTHLY"なら、これは月額コミットメントサブスクリプションであるcommitmentInfo.billingPeriodNumberは現在が何回目の請求期間かを示すcommitmentInfo.totalBillingPeriodsは固定で12commitmentInfo.commitmentExpiresDateはコミットメント期間全体の終了時刻.upFrontタイプの取引では、commitmentInfoはnil
サーバー側JWSRenewalInfoのコミットメント更新情報
(07:59)
{
"renewalBillingPlanType": "MONTHLY",
"commitmentInfo": {
"commitmentAutoRenewProductId": "plus.standard.annual",
"commitmentAutoRenewStatus": 0,
"commitmentRenewalDate": 1812447660000,
"commitmentRenewalPrice": 10990,
"commitmentRenewalBillingPlanType": "BILLED_UPFRONT"
}
}
重要ポイント:
commitmentAutoRenewStatusが0の場合、ユーザーはコミットメント期間終了後に更新しない設定にしているcommitmentRenewalBillingPlanTypeはコミットメント期間終了後の更新プランタイプを示す- この例では、ユーザーはコミットメント期間終了後に一括前払いの年額サブスクリプションへ移行することを選んでいる
commitmentInfoは、現在のサブスクリプションがコミットメント期間中である場合にだけrenewal infoへ現れる
オファーコード引き換えSheet
(09:58)
struct OfferCodeRedemption: View {
@State var presentingOfferCodeSheet: Bool = false
var body: some View {
Button("Redeem Offer Code") {
presentingOfferCodeSheet = true
}
.offerCodeRedemption(options: [], isPresented: $presentingOfferCodeSheet) { result in
switch result {
case .success(let verificationResult):
switch verificationResult {
// Verify the transaction, give the customer access to
// the purchased content, and then finish the transaction
}
case .failure(let error):
// Handle error
}
}
}
}
重要ポイント:
.offerCodeRedemptionはVerificationResultを返すようになり、引き換え結果を明確に追跡できるoptionsパラメータは、引き換え動作を構成するRedeemOption値の配列を受け取る- 引き換え成功時、
verificationResultにはtransactionオブジェクトが含まれる - UIKitでは
presentOfferCodeRedeemSheetを使って同じ機能を実装する
主な示唆
サブスクリプション製品に月額コミットメントプランを追加する
何をするか: 既存の年額サブスクリプション製品に、12か月コミットメント付きの月額支払いオプションを構成し、アプリ内で優先表示します。
なぜやる価値があるか: ユーザーの初回支払いハードルを下げつつ、12か月分のサブスクリプション収益をロックできます。価格感度の高いユーザーにとっては、年額総額より月額支払いのほうが受け入れやすくなります。
始め方: App Store Connectで既存の1年期間の自動更新サブスクリプションを見つけ、“monthly with a 12-month commitment”の利用可否を設定します。コードでは.preferredSubscriptionPricingTermsを使って.monthlyプランを絞り込み、優先表示します。
コミットメント進捗追跡UIを構築する
何をするか: アプリのアカウント画面またはサブスクリプション管理ページで、ユーザーがコミットメント期間の何か月目にいるか、残り何期あるかを表示します。
なぜやる価値があるか: 透明性はユーザーの信頼を高め、「12か月契約だと知らなかった」という問い合わせを減らせます。同時に、コミットメント期間終了前の更新判断を助けられます。
始め方: Transaction.currentEntitlementsから最新の取引を取得し、commitmentInfoフィールドを読み取り、billingPeriodNumberとtotalBillingPeriodsで進捗を計算して表示します。
オファーコード引き換えロジックをアップグレードする
何をするか: 既存のオファーコード引き換え呼び出し箇所を新しいAPIへ移行し、明確な引き換え結果コールバックを得ます。
なぜやる価値があるか: 古いAPIは引き換え完了後に直接結果を返さず、Transaction.updatesで非同期に監視する必要があり、実装が複雑でミスが起きやすいものでした。新APIは成功または失敗を直接返します。
始め方: コード内のpresentOfferCodeRedeemSheet呼び出しを検索し、VerificationResultコールバック付きの新バージョンへ置き換えます。Xcode 27のStoreKit Testingで引き換えフローをテストします。
審査提出フローを統一する
何をするか: IAPの審査提出を統一されたreviewSubmissionsワークフローへ取り込み、AppバイナリやIn-App Eventsと一緒にまとめて提出します。
なぜやる価値があるか: 「Appは公開済みだがIAPはまだ審査中」という気まずい状況を避けられます。統一提出では、すべての審査項目が一緒に承認または却下され、状態が完全に同期します。
始め方: 既存のCI/CDスクリプトを確認し、古いIAP専用提出APIの呼び出しをreviewSubmissionsとreviewSubmissionItemsリソースへ移行します。
サブスクリプションBundlesとSuitesに備える
何をするか: 複数のAppや複数のサブスクリプション製品がある場合、サブスクリプションBundleまたはSuiteの製品構成を前もって計画します。
なぜやる価値があるか: Bundleは個別購入可能な複数のサブスクリプションを割引価格でまとめ、Suiteは一連の関連App向けに、全体としてのみ存在するサブスクリプショングループを提供します。どちらもサブスクリプション収益を伸ばす可能性があります。
始め方: Xcode 27でBundlesとSuitesのAPIをテストし、Appleが今年後半に発表する商用化の詳細に注目します。
関連セッション
- StoreKit 2とXcodeのStoreKit Testingの新機能 — StoreKit 2の新機能とXcodeにおけるテストのベストプラクティス
- App Store ConnectのRetention Messagingを探る — 12か月コミットメントサブスクリプションの精密な引き留めに対応する、サーバー間Retention Messaging API
- App Store Connectの新機能 — 審査提出ワークフローの詳しい解説
- App Store Offersを実装する — オファーコードとサブスクリプションオファーの構成と実装
コメント
GitHub Issues · utterances