ラベル SDK の投稿を表示しています。 すべての投稿を表示
ラベル SDK の投稿を表示しています。 すべての投稿を表示

2010年12月22日水曜日



f:id:bs-android:20101221182358p:image


このトピックは「Google Analytics SDK for Android」と「Android Developer’sのブログ記事」を参考にしています。


SDKの概要


Google Analytics SDK for Androidは、Google Analytics for Mobile Apps SDKの一つで、モバイルアプリの操作を追跡し、それをGoogle Analyticsへレポートするインタフェースを提供します。SDKを利用すると主に下記のものが測定可能です。




  • 訪問者数

  • セッションの滞在時間

  • バウンスレート(直帰率:ウェブサイトを訪問し、サイト内をじっくり閲覧せずに離れた訪問者の割合のこと)

  • ユニーク訪問者数


モバイルアプリケーションの追跡は、Webサイトのページの追跡モデルに対して、若干の構造的な違いがあります。SDKはウェブサイトの訪問者を追跡し、Webページのウィジェットとやりとりを行うモデルを使用しています。したがって、以下で使用される用語は従来のウェブサイトの追跡モデルを、モバイルアプリケーションの追跡として置き換えたものとなります。


このSDKがどのように機能するかを理解するため、Analyticsで追跡する方法に詳しくなるべきです。Analyticsとやりとりするアプリを作るには、以下のモバイル追跡SDKを使用してください:


ページビュー追跡

ページビューは、伝統的なWebサイトのトラフィック量を図る標準的な指標です。モバイルアプリはHTMLページを含んでいないので、ページビューのリクエストを「いつ」「どれくらい」発生させるかを決定する必要があります。また、ページビューのリクエストはディレクトリの構造に基づいたレポートとして設計されています。そのため、Analyticsのコンテンツレポート中の、ページのパス名を使用するため、明示的な要求用の名前を用意する必要があります。選択された名前は実際のHTMLのページがなくとも、ページパスとしてAnalyticsのレポート中に設定されます。


イベント追跡

Analyticsでは、イベントはページビューのリクエストから、ユーザーのウェブページの要素とのやりとりを明確に追跡するように設計されています。Google Analyticsのイベント追跡機能を利用して、Analyticsのレポートインタフェースのイベント追跡セクション中にレポートされる呼び出しを、追加で利用できます。イベントはカテゴリを利用してグループ化され、また、イベント毎のラベルも利用でき柔軟性の高いレポートを提供します。例えば、マルチメディアのアプリはビデオのカテゴリとビデオ名毎のラベルに対して、再生/停止/一時停止を行う事ができます。Google Analyticsレポートはビデオのカテゴリにタグ付けされた全てのイベントを収集します。イベント追跡の情報については、イベントトラッキングガイドを参照して下さい。


カスタム変数

カスタム変数は名前と値のペアのタグで、Google Analyticsの追跡を強化するために追跡コード中に挿入することができます。使用方法に関する情報は、カスタム変数ガイドを参照して下さい。




はじめよう


システム要件

Google Analyticsの追跡システムにAndroidアプリを統合するには、以下のものが必要です:




セットアップ



  • libGoogleAnalytics.jar をプロジェクトの /libs ディレクトリに追加します。

  • プロジェクトのAndroidManifest.xmlに以下のパーミッションを追加します:


    • <uses-permission android:name="android.permission.INTERNET" />

    • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />




SDKに含まれているサンプルのアプリケーションは、セットアップが成功したらプロジェクトがどのような構成となっているべきかを示すものとなっています。Analyticsが統合された自身のアプリのテンプレートとして、自由に利用しても構いません。


SDKを利用する


SDKを利用する前に、www.google.com/analyticsでフリーのアカウントを最初に取得し、適当な(偽の)WebサイトのURL(例:http://mymobileapp.mywebsite.com)を使ったアカウントに、Webサイトプロフィールを作成しなければなりません。プロフィールを生成したら、WebプロパティIDを書き写すかコピーを保管してください。



WebプロパティIDはまた、追跡コードである「UAナンバー」として知られており「UA-xxxxx-yy」のような形式となっています。xとyは各プロフィールのユニークな番号を示します。追跡オブジェクトをインスタンス化する際はWebプロパティIDを明示する必要があります。詳しくはWebプロパティを御覧ください。



SDKの使用の際には、ユーザに対して、アプリケーション自身や利用規約で、匿名でアプリケーション中のユーザの活動を追跡し、レポートする権利を有していることを示す必要があります。さらに、Google Analytics SDKの使用に関して、アカウントのサインアップ時にGoogle Analytics利用規約に同意する必要があります。


追跡を開始する

GoogleAnalyticsTracker.getInstance()をコールして、シングルトンのトラッカーを取得します。startメソッドをコールすると、WebプロパティIDが渡されて、アクティビティの追跡が開始されます。アクティビティのonCreateメソッド中で直接このメソッドをコールすると良いでしょう。例:



package com.google.android.apps.analytics.sample;

import com.google.android.apps.analytics.GoogleAnalyticsTracker;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class TestActivity extends Activity {

GoogleAnalyticsTracker tracker;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

tracker = GoogleAnalyticsTracker.getInstance();

// 手動のディスパッチモードで追跡を開始する...
tracker.start("UA-YOUR-ACCOUNT-HERE", this);

// あるいは、ディスパッチ間隔(秒)で指定して追跡を開始することも可能
//tracker.start("UA-YOUR-ACCOUNT-HERE", 20, this);

setContentView(R.layout.main);
Button createEventButton = (Button)findViewById(R.id.NewEventButton);
createEventButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tracker.trackEvent(
"Clicks", // カテゴリ
"Button", // アクション
"clicked", // ラベル
77); // 値
}
});

Button createPageButton = (Button)findViewById(R.id.NewPageButton);
createPageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// "Medium"名、"MobileApp"の値、セッションレベルのスコープで、このページビューにカスタム変数を追加する
// パラメータは順に、「Index (1~5)」「名前」「値」「スコープ」
// スコープの定義:訪問者=1, セッション=2, ページ=3(デフォルト)
tracker.setCustomVar(1, "Navigation Type", "Button click", 2);

// ページビューを追跡します。これはおそらく、アプリケーションを追跡する方法として良い方法でよく使われるでしょう。
// 例えば、
// tracker.trackPageView("/help");      > ヘルプ画面を誰が見たか追跡する
// tracker.trackPageView("/level2");     > 誰がゲームのレベル2に達したかを追跡する
// tracker.trackPageView("/uploadScreen"); > 誰がアップロード画面を利用したかを追跡する
tracker.trackPageView("/testApplicationHomeScreen");
}
});

Button quitButton = (Button)findViewById(R.id.QuitButton);
quitButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});

Button dispatchButton = (Button)findViewById(R.id.DispatchButton);
dispatchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 手動でディスパッチを開始する。一定間隔でディスパッチする方法で開始した場合は不要。
tracker.dispatch();
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// これ以上必要のない追跡を停止する
tracker.stop();
}
}


カスタム変数のスコープの定義

カスタム変数に定義できるスコープは次の3種類が存在します。




  • 訪問者スコープ(=1):端末でアプリケーションが最初に動作する時のみ呼び出します。同じインデックスでカスタム変数を生成、または、最初の変数を上書きしてはいけません。どのバージョンのアプリが使用されたか、どの種類の電話か、ライトとフルバージョンのアプリとの比較、または、アプリケーションのインストールから全く変化しない何らかのデータを送信するのに便利です。

  • セッションスコープ(=2):アクティビティが開始する毎に1度だけ呼び出します。同じインデックスで異なるカスタム変数を生成しない場合、アクティビティのライフサイクル中の全てのページビューやイベントに対して適用されます。

  • ページスコープ(=3):trackEventやtrackPageViewの直前にカスタム変数を適用する必要がある場合に呼び出します。メソッドが呼び出される度に動作します。スコープが指定されていない場合、これがデフォルトになります。


ページビューとイベントの追跡

ページビューの追跡は簡単です:ページビューを起動したい時に都度トラッカーオブジェクトの trackPageView をコールするだけです。イベントを記録するためには trackEvent をコールします。ページビューとイベントの詳細は、上記のSDKの概要を参照して下さい。


カスタム変数を利用する

カスタム変数の追加もまた簡単です:モバイルSDKによって提供される setCustomVar メソッドを利用するだけです。それぞれのカスタム変数のインデックスがどのようにマッピングされるかを前もって計画するだけで、既に存在する変数の上書きはしません。


カスタム変数の詳細な情報は、カスタム変数ガイドを参照して下さい。setCustomVar メソッドは直接、自身のデータをAnalyticsに送らないことに注意して下さい。次のページビューまたはイベント発生時に併せて送信されます(ピギーバックと呼ばれる方式です)。次の送信までの間はローカルのSQLITEデータベースに追跡情報が保存されます。ページビューやイベントの追跡前に setCustomVar をコールする必要があります。


バッチ処理で統計情報をアップロードする

接続が維持され続ける事やバッテリーの過負荷を防ぐため、追跡のリクエストをバッチ処理することをお勧めします。バッチリクエストを行いたければいつでも、追跡オブジェクトの dispatch メソッドをコールすることができ、手動でも一定間隔毎でもどちらでも実行することができます。



Tip: アプリケーション内で発生する他のHTTPリクエストにトラッカーをバンドルし、ディスパッチすることで、オーバーヘッドを低減することができます。



既知の不具合

不正確なタイムスタンプの可能性:タイムスタンプは Google Analyticsへアプリケーションからディスパッチされた時点で記録されますので、ユーザが長期間に渡りオフラインであった場合、タイムスタンプは100%正確ではないかもしれません。


リファラーの追跡


Android 1.6のOSリリースで、Androidマーケットへのダウンロードリンク中の、URLパラメータのリファラーがサポートされました。アプリケーション向けGoogle Analytics中の参照/キャンペーン情報を自動的に保持するため、Google Analytics SDK for Androidはこのパラメータを使用します。これは、(例えば、アプリの特定広告の有効性を測るといった場合に役立つような)ページビューやイベントを記録し関連付けるために、アプリケーションのソースをインストールすることを可能にします。



警告:アプリケーション中に生存する間はリファラーが残り続けるため、このリファラー操作は従来の訪問レベルのリファラーとは異なります。Androidでのリファラーのセットアップについては、原文のAndroidマーケットのリファラー追跡を御覧ください。



追跡を動作させるため、プロジェクトのAndroidManifest.xmlに、以下のブロードキャストレシーバを追加する必要があります。




<receiver android:name="com.google.android.apps.analytics.AnalyticsReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>


Androidマーケットのリファラー追跡

Androidマーケットを通じてGoogle Analyticsのリファラー追跡をセットアップするには、リファラーリンクを生成するURLビルダーを利用します。Analytics SDKは自動的にリファラー情報をパースして記録し、Analyticsのレポートとして公開します。リファラーリンクを生成するには、下記のフィールドを埋めてください。*1


パッケージ名、キャンペーンソース、キャンペーンミディアムとキャンペーン名は必須です。それぞれのパラメータの詳細な説明は、下記のテーブルを参照して下さい。


リファラーリンクパラメータ







































パラメータ必須説明
utm_sourceキャンペーンソース:サーチエンジン、ニュースレター、その他のソースの特定に使用します。utm_source=google
utm_mediumキャンペーン媒体:eメールやコストパークリック(cpc)のような媒体の特定に使用します。utm_medium=cpc
utm_termキャンペーン用語:広告のために提供するキーワードを有料の検索で使用します。utm_term=running+shoes
utm_contentキャンペーンのコンテンツ:A/Bテストや、同じURLが指定された異なる広告やリンクのための、コンテンツをターゲットとした広告に使用します。 utm_content=logolink
utm_content=textlink
utm_campaignキャンペーン名:特別な製品プロモーションや戦略的なキャンペーンを特定するために、キーワードの解析に使用されます。utm_campaign=spring_sale


アプリケーションのリファラー情報を渡すためのマーケットへのリンクは、下記の通りです:


http://market.android.com/search?q=pname:<package>&referrer=<referral>


<package>はアプリケーションのパッケージ名、<referral>はAnalyticsのキャンペーン情報のリストをエンコードしたURLです。URLを生成するツールが下記にあります。


http://code.google.com/mobile/analytics/docs/android/#android-market-tracking


利用シーンの例


Androidに特徴的な例をあげると、ユーザーがフルバージョンのアプリを持っているかどうかに依存するステータス、"Full"または"Lite"の状態を有する"アプリケーションタイプ(AppType)"が挙げられるでしょう。AnalyticsのWebインタフェースを使って、"Lite"ユーザだけを確認したり、特定のバージョンがどの位使用されているかを見たり、"Lite"と"Full"セグメントとの違いを見ることができるでしょう。


利用規約を守る――個人情報は追跡してはならない!


Google Analyticsはそれ自身の利用規約に基づいているため、それらを読み、守ることは非常に重要です。特にAndroidアプリケーションの中にこれらの情報は存在するため、Analyticsサーバに個人を特定できる情報を送信してはいけません。つまり、訪問者レベルのカスタム変数に「電話番号」「名前」「eメールアドレス」を含む事はできないということです。直感的ではないですが、しかしながらこれは重要で、アプリケーションがWebアプリケーションのクライアントであれば(例えば、CRMやショッピングサイト)、Analyticsに店舗の情報(ユーザIDやトランザクションIDといった、Webバックエンドに格納される個人が特定できるものと結合可能な情報)を格納できないことを意味します。


実行結果


今回はSDKに付属するサンプルアプリを使用しました。


事前にGoogle Analyticsのアカウントを作成

f:id:bs-android:20101221174445p:image


Google Analyticsのサイトに移動し、適当なURLとアカウントを入力。URLとアカウントは実在しないドメインでも良いです。





f:id:bs-android:20101221174446p:image


連絡先情報を入力(誰が連絡してくるのだろう・・・)





f:id:bs-android:20101221174447p:image


利用規約を読んで同意するにチェック。この規約はSDKを利用するアプリにも適用されます。





f:id:bs-android:20101221174448p:image


Web用のコードスニペットが表示されるので、そこに記載されている「UA-XXXXX-Y」の文字列を保存しておく。





SDKを搭載したアプリを操作する

f:id:bs-android:20101221173337p:image


アプリ自体は至ってシンプルです。ボタンクリックによって、ページビューやイベントの追跡が発生します。





Google Analytics上のレポート例



  • レポートは初めて追跡を開始してから数時間(最大24時間)を経過しなければ表示されません。


f:id:bs-android:20101221174444p:image


f:id:bs-android:20101222004309p:image


f:id:bs-android:20101222004310p:image


f:id:bs-android:20101222004311p:image


このように、アプリから送信されたページビューやイベントの追跡情報が、Google Analyticsに表示されます。カテゴリ毎、ラベル毎、アクション毎など、様々な切り口から分析することができます。


まとめ


AndroidとGoogle Analyticsを使用すると、上記のように様々なユーザの操作などを情報を追跡する事ができます。このあたりの連携はさすがGoogle、といったところでしょうか。これらの追跡情報から、ユーザにとって使いやすいUIの配置を理論的に検討することもできるでしょう。


しかしながら、使い方によっては、ユーザーにとって知られたくない情報も収集されてしまう可能性もありますので、やはりアプリケーション内でこのSDKを使用している場合は、インストール時などにユーザーに対して情報を追跡している旨を伝え、事前の承諾を得る形で使用するべきでしょう(いわゆる、"オプトイン"方式)。



文責:技術部 植物工場研究G 瀬戸 直喜






Google Analytics SDK for Androidでユーザーのアプリ操作を追跡する



f:id:bs-android:20101221182358p:image


このトピックは「Google Analytics SDK for Android」と「Android Developer’sのブログ記事」を参考にしています。


SDKの概要


Google Analytics SDK for Androidは、Google Analytics for Mobile Apps SDKの一つで、モバイルアプリの操作を追跡し、それをGoogle Analyticsへレポートするインタフェースを提供します。SDKを利用すると主に下記のものが測定可能です。




  • 訪問者数

  • セッションの滞在時間

  • バウンスレート(直帰率:ウェブサイトを訪問し、サイト内をじっくり閲覧せずに離れた訪問者の割合のこと)

  • ユニーク訪問者数


モバイルアプリケーションの追跡は、Webサイトのページの追跡モデルに対して、若干の構造的な違いがあります。SDKはウェブサイトの訪問者を追跡し、Webページのウィジェットとやりとりを行うモデルを使用しています。したがって、以下で使用される用語は従来のウェブサイトの追跡モデルを、モバイルアプリケーションの追跡として置き換えたものとなります。


このSDKがどのように機能するかを理解するため、Analyticsで追跡する方法に詳しくなるべきです。Analyticsとやりとりするアプリを作るには、以下のモバイル追跡SDKを使用してください:


ページビュー追跡

ページビューは、伝統的なWebサイトのトラフィック量を図る標準的な指標です。モバイルアプリはHTMLページを含んでいないので、ページビューのリクエストを「いつ」「どれくらい」発生させるかを決定する必要があります。また、ページビューのリクエストはディレクトリの構造に基づいたレポートとして設計されています。そのため、Analyticsのコンテンツレポート中の、ページのパス名を使用するため、明示的な要求用の名前を用意する必要があります。選択された名前は実際のHTMLのページがなくとも、ページパスとしてAnalyticsのレポート中に設定されます。


イベント追跡

Analyticsでは、イベントはページビューのリクエストから、ユーザーのウェブページの要素とのやりとりを明確に追跡するように設計されています。Google Analyticsのイベント追跡機能を利用して、Analyticsのレポートインタフェースのイベント追跡セクション中にレポートされる呼び出しを、追加で利用できます。イベントはカテゴリを利用してグループ化され、また、イベント毎のラベルも利用でき柔軟性の高いレポートを提供します。例えば、マルチメディアのアプリはビデオのカテゴリとビデオ名毎のラベルに対して、再生/停止/一時停止を行う事ができます。Google Analyticsレポートはビデオのカテゴリにタグ付けされた全てのイベントを収集します。イベント追跡の情報については、イベントトラッキングガイドを参照して下さい。


カスタム変数

カスタム変数は名前と値のペアのタグで、Google Analyticsの追跡を強化するために追跡コード中に挿入することができます。使用方法に関する情報は、カスタム変数ガイドを参照して下さい。




はじめよう


システム要件

Google Analyticsの追跡システムにAndroidアプリを統合するには、以下のものが必要です:




セットアップ



  • libGoogleAnalytics.jar をプロジェクトの /libs ディレクトリに追加します。

  • プロジェクトのAndroidManifest.xmlに以下のパーミッションを追加します:


    • <uses-permission android:name="android.permission.INTERNET" />

    • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />




SDKに含まれているサンプルのアプリケーションは、セットアップが成功したらプロジェクトがどのような構成となっているべきかを示すものとなっています。Analyticsが統合された自身のアプリのテンプレートとして、自由に利用しても構いません。


SDKを利用する


SDKを利用する前に、www.google.com/analyticsでフリーのアカウントを最初に取得し、適当な(偽の)WebサイトのURL(例:http://mymobileapp.mywebsite.com)を使ったアカウントに、Webサイトプロフィールを作成しなければなりません。プロフィールを生成したら、WebプロパティIDを書き写すかコピーを保管してください。



WebプロパティIDはまた、追跡コードである「UAナンバー」として知られており「UA-xxxxx-yy」のような形式となっています。xとyは各プロフィールのユニークな番号を示します。追跡オブジェクトをインスタンス化する際はWebプロパティIDを明示する必要があります。詳しくはWebプロパティを御覧ください。



SDKの使用の際には、ユーザに対して、アプリケーション自身や利用規約で、匿名でアプリケーション中のユーザの活動を追跡し、レポートする権利を有していることを示す必要があります。さらに、Google Analytics SDKの使用に関して、アカウントのサインアップ時にGoogle Analytics利用規約に同意する必要があります。


追跡を開始する

GoogleAnalyticsTracker.getInstance()をコールして、シングルトンのトラッカーを取得します。startメソッドをコールすると、WebプロパティIDが渡されて、アクティビティの追跡が開始されます。アクティビティのonCreateメソッド中で直接このメソッドをコールすると良いでしょう。例:



package com.google.android.apps.analytics.sample;

import com.google.android.apps.analytics.GoogleAnalyticsTracker;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class TestActivity extends Activity {

GoogleAnalyticsTracker tracker;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

tracker = GoogleAnalyticsTracker.getInstance();

// 手動のディスパッチモードで追跡を開始する...
tracker.start("UA-YOUR-ACCOUNT-HERE", this);

// あるいは、ディスパッチ間隔(秒)で指定して追跡を開始することも可能
//tracker.start("UA-YOUR-ACCOUNT-HERE", 20, this);

setContentView(R.layout.main);
Button createEventButton = (Button)findViewById(R.id.NewEventButton);
createEventButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tracker.trackEvent(
"Clicks", // カテゴリ
"Button", // アクション
"clicked", // ラベル
77); // 値
}
});

Button createPageButton = (Button)findViewById(R.id.NewPageButton);
createPageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// "Medium"名、"MobileApp"の値、セッションレベルのスコープで、このページビューにカスタム変数を追加する
// パラメータは順に、「Index (1~5)」「名前」「値」「スコープ」
// スコープの定義:訪問者=1, セッション=2, ページ=3(デフォルト)
tracker.setCustomVar(1, "Navigation Type", "Button click", 2);

// ページビューを追跡します。これはおそらく、アプリケーションを追跡する方法として良い方法でよく使われるでしょう。
// 例えば、
// tracker.trackPageView("/help");      > ヘルプ画面を誰が見たか追跡する
// tracker.trackPageView("/level2");     > 誰がゲームのレベル2に達したかを追跡する
// tracker.trackPageView("/uploadScreen"); > 誰がアップロード画面を利用したかを追跡する
tracker.trackPageView("/testApplicationHomeScreen");
}
});

Button quitButton = (Button)findViewById(R.id.QuitButton);
quitButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});

Button dispatchButton = (Button)findViewById(R.id.DispatchButton);
dispatchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 手動でディスパッチを開始する。一定間隔でディスパッチする方法で開始した場合は不要。
tracker.dispatch();
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// これ以上必要のない追跡を停止する
tracker.stop();
}
}


カスタム変数のスコープの定義

カスタム変数に定義できるスコープは次の3種類が存在します。




  • 訪問者スコープ(=1):端末でアプリケーションが最初に動作する時のみ呼び出します。同じインデックスでカスタム変数を生成、または、最初の変数を上書きしてはいけません。どのバージョンのアプリが使用されたか、どの種類の電話か、ライトとフルバージョンのアプリとの比較、または、アプリケーションのインストールから全く変化しない何らかのデータを送信するのに便利です。

  • セッションスコープ(=2):アクティビティが開始する毎に1度だけ呼び出します。同じインデックスで異なるカスタム変数を生成しない場合、アクティビティのライフサイクル中の全てのページビューやイベントに対して適用されます。

  • ページスコープ(=3):trackEventやtrackPageViewの直前にカスタム変数を適用する必要がある場合に呼び出します。メソッドが呼び出される度に動作します。スコープが指定されていない場合、これがデフォルトになります。


ページビューとイベントの追跡

ページビューの追跡は簡単です:ページビューを起動したい時に都度トラッカーオブジェクトの trackPageView をコールするだけです。イベントを記録するためには trackEvent をコールします。ページビューとイベントの詳細は、上記のSDKの概要を参照して下さい。


カスタム変数を利用する

カスタム変数の追加もまた簡単です:モバイルSDKによって提供される setCustomVar メソッドを利用するだけです。それぞれのカスタム変数のインデックスがどのようにマッピングされるかを前もって計画するだけで、既に存在する変数の上書きはしません。


カスタム変数の詳細な情報は、カスタム変数ガイドを参照して下さい。setCustomVar メソッドは直接、自身のデータをAnalyticsに送らないことに注意して下さい。次のページビューまたはイベント発生時に併せて送信されます(ピギーバックと呼ばれる方式です)。次の送信までの間はローカルのSQLITEデータベースに追跡情報が保存されます。ページビューやイベントの追跡前に setCustomVar をコールする必要があります。


バッチ処理で統計情報をアップロードする

接続が維持され続ける事やバッテリーの過負荷を防ぐため、追跡のリクエストをバッチ処理することをお勧めします。バッチリクエストを行いたければいつでも、追跡オブジェクトの dispatch メソッドをコールすることができ、手動でも一定間隔毎でもどちらでも実行することができます。



Tip: アプリケーション内で発生する他のHTTPリクエストにトラッカーをバンドルし、ディスパッチすることで、オーバーヘッドを低減することができます。



既知の不具合

不正確なタイムスタンプの可能性:タイムスタンプは Google Analyticsへアプリケーションからディスパッチされた時点で記録されますので、ユーザが長期間に渡りオフラインであった場合、タイムスタンプは100%正確ではないかもしれません。


リファラーの追跡


Android 1.6のOSリリースで、Androidマーケットへのダウンロードリンク中の、URLパラメータのリファラーがサポートされました。アプリケーション向けGoogle Analytics中の参照/キャンペーン情報を自動的に保持するため、Google Analytics SDK for Androidはこのパラメータを使用します。これは、(例えば、アプリの特定広告の有効性を測るといった場合に役立つような)ページビューやイベントを記録し関連付けるために、アプリケーションのソースをインストールすることを可能にします。



警告:アプリケーション中に生存する間はリファラーが残り続けるため、このリファラー操作は従来の訪問レベルのリファラーとは異なります。Androidでのリファラーのセットアップについては、原文のAndroidマーケットのリファラー追跡を御覧ください。



追跡を動作させるため、プロジェクトのAndroidManifest.xmlに、以下のブロードキャストレシーバを追加する必要があります。




<receiver android:name="com.google.android.apps.analytics.AnalyticsReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>


Androidマーケットのリファラー追跡

Androidマーケットを通じてGoogle Analyticsのリファラー追跡をセットアップするには、リファラーリンクを生成するURLビルダーを利用します。Analytics SDKは自動的にリファラー情報をパースして記録し、Analyticsのレポートとして公開します。リファラーリンクを生成するには、下記のフィールドを埋めてください。*1


パッケージ名、キャンペーンソース、キャンペーンミディアムとキャンペーン名は必須です。それぞれのパラメータの詳細な説明は、下記のテーブルを参照して下さい。


リファラーリンクパラメータ







































パラメータ必須説明
utm_sourceキャンペーンソース:サーチエンジン、ニュースレター、その他のソースの特定に使用します。utm_source=google
utm_mediumキャンペーン媒体:eメールやコストパークリック(cpc)のような媒体の特定に使用します。utm_medium=cpc
utm_termキャンペーン用語:広告のために提供するキーワードを有料の検索で使用します。utm_term=running+shoes
utm_contentキャンペーンのコンテンツ:A/Bテストや、同じURLが指定された異なる広告やリンクのための、コンテンツをターゲットとした広告に使用します。 utm_content=logolink
utm_content=textlink
utm_campaignキャンペーン名:特別な製品プロモーションや戦略的なキャンペーンを特定するために、キーワードの解析に使用されます。utm_campaign=spring_sale


アプリケーションのリファラー情報を渡すためのマーケットへのリンクは、下記の通りです:


http://market.android.com/search?q=pname:<package>&referrer=<referral>


<package>はアプリケーションのパッケージ名、<referral>はAnalyticsのキャンペーン情報のリストをエンコードしたURLです。URLを生成するツールが下記にあります。


http://code.google.com/mobile/analytics/docs/android/#android-market-tracking


利用シーンの例


Androidに特徴的な例をあげると、ユーザーがフルバージョンのアプリを持っているかどうかに依存するステータス、"Full"または"Lite"の状態を有する"アプリケーションタイプ(AppType)"が挙げられるでしょう。AnalyticsのWebインタフェースを使って、"Lite"ユーザだけを確認したり、特定のバージョンがどの位使用されているかを見たり、"Lite"と"Full"セグメントとの違いを見ることができるでしょう。


利用規約を守る――個人情報は追跡してはならない!


Google Analyticsはそれ自身の利用規約に基づいているため、それらを読み、守ることは非常に重要です。特にAndroidアプリケーションの中にこれらの情報は存在するため、Analyticsサーバに個人を特定できる情報を送信してはいけません。つまり、訪問者レベルのカスタム変数に「電話番号」「名前」「eメールアドレス」を含む事はできないということです。直感的ではないですが、しかしながらこれは重要で、アプリケーションがWebアプリケーションのクライアントであれば(例えば、CRMやショッピングサイト)、Analyticsに店舗の情報(ユーザIDやトランザクションIDといった、Webバックエンドに格納される個人が特定できるものと結合可能な情報)を格納できないことを意味します。


実行結果


今回はSDKに付属するサンプルアプリを使用しました。


事前にGoogle Analyticsのアカウントを作成

f:id:bs-android:20101221174445p:image


Google Analyticsのサイトに移動し、適当なURLとアカウントを入力。URLとアカウントは実在しないドメインでも良いです。





f:id:bs-android:20101221174446p:image


連絡先情報を入力(誰が連絡してくるのだろう・・・)





f:id:bs-android:20101221174447p:image


利用規約を読んで同意するにチェック。この規約はSDKを利用するアプリにも適用されます。





f:id:bs-android:20101221174448p:image


Web用のコードスニペットが表示されるので、そこに記載されている「UA-XXXXX-Y」の文字列を保存しておく。





SDKを搭載したアプリを操作する

f:id:bs-android:20101221173337p:image


アプリ自体は至ってシンプルです。ボタンクリックによって、ページビューやイベントの追跡が発生します。





Google Analytics上のレポート例



  • レポートは初めて追跡を開始してから数時間(最大24時間)を経過しなければ表示されません。


f:id:bs-android:20101221174444p:image


f:id:bs-android:20101222004309p:image


f:id:bs-android:20101222004310p:image


f:id:bs-android:20101222004311p:image


このように、アプリから送信されたページビューやイベントの追跡情報が、Google Analyticsに表示されます。カテゴリ毎、ラベル毎、アクション毎など、様々な切り口から分析することができます。


まとめ


AndroidとGoogle Analyticsを使用すると、上記のように様々なユーザの操作などを情報を追跡する事ができます。このあたりの連携はさすがGoogle、といったところでしょうか。これらの追跡情報から、ユーザにとって使いやすいUIの配置を理論的に検討することもできるでしょう。


しかしながら、使い方によっては、ユーザーにとって知られたくない情報も収集されてしまう可能性もありますので、やはりアプリケーション内でこのSDKを使用している場合は、インストール時などにユーザーに対して情報を追跡している旨を伝え、事前の承諾を得る形で使用するべきでしょう(いわゆる、"オプトイン"方式)。



文責:技術部 植物工場研究G 瀬戸 直喜






2010年12月14日火曜日



f:id:bs-android:20101212111045p:image


原文はこちら


概要


layoutoptは、アプリケーションのレイアウトとレイアウトヒエラルキーを最適化するためのツールです。レイアウトファイルやリソースファイルを原因とする、アプリケーションのパフォーマンスに影響を及ぼす非効率な、あるいはその他のタイプの問題を素早くチェックすることができます。


ツールを実行するには、ターミナルを開いて SDKのtools/ディレクトリから layout <リソース名> を起動します。コマンド引数には、解析したい未コンパイルのリソースXMLファイルかディレクトリを指定します。


実行時にツールは指定のXMLファイルを読み込み、事前に定義されたルールセットに従ってレイアウトの構造を解析します。問題を発見した場合は、問題、ファイル名、行番号、問題の概要に関する情報と共に、推定される解決方法のいくつかを出力します。




使い方


lyaoutopt を実行するには、引数にレイアウトリソースのリスト(スペース区切りで複数可)を指定します:



layoutopt <XMLファイルのリスト または ディレクトリ>


例:



$ layoutopt res/layout-land
$ layoutopt res/layout/main.xml res/layout-land/main.xml


実行結果の例


$ layoutopt samples/
samples/compound.xml
7:23 The root-level <FrameLayout/> can be replaced with <merge/>
11:21 This LinearLayout layout or its FrameLayout parent is useless
samples/simple.xml
7:7 The root-level <FrameLayout/> can be replaced with <merge/>
samples/too_deep.xml
-1:-1 This layout has too many nested layouts: 13 levels, it should have <= 10!
20:81 This LinearLayout layout or its LinearLayout parent is useless
24:79 This LinearLayout layout or its LinearLayout parent is useless
28:77 This LinearLayout layout or its LinearLayout parent is useless
32:75 This LinearLayout layout or its LinearLayout parent is useless
36:73 This LinearLayout layout or its LinearLayout parent is useless
40:71 This LinearLayout layout or its LinearLayout parent is useless
44:69 This LinearLayout layout or its LinearLayout parent is useless
48:67 This LinearLayout layout or its LinearLayout parent is useless
52:65 This LinearLayout layout or its LinearLayout parent is useless
56:63 This LinearLayout layout or its LinearLayout parent is useless
samples/too_many.xml
7:413 The root-level <FrameLayout/> can be replaced with <merge/>
-1:-1 This layout has too many views: 81 views, it should have <= 80!
samples/useless.xml
7:19 The root-level <FrameLayout/> can be replaced with <merge/>
11:17 This LinearLayout layout or its FrameLayout parent is useless


実行結果の読み方

実行結果は下記の順で出力されています。




  • 解析対象のXMLファイル名

  • 開始行番号:終了行番号

  • 問題の内容 または 最適化された内容

  • 解決のためのヒント


注意点


コマンドを実行しても、リソースファイルが自動で変換されることはありません。あくまでも診断ツールです。


対応バージョン


SDK Tools Rev3(Android 1.5)以降


まとめ


Androidアプリ開発者として、レイアウトの複雑化に伴うパフォーマンスの低下には関心を持たざるを得ないので試してみましたが、特に複雑なレイアウトを持つアプリケーションに対して使ってみる価値があると感じました。


また、実行結果の例では、レイアウトのタグが置き換えられていたり、使われていないレイアウトが指摘されていることは容易に想像できたのですが、何気にネストできるレイアウトのレベルは10までであったり、レイアウトが保持できるビューの数が80までであることが記載されていたりして、良い勉強になりました。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





便利な開発ツール:レイアウトを最適化する layoutopt (Android Developers - Dev Guide和訳)



f:id:bs-android:20101212111045p:image


原文はこちら


概要


layoutoptは、アプリケーションのレイアウトとレイアウトヒエラルキーを最適化するためのツールです。レイアウトファイルやリソースファイルを原因とする、アプリケーションのパフォーマンスに影響を及ぼす非効率な、あるいはその他のタイプの問題を素早くチェックすることができます。


ツールを実行するには、ターミナルを開いて SDKのtools/ディレクトリから layout <リソース名> を起動します。コマンド引数には、解析したい未コンパイルのリソースXMLファイルかディレクトリを指定します。


実行時にツールは指定のXMLファイルを読み込み、事前に定義されたルールセットに従ってレイアウトの構造を解析します。問題を発見した場合は、問題、ファイル名、行番号、問題の概要に関する情報と共に、推定される解決方法のいくつかを出力します。




使い方


lyaoutopt を実行するには、引数にレイアウトリソースのリスト(スペース区切りで複数可)を指定します:



layoutopt <XMLファイルのリスト または ディレクトリ>


例:



$ layoutopt res/layout-land
$ layoutopt res/layout/main.xml res/layout-land/main.xml


実行結果の例


$ layoutopt samples/
samples/compound.xml
7:23 The root-level <FrameLayout/> can be replaced with <merge/>
11:21 This LinearLayout layout or its FrameLayout parent is useless
samples/simple.xml
7:7 The root-level <FrameLayout/> can be replaced with <merge/>
samples/too_deep.xml
-1:-1 This layout has too many nested layouts: 13 levels, it should have <= 10!
20:81 This LinearLayout layout or its LinearLayout parent is useless
24:79 This LinearLayout layout or its LinearLayout parent is useless
28:77 This LinearLayout layout or its LinearLayout parent is useless
32:75 This LinearLayout layout or its LinearLayout parent is useless
36:73 This LinearLayout layout or its LinearLayout parent is useless
40:71 This LinearLayout layout or its LinearLayout parent is useless
44:69 This LinearLayout layout or its LinearLayout parent is useless
48:67 This LinearLayout layout or its LinearLayout parent is useless
52:65 This LinearLayout layout or its LinearLayout parent is useless
56:63 This LinearLayout layout or its LinearLayout parent is useless
samples/too_many.xml
7:413 The root-level <FrameLayout/> can be replaced with <merge/>
-1:-1 This layout has too many views: 81 views, it should have <= 80!
samples/useless.xml
7:19 The root-level <FrameLayout/> can be replaced with <merge/>
11:17 This LinearLayout layout or its FrameLayout parent is useless


実行結果の読み方

実行結果は下記の順で出力されています。




  • 解析対象のXMLファイル名

  • 開始行番号:終了行番号

  • 問題の内容 または 最適化された内容

  • 解決のためのヒント


注意点


コマンドを実行しても、リソースファイルが自動で変換されることはありません。あくまでも診断ツールです。


対応バージョン


SDK Tools Rev3(Android 1.5)以降


まとめ


Androidアプリ開発者として、レイアウトの複雑化に伴うパフォーマンスの低下には関心を持たざるを得ないので試してみましたが、特に複雑なレイアウトを持つアプリケーションに対して使ってみる価値があると感じました。


また、実行結果の例では、レイアウトのタグが置き換えられていたり、使われていないレイアウトが指摘されていることは容易に想像できたのですが、何気にネストできるレイアウトのレベルは10までであったり、レイアウトが保持できるビューの数が80までであることが記載されていたりして、良い勉強になりました。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





2010年12月9日木曜日



f:id:bs-android:20101207022545p:image


先日、ADT 8.0.0がリリースされたばかりですが、早速、8.0.1にバージョンアップされました。


変更点は下記の通りです。


依存関係:


ADT 8.0.1 は SDK Tools r8用にデザインされています。まだSDK Tools r8をSDKにインストールしていない場合は、Android SDK and AVD Managerを利用して下さい。


主な変更:




  • これは、ADT 8.0.0 のいくつかのバグを修正した、緊急フォローアップ版です。

  • プロジェクトのコンパイルの失敗とdexエラーの言及について修正しました。

  • リリース版アプリケーションをエクスポートする際の、ProGuardのエラーリポートの改良


8.0.0のリリースノートもあわせてご覧下さい。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





ADT 8.0.1 のリリース変更点まとめ



f:id:bs-android:20101207022545p:image


先日、ADT 8.0.0がリリースされたばかりですが、早速、8.0.1にバージョンアップされました。


変更点は下記の通りです。


依存関係:


ADT 8.0.1 は SDK Tools r8用にデザインされています。まだSDK Tools r8をSDKにインストールしていない場合は、Android SDK and AVD Managerを利用して下さい。


主な変更:




  • これは、ADT 8.0.0 のいくつかのバグを修正した、緊急フォローアップ版です。

  • プロジェクトのコンパイルの失敗とdexエラーの言及について修正しました。

  • リリース版アプリケーションをエクスポートする際の、ProGuardのエラーリポートの改良


8.0.0のリリースノートもあわせてご覧下さい。



文責:技術部 瀬戸 直喜(前・日本Androidの会四国支部長/情報セキュリティスペシャリスト)





2010年12月8日水曜日



f:id:bs-android:20101207145216j:image





はじめに

前回の記事ではAntを使う形で、難読化ツールであるProGuardの適用方法を紹介しました。*1


今回は本日(日本時間12/7)リリースされた Android 2.3(Gingerbread)のSDK(正確にはSDK Tools r8とADT8.0.0)に標準で搭載されたProGuardの適用方法について紹介します。





ProGuardとは


詳細は前回の記事を参照頂きたいのですが、ProGuardが初めての方の為に簡単に説明します。ProGuardはソースコードをコンパイルする際に処理を最適化したり、プログラム中の変数やメソッドを意味のない文字列に置き換え、逆コンパイルされた際に処理の中身をわかりにくくする、いわゆる「難読化」を行うツールです。


これまでもAntを使ってProGuardの適用は行えましたが、最新のSDKでは標準搭載され、Eclipse上から簡単に難読化が行えるようになりました。





GoogleがProGuardを標準搭載した理由


他者による解析を難しくさせるツールを標準機能として載せるということは、裏を返せば「Androidのアプリケーションは、リバースエンジニアリングが容易」ということでしょう。Google公式サイトの解説ページに「ProGuardは完全にオプションとして動作するが、適用を"強くおすすめする"」と書かれています。「Androidアプリ開発者はコードレベルで知的財産を守るべき」という、Googleからの静かなるメッセージなのかもしれません。




ProGuardを有効にする方法


それではどのようにProGuardを適用すればよいか、順を追って解説します。


プロジェクトの作成

Android 2.3のSDKを利用してEclipse上でプロジェクトを新規作成すると、ProGuardの設定が記述された「proguard.cfg」ファイルが自動的に生成されます。このファイルには予め、標準的に必要となる設定が記載されていますので、基本的に修正の必要はありません。


default.propertiesの修正

作成したプロジェクトのホーム直下に配置されているdefault.propertiesの最終行に、下記を追記します。



proguard.config = <proguard.cfgの絶対パス> または <proguard.cfgのプロジェクトホームからの相対パス>


以下はプロジェクトのホームにproguard.cfgが配置されている状態での、default.propertiesの設定の例です。



# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.

# Project target.
target=android-9
proguard.config=proguard.cfg

基本的にはこの設定だけでProGuardが有効になります!*2


ProGuardの設定変更

基本的に前節の設定のみでProGuardが実行されますが、下記のような場合は実行に失敗することがあります。




  • AndroidManifest.xmlファイルのみから参照されているクラス

  • JNIから呼び出されるメソッド

  • 動的参照される変数やメソッド


ProGuardの実行に失敗する場合は、proguard.cfgファイルに -keep オプションを付加した行を追記し、ProGuardの適用を除外する必要があります。



-keep public class <MyClass>


-keepオプションに関する詳しい情報は、前回の記事ProGuardのマニュアルを参照して下さい。





ProGuardを適用する


Antを使う

従来の方法と同様、ant release コマンドでProGuardを適用することが可能です。詳細は前回の記事を参照して下さい。


Eclipseのエクスポート機能を使う

メニューから、ファイル -> エクスポート -> Android -> Export Android application と選択して、アプリケーションへの署名を行い、apkファイルを出力します。

apkファイルの出力と同時に、下記のようなログがEclipseのコンソールビューに出力されているはずです。*3



[2010-12-07 13:05:28 - HelloAndroid] Refreshing resource folders.
[2010-12-07 13:05:28 - HelloAndroid] Starting incremental Pre Compiler: Checking resource changes.
[2010-12-07 13:05:28 - HelloAndroid] Nothing to pre compile!
[2010-12-07 13:05:28 - HelloAndroid] /android-sdk-mac_x86/platform-tools/aapt package -f -v -M /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml -S /Users/seto/Documents/workspace/HelloAndroid/res -A /Users/seto/Documents/workspace/HelloAndroid/assets -I /android-sdk-mac_x86/platforms/android-9/android.jar -F /var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_
[2010-12-07 13:05:28 - HelloAndroid] Found 0 custom asset files in /Users/seto/Documents/workspace/HelloAndroid/assets
[2010-12-07 13:05:28 - HelloAndroid] Locale/Vendor pairs:
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid]
[2010-12-07 13:05:28 - HelloAndroid] ファイル:
[2010-12-07 13:05:28 - HelloAndroid] drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Including resources from package: /android-sdk-mac_x86/platforms/android-9/android.jar
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for drawable
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for layout
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for anim
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for xml
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for raw
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for color
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for menu
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png: 95% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png: 89% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png: 85% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id main from /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml)
[2010-12-07 13:05:28 - HelloAndroid] Opening '/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_'
[2010-12-07 13:05:28 - HelloAndroid] Writing all files...
[2010-12-07 13:05:28 - HelloAndroid] 'res/layout/main.xml' (compressed 49%)
[2010-12-07 13:05:28 - HelloAndroid] 'AndroidManifest.xml' (compressed 61%)
[2010-12-07 13:05:28 - HelloAndroid] 'resources.arsc' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-hdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-ldpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-mdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] Generated 6 files
[2010-12-07 13:05:28 - HelloAndroid] Included 0 files from jar/zip files.
[2010-12-07 13:05:28 - HelloAndroid] Checking for deleted files
[2010-12-07 13:05:28 - HelloAndroid] 終了!
[2010-12-07 13:05:28 - HelloAndroid] ProGuard, version 4.4
[2010-12-07 13:05:28 - HelloAndroid] Reading input...
[2010-12-07 13:05:28 - HelloAndroid] Reading program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:28 - HelloAndroid] Reading library jar [/android-sdk-mac_x86/platforms/android-9/android.jar]
[2010-12-07 13:05:30 - HelloAndroid] 初期化中...
[2010-12-07 13:05:30 - HelloAndroid] 注: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[2010-12-07 13:05:30 - HelloAndroid] 注: there were 1 references to unknown classes.
[2010-12-07 13:05:30 - HelloAndroid] You should check your configuration for typos.
[2010-12-07 13:05:30 - HelloAndroid] Ignoring unused library classes...
[2010-12-07 13:05:30 - HelloAndroid] Original number of library classes: 2750
[2010-12-07 13:05:30 - HelloAndroid] Final number of library classes: 148
[2010-12-07 13:05:30 - HelloAndroid] Printing kept classes, fields, and methods...
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Printing usage to [/Users/seto/Documents/workspace/HelloAndroid/proguard/usage.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 8
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 19
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 6
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 1
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Writing output...
[2010-12-07 13:05:30 - HelloAndroid] Preparing output jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_2607110758288445210.jar]
[2010-12-07 13:05:30 - HelloAndroid] Copying resources from program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:30 - HelloAndroid] Printing classes to [/Users/seto/Documents/workspace/HelloAndroid/proguard/dump.txt]...


下記のように出力されていれば、難読化がされています。



[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...





ProGuard有効時に出力されるファイル/ディレクトリ

ProGuardが適用されると、<プロジェクトのホーム>/proguard/ にディレクトリが生成され、その中に下記のようなファイルが出力されます。*4




  • dump.txt:.apkファイル中のクラスの内部構造が記載されています。

  • mapping.txt:難読化前と難読化後のクラス、メソッド、変数の対応リスト

  • seed.txt:難読化されていないクラスやメンバのリスト

  • usage.txt:.apkファイルから外されたコードのリスト


特に、mapping.txtは、リリースビルドしたapkから送られる難読化されたバグリポート(スタックトレース)を可読化するために必要となります。





ProGuard利用時の注意点


proguardディレクトリは、リリースビルドの際に上書きされます。これらを失うと、リリース後のバグレポートから原因を調査することが困難になりますので、proguardディレクトリの中身(特にmapping.txtファイル)は、リリースバージョン毎に保存しておく必要があります。


Android開発者サイトでは、保存の方法として下記のようなものが推奨されています。




  • リリース時のバージョンまたはビルド番号を、フォルダやファイル名に追記する

  • バージョン管理システムにファイルを登録する





難読化されたスタックトレースをデコードする方法


ProGuardは難読化において相応の効果を発揮するツールではありますが、反面、デバッグに必要な情報までをも難読化させてしまう欠点があります。そのため、最新のAndroid SDKには、難読化されたスタックトレースを可読化するための、シェルスクリプトが付属されています。<sdk_root>/tools/proguard/ ディレクトリにretrace.sh(Windowsの場合、retrace.bat)が格納されていますので、このスクリプトを使用します。


コマンドの書式:



retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]


使用例:



retrace.sh -verbose mapping.txt obfuscated_trace.txt


例のmapping.txtは、リリース時に保存しておいたファイル、obfuscated_trace.txtは、難読化されたバグリポート中のスタックトレースを記載したファイルです。


ちなみに、スタックトレースを記載したファイルを省略した場合、標準入力からスタックトレースを読み込んで、デコードします。





より簡単に使えるようになったProGuardで、あなたのアプリケーションを守りましょう!



文責:技術部 植物工場研究G 瀬戸 直喜




*1:書いた矢先に標準搭載され、記事の価値が半分になり、ついカッとなって追加記事を書いたりはしていません。


*2:簡単すぎて前回の記事は一体何だったんだと言いたくなります。


*3:ログが出力されない場合は、Eclipseのメニュー->環境設定->Android->ビルドの「ビルド出力」のオプションを「詳細」に設定してみてください。


*4:Antで実行した場合、出力先は<プロジェクトのホーム>/bin/proguard/ となります。





Androidとセキュリティ:Android 2.3(Gingerbread) SDKに標準搭載されたProGuardを試す



f:id:bs-android:20101207145216j:image





はじめに

前回の記事ではAntを使う形で、難読化ツールであるProGuardの適用方法を紹介しました。*1


今回は本日(日本時間12/7)リリースされた Android 2.3(Gingerbread)のSDK(正確にはSDK Tools r8とADT8.0.0)に標準で搭載されたProGuardの適用方法について紹介します。





ProGuardとは


詳細は前回の記事を参照頂きたいのですが、ProGuardが初めての方の為に簡単に説明します。ProGuardはソースコードをコンパイルする際に処理を最適化したり、プログラム中の変数やメソッドを意味のない文字列に置き換え、逆コンパイルされた際に処理の中身をわかりにくくする、いわゆる「難読化」を行うツールです。


これまでもAntを使ってProGuardの適用は行えましたが、最新のSDKでは標準搭載され、Eclipse上から簡単に難読化が行えるようになりました。





GoogleがProGuardを標準搭載した理由


他者による解析を難しくさせるツールを標準機能として載せるということは、裏を返せば「Androidのアプリケーションは、リバースエンジニアリングが容易」ということでしょう。Google公式サイトの解説ページに「ProGuardは完全にオプションとして動作するが、適用を"強くおすすめする"」と書かれています。「Androidアプリ開発者はコードレベルで知的財産を守るべき」という、Googleからの静かなるメッセージなのかもしれません。




ProGuardを有効にする方法


それではどのようにProGuardを適用すればよいか、順を追って解説します。


プロジェクトの作成

Android 2.3のSDKを利用してEclipse上でプロジェクトを新規作成すると、ProGuardの設定が記述された「proguard.cfg」ファイルが自動的に生成されます。このファイルには予め、標準的に必要となる設定が記載されていますので、基本的に修正の必要はありません。


default.propertiesの修正

作成したプロジェクトのホーム直下に配置されているdefault.propertiesの最終行に、下記を追記します。



proguard.config = <proguard.cfgの絶対パス> または <proguard.cfgのプロジェクトホームからの相対パス>


以下はプロジェクトのホームにproguard.cfgが配置されている状態での、default.propertiesの設定の例です。



# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.

# Project target.
target=android-9
proguard.config=proguard.cfg

基本的にはこの設定だけでProGuardが有効になります!*2


ProGuardの設定変更

基本的に前節の設定のみでProGuardが実行されますが、下記のような場合は実行に失敗することがあります。




  • AndroidManifest.xmlファイルのみから参照されているクラス

  • JNIから呼び出されるメソッド

  • 動的参照される変数やメソッド


ProGuardの実行に失敗する場合は、proguard.cfgファイルに -keep オプションを付加した行を追記し、ProGuardの適用を除外する必要があります。



-keep public class <MyClass>


-keepオプションに関する詳しい情報は、前回の記事ProGuardのマニュアルを参照して下さい。





ProGuardを適用する


Antを使う

従来の方法と同様、ant release コマンドでProGuardを適用することが可能です。詳細は前回の記事を参照して下さい。


Eclipseのエクスポート機能を使う

メニューから、ファイル -> エクスポート -> Android -> Export Android application と選択して、アプリケーションへの署名を行い、apkファイルを出力します。

apkファイルの出力と同時に、下記のようなログがEclipseのコンソールビューに出力されているはずです。*3



[2010-12-07 13:05:28 - HelloAndroid] Refreshing resource folders.
[2010-12-07 13:05:28 - HelloAndroid] Starting incremental Pre Compiler: Checking resource changes.
[2010-12-07 13:05:28 - HelloAndroid] Nothing to pre compile!
[2010-12-07 13:05:28 - HelloAndroid] /android-sdk-mac_x86/platform-tools/aapt package -f -v -M /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml -S /Users/seto/Documents/workspace/HelloAndroid/res -A /Users/seto/Documents/workspace/HelloAndroid/assets -I /android-sdk-mac_x86/platforms/android-9/android.jar -F /var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_
[2010-12-07 13:05:28 - HelloAndroid] Found 0 custom asset files in /Users/seto/Documents/workspace/HelloAndroid/assets
[2010-12-07 13:05:28 - HelloAndroid] Locale/Vendor pairs:
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid] /
[2010-12-07 13:05:28 - HelloAndroid]
[2010-12-07 13:05:28 - HelloAndroid] ファイル:
[2010-12-07 13:05:28 - HelloAndroid] drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png
[2010-12-07 13:05:28 - HelloAndroid] layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml
[2010-12-07 13:05:28 - HelloAndroid] values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/res/values/strings.xml
[2010-12-07 13:05:28 - HelloAndroid] AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Src: /Users/seto/Documents/workspace/HelloAndroid/AndroidManifest.xml
[2010-12-07 13:05:28 - HelloAndroid] Including resources from package: /android-sdk-mac_x86/platforms/android-9/android.jar
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for drawable
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for layout
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for anim
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for xml
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for raw
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for color
[2010-12-07 13:05:28 - HelloAndroid] applyFileOverlay for menu
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-hdpi/icon.png: 95% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-ldpi/icon.png: 89% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (processed image /Users/seto/Documents/workspace/HelloAndroid/res/drawable-mdpi/icon.png: 85% size of source)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id icon from drawable-hdpi/icon.png #generated)
[2010-12-07 13:05:28 - HelloAndroid] (new resource id main from /Users/seto/Documents/workspace/HelloAndroid/res/layout/main.xml)
[2010-12-07 13:05:28 - HelloAndroid] Opening '/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_1153826279934575801.ap_'
[2010-12-07 13:05:28 - HelloAndroid] Writing all files...
[2010-12-07 13:05:28 - HelloAndroid] 'res/layout/main.xml' (compressed 49%)
[2010-12-07 13:05:28 - HelloAndroid] 'AndroidManifest.xml' (compressed 61%)
[2010-12-07 13:05:28 - HelloAndroid] 'resources.arsc' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-hdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-ldpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] 'res/drawable-mdpi/icon.png' (not compressed)
[2010-12-07 13:05:28 - HelloAndroid] Generated 6 files
[2010-12-07 13:05:28 - HelloAndroid] Included 0 files from jar/zip files.
[2010-12-07 13:05:28 - HelloAndroid] Checking for deleted files
[2010-12-07 13:05:28 - HelloAndroid] 終了!
[2010-12-07 13:05:28 - HelloAndroid] ProGuard, version 4.4
[2010-12-07 13:05:28 - HelloAndroid] Reading input...
[2010-12-07 13:05:28 - HelloAndroid] Reading program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:28 - HelloAndroid] Reading library jar [/android-sdk-mac_x86/platforms/android-9/android.jar]
[2010-12-07 13:05:30 - HelloAndroid] 初期化中...
[2010-12-07 13:05:30 - HelloAndroid] 注: the configuration refers to the unknown class 'com.android.vending.licensing.ILicensingService'
[2010-12-07 13:05:30 - HelloAndroid] 注: there were 1 references to unknown classes.
[2010-12-07 13:05:30 - HelloAndroid] You should check your configuration for typos.
[2010-12-07 13:05:30 - HelloAndroid] Ignoring unused library classes...
[2010-12-07 13:05:30 - HelloAndroid] Original number of library classes: 2750
[2010-12-07 13:05:30 - HelloAndroid] Final number of library classes: 148
[2010-12-07 13:05:30 - HelloAndroid] Printing kept classes, fields, and methods...
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Printing usage to [/Users/seto/Documents/workspace/HelloAndroid/proguard/usage.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 8
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 1
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 19
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 6
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 1
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 2
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Shrinking...
[2010-12-07 13:05:30 - HelloAndroid] Removing unused program classes and class elements...
[2010-12-07 13:05:30 - HelloAndroid] Original number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Final number of program classes: 2
[2010-12-07 13:05:30 - HelloAndroid] Optimizing...
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized classes: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of vertically merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of horizontally merged classes: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of removed write-only fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant fields: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of privatized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of staticized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of finalized methods: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed method parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant parameters: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined constant return values: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined short method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined unique method calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of inlined tail recursion calls: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of merged code blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of variable peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of arithmetic peephole optimizations: 0 (使用不可)
[2010-12-07 13:05:30 - HelloAndroid] Number of cast peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of field peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of branch peephole optimizations: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of simplified instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed instructions: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed local variables: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of removed exception blocks: 0
[2010-12-07 13:05:30 - HelloAndroid] Number of optimized local variable frames: 0
[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...
[2010-12-07 13:05:30 - HelloAndroid] Writing output...
[2010-12-07 13:05:30 - HelloAndroid] Preparing output jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_2607110758288445210.jar]
[2010-12-07 13:05:30 - HelloAndroid] Copying resources from program jar [/private/var/folders/cb/cb2FqG62E5izgbafkF4ouE++--U/-Tmp-/android_16917046672536715.jar]
[2010-12-07 13:05:30 - HelloAndroid] Printing classes to [/Users/seto/Documents/workspace/HelloAndroid/proguard/dump.txt]...


下記のように出力されていれば、難読化がされています。



[2010-12-07 13:05:30 - HelloAndroid] Obfuscating...
[2010-12-07 13:05:30 - HelloAndroid] Printing mapping to [/Users/seto/Documents/workspace/HelloAndroid/proguard/mapping.txt]...





ProGuard有効時に出力されるファイル/ディレクトリ

ProGuardが適用されると、<プロジェクトのホーム>/proguard/ にディレクトリが生成され、その中に下記のようなファイルが出力されます。*4




  • dump.txt:.apkファイル中のクラスの内部構造が記載されています。

  • mapping.txt:難読化前と難読化後のクラス、メソッド、変数の対応リスト

  • seed.txt:難読化されていないクラスやメンバのリスト

  • usage.txt:.apkファイルから外されたコードのリスト


特に、mapping.txtは、リリースビルドしたapkから送られる難読化されたバグリポート(スタックトレース)を可読化するために必要となります。





ProGuard利用時の注意点


proguardディレクトリは、リリースビルドの際に上書きされます。これらを失うと、リリース後のバグレポートから原因を調査することが困難になりますので、proguardディレクトリの中身(特にmapping.txtファイル)は、リリースバージョン毎に保存しておく必要があります。


Android開発者サイトでは、保存の方法として下記のようなものが推奨されています。




  • リリース時のバージョンまたはビルド番号を、フォルダやファイル名に追記する

  • バージョン管理システムにファイルを登録する





難読化されたスタックトレースをデコードする方法


ProGuardは難読化において相応の効果を発揮するツールではありますが、反面、デバッグに必要な情報までをも難読化させてしまう欠点があります。そのため、最新のAndroid SDKには、難読化されたスタックトレースを可読化するための、シェルスクリプトが付属されています。<sdk_root>/tools/proguard/ ディレクトリにretrace.sh(Windowsの場合、retrace.bat)が格納されていますので、このスクリプトを使用します。


コマンドの書式:



retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]


使用例:



retrace.sh -verbose mapping.txt obfuscated_trace.txt


例のmapping.txtは、リリース時に保存しておいたファイル、obfuscated_trace.txtは、難読化されたバグリポート中のスタックトレースを記載したファイルです。


ちなみに、スタックトレースを記載したファイルを省略した場合、標準入力からスタックトレースを読み込んで、デコードします。





より簡単に使えるようになったProGuardで、あなたのアプリケーションを守りましょう!



文責:技術部 植物工場研究G 瀬戸 直喜




*1:書いた矢先に標準搭載され、記事の価値が半分になり、ついカッとなって追加記事を書いたりはしていません。


*2:簡単すぎて前回の記事は一体何だったんだと言いたくなります。


*3:ログが出力されない場合は、Eclipseのメニュー->環境設定->Android->ビルドの「ビルド出力」のオプションを「詳細」に設定してみてください。


*4:Antで実行した場合、出力先は<プロジェクトのホーム>/bin/proguard/ となります。





2009年7月18日土曜日



f:id:bs-android:20090717170456p:image


Android 1.5 SDK Release 3が公開されました。




1.5 Release 2からの主な変更内容は以下の通りです。



Permissions Fixes(パーミッション修正)


カメラとオーディオのパーミッションの記載がなくてもアクセスできてしまっていた問題に対応。


今まではパーミッションの記載がなくても使えていた可能性があるので、関係しそうなアプリを作ってるひとは要チェック。


今回の変更に関係のないパーミッションが必要なアプリもテストしてくださいとのこと。





Resolved Issues, Changes(解決された問題、変更)




  • 新しいバージョンのGoogle API アドオン。com.google.android.mapsのライブラリGeoPointに関するコンパイルエラーに対応。Google API アドオンに関しては http://code.google.com/android/add-ons/google-apis を参照。




  • SDKのアドオンでUSB Vendor IDを指定できるようになった。

  • MacとLinux版SDKでは「android update adb」コマンドで、アドオンをスキャンして、USB Vendor IDをadbで使用できるようになった。Windowsでは"Google"と"HTC"のカスタムUSBドライバーが同梱されており、adbからG1とMagicを認識できるようになった。

  • テレフォニー、センサー、Geoに関する問題が修正された。

  • アップグレードしたアプリケーションをadbを使ってアンインストールするとき、システムが前のバージョンに割り当てられていたパーミッションを適切に復元するようになった。



リリースノート原文





その他の変更


Google API アドオン対応に伴い、Google Mapsのバージョンが上がっていて、乗り換え検索が使えるようになっています。


(HT-03Aに搭載されているデフォルトのGoogle Mapsでは乗り換え検索できません。HT-03Aに新Google Mapsをインストールするには、ロケールを英語にして、Simカードを抜いて、WiFiでネット接続すると、MarketのTravelカテゴリの一番上にGoogle Mapsが出てくるようになるので、そこから新バージョンのインストールが可能です。)





・乗り換え検索


f:id:bs-android:20090717181838p:image


f:id:bs-android:20090717181927p:image


f:id:bs-android:20090717182121p:image


f:id:bs-android:20090717182151p:image





そしてリリースノートには記載がないですが、HT-03Aに搭載されているiWnnのオープンソース版のOpenWnnが搭載されており、ソースコードも公開されています。





・OpenWnn


見た目はJapanese IMEという名前になってます。


f:id:bs-android:20090717204131p:image


アプリケーション管理から覗くとOpenWnnの名前で存在してます。


f:id:bs-android:20090717204209p:image


ソースコードはこちら。


http://android.git.kernel.org/?p=platform/packages/inputmethods/OpenWnn.git;a=tree;h=refs/heads/cupcake;hb=cupcake





repoを使ってソースコードをダウンロードするには



repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake
repo sync


とすれば入手できます。





おまけ


・HT-03AのiWnn


後から出てきたOpenWnnの方がバージョンが新しいですね。


f:id:bs-android:20090717204340p:image


f:id:bs-android:20090717204400p:image





Android 1.5 SDK Release 3公開



f:id:bs-android:20090717170456p:image


Android 1.5 SDK Release 3が公開されました。




1.5 Release 2からの主な変更内容は以下の通りです。



Permissions Fixes(パーミッション修正)


カメラとオーディオのパーミッションの記載がなくてもアクセスできてしまっていた問題に対応。


今まではパーミッションの記載がなくても使えていた可能性があるので、関係しそうなアプリを作ってるひとは要チェック。


今回の変更に関係のないパーミッションが必要なアプリもテストしてくださいとのこと。





Resolved Issues, Changes(解決された問題、変更)




  • 新しいバージョンのGoogle API アドオン。com.google.android.mapsのライブラリGeoPointに関するコンパイルエラーに対応。Google API アドオンに関しては http://code.google.com/android/add-ons/google-apis を参照。




  • SDKのアドオンでUSB Vendor IDを指定できるようになった。

  • MacとLinux版SDKでは「android update adb」コマンドで、アドオンをスキャンして、USB Vendor IDをadbで使用できるようになった。Windowsでは"Google"と"HTC"のカスタムUSBドライバーが同梱されており、adbからG1とMagicを認識できるようになった。

  • テレフォニー、センサー、Geoに関する問題が修正された。

  • アップグレードしたアプリケーションをadbを使ってアンインストールするとき、システムが前のバージョンに割り当てられていたパーミッションを適切に復元するようになった。



リリースノート原文





その他の変更


Google API アドオン対応に伴い、Google Mapsのバージョンが上がっていて、乗り換え検索が使えるようになっています。


(HT-03Aに搭載されているデフォルトのGoogle Mapsでは乗り換え検索できません。HT-03Aに新Google Mapsをインストールするには、ロケールを英語にして、Simカードを抜いて、WiFiでネット接続すると、MarketのTravelカテゴリの一番上にGoogle Mapsが出てくるようになるので、そこから新バージョンのインストールが可能です。)





・乗り換え検索


f:id:bs-android:20090717181838p:image


f:id:bs-android:20090717181927p:image


f:id:bs-android:20090717182121p:image


f:id:bs-android:20090717182151p:image





そしてリリースノートには記載がないですが、HT-03Aに搭載されているiWnnのオープンソース版のOpenWnnが搭載されており、ソースコードも公開されています。





・OpenWnn


見た目はJapanese IMEという名前になってます。


f:id:bs-android:20090717204131p:image


アプリケーション管理から覗くとOpenWnnの名前で存在してます。


f:id:bs-android:20090717204209p:image


ソースコードはこちら。


http://android.git.kernel.org/?p=platform/packages/inputmethods/OpenWnn.git;a=tree;h=refs/heads/cupcake;hb=cupcake





repoを使ってソースコードをダウンロードするには



repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake
repo sync


とすれば入手できます。





おまけ


・HT-03AのiWnn


後から出てきたOpenWnnの方がバージョンが新しいですね。


f:id:bs-android:20090717204340p:image


f:id:bs-android:20090717204400p:image





Related Posts Plugin for WordPress, Blogger...