$30 off During Our Annual Pro Sale. View Details »

[DroidKaigi 2022] 詳解Google Playの新しい定期購入 ~オファーの活用や実装例を添えて~

syarihu
October 05, 2022

[DroidKaigi 2022] 詳解Google Playの新しい定期購入 ~オファーの活用や実装例を添えて~

DroidKaigi 2022で発表した「詳解Google Playの新しい定期購入 ~オファーの活用や実装例を添えて~」の発表資料です。
https://droidkaigi.jp/2022/timetable/363682

syarihu

October 05, 2022
Tweet

More Decks by syarihu

Other Decks in Technology

Transcript

  1. 詳解Google Playの新しい定期購入
    ~オファーの活用や実装例を添えて~
    Taichi Sato / @syarihu
    Giftmall, Inc.
    Android Engineer
    1

    View Slide

  2. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    2

    View Slide

  3. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    3

    View Slide

  4. 従来の定期購入とその課題について
    ● 機能が同じ定期購入でも提供したいオファーなどが違う場合
    は、ひとつの商品(SKU)として追加しなければならない
    ● SKUがどんどん増えていき、管理が複雑になってしまう
    ● SKUを作成するたびにアプリをリリースしなければならない
    4

    View Slide

  5. 従来の定期購入とその課題について
    5
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日

    View Slide

  6. 従来の定期購入とその課題について
    6
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日

    View Slide

  7. 従来の定期購入とその課題について
    7
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日

    View Slide

  8. 従来の定期購入とその課題について
    8
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日、お試し価格: 5,000円

    View Slide

  9. 従来の定期購入とその課題について
    9
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 限定オファー
    ● 請求対象期間: 年間
    ● 価格: 5,000円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日、お試し価格: 4,500円

    View Slide

  10. 従来の定期購入とその課題について
    10
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額プレミアムプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 限定オファー
    ● 請求対象期間: 年間
    ● 価格: 5,000円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,000円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日

    View Slide

  11. 従来の定期購入とその課題について
    ● このように、従来の方法だとSKUが増え続け複雑になってしま

    ● これらの課題を解決し、各定期購入の管理コストを下げ、より
    柔軟にオファーを作成できるように、Googleは定期購入の販
    売方法を再構築した
    11

    View Slide

  12. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    12

    View Slide

  13. 13
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  14. 14
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  15. 15
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  16. 16
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  17. 17
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  18. 18
    https://support.google.com/googleplay/android-developer/answer/12124625 より引用

    View Slide

  19. 19
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    従来の定期購入

    View Slide

  20. 20
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    従来の定期購入

    View Slide

  21. 21
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    従来の定期購入

    View Slide

  22. 22
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    Subscription
    ● 商品名: PROプラン
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  23. 23
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    Subscription
    ● 商品名: PROプラン
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  24. 24
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    Subscription
    ● 商品名: PROプラン
    オファー
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    オファー
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 60日間
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  25. 25
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日
    従来の定期購入

    View Slide

  26. 26
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 期間限定
    提供の条件: デベロッパー指定
    段階:
    ● 1年間 500円 固定割引
    オファー - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円 固定割引
    従来の定期購入 新しい定期購入に再構築した例
    Subscription
    ● 商品名: PROプラン
    オファー - 学生限定
    提供の条件: デベロッパー指定
    段階:
    ● 無料試用 30日間
    ● 3年間 1,500円 固定割引

    View Slide

  27. 27
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    Subscription
    ● 商品名: PROプラン
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  28. 28
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● お試し価格: 5,000円
    Subscription
    ● 商品名: PROプラン
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 期間限定
    提供の条件: デベロッパー指定
    段階:
    ● 1年間 500円 固定割引
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  29. 29
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日、お試し価格: 4,500円
    Subscription
    ● 商品名: PROプラン
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円 固定割引
    従来の定期購入 新しい定期購入に再構築した例

    View Slide

  30. 30
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日
    Subscription
    ● 商品名: PROプラン
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    従来の定期購入 新しい定期購入に再構築した例
    定期購入を解約するまで
    割引価格で利用できてしまう
    定期的な支払いで割引価格が提供で
    きるようになったので、
    今回は例として3年間固定割引にして
    いる
    オファー - 学生限定
    提供の条件: デベロッパー指定
    段階:
    ● 無料試用 30日間
    ● 3年間 1,500円 固定割引

    View Slide

  31. 31
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日
    Base plan - 通常
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 期間限定
    提供の条件: デベロッパー指定
    段階:
    ● 1年間 500円 固定割引
    オファー - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円 固定割引
    従来の定期購入 新しい定期購入に再構築した例
    Subscription
    ● 商品名: PROプラン
    オファー - 学生限定
    提供の条件: デベロッパー指定
    段階:
    ● 無料試用 30日間
    ● 3年間 1,500円 固定割引

    View Slide

  32. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    32

    View Slide

  33. 新しい定期購入の作り方
    1. 定期購入を作成する
    2. 定期購入の下に基本プランを追加する
    ○ 更新期間や地域別の価格などを設定する
    3. 基本プランの下にオファー(特典)を追加する
    ○ 無料試用や特定の価格から割引きたい場合はオファーと
    して追加する
    33

    View Slide

  34. BenefitsとOffer
    ● 定期購入の詳細で編集できる「特典」
    とこれから説明する基本プランに追
    加する「特典」は別物なので注意
    ○ 定期購入の詳細では、定期購入を
    購入することにより得られるメリット
    を記載する
    ● 定期購入の詳細の「特典」は英語で
    はBenefits、基本プランに追加する
    「特典」はOfferとなっているため、本
    発表では基本プランに追加する「特
    典」はオファーとして扱う
    34

    View Slide

  35. 1. 定期購入を作成する
    アイテムID
    ● 定期購入を識別する一意なID
    ● 実装ではProduct Id(旧SKU)
    名前
    ● ユーザーにも表示される定期購入

    35

    View Slide

  36. 2. 基本プランを追加する
    基本プランID
    ● 定期購入ごとに一意なID
    更新の種類
    ● 自動更新 or 前払い
    ● 種類ごとに、1つの定期購入に対し
    て同じ請求対象期間の基本プラン
    を複数作ることはできない
    ○ 月額の基本プランを2つ追加
    するなどはできない
    ○ 無効にしても同じ期間の基本
    プランは追加できないので注

    36

    View Slide

  37. 2. 基本プランを追加する
    タグ
    ● 実装時に基本プランやオファーを識別するため
    のタグ
    ● アプリの実装では基本プランやオファーをタグ
    でしか判別できないため、必ず設定しておく
    ● 基本プランやオファーごとに最大 20個設定でき

    ● 基本プランに設定したタグは、オファーのタグ
    にも継承される
    ○ Play Console上からは見えないが、
    アプリのAPIからオファーのタグを取
    得するときに基本プランに設定したタ
    グも含まれている
    37

    View Slide

  38. 3. オファーを追加する
    ● 追加する対象の基本プランを選択
    して、オファーを追加する
    38

    View Slide

  39. 3. オファーを追加する
    特典ID
    ● オファーを識別する一意な
    ID
    基本プランと公開設定
    ● 基本プランは追加する対象の基本プラン
    が表示される
    ● 公開設定はオファーを提供する提供地域
    を選択する(デフォルトでは基本プランと
    同じ提供地域になる)
    タグ
    ● アプリでオファーを識別するタグ
    ● 用途は基本プランのタグと同じ
    39

    View Slide

  40. 3. オファーを追加する
    提供の条件
    ● 新規ユーザーの獲得
    ● アップグレード
    ● デベロッパー指定
    40

    View Slide

  41. 3. オファーを追加する
    提供の条件
    ● 新規ユーザーの獲得
    この定期購入を利用したことがないか、
    このアプリの定期購入をまったく利用し
    たことが無いユーザーを対象としてオ
    ファーを提供する
    このオファーの対象になるかは購入時
    にGoogle Playが判定する
    41

    View Slide

  42. 3. オファーを追加する
    提供の条件
    ● アップグレード
    特定の定期購入と基本プランを購読中
    のユーザーを対象としてオファーを提
    供する
    このオファーの対象になるかは購入時
    にGoogle Playが判定する
    42

    View Slide

  43. 3. オファーを追加する
    提供の条件
    ● デベロッパー指定
    ユーザーがオファーの対象となるかどう
    かはデベロッパーがアプリ内で指定す

    オファーをアプリ外で販売することはで
    きない
    43

    View Slide

  44. 3. オファーを追加する
    提供の条件
    ● デベロッパー指定
    たとえば、アプリが持つユーザー情報
    を元にオファーを提供するのかを決め
    たい場合は、提供条件をデベロッパー
    指定にする
    44

    View Slide

  45. 3. オファーを追加する
    提供の条件
    ● デベロッパー指定
    また、ユーザーが利用できるオファーの
    一覧をアプリで表示したい場合は、条
    件をデベロッパー指定にする
    デベロッパー指定のオファーにタグを設
    定して、そのタグが設定されたオファー
    のみを表示するなどの使い方ができる
    45

    View Slide

  46. 3. オファーを追加する
    購入フェーズ(段階)
    タイプ
    ● 1回限りのお支払い
    ● 定期的なお支払い
    ● 無料試用
    46

    View Slide

  47. 3. オファーを追加する
    購入フェーズ(段階)
    タイプ
    ● 1回限りのお支払い
    1回だけ固定額または割引した価格を支払
    い、指定した期間だけ利用できる
    たとえば1年間だけ特別に割引したい場合
    は12ヶ月に設定すると、12ヶ月間はその価
    格で利用できる
    その後、基本プランの価格での支払いが
    始まる
    47

    View Slide

  48. 3. オファーを追加する
    購入フェーズ(段階)
    1回限りのお支払い - 価格のオーバーライド
    ● 固定額
    ○ ここで設定した価格に上書きする
    ○ 通常価格が5,000円で、固定額が
    4,000円なら4,000円になる
    ● 割引率
    ○ 通常価格からの割引率( ~ %)
    ○ 通常価格が5,000円で10%に設定し
    たら4,500円
    ● 割引額
    ○ 通常価格からの割引額( ~ 円 )
    ○ 通常価格が5,000円で500円に設定
    したら4,500円
    48

    View Slide

  49. 3. オファーを追加する
    購入フェーズ(段階)
    タイプ
    ● 定期的なお支払い
    2 ~ 52回のいずれかの請求対象期間、固定
    額または割引した価格を支払うことで利用で
    きる
    たとえば年間払いで請求対象期間を
    2回に
    すると、2回目の支払いまでは固定額または
    割引した価格で利用できる
    その後、基本プランの価格での支払いが始
    まる
    49

    View Slide

  50. 3. オファーを追加する
    50
    購入フェーズ(段階)
    価格のオーバーライド
    ● 固定額
    ○ ここで設定した価格に上書きする
    ● 割引率
    ○ 既存価格からの割引率( ~ %)
    ○ 既存価格が5,000円で10%に設定し
    たら4,500円
    ● 割引額
    ○ 既存価格からの割引額( ~ 円 )
    ○ 既存価格が5,000円で500円に設定
    したら4,500円

    View Slide

  51. 3. オファーを追加する
    購入フェーズ(段階)
    タイプ
    ● 無料試用
    無料試用期間を設定する
    既存の定期購入で提供していた無料期
    間は購入フェーズの一部となっている
    ため、無料試用を設定したい場合はこ
    れを利用する
    51

    View Slide

  52. 52
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引
    新しい定期購入の作り方

    View Slide

  53. 53
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引
    新しい定期購入の作り方

    View Slide

  54. 54
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引
    新しい定期購入の作り方

    View Slide

  55. 55
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引
    新しい定期購入の作り方

    View Slide

  56. 56
    新しい定期購入の作り方
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引

    View Slide

  57. 57
    新しい定期購入の作り方
    Subscription
    ● 商品名: PROプラン
    Base plan - 初回限定
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    オファー - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円割引

    View Slide

  58. 基本プランやオファーの反映について
    ● 即時反映されるわけではなく、若干のラグがある
    ● Playストアのアプリデータを消し飛ばすと再取得されることも
    あるので、デバッグ時に更新されないなと思ったらアプリデー
    タを消してみるのがいいかも
    58

    View Slide

  59. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    59

    View Slide

  60. 自動移行された既存の定期購入
    ● 既存の定期購入は、新しい定期購入として自動移行されてい

    ● しかし、自動移行された定期購入は理想の定期購入の構成に
    はならない
    60

    View Slide

  61. 61
    自動移行された既存の定期購入
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日

    View Slide

  62. 62
    自動移行された既存の定期購入
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    月別のプランはp1mの基本プランとして追加されている(半年なら p6m、年間ならp1yになる)

    View Slide

  63. 63
    自動移行された既存の定期購入
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    無料期間は freetrial のオファーとして追加されている

    View Slide

  64. 64
    自動移行された既存の定期購入
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    自動移行されたプランは下位互換性のあるプランとしてマークされている
    下位互換性のある基本プランは、 PBLv5で非推奨になっている querySkuDetailsAsync() メソッドに
    返されるため、PBLv4以前の既存の実装でも問題なく購入できるようになっている

    View Slide

  65. 65
    Subscription
    ● 商品名: PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 月額PROプラン 2ヶ月無料
    ● 請求対象期間: 月別
    ● 価格: 500円
    オファー
    ● 無料期間: 60日
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 60日間
    理想の定期購入の構成 - 月額

    View Slide

  66. 66
    Subscription
    ● 商品名: PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 60日間
    実際に自動移行された定期購入の構成 - 月額
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    Subscription
    ● 商品名: PROプラン 2ヶ月無料

    View Slide

  67. 67
    理想の定期購入の構成 - 年額
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 期間限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額プレミアムプラン 初回限定
    ● 請求対象期間: 年間
    ● 価格: 5,500円
    オファー
    ● 無料期間: 30日
    ● Subscription (SKU)
    ● 商品名: 年額PROプラン 学生限定
    ● 請求対象期間: 年間
    ● 価格: 4,000円
    オファー
    ● 無料期間: 30日
    Base plan - 通常
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    Offer - 期間限定
    提供の条件: 新規ユーザー
    段階:
    ● 1年間 500円 固定割引
    Offer - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Offer - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円 固定割引
    Subscription
    ● 商品名: PROプラン
    Offer - 学生限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 3年間 1,500円 固定割引

    View Slide

  68. 68
    実際に自動移行された定期購入の構成 - 年額
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    Subscription
    ● 商品名:
    年額PROプラン 期間限定
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 5,500円
    Subscription
    ● 商品名:
    年額PROプラン
    Subscription
    ● 商品名:
    年額PROプラン 初回限定
    Subscription
    ● 商品名:
    年額PROプラン 学生限定
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 年間
    ● 価格: 4,000円
    Offer - 期間限定
    提供の条件: 新規ユーザー
    段階:
    ● 1年間 500円 固定割引
    Offer - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Offer - 無料試用
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Offer - 初回限定
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    ● 1年間 1,000円 固定割引

    View Slide

  69. 自動移行された既存の定期購入
    ● 新しい定期購入では、定期購入に基本プランを追加し、基本
    プランにオファーを追加できるようになった
    ○ すでに提供されている定期購入を新しい定期購入の構成
    に移行しようと思うと、期間ごとに定期購入商品が違うた
    め、別の商品に買い直さなければならない
    ○ 自動では移行できないのでこの構成になったのだと思わ
    れる
    69

    View Slide

  70. 既存の定期購入を新しい定期購入にしようとすると…
    ● 既存の定期購入を購読中のユーザーは勝手には移行できな
    いので、そのままにするか、新しい定期購入への切り替え手
    順を用意して移行を促すしかない
    ● それでも移行しないユーザーはいるので、単純に定期購入商
    品が増えて売上管理や分析、実装などが面倒になる
    70

    View Slide

  71. 既存の定期購入を新しい
    定期購入にしようとすると

    既存の定期購入に基本プランを増やす
    こともできるが、一つの定期購入商品
    に対して一つの請求対象期間のみだっ
    たのが、
    71
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月額
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年額
    既存の定期購入の構成

    View Slide

  72. 既存の定期購入を新しい
    定期購入にしようとすると

    新しく作成する一部の定期購入だけ一
    つの定期購入に複数の請求対象期間
    が含まれることになる
    実装上も、定期購入に紐づく基本プラ
    ンをタグを元に探すというステップが必
    要になり、既存の定期購入と実装方法
    が異なるため、そういった点も考慮が必
    要になる
    72
    Base plan
    ● 請求対象期間 : 月間
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1
    新しい定期購入の形

    View Slide

  73. 自動移行された既存の定期購入をどうするか
    ● 新しく作成する定期購入だけ新しい構成に則る
    ● 新しい定期購入の構成に則るのを諦める
    ● 全部新しい定期購入の構成に則るように頑張る
    ○ これはデメリットが多すぎるのでおすすめしません
    73

    View Slide

  74. 新しく作成する定期購入だけ新しい構成に則る
    74
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    自動移行された既存の定期購入

    View Slide

  75. 新しく作成する定期購入だけ新しい構成に則る
    75
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    新しい定期購入
    Base plan
    ● 請求対象期間 : 年間
    自動移行された既存の定期購入
    新しい定期購入だけ定期購入の下に
    複数の期間を追加する

    View Slide

  76. 新しく作成する定期購入だけ新しい構成に則る
    76
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    新しい定期購入
    Base plan
    ● 請求対象期間 : 年間
    新しい定期購入だけ定期購入の下に
    複数の期間を追加する
    自動移行された既存の定期購入
    ● 自動移行された既存の定期購入は定期購入と
    期間がイコールなのでシンプルだったが、一つ
    の定期購入に複数の基本プランが紐づく
    ● 特定の期間(基本プラン)を購入しようとしたと
    き、定期購入に紐づく基本プランを探さなけれ
    ばならないので、既存と新しい定期購入で異な
    る実装をしなければならないため、実装が少し
    複雑になる
    ● 一部だけ違う構成になるので、構成が統一さ
    れておらず管理上も少しややこしくなる

    View Slide

  77. 新しく作成する定期購入だけ新しい構成に則る
    77
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    Base plan
    ● 請求対象期間 : 半年
    自動移行された既存の定期購入
    ● 既存の定期購入は定期購入と期間が
    同じのため、商品名を変えないとおかし
    くなってしまう
    ● 既存の定期購入に別の期間を追加す
    ることはできない

    View Slide

  78. 新しく作成する定期購入だけ新しい構成に則る
    78
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    Subscription
    定期購入1 - 半年払い
    Base plan
    ● 請求対象期間 : 半年
    1つの定期購入に対して 1つの期間のみが
    紐づくように作成する
    自動移行された既存の定期購入

    View Slide

  79. 新しい定期購入の構成に則るのを諦める
    79
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    自動移行された既存の定期購入
    Subscription
    定期購入2 - 月払い
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入2 - 年払い
    Base plan
    ● 請求対象期間 : 年間
    いままでどおり、一つの定期購入に対して一つの
    期間(基本プラン)のみを追加する
    商品の扱いが変わらないのでオファー以外の実装
    は既存の実装がそのまま使える(はず)

    View Slide

  80. 全部新しい定期購入の構成に則るように頑張る
    ※これをやるのはおすすめしません
    80
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    自動移行された既存の定期購入
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    新しい定期購入1
    Base plan
    ● 請求対象期間 : 年間
    案1. 新しい定期購入を作る
    新規ユーザーはこちらを購入させ、
    既存ユーザーはそのままにするか、切り替えを促す(なぜ
    移行しないといけないのか、ユーザーへの説明が難しい)

    View Slide

  81. 全部新しい定期購入の構成に則るように頑張る
    ※これをやるのはおすすめしません
    81
    Base plan
    ● 請求対象期間 : 月間
    Subscription
    定期購入1 - 月払い
    Base plan
    ● 請求対象期間 : 年間
    Subscription
    定期購入1 - 年払い
    自動移行された既存の定期購入
    案2. 既存の定期購入に基本プランを増やす
    新規ユーザーは新しい基本プランを購入させ、
    既存ユーザーはそのままにするか、別の定期購入を購入
    しているユーザーには移行を促す
    既存の定期購入の商品名も変える必要がある
    Base plan
    ● 請求対象期間 : 月間

    View Slide

  82. 自動移行された既存の定期購入をどうするか
    ● 新しく作成する定期購入だけ新しい構成に則る
    ● 新しい定期購入の構成に則るのを諦める
    ○ 新しい定期購入があまり増えないのであればこれが良さそうかも
    ● 全部新しい定期購入の構成に則るように頑張る
    新しい定期購入をどのような構成にするかは予めチームで相談し
    て方針を決めておくとよい
    82

    View Slide

  83. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    83

    View Slide

  84. 既存の定期購入における新しいオファーの活用方法
    ● 既存の定期購入は新しい定期購入の理想の構成にはできな
    いものの、新しい構成に自動移行されているのでオファーの
    活用はできる
    84

    View Slide

  85. 85
    Subscription
    ● 商品名: 月額PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    既存の定期購入における新しいオファーの活用方法
    通常の無料試用

    View Slide

  86. 86
    Subscription
    ● 商品名: 月額PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    既存の定期購入における新しいオファーの活用方法
    Offer
    提供の条件: デベロッパー指定
    段階:
    ● 1ヶ月 20%割引
    通常の無料試用 季節限定セール

    View Slide

  87. 87
    Subscription
    ● 商品名: 月額PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    既存の定期購入における新しいオファーの活用方法
    Offer
    提供の条件: デベロッパー指定
    段階:
    ● 1ヶ月 20%割引
    通常の無料試用 季節限定セール
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 3ヶ月 価格を300円に固定
    期間限定
    新規ユーザー向けセール

    View Slide

  88. 88
    Subscription
    ● 商品名: 月額PROプラン
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 無料試用 30日間
    Base plan
    ● 更新の種類: 自動更新
    ● 請求対象期間 : 月別
    ● 価格: 500円
    既存の定期購入における新しいオファーの活用方法
    Offer
    提供の条件: デベロッパー指定
    段階:
    ● 1ヶ月 20%割引
    通常の無料試用 季節限定セール
    Offer
    提供の条件: デベロッパー指定
    段階:
    ● 1ヶ月 100円割引
    Offer
    提供の条件: 新規ユーザー
    段階:
    ● 3ヶ月 価格を300円に固定
    期間限定
    新規ユーザー向けセール
    過去に購読してくれていた
    ユーザーに対しての
    おかえりなさいオファー

    View Slide

  89. 既存の定期購入における新しいオファーの活用方法
    ● 既存の定期購入では1つの定期購入に対して1つの基本プランしか
    紐付いていないため、別々の期間に同じオファーを提供したい場合
    は、定期購入ごとにオファーを追加する必要がある
    ● オファーが使えるように正しく実装していれば、リリースしなくてもオ
    ファーが提供できる場合がある
    ● 下位互換性の無いオファーを使うにはPBLv5へのアップグレードか
    つ新しいオファーを利用するための実装が必要
    89

    View Slide

  90. 既存の定期購入における新しいオファーの活用方法
    ● どのようなオファーを作成できるのかをチームに共有し、オ
    ファーの条件に応じて適切な実装をすることでオファーを活用
    できるようにしておく
    90

    View Slide

  91. Agenda
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07
    91

    View Slide

  92. Play Billing Library 5.0への移行
    92
    ● 新しい定期購入の仕組みの再構築に合わせて、Play Billing
    Library 5.0(PBLv5)もリリースされた
    ● 新しい定期購入の仕組みや新しいオファーを利用するには
    PBLv5へのアップデートが必須になる
    dependencies {
    def billingVersion = "5.0.0"
    implementation "com.android.billingclient:billing:$billingVersion"
    }

    View Slide

  93. 2020年 2021年 2022年 2023年 2024年
    PBL 3.0
    PBL 3.0
    リリース
    PBL 4.0
    リリース
    PBL 5.0
    リリース
    PBL 6.0
    リリース
    PBL 7.0
    リリース
    93
    PBL 4.0
    PBL 5.0

    View Slide

  94. Play Billing Library 5.0への移行
    94
    ● PBL 3.xのサポートは2022年11月に終了する
    ● 2022年11月以降、PBLを利用しているアプリがアプリの更新
    を公開するにはPBL 4.x以上にアップグレードする必要がある
    ● PBL 5.0は、新しい定期購入の機能へ順次対応できるように、
    古いメソッドは非推奨の形で残っている

    View Slide

  95. Play Billing Library 5.0への移行
    95
    ● 4.xへのアップグレードと5.xへのアップグレードの移行コスト
    はほとんど変わらないため、まだ 3.xを利用しているアプリは
    一旦5.0にアップグレードするのがおすすめ
    ● すでに4.xを利用しているアプリも、一旦5.0に上げておき、
    5.0から追加された機能や非推奨のメソッドは画面ごとに置き
    換えるなど、順次対応していくのがおすすめ

    View Slide

  96. PBLv3からv4へのアップグレードは必要があれば
    こちらの技術書を参考に…
    96
    https://techbooster.booth.pm/items/3101567

    View Slide

  97. Agenda
    97
    従来の定期購入とその課題について
    再構築された新しい定期購入
    新しい定期購入の作り方
    自動移行された既存の定期購入
    既存の定期購入における新しいオファーの活用方法
    Play Billing Library 5.0への移行
    Play Billing Library 5.0の機能をサポートする
    01
    02
    03
    04
    05
    06
    07

    View Slide

  98. Play Billing Library 5.0の変更サマリ
    98
    ● SkuDetailsに置き換わる、ProductDetailsが新たに追加された
    ○ ProductDetailsには、すべての基本プランとそれに紐づくすべ
    てのオファー情報が含まれる
    ● Sku関連のメソッドなどの命名がProductになったものが追加され

    ● それに伴い、Sku関連のクラスやメソッドなどはすべて非推奨になっ

    View Slide

  99. Play Billing Library 5.0の変更サマリ
    99
    ● SkuDetailsによる購入フローでは、skuは商品自体に定期購
    入の期間も含まれていたため、SkuDetailsを渡せば購入でき
    ていた
    ● ProductDetailsによる新しい定期購入の購入フローでは、
    ProductDetailsの中に複数の基本プラン(定期購入の期間)
    やオファーが含まれるため、基本プランやオファーを選択する
    実装が必要になった

    View Slide

  100. 100
    sku( pro_monthly )を元にSkuDetailsを取得
    SkuDetailsを使って購入をリクエストする
    skuがpro_monthlyのSkuDetails
    ● これまでは商品自体に購入期間も含まれていたため、
    SkuDetailsだけで購入を開始できた
    Play Billing Library 4.xまでのSkuDetailsを使った購入までの処理の流れ

    View Slide

  101. 101
    sku( pro_monthly )を元にSkuDetailsを取得
    SkuDetailsを使って購入をリクエストする
    skuがpro_monthlyのSkuDetails
    ● これまでは商品自体に購入期間も含まれていたため、
    SkuDetailsだけで購入を開始できた
    Play Billing Library 4.xまでのSkuDetailsを使った購入までの処理の流れ

    View Slide

  102. 102
    sku( pro_monthly )を元にSkuDetailsを取得
    SkuDetailsを使って購入をリクエストする
    skuがpro_monthlyのSkuDetails
    ● これまでは商品自体に購入期間も含まれていたため、
    SkuDetailsだけで購入を開始できた
    Play Billing Library 4.xまでのSkuDetailsを使った購入までの処理の流れ

    View Slide

  103. 103
    sku( pro_monthly )を元にSkuDetailsを取得
    SkuDetailsを使って購入をリクエストする
    skuがpro_monthlyのSkuDetails
    ● これまでは商品自体に購入期間も含まれていたため、
    SkuDetailsだけで購入を開始できた
    Play Billing Library 4.xまでのSkuDetailsを使った購入までの処理の流れ

    View Slide

  104. 104
    offerTag = p1m
    offerTag = free-trial
    offerTag = free-trial-60days
    Play Billing Library 5.0からのProductDetailsを使った購入までの処理の流れ

    View Slide

  105. 105
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro_plan )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からのProductDetailsを使った購入までの処理の流れ

    View Slide

  106. 106
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro_plan )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からのProductDetailsを使った購入までの処理の流れ

    View Slide

  107. 107
    val product = QueryProductDetailsParams.Product
    .newBuilder()
    .setProductId("pro_plan")
    .setProductType(BillingClient.ProductType.SUBS)
    .build()
    val queryProductDetailsParams = QueryProductDetailsParams
    .newBuilder()
    .setProductList(listOf(product))
    .build()
    ProductDetailsを取得するためのパラメータを生成する

    View Slide

  108. 108
    val product = QueryProductDetailsParams.Product
    .newBuilder()
    .setProductId("pro_plan")
    .setProductType(BillingClient.ProductType.SUBS)
    .build()
    val queryProductDetailsParams = QueryProductDetailsParams
    .newBuilder()
    .setProductList(listOf(product))
    .build()
    ProductDetailsを取得するためのパラメータを生成する

    View Slide

  109. 109
    val product = QueryProductDetailsParams.Product
    .newBuilder()
    .setProductId("pro_plan")
    .setProductType(BillingClient.ProductType.SUBS)
    .build()
    val queryProductDetailsParams = QueryProductDetailsParams
    .newBuilder()
    .setProductList(listOf(product))
    .build()
    ProductDetailsを取得するためのパラメータを生成する

    View Slide

  110. 110
    val product = QueryProductDetailsParams.Product
    .newBuilder()
    .setProductId("pro_plan")
    .setProductType(BillingClient.ProductType.SUBS)
    .build()
    val queryProductDetailsParams = QueryProductDetailsParams
    .newBuilder()
    .setProductList(listOf(product))
    .build()
    ProductDetailsを取得するためのパラメータを生成する

    View Slide

  111. 111
    ProductDetailsを取得する
    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams
    ) { billingResult: BillingResult, productDetailsList ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
    productDetailsList.isNotEmpty()
    ) {
    onResponse(productDetailsList)
    } else {
    // エラーハンドリング
    }
    }

    View Slide

  112. 112
    ProductDetailsを取得する
    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams
    ) { billingResult: BillingResult, productDetailsList ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
    productDetailsList.isNotEmpty()
    ) {
    onResponse(productDetailsList)
    } else {
    // エラーハンドリング
    }
    }

    View Slide

  113. 113
    ProductDetailsを取得する
    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams
    ) { billingResult: BillingResult, productDetailsList ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
    productDetailsList.isNotEmpty()
    ) {
    onResponse(productDetailsList)
    } else {
    // エラーハンドリング
    }
    }

    View Slide

  114. 114
    ProductDetailsを取得する
    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams
    ) { billingResult: BillingResult, productDetailsList ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK &&
    productDetailsList.isNotEmpty()
    ) {
    onResponse(productDetailsList)
    } else {
    // エラーハンドリング
    }
    }

    View Slide

  115. 115
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro_plan )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からの購入までの処理の流れ

    View Slide

  116. 116
    基本プランとそれに紐づくオファーを探す
    // 基本プラン(オファー無し)と基本プランに紐づくオファーが取得できる
    val p1mOfferDetailsList = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    // 基本プランに設定したタグを探す
    // 基本プランに紐づくオファーには基本プランに設定したタグが継承されるため、
    // タグが一意であれば基本プランとそれに紐づくオファーが取得できる
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }

    View Slide

  117. 117
    基本プランとそれに紐づくオファーを探す
    // 基本プラン(オファー無し)と基本プランに紐づくオファーが取得できる
    val p1mOfferDetailsList = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    // 基本プランに設定したタグを探す
    // 基本プランに紐づくオファーには基本プランに設定したタグが継承されるため、
    // タグが一意であれば基本プランとそれに紐づくオファーが取得できる
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }

    View Slide

  118. 118
    基本プランとそれに紐づくオファーを探す
    // 基本プラン(オファー無し)と基本プランに紐づくオファーが取得できる
    val p1mOfferDetailsList = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    // 基本プランに設定したタグを探す
    // 基本プランに紐づくオファーには基本プランに設定したタグが継承されるため、
    // タグが一意であれば基本プランとそれに紐づくオファーが取得できる
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }

    View Slide

  119. 無料期間30日のオファーのSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[0]
    offerDetails.offerTags = p1m, free-trial
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=1
    pricingPhase.billingPeriod=P4W2D
    pricingPhase.formattedPrice=無料
    pricingPhase.priceAmountMicros=0
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=FINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [1]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    119
    基本プランとそれに紐づくオファーを探す
    無料期間60日のオファーのSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[1]
    offerDetails.offerTags = p1m, free-trial-60days
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=1
    pricingPhase.billingPeriod=P8W4D
    pricingPhase.formattedPrice=無料
    pricingPhase.priceAmountMicros=0
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=FINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [1]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━

    View Slide

  120. 無料期間30日のオファーのSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[0]
    offerDetails.offerTags = p1m, free-trial
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=1
    pricingPhase.billingPeriod=P4W2D
    pricingPhase.formattedPrice=無料
    pricingPhase.priceAmountMicros=0
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=FINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [1]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    120
    基本プランとそれに紐づくオファーを探す
    無料期間60日のオファーのSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[1]
    offerDetails.offerTags = p1m, free-trial-60days
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=1
    pricingPhase.billingPeriod=P8W4D
    pricingPhase.formattedPrice=無料
    pricingPhase.priceAmountMicros=0
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=FINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [1]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━

    View Slide

  121. オファー無し(基本プラン) のSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[2]
    offerDetails.offerTags = p1m
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    121
    基本プランとそれに紐づくオファーを探す

    View Slide

  122. オファー無し(基本プラン) のSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[2]
    offerDetails.offerTags = p1m
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    122
    基本プランとそれに紐づくオファーを探す

    View Slide

  123. 123
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からの購入までの処理の流れ

    View Slide

  124. オファーの選択ロジックを考える
    124
    ● 基本プランに複数のオファーが紐付いているとき、どのオ
    ファーをユーザーに購入させるのかはアプリが決めなければな
    らない
    ● たとえば、オファーの中で一番低い価格のオファーを選択する
    ように実装しておけば、無料期間があれば無料期間のオファー
    が選択されるなど

    View Slide

  125. オファーの選択ロジックを考える
    125
    ● また、たとえば次のようなケースではGoogle Playに判定を任
    せることはできないので、タグを使ってどのオファーを優先させ
    るのかをアプリ側で判定する必要がある
    ○ 季節限定でオファーを提供したい
    ○ アプリが持つユーザー情報を元に特定のユーザー向けに
    オファーを提供したい

    View Slide

  126. オファーの選択ロジックを考える
    126
    ● 通常時は一番低い価格のオファーが選択されるようにしてお
    き、何らかの条件に一致したユーザーにはそのユーザーに対
    して特別なオファーが適用されるようにするなど、どのようにオ
    ファーを選択するのかは予めチームで相談して決めておくとよ

    View Slide

  127. オファーの選択ロジックを考える
    127
    ● 今回は、Play Billing Libraryのサンプルにもある一番低い価
    格のオファーを選択するロジックを例に説明する

    View Slide

  128. 128
    オファーの中で一番低い価格のオファーを探して取得する
    // オファーの中で一番低い価格のオファーを探して取得する
    private fun List.findOffer(): ProductDetails.SubscriptionOfferDetails? {
    var lowestPrice = Long.MAX_VALUE
    var selectedOfferDetails: ProductDetails.SubscriptionOfferDetails? = null
    this.forEach { offerDetails ->
    offerDetails.pricingPhases.pricingPhaseList.forEach { pricingPhase ->
    // 価格が一番低いオファーを探して保持する
    if (pricingPhase.priceAmountMicros < lowestPrice) {
    lowestPrice = pricingPhase.priceAmountMicros
    selectedOfferDetails = offerDetails
    }
    }
    }
    return selectedOfferDetails
    }

    View Slide

  129. 129
    オファーの中で一番低い価格のオファーを探して取得する
    // オファーの中で一番低い価格のオファーを探して取得する
    private fun List.findOffer(): ProductDetails.SubscriptionOfferDetails? {
    var lowestPrice = Long.MAX_VALUE
    var selectedOfferDetails: ProductDetails.SubscriptionOfferDetails? = null
    this.forEach { offerDetails ->
    offerDetails.pricingPhases.pricingPhaseList.forEach { pricingPhase ->
    // 価格が一番低いオファーを探して保持する
    if (pricingPhase.priceAmountMicros < lowestPrice) {
    lowestPrice = pricingPhase.priceAmountMicros
    selectedOfferDetails = offerDetails
    }
    }
    }
    return selectedOfferDetails
    }

    View Slide

  130. 130
    オファーの中で一番低い価格のオファーを探して取得する
    // オファーの中で一番低い価格のオファーを探して取得する
    private fun List.findOffer(): ProductDetails.SubscriptionOfferDetails? {
    var lowestPrice = Long.MAX_VALUE
    var selectedOfferDetails: ProductDetails.SubscriptionOfferDetails? = null
    this.forEach { offerDetails ->
    offerDetails.pricingPhases.pricingPhaseList.forEach { pricingPhase ->
    // 価格が一番低いオファーを探して保持する
    if (pricingPhase.priceAmountMicros < lowestPrice) {
    lowestPrice = pricingPhase.priceAmountMicros
    selectedOfferDetails = offerDetails
    }
    }
    }
    return selectedOfferDetails
    }

    View Slide

  131. 131
    オファーの中で一番低い価格のオファーを探して取得する
    // オファーの中で一番低い価格のオファーを探して取得する
    private fun List.findOffer(): ProductDetails.SubscriptionOfferDetails? {
    var lowestPrice = Long.MAX_VALUE
    var selectedOfferDetails: ProductDetails.SubscriptionOfferDetails? = null
    this.forEach { offerDetails ->
    offerDetails.pricingPhases.pricingPhaseList.forEach { pricingPhase ->
    // 価格が一番低いオファーを探して保持する
    if (pricingPhase.priceAmountMicros < lowestPrice) {
    lowestPrice = pricingPhase.priceAmountMicros
    selectedOfferDetails = offerDetails
    }
    }
    }
    return selectedOfferDetails
    }

    View Slide

  132. 132
    オファーの中で一番低い価格のオファーを探して取得する
    // オファーの中で一番低い価格のオファーを探して取得する
    private fun List.findOffer(): ProductDetails.SubscriptionOfferDetails? {
    var lowestPrice = Long.MAX_VALUE
    var selectedOfferDetails: ProductDetails.SubscriptionOfferDetails? = null
    this.forEach { offerDetails ->
    offerDetails.pricingPhases.pricingPhaseList.forEach { pricingPhase ->
    // 価格が一番低いオファーを探して保持する
    if (pricingPhase.priceAmountMicros < lowestPrice) {
    lowestPrice = pricingPhase.priceAmountMicros
    selectedOfferDetails = offerDetails
    }
    }
    }
    return selectedOfferDetails
    }

    View Slide

  133. 133
    オファーの中で一番低い価格のオファーを探して取得する
    // p1mの基本プランの中の一番価格の低いオファーを取得する
    val p1mOfferDetails = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }
    .findOffer()

    View Slide

  134. 134
    オファーの中で一番低い価格のオファーを探して取得する
    // p1mの基本プランの中の一番価格の低いオファーを取得する
    val p1mOfferDetails = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }
    .findOffer()

    View Slide

  135. 135
    オファーの中で一番低い価格のオファーを探して取得する
    // p1mの基本プランの中の一番価格の低いオファーを取得する
    val p1mOfferDetails = subscriptionOfferDetailsList
    .filter { subscriptionOfferDetails ->
    subscriptionOfferDetails.offerTags.any { offerTag -> offerTag == "p1m" }
    }
    .findOffer()

    View Slide

  136. 無料期間30日のオファーのSubscriptionOfferDetails
    val offerDetails = p1mOfferDetailsList[0]
    offerDetails.offerTags = p1m, free-trial
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [0]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=1
    pricingPhase.billingPeriod=P4W2D
    pricingPhase.formattedPrice=無料
    pricingPhase.priceAmountMicros=0
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=FINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    offerDetails.pricingPhases.pricingPhaseList [1]
    ━━━━━━━━━━━━━━━━━━━━
    pricingPhase.billingCycleCount=0
    pricingPhase.billingPeriod=P1M
    pricingPhase.formattedPrice=¥500
    pricingPhase.priceAmountMicros=500000000
    pricingPhase.priceCurrencyCode=JPY
    pricingPhase.recurrenceMode=INFINITE_RECURRING
    ━━━━━━━━━━━━━━━━━━━━
    136
    基本プランとそれに紐づくオファーを探す
    ● 今回のロジックだと価格しか見ていな
    いので、価格が低いかつ一番最初に
    見つかった30日のオファーが選択さ
    れる
    ● 無料期間の長いものを選択するに
    は、これに追加してbillingPeriodが
    長いものを優先するなど、提供するオ
    ファーに応じてユーザーに一番有利
    なオファーが選択されるなどの工夫を
    したほうがよい

    View Slide

  137. 137
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro_plan )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からの購入までの処理の流れ

    View Slide

  138. 138
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)

    View Slide

  139. 139
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)

    View Slide

  140. 140
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)
    ● 存在しないオファートークンを渡すとエラーになるが、空文字
    を渡すとエラーにはならず、基本プランやオファーは自動で選
    択される
    ● テスト購入で試した感じ、おそらく基本プランの作成が早いも
    のが選択されている(確証はない)
    ● ここではorEmptyしているが、意図しない商品の購入画面が
    表示される恐れがあるため、空の場合は購入画面は表示せ
    ず、アプリ側でエラーとして扱ったほうがよいかもしれない

    View Slide

  141. 141
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)

    View Slide

  142. 142
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)

    View Slide

  143. 143
    購入をリクエストする
    // 購入をリクエストするオファートークンを取得
    val offerToken = p1mOfferDetails?.offerToken.orEmpty()
    val productDetailsParams = ProductDetailsParams.newBuilder()
    .setProductDetails(productDetails)
    .setOfferToken(offerToken)
    .build()
    val flowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(listOf(productDetailsParams))
    .build()
    billingClient.launchBillingFlow(activity, flowParams)

    View Slide

  144. 144
    購入対象の基本プランとそれに紐づくすべてのオファーの中か
    ら、どのオファーを提供する(またはオファー無しで提供する)の
    かを何らかのロジックで決める
    ProductDetailsのSubscriptionOfferDetailsのリストから、
    基本プランに設定したタグ(
    p1m)を元に基本プランとそれに紐
    づくオファーを探す
    Product Id( pro_plan )を元にProductDetailsを取得
    Product IdがproのProductDetails
    ● ProductDetailsのSubscriptionOfferDetailsのリストに
    すべての基本プランやそれに紐づくすべてのオファー
    の情報が含まれる
    SubscriptionOfferDetailsのリスト
    ● 購入対象の基本プランとそれに紐づくすべてのオファーが含ま
    れる
    SubscriptionOfferDetails
    ● 購入対象の基本プランとオファーのセットが含まれる
    SubscriptionOfferDetailsに含まれるofferTokenを使って購入
    をリクエストする
    Play Billing Library 5.0からの購入までの処理の流れ

    View Slide

  145. Play Billing Library 5.0の機能をサポートする
    145
    1. Play Consoleで基本プランやオファーにタグを設定する
    ○ 基本プランが正しく判別できるように、基本プランのタグは必ず一意な
    タグを設定しておく
    2. オファーの決定ロジックを決める
    ○ 先に決めておかないとオファーを正しく活用できない
    ○ たとえばオファーの中で一番低い価格のオファーを自動で選択するな
    どを予め決めておき、チーム内で合意をとっておく

    View Slide

  146. Play Billing Library 5.0の機能をサポートする
    146
    3. SkuDetailsを使った購入フローの実装から、ProductDetails
    を使った購入フローの実装に置き換える
    ○ ProductDetailsから基本プランやオファーを取得し、オ
    ファーの選択ロジックなどを実装する
    4. Skuと名のつく非推奨になったクラスやメソッドが残っていない
    か確認して、残っていればProductと名のつくものに置き換え

    View Slide

  147. 参考資料
    147
    ● Success on Google Play with new acquisition, engagement, and monetization tools
    ○ 新しい定期購入にした背景や変更点の概要
    ○ https://youtu.be/7ky2PZl16i4
    ● Google Play Console での定期購入に関する最近の変更 - Play Console ヘルプ
    ○ 下位互換性についての説明
    ○ https://support.google.com/googleplay/android-developer/answer/12124625
    ● 定期購入について理解する - Play Console ヘルプ
    ○ 新しい定期購入の仕組みや機能などについての説明
    ○ https://support.google.com/googleplay/android-developer/answer/12154973
    ● May 2022 subscription changes guide | Google Play's billing system | Android Developers
    ○ Backend APIを含めたサブスクリプションの変更に関する説明
    ○ https://developer.android.com/google/play/billing/compatibility?hl=ja

    View Slide

  148. 参考資料
    148
    ● Google Play Billing Library 4 to 5 Migration Guide
    ○ PBL 4から5へのマイグレーション(課金アイテム取得方法の before/afterなど)
    ○ https://developer.android.com/google/play/billing/migrate-gpblv5?hl=ja
    ● Android Developers Blog: What's new in Google Play
    ○ 課金含めたGoogle Play関連まとめ
    ○ https://android-developers.googleblog.com/2022/05/whats-new-in-google-play.html
    ● Play Billing Library 5 を使用してアプリ内で定期購入を販売する
    ○ PBLv5のcodelab
    ○ https://codelabs.developers.google.com/play-billing-codelab?hl=ja#0
    ● play-billing-samples/PlayBillingCodelab
    ○ PBLv5のcodelabのサンプルコード
    ○ https://github.com/android/play-billing-samples/tree/main/PlayBillingCodelab

    View Slide

  149. ありがとうございました
    Taichi Sato / @syarihu
    Giftmall, Inc.
    Android Engineer
    149

    View Slide