iOSアプリ開発で収益化する方法まとめ:有料アプリ・アプリ内購入・サブスクの実装入門
はじめに
iOSアプリをApp Storeで収益化する方法は、大きく分けると次の3つです。
- 有料アプリ
- アプリ内購入、いわゆる In-App Purchase / IAP
- サブスクリプション
この記事では、これからiOSアプリを収益化したい開発者向けに、それぞれの違い、App Store Connectで必要な設定、StoreKit 2を使った実装の考え方を整理します。
なお、App Storeで有料アプリやアプリ内購入を提供するには、Apple Developer Programへの登録に加えて、App Store Connectで「有料アプリ契約」に同意する必要があります。Apple公式ヘルプでも、有料アプリの販売やアプリ内購入の提供にはAccount HolderによるPaid Apps Agreementへの署名が必要と説明されています。
収益化方法の全体像
| 方法 | ユーザーの支払いタイミング | 向いているアプリ | 実装の複雑さ |
|---|---|---|---|
| 有料アプリ | アプリ購入時 | 買い切りツール、専門アプリ | 低 |
| 消耗型アプリ内購入 | 必要な時に都度購入 | ゲーム内通貨、チケット、ポイント | 中 |
| 非消耗型アプリ内購入 | 一度だけ購入 | 広告削除、Pro機能解放、追加コンテンツ | 中 |
| 自動更新サブスク | 月額・年額などで継続課金 | SaaS、学習、ニュース、AI機能、コンテンツ配信 | 高 |
AppleのApp Store Connectヘルプでは、アプリ内購入の種類として、消耗型、非消耗型、自動更新サブスクリプション、非更新サブスクリプションが説明されています。
App Storeの手数料について
App Storeの手数料は、一般的には売上からAppleのコミッションが差し引かれ、残りが開発者の収益になります。
特に個人開発者や小規模チームの場合は、App Store Small Business Programを確認しておきましょう。このプログラムでは、対象条件を満たす開発者について、有料アプリおよびアプリ内購入の手数料率が15%に引き下げられます。Apple公式ページでは、前暦年の全アプリの合計収益額が100万米ドル以内の既存デベロッパや新規デベロッパが対象になると説明されています。
ざっくり言うと、次のような考え方です。
ユーザーが支払う金額
- Appleの手数料
- 税金や調整額など
= 開発者の受取額
ただし、国や地域、税金、価格設定、プログラム参加状況によって実際の受取額は変わります。正確な金額はApp Store Connectの「売上とトレンド」や「支払と財務レポート」で確認するのが安全です。
1. 有料アプリ
有料アプリとは
ユーザーがApp Storeでアプリをダウンロードする時点で料金を支払うモデルです。
たとえば次のようなアプリに向いています。
- 高機能な買い切りツール
- 専門職向けアプリ
- 広告なしのユーティリティ
- 一度購入すれば継続運用コストが低いアプリ
メリット
実装がシンプルです。アプリ内で課金処理を作る必要がありません。
また、ユーザーから見ると「買えば全部使える」という分かりやすさがあります。
デメリット
無料アプリに比べてダウンロードの心理的ハードルが上がります。
また、購入前に価値を体験してもらいにくいため、スクリーンショット、説明文、レビュー、実績が重要になります。
App Store Connectでの設定
大まかな流れは次のとおりです。
App Store Connect
→ マイApp
→ 対象アプリ
→ 価格および配信状況
→ 価格を設定
有料アプリの場合、アプリ自体の価格を設定します。アプリ内購入の実装は不要です。
2. アプリ内購入
アプリ内購入とは
アプリ本体は無料または有料で配信し、アプリ内で追加機能やデジタルコンテンツを販売する仕組みです。
Appleは、アプリ内購入の設定にApp Store Connect、StoreKitフレームワーク、In-App Purchase APIを使用すると説明しています。StoreKitでは商品情報の取得、支払い処理、購入後の商品提供などを扱います。
アプリ内購入の種類
代表的な種類は次のとおりです。
| 種類 | 説明 | 例 |
|---|---|---|
| 消耗型 | 使うとなくなる | ゲーム内通貨、回数券、AI生成クレジット |
| 非消耗型 | 一度買うと永続的に使える | 広告削除、Pro機能、追加テーマ |
| 自動更新サブスク | 定期的に自動更新される | 月額Proプラン、年額プレミアム |
| 非更新サブスク | 期限付きだが自動更新されない | 期間限定パス、シーズンチケット |
デジタル商品は基本的にIAPを使う
アプリ内でデジタルコンテンツやデジタル機能を販売する場合、原則としてAppleのアプリ内購入を使う必要があります。App Review Guidelinesは、アプリ審査やアプリ内購入の要件・制限を確認するための重要な一次情報です。
たとえば、次のようなものはIAPの対象になりやすいです。
- 広告削除
- プレミアム機能の解放
- アプリ内で使うポイント
- デジタルコンテンツ
- AI生成回数の追加
- クラウド機能の有料プラン
一方、物理商品や現実世界のサービスなどは、Apple Payや外部決済が使えるケースもあります。ただし、アプリの内容や地域によってルールが変わることがあるため、必ずApp Review Guidelinesを確認してください。
3. サブスクリプション
サブスクとは
サブスクリプションは、ユーザーが月額・年額などで継続的に支払うモデルです。
たとえば次のようなアプリに向いています。
- 学習アプリ
- ニュースアプリ
- 動画・音声コンテンツ
- AIチャットや画像生成アプリ
- 業務支援SaaS
- クラウド同期が必要なアプリ
Appleは、自動更新サブスクリプションについて、StoreKitやApp Store Server APIを使って購読状態を識別でき、App Store Server Notificationsを有効にすることで購読状態の変更をリアルタイムに把握できると説明しています。
サブスク実装で重要なこと
サブスクは単に購入ボタンを置くだけでは不十分です。
実装では、最低限次の状態を考慮します。
- 未購入
- 購読中
- 無料トライアル中
- 解約済みだが期限内
- 期限切れ
- 請求失敗
- 猶予期間中
- 返金・取消
- プラン変更
特にサーバー側で権限管理をするアプリでは、App Store Server APIやApp Store Server Notificationsの利用を検討します。App Store Server APIは、サーバーからユーザーのアプリ内購入情報を取得するためのREST APIで、返されるトランザクション情報や更新情報はJWS形式で署名されます。
StoreKit 2での基本実装
ここからは、StoreKit 2を使った基本的な実装イメージを紹介します。
StoreKit 2は、SwiftとSwiftUIに合わせた比較的新しいAPIで、Appleはデジタル商品やサービスを安全に購入できる仕組みとしてStoreKitを提供しています。
商品IDを決める
App Store Connectで作成する商品IDは、アプリ側でも使います。
例:
enum ProductID {
static let removeAds = "com.example.myapp.remove_ads"
static let proMonthly = "com.example.myapp.pro.monthly"
static let proYearly = "com.example.myapp.pro.yearly"
}
命名は自由ですが、Bundle IDに近い形式にしておくと管理しやすいです。
com.example.myapp.remove_ads
com.example.myapp.credit_100
com.example.myapp.pro.monthly
com.example.myapp.pro.yearly
商品情報を取得する
import StoreKit
@MainActor
final class StoreManager: ObservableObject {
@Published var products: [Product] = []
@Published var purchasedProductIDs: Set<String> = []
private let productIDs: Set<String> = [
ProductID.removeAds,
ProductID.proMonthly,
ProductID.proYearly
]
func loadProducts() async {
do {
products = try await Product.products(for: productIDs)
} catch {
print("Failed to load products:", error)
}
}
}
Product.products(for:)で、App Store Connectに登録した商品情報を取得します。
価格やローカライズされた商品名はApp Store側から取得できるため、アプリ内に固定文字列として価格を書かない方が安全です。
購入処理を書く
extension StoreManager {
func purchase(_ product: Product) async {
do {
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
purchasedProductIDs.insert(transaction.productID)
await transaction.finish()
case .userCancelled:
print("User cancelled")
case .pending:
print("Purchase pending")
@unknown default:
print("Unknown purchase result")
}
} catch {
print("Purchase failed:", error)
}
}
private func checkVerified<T>(
_ result: VerificationResult<T>
) throws -> T {
switch result {
case .unverified:
throw StoreError.failedVerification
case .verified(let safe):
return safe
}
}
}
enum StoreError: Error {
case failedVerification
}
ポイントは、購入結果が成功しても、必ず検証済みかどうかを確認することです。
また、トランザクション処理が完了したら transaction.finish() を呼びます。
購入済み状態を復元・同期する
非消耗型の購入やサブスクでは、購入済み状態の復元が重要です。
extension StoreManager {
func updatePurchasedProducts() async {
var purchasedIDs: Set<String> = []
for await result in Transaction.currentEntitlements {
do {
let transaction = try checkVerified(result)
purchasedIDs.insert(transaction.productID)
} catch {
print("Unverified transaction:", error)
}
}
purchasedProductIDs = purchasedIDs
}
}
Transaction.currentEntitlementsを使うと、現在有効な権利を確認できます。
たとえば、広告削除を購入済みかどうかは次のように判定できます。
var hasRemovedAds: Bool {
purchasedProductIDs.contains(ProductID.removeAds)
}
サブスクの場合も、現在有効なProduct IDをもとにPro機能を解放できます。
var isProUser: Bool {
purchasedProductIDs.contains(ProductID.proMonthly)
|| purchasedProductIDs.contains(ProductID.proYearly)
}
SwiftUIの画面例
import SwiftUI
import StoreKit
struct StoreView: View {
@StateObject private var store = StoreManager()
var body: some View {
List {
Section("購入可能な商品") {
ForEach(store.products) { product in
Button {
Task {
await store.purchase(product)
}
} label: {
HStack {
VStack(alignment: .leading) {
Text(product.displayName)
.font(.headline)
Text(product.description)
.font(.subheadline)
}
Spacer()
Text(product.displayPrice)
.bold()
}
}
}
}
Section("状態") {
if store.isProUser {
Text("Proプランが有効です")
} else {
Text("無料プランです")
}
}
}
.task {
await store.loadProducts()
await store.updatePurchasedProducts()
}
}
}
App Store Connectでの設定手順
アプリ内購入やサブスクを使う場合、実装だけでなくApp Store Connect側の設定が必要です。
共通の流れ
1. App Store Connectにログイン
2. マイAppを開く
3. 対象アプリを選択
4. 「収益化」または「機能」からアプリ内購入を設定
5. 商品ID、価格、表示名、説明文を登録
6. 審査情報を入力
7. アプリのバージョンと一緒に審査へ提出
消耗型・非消耗型のアプリ内購入は、App Store Connectの「In-App Purchases」から追加します。Apple公式ヘルプでは、追加ボタンからConsumableまたはNon-Consumableを選択し、参照名とProduct IDを入力して作成する流れが説明されています。
サブスクの場合
サブスクでは、通常の商品より設定項目が多くなります。
- サブスクリプショングループ
- 月額プラン
- 年額プラン
- 無料トライアル
- 初回オファー
- プロモーションオファー
- 価格
- ローカライズ
- 審査用スクリーンショット
月額プランと年額プランを同じサブスクリプショングループに入れることで、ユーザーはプラン変更ができます。
テスト方法
課金実装ではテストが非常に重要です。
XcodeのStoreKit Testing
開発初期は、XcodeのStoreKit Testingを使うと便利です。
Apple公式ドキュメントでは、XcodeのStoreKit TestingはApp Storeサーバーへの接続なしで、ローカルに構成したアプリ内購入をテストできる環境だと説明されています。
メリット:
- App Store Connect設定前でも試せる
- Sandbox Apple IDが不要
- 購入、更新、期限切れなどをローカルで再現しやすい
Sandboxテスト
App Store Connectに商品を登録した後は、Sandbox環境でテストします。
確認したい項目は次のとおりです。
- 商品一覧が取得できるか
- 購入できるか
- キャンセル時に壊れないか
- 購入済み状態を復元できるか
- サブスク更新を扱えるか
- 期限切れ時に機能制限できるか
- サーバー側の権限状態と同期できるか
サーバーは必要か?
結論から言うと、アプリの種類によります。
サーバーなしでもよいケース
- 広告削除
- ローカル機能のPro解放
- シンプルな非消耗型購入
- 個人開発の小規模アプリ
この場合、StoreKit 2で現在の権利を確認し、アプリ内で機能を解放するだけでも実装できます。
サーバーがあった方がよいケース
- ユーザーアカウントがある
- 複数端末で権限を同期したい
- AI APIなどサーバーコストが発生する
- Web版やAndroid版ともプランを統合したい
- 不正利用を抑止したい
- サブスク状態をバックエンドで管理したい
特にAIアプリやSaaS系アプリでは、サブスク状態をサーバー側で管理する方が安全です。
構成例は次のようになります。
iOS App
↓ StoreKitで購入
App Store
↓ トランザクション情報
Backend API
↓ App Store Server APIで検証
Database
↓
ユーザーのプラン状態を保存
よくある設計パターン
パターン1:広告削除
モデル: 非消耗型アプリ内購入
商品ID: com.example.myapp.remove_ads
実装: 購入済みなら広告SDKを表示しない
一度購入すれば永続的に有効にするだけなので、最初の課金実装としては比較的シンプルです。
パターン2:AI生成クレジット
モデル: 消耗型アプリ内購入
商品ID: com.example.myapp.credit_100
実装: 購入後、サーバーDBに100クレジット加算
消耗型は「使うとなくなる」ため、サーバー側で残高管理する設計がおすすめです。
パターン3:Proプラン
モデル: 自動更新サブスクリプション
商品ID:
- com.example.myapp.pro.monthly
- com.example.myapp.pro.yearly
実装: 有効期間内ならPro機能を解放
月額・年額の両方を用意すると、ユーザーに選択肢を出せます。年額プランは割引を見せやすいため、継続利用が見込めるアプリと相性が良いです。
実装時の注意点
1. 価格をアプリ内にハードコードしない
価格は国や地域によって変わります。
Text(product.displayPrice)
のように、StoreKitから取得した表示価格を使いましょう。
2. 購入ボタンの前に価値を説明する
課金画面では、いきなり価格を見せるよりも、先に価値を伝えることが重要です。
Proプランでできること:
- 広告なし
- 無制限保存
- AI生成回数アップ
- クラウド同期
- 優先サポート
3. 復元ボタンを用意する
ユーザーが端末変更や再インストールをした場合に、購入を復元できる導線を用意しましょう。
Button("購入を復元") {
Task {
try? await AppStore.sync()
await store.updatePurchasedProducts()
}
}
4. 審査メモを書く
アプリ内購入がある場合、App Reviewのメモに「どこで購入できるか」「購入すると何が解放されるか」を書いておくと、審査がスムーズになります。AppleのApp Review Guidelinesでも、分かりにくい機能やアプリ内購入については、App Reviewのメモ欄に詳細な説明を含めるよう案内されています。
5. サブスクは解約後も期限内なら使える
サブスクは、ユーザーが解約しても、支払い済みの期間が終わるまでは機能を使えるのが基本です。
そのため、単純に「解約したら即停止」ではなく、「現在の有効期限」を見て機能を制御します。
どの収益化モデルを選ぶべきか
個人的には、次のように考えると選びやすいです。
| アプリの性質 | おすすめ |
|---|---|
| 一度買えば完結する | 有料アプリ or 非消耗型IAP |
| 無料で試してから課金してほしい | 非消耗型IAP |
| 継続的に価値を提供する | サブスク |
| サーバーコストが継続的にかかる | サブスク |
| ゲーム内アイテムやポイント | 消耗型IAP |
| 広告を消したい | 非消耗型IAP |
特に最近のアプリでは、最初は無料で使えるようにして、必要に応じてPro機能やサブスクへ誘導するモデルが採用しやすいです。
無料アプリ
↓
一部機能を体験
↓
価値を理解
↓
Pro機能 or サブスク購入
まとめ
iOSアプリの収益化は、単に「課金ボタンを置く」だけではなく、ビジネスモデル、App Store Connectの設定、StoreKit実装、審査対応、サーバー設計まで含めて考える必要があります。
整理すると次のとおりです。
有料アプリ:
実装は簡単。ただし購入前のハードルが高い。
アプリ内購入:
無料アプリと相性がよい。広告削除やPro機能解放に向いている。
サブスク:
継続的な価値提供に向いている。状態管理とサーバー連携が重要。
まずは、非消耗型の「広告削除」や「Pro機能解放」から始めると、StoreKit 2の基本を理解しやすいと思います。
その後、ユーザーアカウントやサーバー連携が必要になったタイミングで、App Store Server APIやApp Store Server Notificationsを導入していくのがおすすめです。
参考
- Apple Developer: In-App Purchase
- Apple Developer: StoreKit
- Apple Developer: Auto-renewable Subscriptions
- Apple Developer: App Store Server API
- Apple Developer: App Store Small Business Program
- Apple Developer: App Review Guidelines