📘

モバイルアプリをリーダーアプリとして実装してアプリ内購入の実装を回避する

2025/01/20に公開

リーダーアプリとは

リーダーアプリとは雑誌、新聞、書籍、オーディオ、音楽、ビデオなどのデジタルコンテンツの閲覧をアプリの主な機能として提供するアプリです。

通常、モバイルアプリ内で有料コンテンツを利用する場合はアプリ内購入を実装してアプリ内から有料コンテンツを購入できるようにする必要があります。

リーダーアプリとして実装されたアプリはその限りではなく、アプリ外で作成されたアカウントにアプリからサインイン => そのアカウントで購入したコンテンツをアプリで閲覧することができます。

今回は他のウェブサイトでアカウント作成とコンテンツの購入をする前提で、そのコンテンツを閲覧するアプリをFlutterでリーダーアプリとして実装しました。無事にAppStore・PlayConsoleの審査に通すことができたので記事にして残しておきます。

各プラットフォームにおける定義

Apple

アプリレビューガイドラインの3.1.3(a)にリーダーアプリについての記述があります。

3.1.3(a) 「リーダー」アプリ: アプリにより、ユーザーは、過去に購入したコンテンツまたはコンテンツ購読(具体的には、雑誌、新聞、書籍、オーディオ、音楽、ビデオ)にアクセスすることができます。読者」アプリは、無料層向けのアカウント作成機能、および既存顧客向けのアカウント管理機能を提供することができます。リーダーアプリの開発者は、アカウントを作成または管理するために、開発者が所有または管理しているウェブサイトへの情報リンクをアプリ内で提供する外部リンクアカウント資格を申請することができます。外部リンクアカウントの詳細については、こちらをご覧ください。

https://developer.apple.com/app-store/review/guidelines/#reader-apps

「コンテンツを見る + アカウント作成機能を持つアプリ」ということだと思います。

「外部リンクアカウント資格」という記述がありますが、iOSにおけるリーダーアプリには2つの種類があり、実装する時の要件が少し変わってきますので後述します。

Google

PlayConsoleヘルプの以下の箇所にリーダーアプリについての記述があります。

Google Play で消費専用(リーダー)アプリを提供できますか?
はい。Google Play では、有料サービスの一部であっても、アプリを消費のみにすることができます。たとえば、ユーザーはアプリを開いたときにログインし、別の場所で有料コンテンツにアクセスできます。
消費のみとは、デジタルか物理かを問わず、いかなる製品またはサービスも アプリ内から購入できないことを意味することに注意してください。

https://support.google.com/googleplay/android-developer/answer/10281818?hl=en&sjid=2697937958740810643-AP#zippy=%2Ccan-i-offer-a-consumption-only-reader-app-on-google-play

「サービス自体が有料であっても、それを閲覧するだけのアプリもリリース可能」ということだと思います。

リーダーアプリの種類

iOSではアカウントを作成するウェブサイトに遷移するためのリンクをアプリ内に置くかどうかによって少し実装方法が変わります。
Androidでは外部サイトへのリンクについての記述は見つけられなかったため、どちらで作るかを特に意識する必要はなさそうです。

アカウントを作成するための外部リンクを持たないアプリ

kindleなどがこれにあたります。

これらのアプリではアプリ内にアカウント作成が可能なウェブサイトへ遷移するリンクを持ちません。アプリ内でのアカウント作成機能 or アカウントは既に持っている前提でアプリにログインする機能を持ちます。

アカウントを作成するための外部リンクを持つアプリ

Netflix、コミックシーモアなどがこれにあたります。

これらのアプリではアプリ内にアカウント作成が可能なウェブサイトへ遷移するリンクが設置されています。

また、リンクを介してウェブサイトへ遷移するにはAppleの要件で決められたモーダルシートを出して「これからこのアプリではなくて外部のサイトに遷移しますよ」ということをユーザーに伝える必要があります。

今回実装したのは後者のアカウントを作成するための外部リンクを持つアプリです。後述のアプリの実装でもこちらの実装手順を紹介します。

外部リンクを持つリーダーアプリの実装

リーダーアプリの中にアカウントを作成できるウェブサイトへのリンクを置きたい場合、単にリンクを置くことはできずAppleDeveloperで定められている要件に従う必要があります。

ウェブサイトへのリンクを持つリーダーアプリについてはこちらに詳細な要件が記載されています。
https://developer.apple.com/support/reader-apps/

外部リンクアカウント資格の申請

アプリ内にアカウント作成のための外部リンクを配置する場合、「外部リンクアカウント資格」を申請する必要があります。これはAppleDeveloperProgramのアカウントホルダーがリクエストフォームから申請することができます。

フォームを見るとわかるのですが、自由記述ではなく決まった質問に対して回答を選択していく形式になっています。

スクリーンショットの通りに回答しない場合は「Your app is not eligible for this entitlement.」というメッセージが表示されて申請することができません。つまりアプリの内容をAppleに伝えるというよりは、実装しているアプリが外部リンク付きのリーダーアプリの要件に適合しているか確認することが目的のフォームであることがわかります。

またAppStoreもしくはTestFlightのURLが必須になっており最低でもTestFlightでリリースが完了していないと申請すること自体ができないため、早めに準備しておく必要があります。

リクエストの結果についてはアカウントホルダーのメールアドレス宛に以下のようなメールが来て通知されます。

今回はリクエストの翌日に結果が返ってきました。リクエストの結果、審査がどこまで進んでいるかなどは確認できなそうなのでメールを待つしかなさそうです(不安)。

外部リンクアカウント資格を有効にする

.entitlementsファイルの更新

.entitlementsファイルに外部リンクアカウント資格が有効になっていることを示すキーペアを追加します。

	<key>com.apple.developer.storekit.external-link.account</key>
	<true/>

https://developer.apple.com/documentation/bundleresources/entitlements#StoreKit

Info.plistファイルの更新

Info.plistに外部リンクのURLを追加します。

これは文字列値を持つ辞書型の値になっておりキーは地域コードになります。国際化などを意識しない場合は*を指定すればどの地域でも同じ外部リンクに遷移するようにできます。

後続で外部リンクを実装するときに提供するモーダルシートを内のリンクをタップするとこのURLに自動的に遷移するようになります。Info.plistに含める必要があることからわかるように遷移先の外部リンクを変更するにはInfo.plistの変更を行って再度審査に提出する必要があります。

	<key>SKExternalLinkAccount</key>
	<dict>
		<key>*</key>
		<string>外部リンクのURL</string>
	</dict>

https://developer.apple.com/documentation/bundleresources/information_property_list/skexternallinkaccount/

外部リンクの実装

アプリで外部リンクを実装する資格を有効にしたら、アプリ内にリンクを実装していきますがリンクの見た目や文言にもいくつか守らなければいけない要件があります。

気にしておいた方が良さそうなのは、この辺りでしょうか。

  • ユーザーを保護するため(たとえば、プライバシー)、URL に追加のパラメータを渡さない。
  • ウェブサイトで入手可能な商品の価格を含む文言を含めたり、そのような文言とともに使用したりしないでください(許容される文言には、「アカウントを作成または管理するには、example.com にアクセスしてください」などがあります)。
  • 標準の HTML リンク (青い下線付きテキスト) のようにフォーマットされ、Web サイトのドメイン名が含まれていること。
  • リダイレクトや中間リンク、ランディング ページなしで、Web サイトに直接アクセスできます。

リンクをタップした後は決められた要件のモーダルシートを出して、ユーザーがアプリがのウェブサイトに遷移することを伝える必要があります。

canMakePaymentsというAPIが提供されており、これを呼び出すと実装済みのモーダルシートが表示されるようになっているため自前で実装する必要はありません。

FlutterではこのAPIを呼び出すexternal_link_accountというライブラリが有志によって提供されていますが、更新は止まっていそうです。中身のコードもあまり複雑ではなかったので、今回はライブラリを参考に自前で実装しました。

https://pub.dev/packages/external_link_account

審査提出

AppStore・PlayConsoleともに「このアプリはリーダーアプリです」というチェックボックスのようなものはありません。提出したアプリの実装を元にプラットフォーム側が判断するようになっているのかなと思います。

1回目

AppStoreの1回目は調査不足でリーダーアプリの要件を満たしていない状態でアプリを提出してしまったため「有料コンテンツを見れるようにするなら、アプリ内購入を実装してよ」という指摘でリジェクトされてしまいました。

リジェクトされるとリジェクト理由が該当するガイドラインのリンクを送ってくれますが、具体的にアプリのどこが適合していないかは指摘してくれません(下手に明言して変な前例を作らないようにしているのかもしれません)。

Androidは特に何の指摘もなく審査に合格しました。

2回目

記事の通りリーダーアプリの要件に従い外部リンクの実装を行いました。

アプリ内購入についての指摘は無くなったためリーダーアプリとしては認められたようでしたが、アプリではなくアカウント登録を行うウェブサイトについての指摘でリジェクトされてしまいました。具体的にはアカウント登録フォームで電話番号の登録が必須になっており「ユーザーがこのアプリを使用するために必須ではない情報を収集するな」という理由でのリジェクトです。

モバイルアプリの内容についてレビューされるものとばかり思っていたので、ここまで細かく見られるのは驚きでした。

3回目

アカウント登録を行うウェブサイトを修正して再度審査に出したところ、AppStore審査にも合格しました🎉

まとめ

今回は記事の通りの実装で審査に通りましたが、この通りに実装すればリーダーアプリとして認められアプリ内購入の実装が不要になることを保証するものではありません。

2025年1月現在は記事の通りの仕様ですが、ガイドラインやStoreKitも日々更新されているため常に公式のガイドラインを参照することが重要です。

どんなにガイドラインを読み込んでも結局審査に通らなければストアにリリースすることはできないので、早い段階で一度審査に出してみるのが一番良いと思いました。

PrAha

Discussion