2013年5月31日金曜日

無料のGitプライベートリポジトリが利用できる "gitBREAK"

 株式会社ビズリーチが提供しているcodebreak;(コードブレイク)にて、Gitリポジトリの無料ホスティングサービス「gitBREAK」サービスを提供開始したとの事で早速登録してみました。

codebreakサイトURL(http://www.codebreak.com/)

■すごいところ:

  • プライベートリポジトリが無料
  • プライベートリポジトリの数が無制限
  • 共有可能ユーザー数も無制限
  • サイトが日本語

無料でプライベートリポジトリが作れるサービスとしては、
Bitbucket (http://www.atlassian.com/ja/software/bitbucket/overview) 
もありますが、こちらは 無料プランだと共有できるユーザーは5人までの制限が付きます。

無料で制限なしなんて素晴らしいサービスだ!
などと浮かれて登録したら思ったよりゴールまでの道のりが長く大変でした。

注意点としては、この「gitBREAK」は "codebreak;"のサービスの一環であるということ。

codebreak;(コードブレイク) とは...
 『コードブレイクは、IT・Webエンジニアのコラボレーションを支援する、エンジニア限定のサイトです。』 (コードブレイクのページ (https://www.codebreak.com/contents/about/) より引用)
要約すると、職業としてのプログラマやシステムエンジニアなどのIT屋さん限定だとのことです。

 私はcodebreak;を利用するのが初めてなので、codebreak;のアカウント作成から行ったのですが、gitBreakのフル機能を使うには、アカウントにレジュメを入力しなければならないとのこと。
 そのレジュメを記入した上で審査され、審査通過して初めて上記の素晴らしい無制限サービスを享受できるのです。レジュメの審査には3営業日程かかるとのことですが、レジュメの審査が通らない内は以下の制限付きサービス内容で我慢するしかありません。

■レジュメ審査通過前のサービス内容

  • パブリックリポジトリ数:無制限
  • プライベートリポジトリ数:1個 -->レジュメ承認されたら無制限に
  • 使用可能容量:200MB -->審査後も変更なし。

 このレジュメ入力作業が大変です。特に職務経歴書の形式がここと違った場合、転職活動する気分でレジュメを再作成していくことになります。これがとても面倒です。

そしてここまで来て気が付きました。「容量:200MB」だということに。
足りない…。そこは無制限じゃないんだ。。。
Bitbucketは容量無制限なので気にしていなかった。

どうもこの使用可能容量を増やすためには 100MB増やす為に1人の codebreak;への招待が必要だという記述があります。(最大紹介数10人 = 100MB x 10人 = 最大1GB 増やせる。)
この招待は、した側もされた側も両方に100MB入るのとのことです。

■結論

 確かに0円でプライベートリポジトリを作成できます。ただ、Bitbucketのソレとは明らかに何か違う「無料」でした。 「0円でGitリポジトリを複数持ち、かつ大勢のユーザーと共有したい。でも公開はできない。」という場合は今のところgitBREAK一択なのではないでしょうか。しかし、いかんせん容量が小さいのがネックです。(招待できる人がいるなら別ですが。。。)

Amazon In-App Purchasing API (アプリ内課金) テスト方法

Amazon Distribution Portalの公式マニュアル(英語)は下記URL先です。
(https://developer.amazon.com/sdk/in-app-purchasing/documentation/testing-iap.html)
開発環境と動かしたいアプリが揃ったら、次は動かす環境の整備です。

Amazon SDK APIのテストについて

 Amazon In-App Purchasing API には、検証環境というものが存在しません。しかも、Amazon SDK APIを通じてAmazon Client経由で通信を行う為には、Distribution Portalを通じて公開されているアプリでなければなりません。

SDK Tester

 それじゃ公開するまでテストもできないの?そんな訳ありません。Amazonはテストの為のAmazon Clientの動きをエミュレートするアプリを用意しています。

"SDK Tester" は、Amazon SDK の開発者がアプリ公開前に本番環境を想定してテストすることができる開発ツールです。これにより開発者は、Amazon SDK APIによって生成される全てのレスポンスをカバーするテストをアプリ公開前に実行できます。Amazonは、このSDK Testerでテストして動作したコードは本番でも同じく動作することを保証しています。

 SDK Testerでは、テストユーザーの購入情報(レシート)を消したり、キャンセル処理を行うことができます。また、ユーザーを変更したり、IAP-APIのレスポンスステータスを任意に変更することができます。

SDK Tester の仕組み

 IAP-APIは、動作しているアプリがDistribution Portalで公開されているアプリかどうかを判別し、公開されていない(開発中の)アプリである場合、SDKTesterアプリへ接続します。(もちろんSDK Testerをインストールしていないとだめですが。。。)

 公開後は勝手にIAP-APIがAmazonClient側へ接続しに行ってくれるので、テスト時と本番時に設定を変えるとかの差異がなく非常に便利です。

SDK Tester のインストール

 Amazon Distribution Portal (https://developer.amazon.com/sdk.html) からダウンロードできる、Amazon SDK (Apps-SDK.zip)に含まれています。

格納されている場所は、
"<Apps-SDK.zipを解凍したディレクトリ>/Apps-SDK/InAppPurchasing/tools/AmazonSDKTester.apk"です。

この AmazonSDKTester.apk を デバイスにインストールします。
※インストールには、Android 2.3.3 (Android API Level 10) 以上の端末が必要です。
 Kindleなら第1世代からインストールできます。

Windowsならコマンドプロンプトから以下のコマンドでインストールできます。
※<Android SDKのインストールされているディレクトリ>\sdk\platform-toolsへパスを通しておいてください。

C:\>adb install -s <デバイスID> <App-SDK.zipを解凍したディレクトリ>\Apps-SDK\InAppPurchasing\tools\AmazonSDKTester.apk
デバイスIDの調べ方は、"adb devices" コマンドで接続されているデバイス、エミュレータのデバイスIDを確認することができます。

アイテムデータ定義ファイルの準備

 Distribution Portalでも課金アイテムは定義しなければなりませんが、同じくSDK Testerにも課金アイテムの定義が必要です。
SDK Testerでは、JSONファイルで課金アイテムの定義を行います。

 SDK Testerは、デバイスの "/mmt/sdcard/amazon.sdktester.json"ファイルを読み込み、その情報をもとにIAP-APIへレスポンスしてくれます。 このときJSONファイルに定義する課金アイテムの情報へ本番と同じデータを入力できるのがいいところです。

  • 定義構造

     amazon.sdktester.json の定義はJSON形式に従い、以下のような構造で行います。この時、SKUの順序は関係ありません。
    {
        SKU_1:{IAP_Item_1_Description},
        SKU_2:{IAP_Item_2_Description},
        .
        .
        .
        SKU_n:{IAP_Item_n_Description
    }
            
    上記のとおり、複数のSKUを並べて定義できます。この時、SKU定義間の "," に注意してください。尚、コンテンツタイプによって項目の定義内容は異なります。

  • 定義要素:Consumable / Entitled

     Consumable Content(消費型コンテンツ)と Entitled Content(買いきり型コンテンツ)の課金アイテム定義項目は以下のとおりです。
    {
      ...
      ”(SKU文字列)” : 
      {
        "itemType": "ENTITLED" または "CONSUMABLE", 
        "price": (金額の数字),
        "title": "(商品名称)"
        "description": "(商品説明文)",
        "smallIconUrl": "(商品画像アイコン(サムネイル)URL)"
      }
      ...
    }
            

  • 定義要素:Subscription

     期間購入(Subscription)型コンテンツのアイテム定義項目は以下のとおりです。
    {
      ...
      ”com.amazon.buttonclicker.subscription.1mo (SKU文字列)” : 
      {
        "itemType": "SUBSCRIPTION",
        "price": (金額の数字),
        "title": "(商品名称)",
        "description": "(商品説明文)",
        "smallIconUrl": "(商品画像アイコン(サムネイル)URL)",
        "subscriptionParent": "com.amazon.buttonclicker.subscription"
      }
       ...
    }
            
     定義自体はほとんど変わりません。しかし、他と大きく違うのが "subscriptionParent"(親SKU)を指定している点です。 サブスクリプションの親SKUは、サブスクリプションが何のためにあるのかを表します。そしてその親SKUに紐づく子SKUは、価格や期間を表す条件のSKUとなります。
     この紐付けを行うことで、例えば「○○新聞の定期購読」の「1か月間のサブスクリプション」を購入したのに、 「1週間のサブスクリプション」を重複して買うことを防ぐことができます。

SDK Testerの使い方

 SDKテスターのスタート画面です。真ん中の3つのボタンをタップすると、それぞれの機能の画面を表示します。


  • Active Transactions

     有効な取引情報を表示します。また、テストの為にその取引をキャンセル(返品)すること取引情報をクリアすることができます。

  • Change Logged in User

     現在ログイン中のユーザー名を表示します。またログイン中のユーザー名を変更することができます。

  • Interactive Mode Preferences

     IAP-APIからのレスポンスを任意に設定できます。



    1. Purchase API

      PurchasingManager.initiatePurchaseRequest() -> ObserverのonPurchaseResponse()へのレスポンスの設定。
      • Default:正常
      • Already Entitled:既に購入済み
      • Invalid Sku:SKUが不正
      • Failed:リクエスト失敗
    2. Purchase Updates API

      PurchasingManager.initiatePurchaseUpdatesRequest() -> ObserverのPurchaseUpdatesResponse()へのレスポンスの設定。
      • Default:正常
      • Failed:リクエスト失敗
    3. Item Data API

      PurchasingManager.initiateItemDataRequest() -> ObserverのonItemDataResponse()へのレスポンスの設定。
      • Default:正常
      • Failed:リクエスト失敗


 これでアプリ内課金処理周りのテストケース前パターンをサクサクこなすことができます。

2013年5月29日水曜日

Amazon App Store In-App Purchasing API (アプリ内課金) の実装 #2

Amazon App Store In-App Purchasing API (アプリ内課金) の実装 #1 のつづき。
#1にて BasePurchasingObserver を継承したサブクラスまで記載したので、今度は PurchasingManager を使って実際に課金を行う処理について。

Purchasing Manager

  • In-App Purchasing API と情報をやりとりする重要なクラスです。Amazon Clientおよび Amazon Platform との間のアクセスを容易にします。
  • Purchasing Managerを使用するには、 #1で示したBasePurchasingObserverクラスを継承したサブクラスをPurchasing Managerへ登録する必要があります。アプリのActivityの onStart()メソッドで登録を行うのがベターです。

PurchasingManagerには以下の5つのメソッドがあります。
  1. registerObserver(PurchasingObserver purchasingObserver)
    • BasePurchasingObserver クラスを継承したサブクラスを PurchasingManager へ登録します。
    • 通常、Activity の onStart() メソッドにて呼出します。
  2. initiateGetUserIdRequest()
    • Amazon Client に現在ログインしているユーザーのアプリ特有IDの取得リクエストを送信します。
    • 通常、Activity の onStart() メソッドにて呼出しますが、いつでも取得できます。
  3. initiatePurchaseUpdatesRequest(Offset offset)
    • オフセットレシート情報のページ区分)指定されたレシート情報を取得するリクエストを送信します。
    • ここで返されるレシート情報は、Entitled Content(買い切り型コンテンツ)及び Subscription Content(期間購入型コンテンツ)のみで、Consumable Content(消費型コンテンツ)情報は取得できません。
    • デバイス間でユーザー購入情報を同期する処理に使用できます。
  4. initiateItemDataRequest(Set skus)
    • 指定されたSKU一連のアイテムデータを取得するリクエストを送信します。
    • コンテンツタイプ全てのアイテム情報を取得できます。
  5. initiatePurchaseRequest(String sku)
    • 指定されたSKUの購入リクエストを送信します。
      ※購入リクエストを行った後 Amazon Clientによって表示される購入ダイアログで購入ボタンをタップしない限り購入されません。
    • コンテンツタイプ全てのアイテムを購入できます。

PurchasingManagerを使う準備

 各所で記述していますが、PurchasingManagerを使用してアプリ内課金関連処理を行う前に最初にPurchasingManagerに対してコールバックさせる為のObserverを登録する必要があります。
@Override
protected void onStart() {
.
.
.
    // BasePurchasingObserverを継承して作成したサブクラスのインスタンスを取得
    IapObserver iapObserver = new IapObserver (this);

    // PurchasingManagerへObserverを登録する。
    com.amazon.inapp.purchasing.PurchasingManager.registerObserver(iapObserver);
.
.
.
}

アプリ特有IDの取得

 IAP-APIの課金では、Amazon ClientにログインしているユーザーIDに対して、そのアプリで使用する課金用のユーザーIDを使って管理を行います。

処理の手順は...
  1. PurchasingManager.initiateGetUserIdRequest()でユーザーID取得リクエストを行う。
  2. ObserverのonGetUserIdResponse(GetUserIdResponse getUserIdResponse)メソッドへコールバックする。
  3. 非同期処理でレスポンスオブジェクトからリクエストのステータス、ユーザーIDを取得してアプリで永続化する。

以下に、PurchasingManagerのユーザー取得リクエストメソッドと該当するObserverのメソッドを記述します。
Observerのより具体的な処理サンプルは #1のObserverサンプルコードを参照してください。
@Override
protected void onStart() {
.
.
.
// ユーザーID取得リクエストを行う
com.amazon.inapp.purchasing.PurchasingManager.initiateGetUserIdRequest();
.
.
.
}

@Override
public void onGetUserIdResponse(GetUserIdResponse getUserIdResponse) {
    // 非同期処理でレスポンスオブジェクトを検証
    new GetUserIdAsyncTask().execute(getUserIdResponse);
}

private class GetUserIdAsyncTask extends AsyncTask
{
    // onGetUserIdResponseで取得したGetUserIdResponseを格納
    GetUserIdResponse getUserIdResponse = params[0];
    
    if (getUserIdResponse.getUserIdRequestStatus() == GetUserIdRequestStatus.SUCCESSFUL) {
        // リクエスト成功。レスポンスからユーザーID取得
        Log.d(TAG, "UserID:" + getUserIdResponse.getUserId());
        // 永続化処理
        .
        .
        .
    } else {
        // リクエスト失敗
        .
        .
        .
    }
}

アイテムの購入処理

 やっと本題のアプリ内課金の購入処理についてです。実際の購入よる課金等の処理は全てIAP-APIが行ってくれるので、アプリ側で実装する内容は、購入情報(レシート)を検証して、その課金アイテムやコンテンツ・機能を使えるようにしてあげるというというものです。
 ストアに登録する商用アプリの場合は上記の他にも、購入権利をローカルに保持して不正が無い様定期的に権限を確認させる機能やマルチユーザー対応、消費型アイテム・コンテンツの管理、デバイス間同期処理を呼ぶ...などなど様々な前後処理が必要になります。しかし、ここではシンプルに購入 → 購入成功ダイアログ表示 までの処理を説明していきます。

※尚、Amazon Developer Portalでの課金アイテムの作り方や、SDKTesterの使い方・登録するJsonファイルなどについては触れません。この辺は別の記事に書いていこうと思います。

処理の手順は...
  1. PurchasingManager.initiatePurchaseRequest("購入アイテムのSKU")でアイテム購入リクエストを行う。
  2. Amazon Clientにて購入ダイアログが表示され、ユーザーが購入ボタンをタップするとIAP-APIで課金処理が行われる。
  3. ObserverのonPurchaseResponse(PurchaseResponse purchaseResponse)メソッドへコールバックする。
  4. 非同期処理でレスポンスオブジェクトからリクエストのステータス、コンテンツタイプなどのレシート情報を検証して課金コンテンツ・機能を利用可能にする。

以下に、PurchasingManagerの購入リクエストメソッドと該当するObserverのメソッドを記述します。
Observerのより具体的な処理サンプルは #1のObserverサンプルコードを参照してください。
// アイテムの購入リクエストを送信する。このリクエスト時にはリクエストIDが返り、
// コールバック後のレスポンスオブジェクトに含まれるリクエストIDと突き合わすことにより
// どのリクエストのレスポンスなのか判断する事ができる。
String requestId = com.amazon.inapp.purchasing.PurchasingManager.initiatePurchaseRequest("購入アイテムのSKU");

@Override
public void onPurchaseResponse(PurchaseResponse purchaseResponse) {
    new PurchaseAsyncTask().execute(purchaseResponse);
}

private class PurchaseAsyncTask extends AsyncTask {
    @Override
    protected Boolean doInBackground(PurchaseResponse... params) {
        // レシート検証処理
        .
        .
        .
    }
}

 非同期処理とUIスレッドの同期については、アプリによって色々な方法があると思いますので細かく触れませんが、私はCountDownLatchで同期させたりしてました。

上記に示した通り、IAP-APIを使うのはかなり簡単です。
PlayStoreの課金処理 (IAB-API v2とか特に)を実装した人ならIAP-APIの方が楽だと思います。

2013年5月28日火曜日

Amazon App Store In-App Purchasing API (アプリ内課金) の実装 #1

AmazonSDKのIn-App Purchasingを使った実装についてメモ。

アプリ内課金の購入処理概略

 In-App Purchasing (IAP) API を使ったアプリ内課金で購入するまでの大まかな処理フローを下図にまとめました。


(※詳細な処理については省略して書いています。)

大雑把に表現するとこんな手順・処理を踏んでアプリ内でアイテムの購入処理を行います。
ここで登場するのは以下の5つです。
  • ユーザー
    アプリを使用し、課金を行う人。
  • Activity
    課金を行うアプリのActivity(画面)。ここではUIスレッドで動作しているActivity。
  • Observer
    PurchasingManagerのレスポンスを監視し、そのレスポンスに対して処理を行うクラス。
  • PurchasingManager
    In-App Purchasing APIと購入情報等のやりとりを行うクラス。
  • AmazonClient
    Amazon App Store (Client)アプリ。ユーザーID管理、Amazon Platformとの通信を行い実際の課金処理を行うためのアプリ。
    実際はIAP-APIとしてPurchasingManagerを経由して情報を受渡されていますが、ここではわかりやすい実体をもつアプリで表記します。

フローを簡単に説明しますと、、、
  1. ユーザーがアプリの画面や確認ダイアログから、アイテム購入ダイアログを表示させる。
  2. ユーザーへAmazonClientのアイテム購入ダイアログを表示させるために、PurchasingManagerにて購入リクエストを送信する。
  3. 購入リクエストをAmazonClientに送信。
  4. 購入リクエストに対して対応するアイテムの購入ダイアログがユーザーに表示され、ユーザーが購入ボタンをタップする。
  5. AmazonClientにて購入処理が行われ、その購入処理結果をObserverにてキャッチする。
  6. レシート情報が送られてくるので、レシート情報をチェック。
  7. レシート情報に従い、購入された課金コンテンツ・機能を利用可能にする。
  8. 購入処理が正常に完了した通知を受け、AmazonClientが購入完了ダイアログをユーザーへ表示して一連の処理が完了する。
主要クラス

IAP-APIの処理にて、キーとなるクラスは以下の2つです。
  • com.amazon.inapp.purchasing.PurchasingManager
    Amazon Platformへのリクエストを行うためのクラスであり、 Amazon Platformからのレスポンスを取得し下記のオブサーバへ返すクラス。
    (フロー図の "PurchasingManager"です。)
  • com.amazon.inapp.purchasing.BasePurchasingObserver
    アプリにてAmazonPlatformからのレスポンスを取得する為に、PurchasingManagerへ登録し レスポンスを監視するクラス(抽象クラス)。
    (フロー図の "Observer" はこのクラスのサブクラスです。)

また、アプリ内課金で使用するクラス、用語について以下に簡単な説明を記述します。
  • アイテム:Item (com.amazon.inapp.purchasing.Item)
    • 課金アイテムのことを表します。商品タイトル、価格、商品説明などの商品情報を含みます。
    • 価格には通貨文字が含まれ、ロケールにもとづいて適切にフォーマットされています。
  • SKU (文字列)
    • 課金アイテムを表すユニークなID。
    • Amazon Developer Portalでログインし、アプリ情報のなかの [In-App Items] メニューにて作成できます。
  • レシート:Receipt (com.amazon.inapp.purchasing.Receipt)
    • ユーザーの全ての購入情報をもつオブジェクトです。
    • 全てのレシートは、レシート検証サービスを経由してアイテムの購入を検証する為に使用できます。 このレシート情報をもとにアプリ内でコンテンツや機能へのアクセス承認を行います。
  • オフセット:Offset (com.amazon.inapp.purchasing.Offset)
    • ページに分けられたレシート情報の位置を表します。
    • オフセットの値は、Base64エンコーディングされておりそのまま見て読める形式ではありません。

ResponceReceiverの登録

 IAP-APIは、全て非同期で処理が実行されます。アプリは、ResponceReceiverクラスを経由してAmazonClientからのBroadcast Intentを受信する必要があります。
 このResponceReceiverクラスは、アプリから直接使用する必要はありません。代わりにアプリに送られてくるBroadcast Intentを受信できる定義をアプリのAndroidManifest.xmlへ定義する必要があります。以下の通り記述してください。

.
.
.

    
        
        
    

.
.
.

※表示上の都合で、<action>タグの閉じるタグを別に設けてますが、「<action... />」で構いません。

BasePurchasingObserver

 Amazon Clientからの Broadcast Intent を取得する Response Receiverの登録が終わったら、次はResponse Receiverからのコールバックを受け取るクラスが必要になります。その為に、BasePurchasingObserverクラスを継承したサブクラスを作成しPurchasingObserverインタフェースを実装してPurchasingManagerへ登録する必要があります。

※このコールバック処理はUIスレッドで実行すると長時間UIスレッドを占有してしまうので通常はAsyncTaskなどの別スレッドで処理します。

以下は、BasePurchasingObserverを継承したサブクラスのサンプルコードです。
こんな感じのクラスを作って、ここでPurchasingManagerを経由してAmazonClientにリクエストした結果を取得し処理を行います。
package com.exsample.account;

import java.util.Date;
import java.util.LinkedList;
import java.util.Map;

import android.app.Activity;
import android.os.AsyncTask;
import android.util.Log;

import com.amazon.inapp.purchasing.BasePurchasingObserver;
import com.amazon.inapp.purchasing.GetUserIdResponse;
import com.amazon.inapp.purchasing.GetUserIdResponse.GetUserIdRequestStatus;
import com.amazon.inapp.purchasing.Item;
import com.amazon.inapp.purchasing.ItemDataResponse;
import com.amazon.inapp.purchasing.Offset;
import com.amazon.inapp.purchasing.PurchaseResponse;
import com.amazon.inapp.purchasing.PurchaseUpdatesResponse;
import com.amazon.inapp.purchasing.PurchasingManager;
import com.amazon.inapp.purchasing.Receipt;
import com.amazon.inapp.purchasing.SubscriptionPeriod;

public class SamplePurchasingObserver extends BasePurchasingObserver {
    
    // ログ出力用タグ
    private final static String TAG = "SamplePurchasingObserver";
    
    // コンストラクタでインスタンス化したアクティビティを受け取り
    // BasePurchasingObserverへコンテキスト渡す.
    public SamplePurchasingObserver(final Activity activity) {
        super(activity);
    }

    //
    // ObserverがPuchasingManagerに登録された時にコールバックします。
    // (PurchasingManager.registerObserver(observer)の後)
    // 
    // @param isSandboxMode サンドボックス環境で実行されているか否か
    //   true  : Amazon Client からの応答を受信している。
    //           (Amazon Client からダウンロードされたapkである場合はこちらを返す。)
    //   false : SDK Testerからの応答を受信している。
    //           (デバッグ、テスト用apkで動かしている場合はこちらを返す。)
    //
    @Override
    public void onSdkAvailable(boolean isSandboxMode) {
        PurchasingManager.initiateGetUserIdRequest();
    }

    // 
    // ユーザーID取得要求(PurchasingManager.initiateGetUserIdRequest())
    // のレスポンスが返った時にコールバックします。
    //
    // @param getUserIdResponse ユーザーID取得要求レスポンス
    //   リクエストが成功している場合、リクエストID、リクエストステータス及び、ユーザIDを含んだ状態で返ります。
    //
    @Override
    public void onGetUserIdResponse(GetUserIdResponse getUserIdResponse) {
        new GetUserIdAsyncTask().execute(getUserIdResponse);
    }

    //
    // アイテムデータ取得要求(PurchasingManager.initiateItemDataRequest())
    // のレスポンスが返った時にコールバックします。
    //
    // @param itemDataResponse アイテムデータ取得要求レスポンス
    //   リクエストが成功している場合、購入可能/購入不可能なアイテムのセットを含んだ状態で返ります。
    //
    @Override
    public void onItemDataResponse(ItemDataResponse itemDataResponse) {
        new ItemDataAsyncTask().execute(itemDataResponse);
    }

    //
    // 購入要求(PurchasingManager.initiatePurchaseRequest())
    // のレスポンスが返った時にコールバックします。
    //
    // @param purchaseResponse 領収書を含む購入要求レスポンス
    //   リクエストが成功している場合、リクエストID、リクエストステータス、購入した領収書を含んだ状態で返ります。
    //
    @Override
    public void onPurchaseResponse(PurchaseResponse purchaseResponse) {
        new PurchaseAsyncTask().execute(purchaseResponse);
    }

    //
    // 購入情報更新要求(PurchasingManager.initiatePurchaseUpdatesRequest())
    // のレスポンスが返った時にコールバックします。
    // この呼び出しは、ユーザーが別のデバイスにアプリをダウンロードした場合や、
    // アプリケーションを初期化・削除後再インストール後などに購入情報を同期する為に使用されます。
    //
    // @param purchaseUpdatesResponse
    //   リクエストが成功している場合、
    //   リクエストID、リクエストステータス、過去購入した領収書、取り消されたSKUのセット、及び該当する場合は次のオフセットを含んだ状態で返ります。
    //
    @Override
    public void onPurchaseUpdatesResponse(PurchaseUpdatesResponse purchaseUpdatesResponse) {
        new PurchaseUpdatesAsyncTask().execute(purchaseUpdatesResponse);
    }
    
    // ユーザー情報取得レスポンスの実処理を実行するAsyncTask.
    // onGetUserIdResponse()へコールバックした後に実行。
    private class GetUserIdAsyncTask extends AsyncTask<GetUserIdResponse, Void, Boolean> {
        @Override
        protected Boolean doInBackground(GetUserIdResponse... params) {
            GetUserIdResponse getUserIdResponse = params[0];

            if (getUserIdResponse.getUserIdRequestStatus() == GetUserIdRequestStatus.SUCCESSFUL) {
                // ユーザーID取得ステータス成功時
                return true;
            } else {
                // ユーザーID取得ステータス失敗時
                Log.d(TAG, "onGetUserIdResponse: Unable to get user ID.");
                return false;
            }
        }
        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            if (result) {
                // ユーザーID取得成功時...購入状態(購入/取消)を更新する要求を開始するなどの処理を記述
            } else {
                // ユーザーID取得失敗時...エラーダイアログ表示処理など
            }
        }
    }
    
    //
    // 課金アイテム情報取得レスポンスの実処理を実行するAsyncTask
    // onItemDataResponse()へコールバックした後に実行。
    // ゲームのストアフロントでアプリ内課金アイテムを表示するときにこの情報を使用します。
    //
    private class ItemDataAsyncTask extends AsyncTask<ItemDataResponse, Void, Void> {
        @Override
        protected Void doInBackground(ItemDataResponse... params) {
            final ItemDataResponse itemDataResponse = params[0];
            
            switch (itemDataResponse.getItemDataRequestStatus()) {
            case SUCCESSFUL_WITH_UNAVAILABLE_SKUS:
                // 購入できないアイテムのSKU
                for (final String sku : itemDataResponse.getUnavailableSkus()) {
                    Log.d(TAG, "Unavailable SKU:" + sku);
                }
            case SUCCESSFUL:
                // 購入可能なアイテムのSKU
                final Map<String, Item> items = itemDataResponse.getItemData();
                for (final String key : items.keySet()) {
                    Item i = items.get(key);
                    Log.d(TAG, "Item: " + i.getTitle() + "\n " +
                               "Type: " + i.getItemType() + "\n " +
                               "SKU: " + i.getSku() + "\n " +
                               "Price: " + i.getPrice() + "\n " +
                               "Description: " + i.getDescription() + "\n");
                }
                break;
            case FAILED:
                // レスポンス失敗
                break;
            }
            return null;
        }
    }

    //
    // onPurchaseResponse()を受信した後に呼び出されます。
    // オブザーバが購入の応答を受信したときに開始され、AsyncTaskが正常に返されるとUIが更新されます。
    //
    private class PurchaseAsyncTask extends AsyncTask<PurchaseResponse, Void, Boolean> {
        @Override
        protected Boolean doInBackground(PurchaseResponse... params) {
            final PurchaseResponse purchaseResponse = params[0];
            if (!purchaseResponse.getUserId().equals("[購入リクエストを行ったユーザーID]")) {
                // カレントログインユーザIDがPurchaseレスポンスから返されたユーザIDと違う場合、
                // レスポンスに含まれるユーザーIDの購入情報を更新する。 
                // ※通常はユーザー別にオフセットの値をこどかへ永続化させておき、その値で購入情報を取得する。
                PurchasingManager.initiatePurchaseUpdatesRequest(Offset.fromString("[リクエストに含まれるユーザーのオフセット値]"));
            }

            switch (purchaseResponse.getPurchaseRequestStatus()) {
            case SUCCESSFUL:
                // 購入成功:
                // レシート情報から購入されたアイテムタイプ・レシート情報を検証し、課金アイテムを利用可能にします。
                final Receipt receipt = purchaseResponse.getReceipt();
                switch (receipt.getItemType())
                {
                case CONSUMABLE:
                    // 消費型コンテンツの場合の処理を記述
                    Log.d(TAG, "Purchasing Response Item is CONSUMABLE.\n" + "Sku=" + receipt.getSku());
                    break;
                case ENTITLED:
                    // 買い切り型コンテンツの場合の処理を記述
                    Log.d(TAG, "Purchasing Response Item is ENTITLED.\n" + "Sku=" + receipt.getSku());
                    break;
                case SUBSCRIPTION:
                    // 期間購入型コンテンツの場合の処理を記述
                    Log.d(TAG, "Purchasing Response Item is Subscription.\n" + "Sku=" + receipt.getSku());
                    break;
                default:
                    break;
                }
                return true;
            case ALREADY_ENTITLED:
                // 重複購入:
                // 顧客が既にアイテムを受け取っている場合、レシート情報は戻りません。
                // レスポンスに格納されたリクエストIDと、PurchasingManagerで購入リクエストを送信するときに返されるリクエストIDを照合することによって、
                // 購入処理が重複したのかを判断し、必要な処理を行います。
                Log.d(TAG, "レスポンスに格納されたリクエストID=" + purchaseResponse.getRequestId());
                break;
            case FAILED:
                // 購入失敗:
                // SKUの購入が無効・購入しなかったなどの場合は、FAILEDステータスが返ります。
                // アプリケーションからリクエストされたSKUとDevPortalのSKUに相違がある場合に発生することがあります。
                break;
            default:
                break;
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean success) {
            super.onPostExecute(success);
            if (success) {
                // 購入成功/重複購入時
            } else {
                // 購入:キャンセルor失敗時
            }
        }
    }

    //
    // Started when the observer receives a Purchase Updates Response Once the AsyncTask returns successfully, we'll
    // update the UI.
    // 固有ユーザIDに紐づく更新された購入情報を処理...
    // オブサーバがonPurchaseUpdatesResponseを受信したときに開始されUI(画面オブジェクト)を更新する。
    //
    private class PurchaseUpdatesAsyncTask extends AsyncTask<PurchaseUpdatesResponse, Void, Boolean> {
        @Override
        protected Boolean doInBackground(PurchaseUpdatesResponse... params) {
            final PurchaseUpdatesResponse purchaseUpdatesResponse = params[0];

            // 更新購入情報のユーザIDが一致する事を確認
            if (!(purchaseUpdatesResponse.getUserId().equals("[購入リクエストを行ったユーザーID]"))) {
                return false;
            }

            // 何らかの理由で顧客が商品を取り消された場合、これらのアイテムのSKUは失効SKUのセットに含まれます。
            // 取り消されたSKUを取得して取り消された購入情報を更新します。
            // ※注意:
            //  getRevokedSkus()は、Entitlement Content (買い切り型コンテンツ) のみに適用され、
            //  期間購入型コンテンツ(Subscription Content)には適用されない。
            for (final String sku : purchaseUpdatesResponse.getRevokedSkus()) {
                Log.d(TAG, "Revoked Sku:" + sku);
            }
            
            switch (purchaseUpdatesResponse.getPurchaseUpdatesRequestStatus()) {
            case SUCCESSFUL:
                // 最終サブスクリプション期間保持変数
                SubscriptionPeriod latestSubscriptionPeriod = null;

                // サブスクリプション格納コレクション
                final LinkedList<SubscriptionPeriod> currentSubscriptionPeriods = new LinkedList<SubscriptionPeriod>();

                // 更新購入情報の全レシートをを読んでサブスクリプションの期間を取得
                for (final Receipt receipt : purchaseUpdatesResponse.getReceipts()) {
                    // レシートのアイテムタイプを取得してアイテムタイプ別に処理を行う
                    switch (receipt.getItemType()) {
                    case ENTITLED:
                        // 売り切り型コンテンツのレシートだった場合
                        Log.d(TAG, "receipt item type is ENTITLED.");
                        break;
                    case SUBSCRIPTION:
                        // 期間購入型(サブスクリプション)コンテンツのレシートだった場合
                        // サブスクリプションの購入情報更新は、次のいずれかの方法で行うことができます:
                        // 1. レシート情報から、ユーザーが現在有効なサブスクリプションを持っているかどうかを判断する。
                        //    ...有効なサブスクリプションを探すため、レシートから終了日のないサブスクリプションがあるかどうかをチェックする。
                        // 2. レシート情報から、ユーザーのサブスクリプション購入履歴を作成する。
                        //    ...過去の有効なサブスクリプションに基づいてコンテンツをアンロックするアプリでは、顧客の購買履歴を作成する必要があります。
                        //       例) 購入者が雑誌の年間購読サブスクリプションを持っている場合、
                        //           例え顧客が現在有効なサブスクリプションを持っていなくとも、顧客は購入したときから現在も雑誌へのアクセス権を持っていることになります。
                        Log.d(TAG, "Receipt Item Type is Subscription.");
                        
                        if (receipt.getSku().equals("アプリで購入できる商品のSKU")) {
                            // サブスクリプションの期間
                            final SubscriptionPeriod subscriptionPeriod = receipt.getSubscriptionPeriod();
                            // サブスクリプション開始日時
                            final Date startDate = subscriptionPeriod.getStartDate();

                            // 最新の開始日を持つ領収書を探す。
                            // 重複するサブスクリプションがある場合は、現在のサブスクリプションコレクションに追加
                            if (latestSubscriptionPeriod == null || startDate.after(latestSubscriptionPeriod.getStartDate())) {
                                // サブスクリプションの最終日時がNUll又は、
                                // 現在のサブスクリプションの開始日時より最後のサブスクリプション期間の開始日が後の場合
                                currentSubscriptionPeriods.clear();
                                latestSubscriptionPeriod = subscriptionPeriod;
                                currentSubscriptionPeriods.add(latestSubscriptionPeriod);
                            } else if (startDate.equals(latestSubscriptionPeriod.getStartDate())) {
                                // サブスクリプションの最終日時がNullでない又は
                                // 現在のサブスクリプションの開始日時より最後のサブスクリプション期間の開始日時が前の場合
                                currentSubscriptionPeriods.add(receipt.getSubscriptionPeriod());
                            }
                        }
                        break;
                    default:
                        break;
                    }
                }

                // すべての領収書が読まれた後、最後(最新)のサブスクリプションを確認します。
                // サブスクリプション終了日が入っている場合、サブスクリプションは期限切れ(無効)です。
                if (latestSubscriptionPeriod != null) {
                    // 全サブスクリプションのコレクションからサブスクリプション期間を取得
                    for (SubscriptionPeriod subscriptionPeriod : currentSubscriptionPeriods) {
                        if (subscriptionPeriod.getEndDate() != null) {
                            // サブスクリプション期間の終了日がある場合、
                            // そのサブスクリプションは有効ではないと判断し、課金アイテムをロックする処理を入れる。
                            break;
                        }
                    }
                }

                // レシートのオフセット永続化処理
                final Offset newOffset = purchaseUpdatesResponse.getOffset();
                // どこかへ保存...
                
                if (purchaseUpdatesResponse.isMore()) {
                    // レシート情報がまだあある場合
                    Log.d(TAG, "Initiating Another Purchase Updates with offset: " + newOffset.toString());

                    // 現在のオフセットを指定してさらに購入状態(購入/取消)情報を更新する要求を開始。
                    // onPurchaseUpdatesResponse(PurchaseUpdatesResponse) にコールバックします。
                    PurchasingManager.initiatePurchaseUpdatesRequest(newOffset);
                }
                return true;
            case FAILED:
                // 購入情報の取得に失敗した場合。
                return false;
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean result)
        {
            super.onPostExecute(result);
            // レスポンスに含まれるリクエストIDや処理結果をもとに処理記述
        }
    }
}

長くなってきたので続きは #2 で。

2013年5月27日月曜日

Amazon App Store In-App Purchasing API (アプリ内課金) 説明

 以前、Amazon app storeにアプリ内課金(サブスクリプション)を実装したアプリを提供した。
その時、Amazon SDKにおける In-App Purchasing APIを使用してアプリ内課金処理を実装したのでその仕組みのメモ。

Amazon App Store

 PC、KindleやAndroidスマートフォン/タブレット向けのアプリマーケット。
(Amazon版 Play Store的なもの)
ユーザーはいつものAmazonアカウントで、いつものお買い物と同じようにアプリやコンテンツを購入することが可能。アプリ提供の他、おすすめ機能、カスタマーレビュー、1-Click決済を含むAmazon同等のショッピング機能が用意されている。
Androidデバイスでこのサービスを利用する為には、Amazon App Store(Client)アプリ(Googleでいうところの Play Storeアプリ的なもの)が必要。

課金の概要

 Amazon App Storeでは、アプリの中からゲーム内通貨、拡張パック、アップグレード、雑誌の購入などをできるようにする仕組みとして、IAP (In-App Purchasing) APIを公開しています。
(AmazonSDKとしてJARライブラリとして公開されており、ポータルサイトからダウンロードできます。)
IAP APIを利用するとデジタルコンテンツやサブスクリプション(定期購読などのこと)をアプリ内で販売することが可能になります。

課金の仕組み

  1. Amazon App Store (Client) と Amazon Service
     Kindle, Androidデバイスにおける Amazon App Storeの課金は、amazon app clientアプリが Amazonのサーバーへ3G/Wi-Fi回線を使用してリクエストを行い、領収書(レシート)を取得してアプリへ返すことで実現しています。

  2. Amazon Clientが担う機能
    • アプリ側で実装しなければならない機能
      1. ユーザーが購入できるようにアプリ内のアイテムのカタログを提示する。
      2. 購入されたアイテム・コンテンツのロック解除。
      3. 購入された消耗アイテムのトラッキング。
      4. 購入したデジタルコンテンツの使用。
    • Amazon App Store (Client)側で行われる機能
      1. 購入手順の管理。
      2. 支払処理の実施。
      3. 決済のセキュリティを含め、Amazon Platformとのセキュアな通信を行う。
      4. 資格を確認し、購入した領収書を検証する。
      5. サブスクリプションの自動更新や取り消しを含む管理を行う。
  3. コンテンツの販売方法
    1. ローカルコンテンツのロック解除方式
    2. リモートコンテンツのダウンロード方式
  4. SKU (technically a stock-keeping unit)
    • 購入可能なアイテムのユニーク(一意)識別子。
    • amazon Distribution Portalの開発者アカウント内で一意である必要がる。
    • ユーザが購入する直接のアイテム定義である。
購入可能なアイテム

Amazon App Storeで購入可能なアイテムは3種類。
  1. Consumable Content(消費型コンテンツ)
    使用に資格やアクセス権を必要とせず、何度でも購入可能。
    そのデバイスでのみ利用可能なコンテンツ。
  2. Entitled Content(買いきり型コンテンツ)
    使用する権利やアクセス権を必要とするコンテンツ。
    1度だけ購入しユーザアカウントが登録されている全ての互換性のあるデバイスで使用することができる。
  3. Subscription Content(期間購入型コンテンツ)
    一定の期間、資格やアクセス権を必要とするコンテンツ。 一定の期間その権利を持ち、自動で更新される。購入したユーザアカウントが登録されている全ての互換性のあるデバイスで使用することができる。
※名称等が若干違う場合があります。

処理のフローや実装、API(PurchasingManagerやBasePurchasingObserver)の詳細はまた別の記事で記載していきたいと思います。
記事内容に誤り等がありましたらご指摘願います。

2013年5月25日土曜日

Amazon AppStore アプリ内課金の実装--準備

はじめる前に

 In-App Purchasing API は、Amazon Mobile App SDKパッケージの一部として利用可能です。 これは、Androidアプリケーションプロジェクトに含めることができるJARライブラリとして提供されています。

 In-App PurchasingのJARライブラリは任意のIDEで利用可能ですが、ここではEclipseを使用して説明しています。 この作業を行う前に、Android開発環境が構築されている必要があります。また、この説明ではIn-App Purchasingを実装する対象となるAndroidアプリケーションプロジェクトが作成されていることを想定しています。作成されていない場合は作成してから作業を行ってください。

App-SDKをダウンロードして展開する

  1. [Apps-SDK.zip] ファイルを Amazon mobile app distribution Portal よりダウンロードしてください。 (https://developer.amazon.com/sdk/download/in-app-purchasing.html)
  2. ダウンロードした [Apps-SDK.zip] ファイルを解凍し、わりやすい場所へ置いてください。
    (※このディレクトリはプロジェクトから参照するようにするため後々移動しなくてよい場所へ配置してください。)

In-App Purchasing JARライブラリをクラスパスに追加する

  1. 追加するプロジェクトのルートフォルダを選択し、コンテキストメニューから [プロパティ] を選択します。
  2. プロパティウィンドウの左ツリーより、[Javaのビルドパス]を選択。
  3. 上部の[ライブラリ] タブをクリック。
  4. 右側の [外部 JAR 追加] ボタンをクリック。
  5. "JAR の選択"ダイアログで、/InAppPurchasing/lib/in-app-purchasing-1.0.3.jarを選択し [開く] ボタンをクリック。
  6. ビルドパスに "in-app-purchasing-1.0.3.jar" が追加されたことを確認して [OK] ボタンでプロパティウィンドウを閉じます。

In-App Purchasing APIリファレンスを追加する

  1. 追加するプロジェクトのルートフォルダを選択し、コンテキストメニューから [プロパティ] を選択します。
  2. プロパティウィンドウの左ツリーより、[Javaのビルドパス]を選択。
  3. 上部の[ライブラリ] タブをクリック。
  4. 先の手順で追加した、"in-app-purchasing-1.0.3.jar" の左側▲をクリックして詳細を表示させる。
  5. [Javadoc ロケーション: (なし)]をダブルクリックまたは、選択して右側の[編集]ボタンをクリック。
  6. "’in-app-purchasing-1.0.3.jar' の Javadoc" ウィンドウで、 Javadoc URLラジオボタンを選択し、Javadoc ロケーション・パスに "/InAppPurchasing/documentation/API-Reference" を指定する。
  7. [in-app-purchasing-1.0.3.jar] の Javadoc ロケーションが変更されたことを確認して、[プロパティ]ウィンドウを [OK]ボタンで閉じる。
これでプロジェクト内でアプリ内課金関連のパッケージのリファレンスがEclipse上で直接見れるようになります。

2013年5月24日金曜日

Amazon Kindle Fire アプリケーション開発環境構築-Kindle Fire SDK Add-on インストール

Kindle Fire SDK Add-on インストール手順

公式ガイドはこちら... https://developer.amazon.com/sdk/fire/setup.html

はじめに

 Kindle用モバイルアプリケーションを作成するためには、Androidアプリケーション開発環境が必要です。 以下の必要なソフトウェアをインストールし、Android開発環境を構築してください。
  • Java Development Kit version 6 (JDK6)
  • Android SDK
  • Eclipse (Java)
  • Eclipse用のAndroid Developer Tools (ADT)
 ※この記事ではAndroid開発環境構築については詳しく触れません。

 新しいKindle FireとKindle Fire HD Tabletのアプリケーションを開発するために、Android SDK 4.0.3 (API 15)をインストールする必要があります。また、Kindle Fire (第1世代)の開発には、Android SDK 2.3.3 (API 10)をインストールする必要があります。

Kindle Fire SDK Add-on サイトの登録

  1. Android SDK Managerを起動する.
    • ADTインストール済みのEclipseから起動する場合
      メニューの [ウィンドウ] -> [Android SDK マネージャー]を選択する。
      (PleadesでEclipseを日本語化している前提です。)
    • コマンドを実行して起動する場合
      <Android SDK インストールディレクトリ>/tools/android を実行する。
  2. Android SDK Managerのメニューから
    [Tools] -> [Manage Add-on Sites...]を選択する。
  3. Android SDK Manager - Add-on Sitesウィンドウが開いたら、[User Defined Sites]タグを選択し、右側の[New...]ボタンを押す。Add-on Site URL入力ダイアログが表示されるので以下のURLを入力し [OK]ボタンを押す。
    http://kindle-sdk.s3.amazonaws.com/addon.xml
    
  4. Add-on Siteを登録したら、Android SDK Manager - Add-on Sitesウィンドウを [Close]ボタンで閉じる。 閉じると同時にAndroid SDK Managerの表示が更新される。
Kindle Fire SDK Add-on のインストール

  1. 以下のパッケージの最新リビジョンをインストールします。パッケージ名の横にあるチェックボックスにチェックをつけてインストール対象に含めてください。
    • Tools
      • Android SDK Tools
      • Android SDK Platform-tools
    • Android 4.0.3 (API 15)
      • SDK Platform
      • ARM EABI v7a System Image
      • Intel x86 Atom System Image
      • Kindle Fire (2nd Generation)
      • Kindle Fire HD 7"
      • Kindle Fire HD 8.9"
    • Android 2.3.3 (API 10)
      • SDK Platform
      • Kindle Fire
    • Extras
      • Kindle Fire Device Definitions
      • Kindle Fire USB Driver(OSXの場合は不要)
      • Android Support Library
      • Intel x86 Emulator Accelerator (HAXM)
  2. パッケージの選択が完了したら、Android SDK Managerの右下にある
    [Install n packages...] ボタンを押してインストールを開始してください。
    ("n" は選択したパッケージ数です。)
  3. Choose Packages to Installダイアログが表示されます。
    インストールするすべてのパッケージのライセンスを確認し、AcceptまたはAccept Licenseラジオボタンを選択して同意してください。インストールするすべてのパッケージのライセンスに同意したら [Install]ボタンを押してインストールを実行します。
  4. インストールには時間がかかる場合があります。インストール完了後、Eclipseを再起動すれば作業完了です。お疲れ様でした!

bloggerへのSyntaxHighlighter導入と表示パラメータ調査メモ

Syntax Highlighterとは

調べものでWebを徘徊している時によく見る、
Blog記事上に綺麗にソースコードを表示する機能を持つJavaScript。


このBlogにもソースコードを載せていきたいので導入した時の調査メモ。

導入方法

  1. Syntax Highlighterを導入する
    Syntax Highlighter Scripts Generatorサイト
    (http://www.way2blogging.org/widget-generators/syntax-highlighter-scripts-generator)
     にて表示させたいテーマと強調表示させたい言語を選択し「Generate」ボタンをクリック。
  2. bloggerのテンプレートへ生成されたリンク・スクリプトをコピペする
    ページ下部に生成された定義が表示されるので、クリップボードへコピーしてBloggerのテンプレートのヘッダーへペースト。
    表示テーマのカスタムをしない場合はこれだけで準備完了!

使い方

  • <pre></pre>で囲った部分がソースコード表示される。 
  • <pre>タグのパラメータを指定することで表示方法を制御できる。
  • HTML編集で以下の様に記述する...
  • <pre class="brush: (強調させたい言語); (パラメータ)...>
        表示するソースコード
    </pre>
    

ソースコードの表示例(Java)

    public class Hoge{
        public static void main (String[] args) {
            ;
        }
    }
    
    この時の記述は以下のとおり。
    class="brush: xxxxx"を強調表示したい言語に置き換えて使用する。
    <pre class="brush: java">
    
    当たり前の話だが、ここで指定する言語指定は最初の定義生成時に選択してbloggerのテンプレートヘッダーに定義されている必要がある。

    ここで表示しているプレーンテキストの場合は以下の通り定義することで強調表示のない表示ができる。
    <pre class="brush: plain">
    

表示を制御するパラメータ

  • auto-links (true/false *default=true)
    投稿コード内の全てのURLをクリック可能なリンクにする。
    /*
     * auto-links: true でURL表示
     * http://devwalker.blogspot.jp
     */
    public class Hoge{
        String url = "http://devwalker.blogspot.jp";
    }
    
  • class-name
    highlighterエレメントにカスタムクラス(スタイル)を指定することができる。
    public class Hoge{
        ;
    }
    
  • collapse (true/false *default=false)
    trueの場合、コードボックスが折り畳まれる。
    /*
     * collapse=trueの場合の表示
     */
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
            // code
        }
    }
    
    titleパラメータと併用すると便利。
    /*
     * collapse=trueの場合の表示
     */
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
            // code
        }
    }
    
  • first-line (数字 *default=1)
    コードの左側に表示される行番号の開始番号を指定する。
    /*
     * 開始行番号を20に指定(first-line: 20)
     */
    public class TestClazz {
        public static void main(String[] args) {
            // code
        }
    }
    
  • gutter (true/false *default=true)
    行番号の表示/非表示設定。
    falseの場合、コードの左側に表示される行番号が非表示になる。
    public class TestClazz {
        public static void main(String[] args) {
            // code
        }
    }
    
  • highlight (数字。複数指定時の場合は[x,x,...]で指定)
    強調表示したいコードの行番号を指定することができる。
    first-lineパラメータで開始行番号を変更した場合は、その変更後の行番号を指定する必要がある。
    /*
     * highlight ="[5, 7]"を指定して強調表示
     */
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
            // code
        }
    }
    
    /*
     * first-line: 21 を指定した場合、highlightオプションも
     * firstlineオプションに指定した開始行番号に基づき指定を変更する。
     * ※highlight: [27, 29]
     */
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
            // code
        }
    }
    
  • html-script (true/false *default=false)
    trueの場合、コード内の任意のHTML/XMLが強調表示される。
    HTMLにPHPなどを混合している場合の表示に便利。特定の言語で動作します。
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>title</title>
    </head>
    <body>
        <script language="JavaScript">
        document.write("...");
        </script>
    </body>
    </html>
    
  • smart-tabs (true/false *default=true)
    スマートタブ機能の有効/無効を指定できる。けどイマイチ違いが良くわかりません。
    タブによる表示のズレを抑えてtab-sizeと同じ半角文字数幅に抑える機能でしょうか?

    smart-tabs:true
    public class Sample {
    12    hello  ya!
    }
    
    smart-tabs:false
    public class Sample {
    12    hello  ya!
    }
    
  • tab-size (数字 *default=4)
    コードボックスのタブサイズを指定できる。
    public class Sample {
     // tab-size:12 を指定するとタブが半角12文字分の扱いとなる
    }
    
  • toolbar (true/false *default=true)
    コードボックスのツールバーの表示/非表示を指定できる。(右上に表示される?ボタン)
    public class Sample {
        //
    }
    
  • title (文字列)
    コードボックスにタイトルを指定できます。
    // title: 'サンプルタイトル'
    public class Sample {
        //
    }
    
  • light (true/false *Default="false")
    trueの場合、行番号とツールバーが非表示になる。1・2行のコードを表示する時に便利。
    // 1・2行だけなら便利かも
    public final static String API_KEY_VALUE = "hogehoge";
    
  • pad-line-numbers (true/false/数字 *Default="false")
    行番号の番号0埋めを指定できるパラメータ。
    true=自動--表示行数に応じて行番号の0埋めをしてくれる。
    false=無効--行番号の0埋めをしない。
    数字=0埋めする桁数を指定。
    // pad-line-numbers: true
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
        /*
         * 表示行数が2桁なので
         * 0埋めされて行番号が表示される。
         */
        }
    }
    
    // pad-line-numbers: false (Default)
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
        /*
         * 行番号が2桁だが、
         * 行番号の0埋め表示はされない。
         */
        }
    }
    
    // pad-line-numbers: 4
    public class TestClazz {
        private final static String HOGE = "hoge";
        public static void main(String[] args) {
            /*
             * 指定した桁数で
             * 行番号が0埋め表示される。
             */
        }
    }
    
  • quick-code (true/false *Default="true")
    クイックコードコピー機能の有効/無効を設定します。
    あまりよくわかりません。。。
    // quick-code: false
    public class TestClazz {
        private final static String HOGE = "hoge";
    }
    

SyntaxHighlighterのコードより調査...