KLabGames Tech Blog

KLabは、多くのスマートフォン向けゲームを開発・提供しています。 スマートフォン向けゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。 このブログでは、KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、広く紹介していきます。

カテゴリ: KG SDK

プロモーションコード(promo code)とは

今年(2016年)の1月くらいから、Androidではプロモーションコードの機能が使えるようになりました。プロモーションコードとは利用者に対して無料でアプリそのものやアプリ内アイテム、機能のアンロック等を提供できるもので、開発者が作成したコードは利用規約の下で自由に配布が可能なため、強力なプロモーション効果が期待できます。

今回はAndroid DevelopersのIn-app Promotionsの翻訳をご紹介します。

注意事項:

  • このページは Google Inc. とは無関係であり、内容は無保証です
  • 参照した文書 は 2016/5/17時点のものです。これ以降にドキュメントが改訂されていた場合、最新の仕様と異なる可能性があります

アプリ内プロモーション(In-app Promotions 和訳)

プロモーションコードを利用することで、開発者は配布数限定の無料コンテンツ・無料の追加機能をユーザに提供できるようになります。作成したプロモーションコードはサービス利用条件の下で配布することが可能で、ユーザはアプリ中またはPlay Storeアプリでコードを入力して無料でアイテムを入手することができます。プロモーションコードを様々な場面で活用することで、開発者はユーザとのふれあいの機会をさらに広げることができます。
例として次のような利用法が考えられます。

  • ゲームアプリであれば、とあるイベントへ招待された出席者向けの特典として、専用の特別アイテム(例としてキャラクターや装飾アイテムなど)を作ることができます。会場でプロモーションコードがプリントされた紙のカードを出席者に配布すれば、コードを入力したユーザだけにその特別アイテムをアンロックできます。
  • プロモーションコードを地元の商店や企業で配布すれば、アプリの試用を促すことができます。これにより潜在的なユーザの獲得につなげることができます。
  • 「友人と家族」用の専用コードを開発者の社内で配り、友人たちにシェアするといったことができます。

プロモーションコードは必ず何らかの product ID (または SKU)と関連づけられます。作成済みの in-app プロダクトからプロモーションコードを作成できます。そのプロダクトをPlay Storeで販売しないようにすれば、プロモーションコードでのみ入手可能なアイテムとすることができます。Play Storeやアプリ内でプロモーションコードを入力すると、ユーザには通常通り決済した時と同じようにアイテムが付与されます。すでにアプリ内課金としてIn-app Billing version3 を利用中であれば、プロモーションコード対応を追加するのは簡単です。

プロモーションコードの作成と利用

プロモーションコードは Google Play Developer Console で作成します。各コードはDeveloper Consoleで登録済みの商品ひとつに紐付きます。

入手したプロモーションコードを商品引き替えに利用するには、次の二つの方法があります。

  • In-app Billing の実装 で説明されているとおり、アプリ内の通常の購入フローの中でプロモーションコードを入力します。これはアプリから見れば通常の購入と全く同様で、ユーザにとっては代金の代わりにプロモーションコードを利用することだけが異なることになります。
  • Google Play Storeアプリ内からコードを入力します。ユーザがここでコードを入力すると、Play Storeはそのユーザに対して対象アプリを起動するよう通知する(最新バージョンのアプリがインストール済みの場合)か、または対象アプリのダウンロード、もしくはアップデートを促します。(現在のところGoogle Play Webストア上でのプロモーションコード入力は非対応です)

プロモーションコードが消費型プロダクト用の場合、その商品の別のプロモーションコードが再度利用できるのは初めのものが消費された になります。例えば、とあるゲームでプロモーションコードを使ってライフ追加のアイテムを提供していたとします。ベティはそのアイテムのプロモーションコードを二つ持っており、プロモーションコードを一つ利用してからゲームを起動します。するとアイテムが消費されてベティの持つキャラクターには追加ライフが付与された状態になります。ここで初めて、もうひとつのプロモーションコードを利用してさらにライフを追加できるようになります。
(最初に入力したプロモーションコードで入手したアイテムが消費されるまでは、別のコードを利用することはできません)

アプリでのプロモーションコード対応

アプリにプロモーションコード対応を組み込むには、アプリの起動(start)時または復帰(resume)時に必ず getPurchases() メソッドを呼び出す必要があります。このメソッドが返すものは現在未消費の購入商品全てであり、これにはプロモーションコードで引き替えられた購入内容も含まれます。これを実現する一番簡単な方法は、アクティビティの onResume() メソッド内で getPurchases() を呼び出すことです。こうすることで、アクティビティが生成されるタイミングだけでなく復帰時にもコールバックが呼ばれるようになります。起動時や復帰時に getPurchases() を呼び出せば、ユーザが購入したもの、およびアプリが起動していない間にプロモーションコードで引き替えた内容も含めて全ての内容を取得することが保証できます。この方法が良いのは、さらにユーザがアプリ内で購入を行ったが何らかの理由で処理が失敗した場合でも、次回アクティビティが復帰し getPurchases() が呼び出されば、アプリが購入に関する情報を再度見つけられるようになることです。

上記に加えて、アプリ内でユーザがプロモーションコードを入力できるようにしておく必要があります。すでにアプリ内課金の処理(In-app Billingリクエストの作成 に記載)に対応済みであれば、自動的にアプリ内でのプロモーションコードの引き替えにも対応できていることになります。アプリ内課金のUIが起動されるとユーザにはプロモーションコードで支払いをするオプションが示され、その操作の結果として onActivityResult() メソッドは購入が完了したかどうかを示すインテントを受け取ります。この場合でも、購入や消費処理が正しく終了しなかった場合に備えてアプリ起動時や復帰時に getPurchase() を呼び出す必要はあります。たとえばプロモーションコードでのアイテム引き替えには成功したものの、それを利用する前にアプリが強制終了したとします。それでも次の起動時にアプリは getPurchases() を呼び出すため、購入に関する情報を取得できることになります。

アプリ起動中にPlay Storeアプリ内でプロモーションコードが利用された場合についても想定しておかなくてはなりません。アプリに PURCHASES_UPDATED インテントのリスナを登録しておけば、ユーザがコードを利用したことはアプリから即座に検知することができます。Play Storeはユーザがプロモーションコードを利用するとこのインテントを送信します。

PURCHASES_UPDATEDインテントを検知するには、"com.android.vending.billing.PURCHASES_UPDATED" を処理するBroadcastReceiverオブジェクトを動的に生成して登録するようにしてください。次のようなコードを記述し、アクティビティの onResume() メソッド内でレシーバーの登録を行います。

IntentFilter promoFilter =
    new IntentFilter("com.android.vending.billing.PURCHASES_UPDATED");
registerReceiver(myPromoReceiver, promoFilter);

ユーザが購入処理を行うとシステムは登録されたレシーバーの onReceive() メソッドを実行します。このメソッド内では getPurchases() を呼び出し、ユーザがどの購入を行ったかを精査する必要があります。

アクティビティの onPause() メソッドでは、アプリ起動中でない時のシステム負荷を下げるため次のようにBroadcastReceiverを削除するようにしてください。

unRegisterReceiver(myPromoReceiver);

注意:アプリのマニフェストでのBroadcastReceiverの登録は行わないでください。マニフェストでreceiverを宣言してしまうと、アプリが起動していない状態でユーザが何らかの購入を行った際、システムはインテント処理のためにそのアプリを起動してしまうことになります。この動作は必要でないばかりか、むしろユーザを苛立たせることになりかねません。これを避けるため、ユーザがアプリを起動したタイミングで getPurchases() を呼び出して、アプリ非起動時に作成された購入情報を取得するようにすると良いでしょう。

アプリ内プロモーションのテスト

アプリ内プロモーションに対応した際は、次のユースケースをテストするようにして下さい。

ユーザが対象アプリ内からプロモーションコードを入力する

プロモーションコードが対象アプリ内における課金フローの中で利用された場合、In-app Billingリクエストの作成で示すように、システムは購入処理のためアクティビティの onActivityResult() メソッドを起動します。ユーザが金銭、プロモーションコードどちらで購入を行った場合でも onActivityResult() にて購入結果が正しく処理されることを確認してください。

ユーザがPlay Store内からプロモーションコードを入力する

プロモーションコードがPlay Store内で利用された場合には、いくつか想定しておくべきケースがあります。それぞれのパターンについて検証を行うようにしてください。

対象アプリがインストールされていない場合

対象アプリがデバイスにインストールされていない状態でユーザがプロモーションコードを入力すると、Play Storeはそのユーザに対してアプリのインストールを促します。(対象アプリがインストールされているがそれが最新のバージョンでない場合は、Play Storeはアプリのアップデートを促します) 対象アプリがインストールされていない場合のテストとして、次の手順をデバイスから実施するようにしてください。

  1. ユーザが Play Store上でプロモーションコードを入力する。Play Storeはユーザに対して対象アプリのインストールを促す
  2. ユーザが対象アプリをインストールして起動する。ここでアプリの起動処理を確認し、アプリが getPurchases() を呼び出していること、プロモーションコードによる購入が正しく検出できていることを検証する
対象アプリがインストール済みだが、起動中でない場合

対象アプリがデバイスにインストールされている状態でプロモーションコードを入力すると、Play Storeはそのユーザに対象アプリに切り替わることを通知します。デバイスに対象アプリがインストール済みだが起動状態ではない場合のテストとして、次の手順を実施してください。

  1. ユーザが Play Store上でプロモーションコードを入力する。Play Storeはユーザに対して対象アプリに切り替わることを通知する
  2. ユーザが対象アプリを起動する。ここでアプリの起動処理を確認し、アプリが getPurchases() を呼び出していること、プロモーションコードによる購入が正しく検出できていることを検証する
対象アプリがインストール済みで、起動中の場合

デバイス上でアプリが起動中の時にプロモーションコードが入力された場合には、Play Storeは対象アプリに対して PURCHASES_UPDATED インテントで通知を行います。次の手順でテストを行ってください。

  1. ユーザが対象アプリを起動する。アプリ自体が正しく登録されており、 PURCHASES_UPDATED インテントを処理できる状態になっていることを確認する
  2. ユーザがPlay Storeアプリを起動しプロモーションコードを入力すると、Play Storeは PURCHASES_UPDATED インテントを送信する。ここでそのインテントを処理するため、アプリの BroadcastReceiver.onReceive() コールバックが呼ばれていることを確認する
  3. 上記の onReceive() メソッドでは getPurchases() を呼び出してインテントに応答する必要がある。ここでは上記のメソッドの呼び出し、およびユーザが入力したプロモーションコードにより作成された購入情報が正しく検出できていることを確認する
  4. ユーザがタスクの切り替えを行い対象アプリに戻る。ここで、購入されたアイテムが付与されていることを確認する

実際にプロモーションコードを実装してみると?

'In-app Promotions'の翻訳は以上ですが、最後に実際にプロモーションコードを利用する際のポイントを簡単に記載しておきます。

まず、プロモーションコードはIn-app Billingが利用できる地域全てで利用できるわけではありません。2016年5月現在ではアメリカや日本など16カ国となっており、プロモーション対象ユーザがこれらの地域に含まれているか確認しておく必要があります。
またKLabで実施したテストから、 少なくとも現状の振る舞いからは いくつか注意すべき点があることが分かっています。

  1. 購入情報のうち、'Order Id'(orderId)および'Developer Payload'(developerPayload)は設定されない
  2. 発行済みのプロモーションコードのうち、どのコードが利用されたかを知る手段は(恐らくは)無い

1.については、独自サーバでコンテンツを付与するようなアプリを提供している場合、一意性のチェックをOrder Idで行っていたり、セキュリティチェックをDeveloper Payloadで行っているような場合に影響するでしょう。(後者の属性が省かれる理由は、Google Play Storeアプリから直接プロモーションコードが入力された場合、ペイロードを対象アプリ中から設定する機会がないことによる制限ではないかと思われます)
このため、すでに実装済みのIn-app Billing処理を改修して提供する場合にはこの点に注意が必要です。
また 2.についてですが、購入情報の中には利用されたプロモーションコードの情報は含まれていない(と思われる)ため、コード毎の使用記録等の追跡は不可能ということになりそうです。
ちなみにプロモーションコードの利用に関する情報はDeveloper Consoleでも少なくとも現時点では確認ができないようです。

また、上記の資料ではWeb版のプレイストアではプロモーションコードに未対応の旨が記載されていますが、現在Web版TOPからプロモコードを入力するUIへの導線が存在する(TOP左下の「コードを利用」のリンク)ようで、ヘルプにもその記述があります。

プロモーションコード利用に関するベストプラクティスは今後もこちらでご案内する予定です。

KG SDKについて

KG SDK は、Androidのプロモーションコードといった新しい機能にもいち早く対応し、ゲーム開発を最適化することを目指しています。
KG SDKの概要についてはこちら を、お問い合わせにつきましてはこちら をご覧下さい。


Shimanuki

はじめに

先日KLabではパブリッシングパートナー会社様及び共同開発パートナー会社様向けに、 「モバイルオンラインゲーム開発SDK」として、社内で開発・利用を推進しているライブラリ群の提供を開始しました。
今日はこのSDKに含まれているストア課金処理ライブラリおよび仮想通貨管理ライブラリについて、その提供の背景と概要についてお話しします。

ストア課金処理ライブラリ・仮想通貨管理ライブラリ提供の背景

多くのスマートフォン用アプリには、アプリの中から追加で課金を行うことでロックされた機能を有効化したり、新たなコンテンツを追加したりする機能があります。
これを実現しているのがアプリ内課金の機能です。オンラインゲームでは仮想通貨の購入やゲーム内機能をアンロックする目的で利用されるケースが多いようです。

このアプリ内課金は基本的にアプリ(スマートフォン端末)とGoogle PlayやiTunesなどの決済サーバ間で完結します。
つまり運営者が独自にサーバを用意することは仕様上必須ではありませんが、一方でオンラインゲームの運営サーバ(以降、リモートサーバ)側ではコンテンツの付与などをそのサーバ上で間違いなく行う必要があるため、アプリとリモートサーバとの連携処理を適切に実装する必要があります。

構成概念図

このようなリモートサーバにおける課金処理で特に注意しなければならないのが、購入情報の検証すなわち不正対策と、そこで付与されるコンテンツ=仮想通貨の管理に関する実装です。

決済プラットフォームが提供している仕様書の内容だけでは、オンラインゲームに特化したベストプラクティスといったことまではあまり読み取ることができません。
つまりこれらの処理は運用ノウハウといえる領域であり、各社独自に工夫を凝らしている状況ではないかと思います。

前置きが長くなりましたがこのストア課金処理ライブラリおよび仮想通貨管理ライブラリの目的は、このリモートサーバ側の「購入情報の検証」および「仮想通貨の管理」に関するKLabの運用ノウハウを透過的に、つまり容易に利用可能にすることでオンラインゲーム開発者が本来の作業に集中できるようにすることにあります。
なお、これらの機能はモジュール化されており自由に組み合わせることが可能な設計としています。

購入情報の検証 (ストア課金処理ライブラリ)

オンラインゲームのように購入情報をアプリからインターネットを介してリモートサーバに送信し、リモートサーバ上でコンテンツ付与を行う際に注意しなければならないのが不正対策です。
具体的に言うとアプリ内課金に関する処理を迂回するようにアプリそのものを改ざんされたりすることもありますし、偽の購入情報を送りつけるようなツールも横行していますので、このような不正利用者によるただ乗りがないよう考慮して検証を実装する必要があるわけです。

ただしオンラインゲームに関して言うと、アプリ内課金に必ずリモートサーバが介在するためスタンドアロンアプリ=リモートサーバを必要としないアプリに比べると不正対策は比較的容易です。
というのもアプリについてはバイナリ自体やメモリ改ざんが技術的に可能でも、サーバ側を乗っ取ってプログラムを書き換えるようなことはそれと比較してずっと難しいからです。
つまりオンラインゲームにおいてはサーバサイドでの検証を適切に漏れなく行うことで、不正利用をほぼ100%防ぐことができます。

ストア課金処理ライブラリでは次のようなチェックを実施することで不正対策を行っています。

  • 署名あるいは検証サーバを利用した検証の実施
  • 購入情報内の決済IDによる一意性の担保
  • 購入情報に含まれる製品IDや商品IDの存在チェック
  • などなど……

上記でおわかりのように一つひとつの処理は技術的に難易度が高いものではありません。
ただしこのような手続きはアプリ毎の依存部分があまりないことや、実際には検証サーバへの接続処理やリトライ処理等エラーハンドリング、各種ログ実装(忘れがちになる部分ですが運用では重要です)など煩雑な対応も付随して多く発生するためライブラリ化するメリットが大きいところといって良いと思います。

仮想通貨の管理 (仮想通貨管理ライブラリ)

日本国内向けに有償で発行が行われた仮想通貨は、発行額や発行形態に応じて資金決済に関する法律(資金決済法)という法律の適用を受けることがあります。
目的は利用者保護にあり、この場合事業者および発行する仮想通貨の名称や単価等を監督省庁に届け出る必要がありますし、事業者に万が一のこと(破産など)があったときに備えて仮想通貨発行額に応じた発行保証金の供託を行わなければならないことになっています。

これを実現するには一貫したルールで仮想通貨の付与・利用を行う必要がありますし、さらにこれらの入出力ログは厳密に管理されなければなりません。
このためKLabでは仮想通貨は種別毎に先入先出法で管理することで入出力を厳格にルール付けした上で残高管理を行っているのですが、このような実装は一定の会計知識も必要ですし、やや複雑な手続きになりがちな上に万が一不具合があった場合にはその損害も計り知れません。
そこでこのような処理をカプセル化し、付随する固有の業務処理におけるトランザクション管理やロック機構がテンプレート化されたライブラリとして提供することで仮想通貨の正確な管理・運用を支援しています。

さいごに

このライブラリの検証処理機能としては現在 python向けにIn-App Purchase(App Store)用とIn-app Billing(Google Playストア)用のものを提供しており、以後ニーズを見ながら他の決済プラットフォーム向けのものを提供予定です(動作環境等詳細につきましては までお問い合わせください)。
ライブラリの開発チームでは常に最新の情報を把握して、プログラムへの反映を継続して行うようにしています。

KLabではこのようにアプリの開発や運用で得られた知見を、各種ライブラリやフレームワークといった共通のコンポーネントとして集約することにより開発業務の効率化を進めています。

9/17から開催される東京ゲームショウでも当社コーナーを出展していますので、興味を持たれた方はぜひ遊びに来てくださいね。


Shimanuki

↑このページのトップヘ