作るもの
このコードラボでは、ノーコードのリモートビルダーである RevenueCat Paywalls V2 でペイウォールを設計し、
RevenueCatUI を使って SwiftUI アプリでネイティブに表示します。ペイウォールをハードコードすることはありません。
ダッシュボードで作って公開するので、あとからアプリのアップデートなしに、あなた(またはマーケティングチーム)が変更できます。
ペイウォールの設計には、実際のペイウォールがどう作られているかを分析した RevenueCat の State of Subscription Apps 2026 のデータに基づいた選択を使います。
- ペイウォールに2 つのプラン(もっとも一般的なレイアウトで、41〜60 パーセントのアプリが採用)。
- 年額オプションに割引バッジを付けた強調プラン(74.5 パーセントのペイウォールが価格を強調)。
- 無料トライアルの案内(54 パーセントのペイウォールに掲載)と「Cancel anytime」の安心感。
- 「Continue」の CTA(もっとも一般的な行動喚起)。カウントダウンタイマーや進捗バーは使いません(上位のペイウォールにはほぼ見られません)。
Paywalls V2 とは
Paywalls V2 は、ノーコードでリモート設定でき、完全にネイティブなペイウォールビルダーです。 RevenueCat ダッシュボードでビジュアルに設計すると、SDK がネイティブにレンダリングします(iOS では SwiftUI、Android では Jetpack Compose)。 リモートなので、アプリのアップデートを出さずにペイウォール全体を変更できます。
これが重要な理由は次のとおりです。
- リリースなしで反復できる。文言、レイアウト、価格の強調、画像をダッシュボードから編集できます。
- ネイティブである。Web ビューではなく、ネイティブコンポーネントでレンダリングし、ライト/ダークモードに合わせて表示します。
- 実験に活かせる。ペイウォールは Offering に紐付くため、A/B テストできます(ステップ 10)。
purchases-ios 5.16.0 以降が必要です(ほかのプラットフォームでも最近の SDK バージョンが必要)。
従来のビルダーはレガシーペイウォールと呼ばれ、テンプレート変数名が異なります。
Offering とパッケージを設定する
ペイウォールは Offering 内のパッケージをレンダリングするので、まずそこから設定します (RevenueCat ダッシュボードのプロジェクト内)。
- ストア商品(月額と年額のサブスクリプション)が存在し、RevenueCat にインポートされているか確認します。
- 両方の商品を
proエンタイトルメントに紐付けます。 - デフォルトの Offering に、
$rc_monthlyと$rc_annualの 2 つのパッケージを追加し、それぞれに対応する商品をラップします。
Offering とパッケージがはじめての場合は 商品と価格を取得するを参照してください。
エディターでペイウォールを設計する
ダッシュボードで Paywalls を開き、Create paywall をクリックします。テンプレートから始め(推奨)、エディターのペイウォールプロパティ(「Select an Offering for your Paywall」)で Offering に紐付けます。ここからデータに基づいたレイアウトを作ります。
- Package コンポーネント 2 つ:月額用と年額用。2 プランのペイウォールがもっとも一般的なレイアウトです。
- 年額プランを強調し、discount 変数を使って割引バッジを追加します。
proで何がアンロックされるかを示す Feature list と、短い見出しを追加します。- 無料トライアルの案内と 「Cancel anytime」の一文を追加します。
- Purchase button(CTA)のラベルを 「Continue」に設定します。
テンプレート変数(二重中かっこ)を使うと、価格やオファーが常にストアから取得されます。
{{ product.price }} -> "$9.99" (the package price)
{{ product.price_per_period }} -> "$59.99/year" (price with the billing period)
{{ product.relative_discount }} -> "37%" (annual savings vs the priciest plan)
{{ product.offer_price }} -> "free" (the intro/trial price, when there is one)
満足できたら Publish をクリックします。アプリのアップデートなしに、すぐ公開されます。
RevenueCatUI をインストールする
ペイウォールは RevenueCatUI ライブラリを通じてレンダリングされます。Xcode で Swift パッケージ
https://github.com/RevenueCat/purchases-ios-spm.git を追加し、
RevenueCat と RevenueCatUI の両方のプロダクトを選択します。
import SwiftUI
import RevenueCat // the core SDK
import RevenueCatUI // the paywall views
purchases-ios 5.16.0 以降が必要です。SDK はアプリ起動時にすでに構成されているはずです
(ステップ 1 の前提条件を参照)。
presentPaywallIfNeeded でアクセスを制御する
ペイウォールを表示するもっとも簡単な方法は、presentPaywallIfNeeded view modifier です。
ユーザーがエンタイトルメントを持たないときにだけ Offering のペイウォールを表示し、
エンタイトルメントを得た時点で自動的に閉じます。
import SwiftUI
import RevenueCat
import RevenueCatUI
struct RootView: View {
var body: some View {
ContentView()
.presentPaywallIfNeeded(
requiredEntitlementIdentifier: "pro",
// For a hard paywall, add: presentationMode: .fullScreen
purchaseCompleted: { customerInfo in
print("Purchased: \(customerInfo.entitlements.active.keys)")
},
restoreCompleted: { customerInfo in
// Dismisses automatically if "pro" is now active.
print("Restored: \(customerInfo.entitlements.active.keys)")
}
)
}
}
ハードペイウォール(購入するまで先へ進めないもの)にするには、
presentationMode: .fullScreen で全画面表示します。データではハードペイウォールのほうがフリーミアムよりはるかにコンバージョンが高いため、
サブスクリプションが必要なコンテンツでよく選ばれます。
シートで PaywallView を表示する
任意のタイミングでペイウォールを表示したいとき(たとえば「Upgrade」ボタンから)は、シートで
PaywallView を表示します。現在の Offering のペイウォールをレンダリングします。
struct SettingsView: View {
@State private var showPaywall = false
var body: some View {
Button("Upgrade to Pro") { showPaywall = true }
.sheet(isPresented: $showPaywall) {
// No need to wrap this in a ScrollView, the paywall handles scrolling.
PaywallView()
}
}
}
PaywallView() は現在の Offering を使います。特定の Offering を表示するには
(この場合 A/B 実験のルーティングは無効になります)、明示的に渡します:PaywallView(offering: yourOffering)。
displayCloseButton パラメータは V2 ペイウォールでは効果がありません。
閉じるボタンが必要なら、代わりにエディターでコンポーネントとして追加してください。
完了と閉じる操作を処理する
購入、復元、そしてユーザーがペイウォールを閉じようとする操作に反応するハンドラを付けます。
.sheet(isPresented: $showPaywall) {
PaywallView()
.onPurchaseCompleted { customerInfo in
// Verify access before unlocking; receiving CustomerInfo is not proof of entitlement.
if customerInfo.entitlements.active["pro"]?.isActive == true {
showPaywall = false
}
}
.onRestoreCompleted { customerInfo in
if customerInfo.entitlements.active["pro"]?.isActive == true {
showPaywall = false
}
}
.onRequestedDismissal {
// Fires on close-button tap (or purchase completion).
showPaywall = false
}
}
CustomerInfo を渡してくれても、
それだけではユーザーがアクセス権を持つとはかぎりません。コンテンツをアンロックする前に
customerInfo.entitlements.active["pro"]?.isActive を確認してください。PaywallView は
onRequestedDismissal を使います(onDismiss modifier はありません)。
ほかのプラットフォームで表示する
同じダッシュボードのペイウォールが、あらゆるプラットフォームでレンダリングされます。表示 API は次のとおりです。
React Native
import RevenueCatUI, { PAYWALL_RESULT } from 'react-native-purchases-ui';
const result = await RevenueCatUI.presentPaywallIfNeeded({
requiredEntitlementIdentifier: 'pro',
});
// result is PURCHASED, RESTORED, CANCELLED, ERROR, or NOT_PRESENTED
Android (Jetpack Compose)
// paywallActivityLauncher is a PaywallActivityLauncher created in onCreate.
// Launch the paywall only if the entitlement is missing:
paywallActivityLauncher.launchIfNeeded(requiredEntitlementIdentifier = "pro")
Flutter
import 'package:purchases_ui_flutter/purchases_ui_flutter.dart';
final result = await RevenueCatUI.presentPaywallIfNeeded("pro");
// result is a PaywallResult: notPresented, error, cancelled, purchased, restored
テスト、A/B、まとめ
テスト
proを持たないユーザーとしてアプリを実行し、2 つのプラン、強調された年額オプション、トライアルの一文、「Continue」の CTA を備えたペイウォールが表示されるか確認します。- サンドボックス購入を完了し、ペイウォールが閉じてコンテンツがアンロックされるか確認します。
- ダッシュボードでペイウォールを編集して公開し、再起動します。新しいビルドなしで変更が反映されます。
次は A/B テスト
本当の成果はテストから生まれます。ペイウォールは Offering に紐付くため、別のペイウォールを持つ 2 つ目の Offering を作り、 RevenueCat の Experiment を実行してどちらのコンバージョンが高いかを確かめられます。 さらに Targeting と Placements を使えば、オーディエンスごとに異なるペイウォールを配信できます。
作ったもの
データに基づいた 2 プランのレイアウトを持つ、リモートかつノーコードのネイティブペイウォールです。
presentPaywallIfNeeded と PaywallView で SwiftUI に表示し、
あらゆるプラットフォームでのレンダリングと実験への活用に対応しています。
次のステップ
- iOS のアプリ内課金とペイウォール:SDK 連携の全体を扱うコードラボ。
- 商品と価格を取得すると 導入価格の対象か確認する:Offering を組み立てる要素。
- RevenueCat: Paywalls と Displaying Paywalls。