2013年1月28日月曜日

多言語対応 Supporting Different Languages

参照元(翻訳): Supporting Different Languages | Android Developers

アプリケーションのコードからUIに使っている文字列を抜き出し、それらを別ファイルへ保存しておくことは良い慣習である。Androidは各プロジェクト毎にリソースディレクトリを持つことで、これを容易に行える。

プロジェクトの作成にAndroid SDK Toolsを使えば、プロジェクトのトップレベルに res/ ディレクトリが生成されている。様々なリソースタイプに対するサブディレクトリがこのres/ディレクトリにある。いくつかのデフォルトのファイル、例えば res/values/strings.xml があり、これはstringの値を保持している。


Create Locale Directories and String Files

より多くの言語をサポートするためにres/の中に values ディレクトリを追加作成し、valueはハイフンとISO国コードをディレクトリ名の後ろに付加する。例えば、values-es/ は言語コード"es"の地域に対するリソースを含むディレクトリである。Androidは実行時に端末のロケール設定に従って適したリソースをロードする。

サポートする言語を決めたら、サブディレクトリとstringファイルを次のように作成する。

MyProject/
    res/
       values/
           strings.xml
       values-es/
           strings.xml
       values-fr/
           strings.xml

各ロケールに対するstringの値を適切なファイルへ加える。

実行時に、ユーザーの端末にセットされているロケールに応じて、適切なstringリソースのセットがAndroid systemによって使用される。

例えば、次の例は異なる言語に対する違うstringリソースである。

English(default locale), /values/strings.xml:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">My Application</string>
    <string name="hello_world">Hello World!</string>
</resources>

Spanish, /values-es/strings.xml:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">Mi Aplicación</string>
    <string name="hello_world">Hola Mundo!</string>
</resources>

French, /values-fr/strings.xml:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">Mon Application</string>
    <string name="hello_world">Bonjour le monde !</string>
</resources>

note: どのようなリソースタイプにもロケール修飾子(またはコンフィギュレーション修飾子)は使用できる。例えばbitmap drawableのローカライズされたバージョンを提供したいときなど。詳しくはLocalizationを参照のこと。

Use the String Resources

<string>のname属性によって定義されたリソース名を用いることでコードやそのほかのXMLファイルの中でstringリソースを参照することが可能である。

ソースコートの中で次のシンタックスでstringリソースを参照できる。R.strng.<string_name>.このような文字リソースを受け取るメソッドはいくつもある。例えば次のよう。

// Get a string resource from your app's Resources
String hello = getResources().getString(R.string.hello_world);

// Or supply a string resource to a method that requires a string
TextView textView = new TextView(this);
textView.setText(R.string.hello_world);

XMLファイルでは、string値を代入できるXMLの属性であればどこでも次のシンタックスでstringリソースを参照できる。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

2013年1月26日土曜日

アプリ内課金商品の購入 Purchase In-app Billing Products

参照元(翻訳): Purchasing In-app Billing Products | Android Developers

アプリがGoogle Playと接続すると、アプリ内商品の購入リクエストが行える。Google Playによってユーザーが支払い方法を入力するためのチェックアウトのインターフェイスが提供されるので、アプリケーション側で直接支払いの処理を扱う必要はない。

アイテムが購入されると、Google Playはユーザーが所有していることを認識し、アイテムが消費されるまでは同じユーザーが同じ商品IDのアイテムを購入できないようにする。あなたはアプリ内でのアイテムの消費をコントロールでき、再び購入可能にするようGoogle Playに通知することができる。

また、あなたはGoogle Playに問い合せて、すぐにユーザーの購入したリストを検索することができる。これは例えば、アプリ起動時にユーザーの購入状態を復元したいときに役立つ。


Purchase an Item

購入リクエストはIabHelperインスタンスのlaunchPurchaseFlow(Activity, String, int, OnIabPurchaseFinishedListener, String)を呼ぶことで開始する。この呼び出しはアクティビティのメインスレッドから行う必要がある。launchPurchaseFlowメソッドのパラメータは次のとおり。
  • 最初の引数は呼び出すアクティビティ。
  • 2つめ引数は購入するアイテムのID(SKU)。商品名ではなくIDを与える。デベロッパーコンソールで前もってそのアイテムを定義し有効にしておかないと認識に失敗する。
  • 3つめの引数はリクエストコード。これは正のintegerが可能で、Google Playはこの値をアクティビティのonActivityResult呼び出しに購入レスポンスと共に返す。
  • 4つめは引数はリスナーで、購入処理が完了しGoogle Playからの購入レスポンスを扱うときに通知される。
  • 5つめの引数は'developer payload'の文字列で、オーダーに対する追加情報(空の文字列でもよい)を送るために使用できる。これは典型的には、購入リクエストをユニークに識別する文字列トークンを渡すのに使われる。string値を指定すると、Google Playはこの値を購入レスポンスと共に返す。続いてあなたがこの購入の問合せを行うとき、Google Playはこの値と購入詳細を返す。
    Security Recommendation: 実践的にはあなたのアプリケーションで購入を行ったユーザーを識別するのに役立つ文字列を渡すと良い。そうすることで、あなたは後からユーザーのこの購入が正当なものであることを確かめられる。消耗するアイテムに対してはランダムな文字列を使うが、永続的なアイテムに対してはユーザーをユニークに識別する文字列を使うべきだろう。
次の例は商品ID SKU_GASに対して、任意のリクエストコード値(10001)、エンコードしたpayload文字列を使って購入リクエストを行う方法を示している。

mHelper.launchPurchaseFlow(this, SKU_GAS, 10001,   
   mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

購入のオーダーがうまくいくと、Google Playからのレスポンスデータが保存されたPurchaseオブジェクトがリスナーに渡される。

次の例はリスナーで購入レスポンスをどのように扱えるかを示している。このレスポンスは購入オーダーが成功したかどうか、ユーザーが購入したのがgasなのかpremium upgradeなのかによって異なる。この例ではgasは複数回購入可能な商品なので、あなたはユーザーが再び購入可能になるように購入を消費すべきである。詳しくはのちのセクションで。premium upgradeは一度のみの購入商品なので、それを消費する必要はない。ユーザーが新たにアイテムを購入したことが分かるように、UIをすぐに更新するのが良い。

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener 
   = new IabHelper.OnIabPurchaseFinishedListener() {
   public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
   {
      if (result.isFailure()) {
         Log.d(TAG, "Error purchasing: " + result);
         return;
      }      
      else if (purchase.getSku().equals(SKU_GAS)) {
         // consume the gas and update the UI
      }
      else if (purchase.getSku().equals(SKU_PREMIUM)) {
         // give user access to premium content and update the UI
      }
   }
};

Security Recommendation: Google Playから購入レスポンスを受け取ったとき、返ってきたデーターのsignature、orderId、Purchaseオブジェクトの中のdeveloperPaylaodの文字列が期待している値かどうか確かめる。oderIdは以前に処理していないユニークな値か、developerPayloadはこの購入リクエストに対して送ったトークンと適合しているかを確かめる。さらに用心するなら、この確認は自社サーバーで行うべきである。


Query Purchased Items


購入が成功すると、このユーザーの購入データはGoogle Playのアプリ内課金サービスによってローカルにキャッシュされる。アプリの開始時や再開時など頻繁にアプリ内課金サービスにユーザーの購入商品を問い合わせることは良い実践で、これによりユーザーの現在の商品所有状態が常にアプリ内で反映される。

ユーザーの購入を復元するために、IabHelperインスタンスでqueryInventoryAsync(QueryInventoryFinishedListener)を呼び出す。QueryInventoryFinishedListenerの引数は問い合わせが完了し、そのレスポンスを処理するときに通知されるリスナーである。メインスレッドから安全に呼ぶことができる。

mHelper.queryInventoryAsync(mGotInventoryListener);

問い合わせが完了すると、問い合わせ結果がInventoryオブジェクトに保存されリスナーに渡される。アプリ内課金のサービスは、端末に現在ログインしているユーザーアカウントが行った購入のみを返す。

IabHelper.QueryInventoryFinishedListener mGotInventoryListener 
   = new IabHelper.QueryInventoryFinishedListener() {
   public void onQueryInventoryFinished(IabResult result,
      Inventory inventory) {

      if (result.isFailure()) {
        // handle error here
      }
      else {
        // does the user have the premium upgrade?
        mIsPremium = inventory.hasPurchase(SKU_PREMIUM);        
        // update UI accordingly
      }
   }
};


Consume a Purchase

Google Playでの購入アイテムの所有情報を追跡するためにIn-app Billing Version 3が使える。一度アイテムが購入されると、アイテムは"owned"と見なされその状態では再びGoogle Playから購入することはできない。再びアイテムを購入可能にするには、そのアイテムに対する消費リクエストを送らなければならない。管理しているアプリ内商品はすべて消費可能であるが、アプリ内での消費メカニズムはあなた次第である。例えば、ゲーム内通貨やreplensihable game tokensなどユーザーが何度も購入したいような一時的に役立つ物に対しては消費を実装する。プレミアムアップグレードのような一度購入すると永続的な効果がある物に対しては消費を実装しないだろう。

アプリ内商品のユーザーへの提供をどの様に管理し、追跡するかはあなたの責務である。例えば、ユーザーがゲーム内通貨を購入すれば、あなたプレイヤの資金に購入した分を追加すべきだろう。

Security Recommendation: アプリ内商品(消費あり)の効果をユーザーに提供する前に、あなたは消費リクエストを送らなければならない。アイテムを提供する前に消費レスポンスの成功を受け取るようにする。

購入消費を記録する為にIabHelperインスタンスからconsumeAsync(Purchase, OnConsumeFinishedListener)を呼ぶ。このメソッドの最初の引数はPurchaseオブジェクトで消費アイテムを指す。2番目の引数はリスナーで消費処理が完了しGoogle Playからの消費レスポンスを扱うときに通知される。この呼び出しはメインスレッドから行って良い。

この例では、ユーザーがアプリ内で購入したガスのアイテムを消費する。

mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), 
   mConsumeFinishedListener);

次の例はOnConsumeFinishedListenerの実装方法を示している。

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
   new IabHelper.OnConsumeFinishedListener() {
   public void onConsumeFinished(Purchase purchase, IabResult result) {
      if (result.isSuccess()) {
         // provision the in-app purchase to the user
         // (for example, credit 50 gold coins to player's character)
      }
      else {
         // handle error
      }
   }
};

Check for Consumable Items on Startup
ユーザーがアプリケーション起動したとき、消費アイテムをチェックすることは重要である。一般的に、最初にあなたはアプリ内課金サービスにユーザーの消費したアイテムを問い合わせる(queryInventoryAsync)。それから、消費しうるPurchaseオブジェクトをInventoryから取得する。もしユーザーによって所有されている消費アイテムを発見したら、すぐにGoogle Playに消費リクエストを送り、ユーザーにアイテムを提供する。起動時のこのチェックの実装の仕方はTrivialDriveサンプルを参照のこと。

2013年1月22日火曜日

販売のためのアプリ内商品の確立 Establishing In-app Billing Products for Sale

参照元(翻訳): Establishing In-app Billing Products for Sale | Android Developers

課金アプリを公開する前に、Google Play Developer Consoleで販売可能なデジタル商品のプロダクトリストを定義する。

Specify In-app Products in Google Play

デベロッパーコンソールでアプリ内商品の情報を定義し、商品リストをアプリに関連付ける。
  1. 署名されたAPKファイルをビルドする。
  2. デベロッパーコンソールで作成したアプリのエントリーを開く。
  3. APKタブからUpload new APKをクリックし署名済みAPKをアップロードする。まだ公開はしない!
  4. アップロードしたアプリのin-app Productsタブをクリックする。
  5. 新しい商品を追加するためのoptionをクリックし、商品情報のフォームを埋める。商品情報は、アイテムのユニークID(SKU)、説明、価格、利用できる国。IDは後ほどアプリで商品詳細の問い合わせに必要なのでメモる。
    important: Version 3は管理されたアプリ内商品のサポートのみを提供する。ゆえに新しいアイテムをデベロッパーコンソールの商品リストに追加するときは、購入タイプが"Managed"であることを確認する。
  6. フォームの入力が終わればすぐに商品はアクティブになりアプリで購入することができる。
    Warning: APKのアップデートから反映まで2-3時間かかる場合がある。もし反映前にテストを行うと、アプリケーションは次のエラーメッセージと共に'purchase cancelled'レスポンスを受け取るだろう。"This version of the application is not enabled for In-app Billing."

Query Items Available for Purchase

Google Playに問合せを行い、アプリに関連づいた商品情報(価格、タイトル、説明、タイプ)をプログラムで検索することができる。これは例えば、ユーザーが利用可能だが所有していないアイテムのリストを表示したいときに便利だ。

Note: 問い合わせを行うときは、商品のIDを明示する必要があるだろう。各商品IDはデベロッパーコンソールの"In-app Products"タブのName/ID欄に並んでいる。

商品情報の検索には、IabHelperインスタンスのqueryInventoryAsync(boolean, List, QueryInventoryFinishedListener)を呼ぶ。

  • 最初の引数は商品情報を検索するかどうかを指定する(trueをセットすべき)。
  • Listはあなたの検索したい商品のID(SKUとも呼ぶ)をひとつ以上含む。
  • 最後のQueryInventoryFinishedListenerは問い合わせが完了しレスポンスを扱うときに呼ばれるリスナーを指定する。
サンプルにある便利なクラスを使用すれば、このクラスは課金リクエストを管理するバックグランドスレッドを操作するので、メインスレッドから安全に問合せを行うことができる。
次のコードはあらかじめデベロッパーコンソールで定義したSKU_APPLEとSKU_BANANAのIDを持ったふたつの商品の詳細を検索する方法を示している。

List additionalSkuList = new List();
additionalSkuList.add(SKU_APPLE);
additionalSkuList.add(SKU_BANANA);
mHelper.queryInventoryAsync(true, additionalSkuList,
   mQueryFinishedListener);

問い合わせが成功すると、クエリーの結果がInventoryオブジェクトに保存され、このオブジェクトはリスナーに返される。

次のコードは検索結果からアイテムの価格を調べる方法を示している。

IabHelper.QueryInventoryFinishedListener 
   mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
   public void onQueryInventoryFinished(IabResult result, Inventory inventory)   
   {
      if (result.isFailure()) {
         // handle error
         return;
       }

       String applePrice =
          inventory.getSkuDetails(SKU_APPLE).getPrice();
       String bananaPrice =
          inventory.getSkuDetails(SKU_BANANA).getPrice();

       // update the UI 
   }
}

アプリ内課金の準備 Preparing Your In-app Billing Application

参照元(翻訳): Preparing Your In-app Billing Application | Android Developers

まずはIn-app Billing Version 3 APIを含むライブラリーをプロジェクトに追加する必要がある。Google Playと通信するためのパーミッションをアプリに設定することに加え、使用するAPI versionがGoogle Playでサポートされているか確認しなければならない。


Download the Sample Application

ここでは、アプリ内課金のサンプルアプリ「TrivialDrive」を実装の参考に使用する。このサンプルは課金サービスとmarshal and unmarshal data typesをすばやくセットアップしたり、アプリのメインスレッドからの課金リクエストを処理したりする便利なクラスを含む。

サンプルアプリのダウンロード:
  1. Android SKD Managerを開く。
  2. SDK Managerの中のExtrasセクションを開く。
  3. Google Play Billing Libraryを選択する。In-app BillingのVersion 3以上が選択されていることを確認する。
  4. ダウンロードを完了するためにinstallをクリックする。
/your/sdk/location/extras/google/play_billing/in-app-billing-v03 にサンプルファイルがインストールされる。


Add Your Application to the Developer Console

Google Play Developer Consoleで課金アプリの公開やアプリ内で購入可能な様々なデジタル商品の管理を行う。デベロッパーコンソールで新しいアプリのエントリーを作成したとき、自動的にアプリのpublic license keyが作られる。このキーはアプリからGoogle Playへのセキュリティ接続を確立するために必要である。アプリに対して一度だけこのキーの生成が必要で、apkファイルをアップデートするときはこれらのステップを繰り返す必要はない。

デベロッパーコンソールにアプリを追加:
  1. Google Play Developer Consoleにログイン。アプリ内アイテムを売るためにはGoogle Checkout Merchantアカウントが必要。
  2. もしまだ新しいバージョンのデベロッパーコンソールにログインしていない場合は、Try the new designをクリックする。
  3. All ApplicationsタブにあるAdd new applicationをクリックし、アプリ名を入力、Prepare Store Listingをクリックする。
  4. Service & APIs タブからアプリのために生成されたpublic license keyをメモる。これはBase64 の文字列で後にアプリのコードに組み込む必要がある。

Add the In-app Billing Library

Version 3を使うために、Android projectにIInAppBillingService.aidlファイルを追加しなければならない。Android Interface Definition Language (AIDL)ファイルはGoogle Play serviceとのインターフェイスを定義したものだ。

IInAppBillingService.aidlファイルはサンプルアプリのなかにある。新しいアプリの作成 or 既存のアプリの変更のどちらかによって、次の指示に従う。

New Project
  1. TrivialDraiveのサンプルファイルをAndroid projectにコピーする。
  2. これらのサンプルファイルのパッケージ名をあなたのプロジェクトで使用するパッケージ名に修正する。Eclipseではパッケージ名を右クリック、Refactor > Renameのショートカットが使える。
  3. AndroidManifest.xmlファイルを開きパッケージ属性の値を使用するパッケージ名に更新する。
  4. コンパイルがうまくいくようにimport statementを要求のある通り修正する。Eclipseではエラーを出しているファイル上でCtrl+Shift+Oのショートカットが使える。
  5. サンプルをあなたのアプリケーションを作成するために修正する。デベロッパーコンソールのBase64 public license keyをあたなのMainActivity.java上でコピーすることを忘れないように。
Existing Project
  1. IInAppBillingService.aidlファイルをAndroid projectに追加。
    • Eclipseを使っていれば、/src ディレクトリーにaidlファイルをインポートする。
    • そうでない場合は、次のディレクトリを作ってaidlファイルをコピーする。 /src/com/android/vending/billing
  2. アプリをBuildして、IInAppBillingService.javaファイルが /gen ディレクトリに生成されていることを確認する。
  3. TrivialDriveサンプルの /util ディレクトリのhelperクラスをプロジェクトに追加する。あなたのプロジェクトのコンパイルがうまくいくようにパッケージ名宣言を忘れずに変更する。
これであなたのプロジェクトはIn-app Billing Version 3ライブラリーを含んでいる。


Set the Billing Permission

Google Playの課金サービスとやりとりするための権限が必要になる。マニフェストファイルに次の1行を加える。

<uses-permission android:name="com.android.vending.BILLING /">


Initiate a Connection with Google Play

アプリから課金リクエストを送るためにActivityとGoogle Playの課金サービスをバインドしなくてはならない。サンプルで与えられたクラスが課金サービスのバインドを処理するので、あなたはネットワークの接続を直接管理しなくてよい。

Google Playとの同期通信をセットアップするために、activityのonCreateメソッドのなかでIabHeplerインスタンスを作成する。コンストラクタにactivityのコンテキストとライセンスキーを渡す。

Security Recommendation:Google Playから与えたれたライセンスキーそのままをコードに組み込まないことを強く勧める。代わりに、実行時に部分文字列を組み合わせて構成したり、暗号化したものを復号してコンストラクタに渡す。これにより悪意あるサードパーティがAPKファイルからライセンスキーの文字列を変更することを難しくする。

IabHelper mHelper;

@Override
public void onCreate(Bundle savedInstanceState) {
   // ...
   String base64EncodedPublicKey;
   
   // compute your public key and store it in base64EncodedPublicKey
   mHelper = new IabHelper(this, base64EncodedPublicKey);
}

次にIabHelperインスタンスのstartSetupメソッドを呼びサービスのバインディグを実行する。メソッドにはOnIabSetupFinishedListenerのインスタンスを渡す。これはIabHelperが非同期セットアップを完了すると呼ばれる。セットアップの一環としてIabHelperはIn-app Billing Version 3 APIがGoogle Playでサポートされているかどうかチェックする。もしこのバージョンがサポートされていなかったりバインディング中にエラーが発生した場合はこのリスナーに通知がいき、エラーメッセージを含んだIabResultオブジェクトが渡される。

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
   public void onIabSetupFinished(IabResult result) {
      if (!result.isSuccess()) {
         // Oh noes, there was a problem.
         Log.d(TAG, "Problem setting up In-app Billing: " + result);
      }            
         // Hooray, IAB is fully set up!  
   }
});

セットアップが正常に完了すると、mHeplerをGoogle Play serviceとの通信に使用できる。アプリを起動したとき、ユーザーがどのアプリ内アイテムを所有しているかを調べることは良い実践である。これについては後のセクションで触れる。

important: アクティビティを終了させるときはアンバインドするのを忘れてはならない。アンバインドしないとデバイスのパフォーマンスを下げる場合がある。アンバインドしリソースを開放するには、アクティビティが終了するときにIabHelperのdisposeメソッドを呼ぶ。

@Override
public void onDestroy() {
   if (mHelper != null) mHelper.dispose();
   mHelper = null;
}

2013年1月20日日曜日

アプリ内商品の販売 Selling In-app Products

参照元(翻訳): Selling In-app Products | Android Developers

ここでは、アンドロイドのアプリ内課金についての一般的な実装方法がわかる。

Google Playのアプリ内課金を使えば、デジタルコンテンツやアプリのアップブレードに対する請求を行うことができる。in app Billing APIを使うことで簡単にアプリに課金を組み込める。Google Playに商品の詳細をリクエストしたり、アプリ内商品のオーダーを発行したり、ユーザーの購入履歴に基づいて所有情報を復帰させたりできる。また、ローカルでの価格や有効性などを問い合わせることもできる。Google Playがユーザーへの課金処理をシームレスにし、より直感的な体験をユーザーへ提供する。

ここではVersion 3 APIでの導入方法を説明する。


Lessons

アプリ内課金の準備 Preparing Your In-app Billing Application
  • サンプルアプリのダウンロード
  • デベロッパーコンソールにアプリを追加
  • アプリ内課金ライブラリーの追加
  • パーミッションの設定
  • Google Playと接続開始
販売のためのアプリ内商品の確立 Establishing In-app Billing Products for Sale
  • アプリ内商品の特定
  • アプリ内商品の詳細問い合わせ
アプリ内課金商品の購入 Purchase In-app Billing Products
  • アイテムの購入
  • 購入したアイテムの問い合わせ
  • 購入品の消費
課金アプリのテスト Testing Your In-app Billing Application
  • 静的な返答でのテスト
  • 独自商品IDでのテスト