2013年2月8日金曜日

課金APIの概略 - Androidのアプリ内課金(In-App Billing)のまとめ (その2)

課金API概略


開発者のアプリは、端末にインストールされているGoogle Playアプリによって公開されているAPIを使って、課金サービスにアクセスする。
Google Playアプリは、課金リクエストとその応答を、Google Playサーバーと開発者のアプリの間で運ぶ。開発者のアプリは直接Google Playのサーバーと通信する事はなく、課金要求は、プロセス間通信(IPC)を介して、Google Playアプリへ送られる。

アプリ課金は、Google Playを介して配布されたアプリの中でのみ実装できる。また、課金要求を完了するには、Google Playアプリがネットワークを通じてGoogle Playサーバーにアクセスする必要がある。

APIの仕様は、Version 2とVersion 3とで大きく異なる。大きな相違点は以下の通り。

  • Version 2は非同期で処理されるが、Version 3では同期で処理される点である。
  • Version 2は、Android 1.6以降でサポートされるが、Version 3は、Android 2.2以降でサポートされる。

Version 3 APIの概略


購入フロー


購入の典型的な流れは以下の通り。
  1. IInAppBillingService#isBillingSupportedのリクエストをGoogle Playに送って、端末がアプリ課金APIをサポートしているかどうかを決定する。
  2. 次に、アプリ開始時もしくはユーザーがログインしたタイミングで、IInAppBillingService#getPurchasesのリクエストを送って、ユーザーが製品を購入済みかどうかをチェックする。Google Playは、購入済みの製品のIDを含むBundleを返す。
  3. 大抵の場合、購入可能なアイテムの情報をユーザーに示す必要がある。Google PlayのDevelopper Consoleで定義した製品の詳細情報を問い合わせるには、IInAppBillingService#getSkuDetailsを送ればよい。Google Playは、価格、タイトル、説明、製品タイプを含むBundleを返す。
  4. 製品がユーザーによって購入されていなければ、即座に購入を開始できる。購入するには、まず、product ID等を含むIInAppBillingService#getBuyIntentを送って購入のためのIntentをGoogle Playから取得する。product IDを指定するため、開発者はDevelopper Consoleで新しい製品を定義したときに、product IDをメモしておく必要がある。その後の流れは以下の通り。
    1. Google Playは購入を開始するためのPendingIntentを含むBundleを返す。
    2. アプリは、PendingIntentをActivity#startIntentSenderForResultを呼び出して、開始させる。
    3. 購入のフローが完了したら、Google Playは、Activity#onActivityResultに応答のIntentを送ってくる。

購入製品の消費


    ユーザーが購入した製品を消費した事にした場合の流れは以下の通り。
    1. IInAppBillingService#getPurchasesのリクエストを送って、ユーザーが製品を購入済みかどうかをチェックする。
    2. 購入していれば、IInAppBillingService#consumePurchaseを呼び出して、消費した事にする。


    2013年2月1日金曜日

    アプリ内課金の製品タイプ - Androidのアプリ内課金(In-App Billing)のまとめ (その1)

    Androidのアプリ内課金の日本語の情報が、古い情報しか見当たらないので、現状(2013年2月)をまとめておく。

    APIのバージョン

    現状で、最初に考えるべき事は、課金のAPIのバージョンを決めることである。
    現在の段階では、APIのバージョンは以下の通り。
    • Version 3(推奨)
    • Version 2
    バージョンの違いによって、販売できる製品(product)、課金APIの処理方式に違いがある。
    結論を先に書くと、定期的に自動課金をする場合(購読タイプの製品)は、Version 2を選択するしかない。(数週間後には、改善されるかもしれない)
    そうでなければ、コーディングが楽な処理方式のVersion 3を選択するべきである。

    販売できる製品タイプ

    Version 3の場合


    管理タイプ製品(managed)


    現在のところ、これしかない。これは、Googleによって購入履歴が管理されている。管理の単位はGoogle Playのユーザーアカウント毎である。

    Googleによって管理される事により、アプリは、どのような場合でも、ユーザーが製品を購入したかどうかをAPIを通じて知る事ができる。例え、アプリが再インストールされた場合や別端末で購入した場合であってもである。

    Version 3の場合はVersion 2と異なり、管理タイプ製品には消費(consume)機能がある。
    通常、管理タイプは、一度購入すると二度と購入することができない。この機能は、一度だけ課金したい場合、例えば、広告を外すとか上位機能を有効にするとかに有用な機能である。
    しかし、何度も購入できる製品の場合、例えばゲームで使う薬草やコイン等の場合は、二度と購入できないのでは困る。そのような場合は、課金タイプに対して、消費APIを呼び出す事により再度購入できるようになる。

    Version 2の場合


    販売できる製品タイプは以下の通り。
    • 管理タイプ製品(managed)
    • 非管理タイプ製品(unmanaged)
    • 購読タイプ製品(subuscription)

    管理タイプ製品


    Google Playのユーザーアカウント毎にに一度だけ購入できるタイプの製品である。広告を外すとか、上位機能を有効にするとかの場合に使う製品である。
    ユーザーが管理タイプの製品を購入すると、Google Playでは、ユーザー毎に各アイテムの購入情報が永続的に管理される。
    もし、ユーザーが一度購入した製品を購入しようとしても、Google Play側で「既に購入済み」のエラーを表示して再購入を予防する。
    このタイプは、ユーザーがアプリを再インストールしたり、データを消去したり、別の新しい端末にインストールした時でも、購入情報をリストアできるため、便利である。

    非管理タイプ製品


    Google Playには、購入情報が保存されないタイプの製品である。つまり、後でGoogle Playに購入情報を問い合わせる事ができない。非管理タイプは、開発者側で購入情報を管理する必要がある。
    また、Google Playは、ユーザーが何度も同じ製品を購入することを阻止しない。
    非管理タイプは、消費されてしまうアイテム、つまりゲームの薬草や燃料などを売るのに向いていいる。このようなアイテムは、アプリの中で消費され、何度も購入するものだからである。

    購読タイプ製品


    これは、開発者が指定した間隔で課金される製品である。ユーザーが購読タイプを購入すると、Google Playとその課金システムは、指定された間隔と金額でユーザーに請求する。一度、ユーザーが購入すると、Google Playは、ユーザーの同意や行動がなくても、永続的に課金を続ける。
    ユーザーは、いつでも購入をキャンセルする事ができる。
    購読は、管理タイプ製品のみ適用できる。一度ユーザーが購入すると、払い戻しの機会はない。払い戻しを求めるユーザーは、開発者に直接連絡しなければならない。

    2011年5月5日木曜日

    Androidで端末がスリープ中でも定期的にバックグラウンド処理を実行する

    結論から言うと、AlarmManagerとPowerManager.WakeLockを組み合わせて使えばよい。
    具体的には、まず、AlarmManagerを使用して、定期的にBroadcastのIntentを投げる。AlarmManager.RTC_WAKEUPを指定して、端末がスリープ中でもBroadcastが行われるようにしておく。
    public class Foo {
        private static final long INTERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
    
        public void setBroadcast() {
            Intent intent = new Intent(this, BarReceiver.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            am.setInexactRepeating(AlarmManager.RTC_WAKEUP, 
                    System.currentTimeMillis(), INTERVAL, pendingIntent);
        }
    }
    次に、BroadcastReceiverを継承したクラスで、BroadcastのIntentを受け取るようにする。端末がスリープ状態だった場合、onReceiveを抜けると、端末が再びスリープ状態に戻るのが仕様なので、 PowerManager.WakeLock#acquier() で、端末がスリープ状態に移行しないようにしておく。(BarReceiverのインスタンスよりも長い期間存在する必要があるので、static変数にしてある) そして、バックグラウンド処理を実行するサービスを起動する。
    public class BarReceiver extends BroadcastReceiver {
        private static PowerManager.WakeLock wl;
        
        @Override
        public void onReceive(Context context, Intent arg1) {
            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BarReceiver");
            wl.acquire();
            
            Intent intent = new Intent(context, BazService.class);
            context.startService(intent);
        }
        
        public static void releaseWakeLock() {
            if (wl != null) {
                wl.release();
            }
        }
    }
    サービスでは、バックグラウンド処理を実行し、最後にPowerManager.WakeLock#release()が実行されるようにして、端末が再びスリープ状態に戻れるようにしておく。
    public class BazService extends Service {
        @Override
        public void onCreate() {
            new Thread(new BazProcess())
            .start();
        }
        
        private class BazProcess implements Runnable {
            
            @Override
            public void run() {
                // ここでバックグラウンド処理を実行。
                BarReceiver.releaseWakeLock()  // 最後に端末がスリープ状態に戻れるようにする。
            }
    }

    2011年4月23日土曜日

    Ubuntuでハイバネートできない問題を解決する

    Ubuntu 10.10をEee PC 1215Nにインストールした直後の状態だと、ハイバネートできない。

    /etc/pm/config.d/unload_moduleのファイルに以下を記述すればOK。

    SUSPEND_MODULES="xhci-hcd"

    この問題は、USB 3.0をサポートしているボードを搭載していると起きる。

    リリースノートにも記載済み。

    UbuntuのSynapticでEclipseとPleiadesをインストールした時のメモ

    Synapitcで、eclipseとpleiadesのパッケージを指定してインストールすればOK。

    インストール後、/usr/lib/eclipse/eclipse.iniファイルに以下を追加

    -javaagent:/usr/lib/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

    その後、以下を一度実行しておく。(インストール後、一度もEclipseを起動していなければ不要のはず)
    $ eclipse -clean

    UbuntuでAndroidの実機をデバッガで接続するための設定

    どこにパラメータがあるのか忘れるのでメモ

    root権限で、/etc/udev/rules.d/51-android.ruleを編集(ファイルがなければ作成)

    以下のような、記述を追加する。「0bb4」の部分はベンダの会社により異なる。(OEMの場合はどうなるんだろう)
    SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"

    詳しい内容や、パラメータについては、以下を参考に。

    http://developer.android.com/intl/ja/guide/developing/device.html