RORK LABEN
FUNDING — RorkがLeft Lane Capital主導で$15Mのシードを調達しましたRORK MAX — Rork MaxはReact NativeではなくネイティブSwiftアプリを生成しますPLATFORM — iPhone・iPad・Watch・Vision Proに対応し、Live ActivitiesやCore MLまで使えますGROWTH — 月間74.3万訪問・成長率85%と利用が伸び続けていますTEST — Companionアプリで有料Apple Developerアカウント無しに実機テストができますSTACK — 本体はReact NativeとExpoで、ウェブラッパーでない真のネイティブ体験を提供しますFUNDING — RorkがLeft Lane Capital主導で$15Mのシードを調達しましたRORK MAX — Rork MaxはReact NativeではなくネイティブSwiftアプリを生成しますPLATFORM — iPhone・iPad・Watch・Vision Proに対応し、Live ActivitiesやCore MLまで使えますGROWTH — 月間74.3万訪問・成長率85%と利用が伸び続けていますTEST — Companionアプリで有料Apple Developerアカウント無しに実機テストができますSTACK — 本体はReact NativeとExpoで、ウェブラッパーでない真のネイティブ体験を提供します
記事一覧/ビジネス
ビジネス/2026-06-30中級

App Store のシステムメッセージを「いい瞬間」まで遅らせる設計

値上げ同意やウィンバック、請求エラーといった App Store のシステムメッセージは、既定では起動直後に割り込んできます。StoreKit 2 の Message を握り、オンボーディングや決済を邪魔しない瞬間まで表示を遅らせる設計を、動く Swift コードでまとめました。

StoreKit8アプリ内課金9Rork Max195収益化62UX5

プレミアム記事

値上げの同意を求めるシートが、新規ユーザーのオンボーディングの3画面目で突然せり上がってきたことがありました。私自身、個人開発で課金のあるアプリをいくつか運用していますが、この割り込みが起きると、その回のオンボーディング完了率がはっきり落ちます。まだ価値を感じる前の人に「価格に同意してください」と迫っているのですから、当然かもしれません。

App Store のシステムメッセージ(値上げ同意・請求エラー・ウィンバックなど)は、既定ではアプリのフォアグラウンド復帰時に StoreKit が勝手に表示します。出すこと自体は避けられませんが、いつ出すかは開発側で握れます。StoreKit 2 の Message を購読し、表示の引き金を自分のタイミングで引く設計をまとめます。Rork Max が生成するネイティブ Swift を前提にしていますが、考え方は react-native-iap などをブリッジする場合にもそのまま使えます。

既定の挙動と、握れるポイント

理解の起点は「メッセージは保留できる」という一点です。StoreKit.Message.messages という非同期シーケンスを購読しておくと、システムが出そうとしたメッセージがアプリに流れてきます。ここで何もしなければ自動表示に任せることになりますが、シーケンスを受け取った時点で for await のループに入っていれば、表示は message.display(in:) を自分で呼ぶまで起きません

つまり「購読する」イコール「自動表示を止めて、表示権をアプリ側に移す」ことになります。受け取ったメッセージはアプリが明示的に出すまで保持され、出さなければ次回起動時にまた届きます。取りこぼしの心配は要りませんが、永遠に出さないのは規約・売上の両面で不利なので、必ずどこかで出し切る設計にします。

メッセージの購読を起動時に1本だけ張る

購読はアプリ全体で1本に保ちます。複数箇所で for await を回すと、同じメッセージが二重に処理されかねません。@MainActor のコーディネーターを1つ用意し、起動直後にループを開始します。

import StoreKit
import SwiftUI
 
@MainActor
final class StoreMessageCoordinator: ObservableObject {
    /// 表示待ちのメッセージ(届いた時刻つき)
    private(set) var pending: [(message: Message, since: Date)] = []
    /// いま表示してよいか(画面状態で更新する)
    var canPresent: Bool = false { didSet { flushIfPossible() } }
 
    private var listenTask: Task<Void, Never>?
 
    func start() {
        guard listenTask == nil else { return }
        listenTask = Task { [weak self] in
            for await message in Message.messages {
                // ここで display を呼ばない限り、システムは自動表示しない
                self?.enqueue(message)
            }
        }
    }
 
    private func enqueue(_ message: Message) {
        // 値上げ同意と請求エラーは売上・規約に直結するので、保留が長引かないよう先頭へ
        switch message.reason {
        case .priceIncreaseConsent, .billingIssue:
            pending.insert((message, Date()), at: 0)
        default:
            pending.append((message, Date()))
        }
        flushIfPossible()
    }
 
    private func flushIfPossible() {
        guard canPresent, let scene = Self.activeScene() else { return }
        let next = pending
        pending.removeAll()
        for item in next {
            do { try item.message.display(in: scene) }
            catch { pending.append(item) } // 出せなければ戻して次の機会に
        }
    }
 
    private static func activeScene() -> UIWindowScene? {
        UIApplication.shared.connectedScenes
            .compactMap { $0 as? UIWindowScene }
            .first { $0.activationState == .foregroundActive }
    }
}

canPresent を画面状態に応じて切り替えるだけで、表示タイミングを完全に制御できます。ポイントは display(in:)UIWindowScene を要求することです。シーンがまだ前面でない瞬間に呼ぶと失敗するので、foregroundActive なシーンが取れたときだけ出します。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
StoreKit 2 の Message.messages を購読し、message.display(in:) を呼ぶ瞬間を自分で選ぶ実装(動く Swift つき)
priceIncreaseConsent / billingIssue / generic の理由ごとに「すぐ出す・後に回す」を切り替える判断表
オンボーディング中・決済中・全画面再生中は保留し、ホームに戻った瞬間に出す保留キューの作り方
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

ビジネス2026-06-14
Rork Max の月200ドルは自分のアプリで元が取れるか、計算式で判断する
Rork Max の月額200ドルに踏み切るか迷ったとき、感覚ではなく損益分岐で決めるための計算式と、コピペで使える小さな試算スクリプトを、個人開発の実感つきで用意しました。
ビジネス2026-05-15
5,000万DLの個人開発者がRork Maxでアプリを作り直した記録:開発時間・品質・収益の実測比較
累計5,000万DLの個人開発者がRork Maxで壁紙アプリを再実装。開発時間・コード品質・AdMob・RevenueCat統合・収益指標を実測比較。AIツールの限界と活用法を正直に報告します。
ビジネス2026-05-05
Rork MaxでiOSとAndroidを同時展開して収益を倍にする — デュアルストア収益化の設計
Rork Maxを使ってiOSとAndroidの両プラットフォームを同時に運用し、それぞれの特性に合わせた収益化戦略を設計する完全ガイド。RevenueCatとAdMobを組み合わせた統合収益管理から、プラットフォーム別の課金設計、収益最大化の実装まで。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →