WWDC Quick Look 💓 By SwiftGGTeam
Appleアプリ内課金の新機能

Appleアプリ内課金の新機能

元の動画を見る

ハイライト

Appleは年額サブスクリプションに、12か月コミットメント付きの月額払いプランを追加しました。ユーザーは月ごとに支払うことで意思決定のハードルを下げられ、開発者は長期サブスクリプション収益を確保できます。StoreKitには表示と購入のためのPricingTermsbillingPlanType APIが追加され、サーバー側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などが含まれます。

重要な点は、billingPeriodNumbertotalBillingPeriodsより小さい場合、ユーザーはまだコミットメント期間中だということです。このとき、ユーザーがシステム設定で自動更新をキャンセルしても、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は廃止予定であり、新しいreviewSubmissionreviewSubmissionItemsリソースへの移行が推奨されます。

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では対応するshowManageSubscriptions APIを使う
  • ユーザーは管理画面で残りの支払い期数とコミットメント期間の更新時期を確認できる
  • 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は固定で12
  • commitmentInfo.commitmentExpiresDateはコミットメント期間全体の終了時刻
  • .upFrontタイプの取引では、commitmentInfonil

サーバー側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
            }
        }
    }
}

重要ポイント:

  • .offerCodeRedemptionVerificationResultを返すようになり、引き換え結果を明確に追跡できる
  • 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フィールドを読み取り、billingPeriodNumbertotalBillingPeriodsで進捗を計算して表示します。

オファーコード引き換えロジックをアップグレードする

何をするか: 既存のオファーコード引き換え呼び出し箇所を新しいAPIへ移行し、明確な引き換え結果コールバックを得ます。

なぜやる価値があるか: 古いAPIは引き換え完了後に直接結果を返さず、Transaction.updatesで非同期に監視する必要があり、実装が複雑でミスが起きやすいものでした。新APIは成功または失敗を直接返します。

始め方: コード内のpresentOfferCodeRedeemSheet呼び出しを検索し、VerificationResultコールバック付きの新バージョンへ置き換えます。Xcode 27のStoreKit Testingで引き換えフローをテストします。

審査提出フローを統一する

何をするか: IAPの審査提出を統一されたreviewSubmissionsワークフローへ取り込み、AppバイナリやIn-App Eventsと一緒にまとめて提出します。

なぜやる価値があるか: 「Appは公開済みだがIAPはまだ審査中」という気まずい状況を避けられます。統一提出では、すべての審査項目が一緒に承認または却下され、状態が完全に同期します。

始め方: 既存のCI/CDスクリプトを確認し、古いIAP専用提出APIの呼び出しをreviewSubmissionsreviewSubmissionItemsリソースへ移行します。

サブスクリプションBundlesとSuitesに備える

何をするか: 複数のAppや複数のサブスクリプション製品がある場合、サブスクリプションBundleまたはSuiteの製品構成を前もって計画します。

なぜやる価値があるか: Bundleは個別購入可能な複数のサブスクリプションを割引価格でまとめ、Suiteは一連の関連App向けに、全体としてのみ存在するサブスクリプショングループを提供します。どちらもサブスクリプション収益を伸ばす可能性があります。

始め方: Xcode 27でBundlesとSuitesのAPIをテストし、Appleが今年後半に発表する商用化の詳細に注目します。

関連セッション

コメント

GitHub Issues · utterances