Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React Native でアプリ内課金の実装をする

React Native でアプリ内課金の実装をする

以下のイベントに登壇した際の資料になります。
https://standfm.connpass.com/event/218812/

YUJI TSUBURAYA

July 28, 2021
Tweet

More Decks by YUJI TSUBURAYA

Other Decks in Technology

Transcript

  1. 2 / 17 仕事
 ・J-CAT という会社を 2019年12月に共同創業 
 ・普段は会社の経営をしたり、Nuxt.js を書いたりしてる

    
 ・実業務では React 書いてなくて、あんまりキャッチアップできてないのが悩み 
 ・その前は BizReach という会社に所属 
 ・このときは React Native 書いてた(v0.48 - v0.52 らへんの時代) 
 ・flowtype だった 懐かしい 
 
 プライベート
 ・Splatoon というゲームをよくやってる(All X) 
 ・Notion 発信活動(Twitter / YouTube / note) 
 ・Fast Notion というアプリの個人開発 👈 今日の話
 自己紹介 - 円谷 雄二
 はじめに

  2. 3 / 17 今日話す内容 -> Fast Notion 課金部分の実装について
 ・半年前はあまり(日本語では)知見がなさげだった 


    ・今回の発表が知見の一部になればなと思ってます -> 今後実装する人の参考になれば 
 ・ついでに、個人開発者ならではのところ話せたら面白いかなと思います 
 ・(企業だとコンプラに引っかかりそうなところ)実装周り なるべくコード晒す 
 ・どこで審査落ちたかとか 
 ・(ほか聞きたいこともしあれば、コメントとか Twitter とかで投げておいてもらえると喜びます!) 
 
 󰢃 きょうは話さないこと
 ・Expo Eject の細かい手順・ハマりポイント 
 ・課金ロジックの細部
 ・In App Purchase ライブラリ API の網羅的解説 
 はじめに

  3. 4 / 17 ・Expo / React Native 製 
 ・現在は一人で開発


    ・2020年4月βリリース、約1.5年くらい運用 
 ・iOS / Android 版両方ある 
 ・合計 25,000 インストールくらい 
 Fast Notion というアプリについて
 個人開発しているアプリについて
 けんすう砲👇
 スワン砲👇
 平岡砲👇

  4. 5 / 17 ・割と普通な構成です。(一人でやる工夫はいろいろしているが)特に声を大にして言及するところはないかも… 
 ・クライアント: React Native / Expo

    / TypeScript / Jest / Sentry 
 ・バックエンド: Python / GCP / Node.js ( Firebase Functions / Express / TypeScript) 
 Fast Notion の技術スタック
 個人開発しているアプリについて
 Client
 API Server 1
 Notion API
 API Server 2

  5. 6 / 17 1. 広告(Admob とか)
 2. アカウント作って継続するのに課金しつづける系(Netflix とか) 


    3. アプリ購入時課金(買い切り ダウンロードするのにお金かかるやつ) 
 4. InAppPurchase(Apple / Google の課金システム使うやつ) 
 - 都度買うやつ(ガチャ回すための石とかそういうやつ) 
 - 月 / 年ごとに支払うやつ サブスク 👈 今日はこれの話
 
 (InAppPurchase 余談)
 ・Apple の課金システム使わないとレビュー通らなかったりする 
 ・あと手数料高いよね(Apple 30%) 
 ・なんとかならんかなあ… 
 (前提知識)一般的なアプリのマネタイズ手法いろいろ
 個人開発しているアプリについて
 HEY の 件で Apple と DHH がケンカしてたり、 
 Epic Games が Apple のこと訴えてたり(裁判中) 

  6. 7 / 17 ・前置き長くなっちゃったけど、このへんから実装の話 
 ・基本は無料
 ・サブスク期間中は +α で全ての機能が開放される 


    ・アプリ内では ProPlan という名称 
 ・ProPlan になっていると、 
 ・DB 連携・履歴保存・登録ページ数上限解除 ...等 
 ・useIsProPlan 的な感じで画面ごとに機能出し分け 
 Fast Notion におけるサブスク課金
 個人開発しているアプリについて
 アプリ内に保存している真偽値を返却 
 Pro Plan になっていない状態(左)、サブスク課金画面(右) 

  7. 8 / 17 ・ネイティブ実装が入るので、スクラッチで実装するのはキツい -> ライブラリ導入がオススメ 
 ・比較表を作ってみた
 ・素の RN

    だったら react-native-iap 一択。 Expo Bare Workflow だったら expo-in-app-purchase も可 
 ・自分は expo-in-app-purchase を採用(expo 使ってたので信頼してた) 
 課金を実現するライブラリ比較
 In App Purchase の実装

  8. 9 / 17 ・ネイティブ実装を TS で薄くラップしてる 
 ・良いところ -> 安心と信頼の

    Expo ドキュメント(読みやすい・厚い) 
 ・react-native-unimodules に依存(ネイティブ層とのブリッジング部分は Expo 製の共通モジュール) 
 
 expo-in-app-purchase について
 In App Purchase の実装

  9. 10 / 17 1. サブスクの支払いができる(1ヶ月プランと1年プランがある) 
 2. サブスク期間内は ProPlan になり全ての機能が開放される

    
 3. 期間外は通常プランに戻る 
 - 期間外の判定はそこまでシビアでなくても良い 
 -> 1秒でも過ぎたら使えない、とかにはしていない 
 -> 適当なタイミングで、Apple のサーバーからサブスク状態を取得する 
 4. Restore できる(Restore については詳しく後ほど説明します) 
 
 󰡇 それぞれの実装について ざっくりコード付きで解説 していきます
 (時間の関係上、Apple に寄せて解説しています) 
 
 実装した要件の言語化(似た要件でアプリ作る人の参考に)
 個人開発しているアプリについて

  10. 11 / 17 ・2021/07/28 現在、Expo 内で唯一の bare workflow でしか使えないモジュールっぽい 


    (ちょっと前まではもうちょっとあった気がするが) 
 
 ・bare workflow 化 するために Eject 
 $ expo eject 
 ・もろもろ選択肢が出るので答えていくと eject 完了 
 
 ・ライブラリのインストール 
 $ yarn add expo-in-app-purchase 
 $ cd ios & pod install
 (実装 1/6)expo-in-app-purchase インストール
 In App Purchase の実装
 https://docs.expo.io/bare/unimodules-full-list/?redirected#only-available-in-the-bare-workflow-currently

  11. 12 / 17 商品データの作成(App Store Connect) 
 ・製品のタイプが選べるので、「自動更新サブスクリプション」を選択(価格・期間を決める) 
 ・この製品

    ID を実装時に使用 
 
 購入時のイベントリスナー登録 
 ・購入フローが完了したとき用のイベントリスナーをあらかじめ登録 setPurchaseListener(() => {});
 ・Fast Notion ではコールバック内で ProPlan のフラグを立ててる 
 
 (実装 2/6)商品データの作成・購入時のイベントリスナー登録
 In App Purchase の実装

  12. 13 / 17 ・どの商品をユーザーに購入してもらうかの UI 作成に必要 
 ・getProductsAsync で商品データを取得
 ・商品データの情報をもとに、価格を表示

    
 ・貨幣コードも同時に返ってくるので、きちんと表示してやる 
 ・ここが雑でハードコーディングしてたら審査落ちた 
 ・(ちゃんとローカライズしろと怒られた) 
 
 
 
 
 
 
 (実装 3/6)商品データの取得・表示
 In App Purchase の実装

  13. 14 / 17 ・await purchaseItemAsync(productId); で購入できる
 ・購入する前に、以下の2つの関数を事前に実行しておく必要があるので注意 
 ・await connectAsync();

    初期化処理
 ・await getProductsAsync([productId]); 製品情報の取得処理 
 ・購入処理が完了すると、実装2 で紹介した setPurchaseListener(({ responseCode, results }) => {}); が発火する
 ・-> 購入に成功した場合、このタイミングで ProPlan のフラグを立てている 
 
 
 
 
 (実装 4/6)購入処理
 In App Purchase の実装

  14. 15 / 17 アプリ起動時にサブスク状態の確認をしてる(けっこう仕様が複雑… 😢 )
 1. const { results

    } = await getPurchaseHistoryAsync(); で購入履歴を取得
 2. 購入履歴をもとに、Apple のレシート検証用サーバーにリクエスト投げる 
 - payload には、購入履歴から取得したレシート情報と、「共有シークレット」を詰める 
 - キーの名前が password はちょっと罠 
 3. レスポンスにサブスクの有効期限が 
 詰まっているので、現在時刻と比較 
 4. 比較結果によって、ProPlan フラグを変更 
 
 
 (実装 5/6)サブスク課金状態の確認
 In App Purchase の実装
 AppStoreConnect から共有シークレット取得 

  15. 16 / 17 ・Restore (購入復元) / すでに購入した人に対しての機能 ・別端末で Fast Notion

    をインストールした場合にも ProPlan に戻せる ・「Restore 機能どこにあるの?」と Apple 様に怒られて審査落ち ・処理内容自体は 実装5「課金状態の確認」とほぼ同じ ・これで一通り実装の解説 Done (実装 6/6)Restore (購入復元)機能
 In App Purchase の実装

  16. 17 / 17 ライブラリに関して
 ・導入するのがオススメ(react-native-iap or expo-in-app-purchase) 
 ・ライブラリを使うとネイティブ実装不要。TS only

    で実装できて開発体験良い 
 
 導入・実装について
 ・Expo の場合は eject 必須 Bare Workflow にする 
 ・コード記述量自体はそこまで多くない ライブラリ使えば気軽に 
 
 さいごに
 ・(特に宣伝ないので)Twitter とかフォローしてもらえると喜びます 
 ・以上で発表終わります ありがとうございました! 
 まとめ
 まとめ