2013年12月14日土曜日

AndroidのFragmentについてのセミナーを実施しました&お知らせ

チームEGGの曽川です。

セミナーについて

レバレジーズ様でAndroidのセミナーを行いました。
今回のテーマはFragmentについてです。
基本的な使い方や、アンチパターンの紹介を行っています。
サンプルコードでは以下を取り扱っています。
・GoogleMapsV2デモ
・YouTubePlayerAPIデモ
・UIあり/なしのフラグメント
・ダイアログフラグメント
・フラグメントやアクティビティのライフサイクル
・タブレット対応
・フラグメントのコールバックについて

以下にリンクを貼っておきますのでご覧ください。
資料
サンプルプロジェクト
サンプルアプリ


お知らせ

さてこの度、チームEGGは法人化し、チームEGG株式会社となりました。
これも皆様のおかげでございます。
また、状況が落ち着いてきましたら正式にお知らせいたしますが、2014年より活動の幅を広げていきたいと思っております。
これからもEGG開発ブログをよろしくお願いいたします。

2013年9月28日土曜日

Androidでゲーム開発する際のTips

チームEGG 曽川です。

こちらのAndroid Developers Blogの翻訳です。
Using the Hardware Scaler for Performance and Efficiency
要はスケーラを1080pxにするとパフォーマンス等で恩恵があるという話です。


パフォーマンス向上と効率化のために、ハードウェアスケーラを使用する

パフォーマンスを要する3Dゲームを開発する場合に、美しいグラフィック、高いフレームレート、よりよいレスポンスをする方法を探すことでしょう。また、バッテリーの節約やもプレイ中にデバイスが熱くなるのも避けたいでしょう。この分野全てにおいての最適化を支援するために、現在ほぼすべてのAndroidデバイスで利用可能なハードウェアスケーラの活用を検討してください。

どのように動作し、なぜ使用するのか

最近のほぼすべてのAndroidデバイスは、ハードウェアビデオスケーラを含むCPUとGPUのチップセットを使用しています。Androidは上位ベルでの統合を提供しており、Javaやネイティブコード(C++)からAndroid 標準APIを介してアプリがスケーラを利用できます。ハードウェアスケーラを利用するには、システムが利用するデフォルトのグラフィックバッファ(デバイスのフルスクリーン解像度にサイズ調整されています)ではなく、固定のグラフィックバッファを使用するだけです。

固定サイズのバッファにレンダリングする場合、デバイスのハードウェアはアスペクト比の調整も含めて、デバイスの画面解像度に合うように拡大や縮小を行います。通常、効率的にレンダリングさせるために、デバイスのフルスクリーンよりも小さい固定サイズのバッファを作成します。(特に、現在の高解像度の画面において)

ハードウェアスケーラを使用するとより効率が良くなる理由はいくつかあります。
1つ目は、ハードウェアスケーラは非常に高速で、マルチタップと表示の乱れを減らすアルゴリズムを通して、素晴らしい表示結果を生成することができます。2つ目は、アプリが小さなバッファにレンダリングされているため、GPUでの演算負荷が減り性能が向上します。3つ目は、少ない演算処理によりGPUは低温で動作し、バッテリーの使用が少なくなります。最後は、使用したいレンダリングバッファのサイズを選択でき、実際の画面解像度にかかわらず全てのデバイスで同じとなります。

フィルレートの最適化

モバイル用のGPUにおいて、ピクセルフィルレートはパフォーマンスを要するゲームアプリのボトルネックとなる主な原因の1つです。最近の携帯端末やタブレットはかなり高い画面解像度を提供し、2Dや3Dのグラフィックをレンダリングすると、大幅にフレームレートが下がります。GPUは最大のフィルレートを埋めるために非常に多くのピクセルを打つため、フレームレートが低下します。

Androidで使用される一般的なチップセットにおける
レンダリングされる解像度別のGPUの消費電力
(データはQualcommが提供)
これらのボトルネックを回避するためには、ゲームが各フレームで描画するピクセルの数を減らす必要があります。これを達成するためにZプリパスの最適化のような方法がありますが、簡単で効果的な方法はハードウェアスケーラを使用することです。

サイズが2560x1600のようなフルサイズのバッファを描画するのではなく、ゲームでは小さなバッファ(例えば1280x720や1920x1080)にすることで、ハードウェアスケーラは追加のコストがなく、できるかぎり少ない画質低下で表示を拡大します。

消費電力と発熱を少なくする

パフォーマンスを要するゲームは多くのバッテリーを消費し、かなり発熱する傾向があります。ゲームの消費電力と発熱に関することはユーザにとって重要であり、開発者にとっても重要な検討事項です。

図に示すように、GPUでの消費電力はレンダリングする解像度が高くなると大幅に増加します。多くの場合、GPUに負荷をかけることはデバイスのバッテリ寿命を減らすことになります。

また、CPU/GPUのレンダリング負荷が増加するにつれて、持っていることが不快になるほど発熱します。発熱するにつれてCPU/GPUを冷やすために、処理速度を調整するように設計されているので、ゲームを処理する順番を抑えることができます。

消費電力と発熱の両方を最小限に抑えるために、ハードウェアスケーラは非常に便利です。小さいバッファにレンダリングするため、GPUは少ない電力でレンダリングし発熱を少なくします。

Android APIからハードウェアスケーラへのアクセス

Androidは、標準のAPIからハードウェアスケーラに簡単にアクセスできます。(JavaコードやAndroidNDKを介したネイティブ(C++)コード)

これには固定サイズのバッファを作成し、レンダリングするためのAPIを使用するだけです。デバイスの実際の画面サイズを考慮する必要はないですが、元の縦横比を保持したい場合には画面とバッファのアスペクト比を一致させるか、バッファのレンダリング領域に画面を合わせます。

Javaコードからは、APIレベル1で導入されたSurfaceViewを通じてスケーラーにアクセスします。ここで、1280x720の解像度で固定サイズのバッファを作成する方法は次のとおりです。

ネイティブコードからスケーラを使用したい場合は、Android 2.3(APIレベル9)で導入されたNativeActivityクラスを介して行います。ここで、NativeActivityを使って1280x720の固定バッファを作成する方法は以下のとおりです。

バッファサイズを指定することで、ハードウェアスケーラが有効にされ、指定されたウィンドウへのレンダリングが対象となります。


グラフィックバッファの選択

固定サイズのグラフィックスバッファを使用する場合、パフォーマンスや処理性能向上と、対象デバイス間での画質バランスにおいてサイズを選択することが重要です。

ハードウェアスケーラを使用するほとんどの高性能3Dゲームは、レンダリングの推奨サイズは1080pxです。図に示すように、1080pxは画質、フレームレート、消費電力において最適な大きさです。もちろん720pxで十分な場合は、良い操作性のためにこの値を使用してください。


さらに

アプリでハードウェアスケーラを使用したい場合は、AndroidフレームワークでレンダリングしているかネイティブAPIでレンダリングしているかに応じて、SurfaceViewNativeActivityのドキュメントを参照してください。

バードウェアスケーラを使用したサンプルコードは近日公開です!

2013年9月15日日曜日

「3秒サムライ」リリースしました。

チームEGG曽川です。

このたびチームEGG初のUnityアプリ「3秒サムライ」をリリースしました。

瞬発力のゲームで、「!」マークが表示されたらタップするというシンプルなゲームです。
ただし、戦えるのは「3秒」。
そのなかでどれだけ敵を倒せるか、姫を助けられるかのゲームです。
こちらからダウンロードできます。
https://play.google.com/store/apps/details?id=com.egg.sansamu&hl=ja
また、3秒サムライの曲はボカロPのmathru氏に作成していただきました。
mathruねっと

技術的な話

このゲームは「Google Play Game Services」や「In-app Billing Version3」のような新しい機能も含んでいます。
Google Play Game Servicesに関してはこちらで講演いたしますので、興味ある方はぜひご参加ください。
http://atnd.org/events/42496

2013年8月8日木曜日

Androidの新機能を使ってみよう(Volley編)を講演しました

チームEGGの曽川です。

Androidの新機能を使ってみよう(Volley編)を講演しました。
YouTubeで検索した動画を表示するデモアプリを作りました。

今回の講演で使用した資料です。
http://goo.gl/9GNkM0

サンプルアプリ
https://bitbucket.org/mobaegg/android_seminar_20130808
Volley
https://android.googlesource.com/platform/frameworks/volley

特にVolleyのキャンセルのハマリポイントは要注意です。
また、深い話はできませんでしたが、セッションCookieを扱ったり、
オレオレ証明書を通したりはHurlStack#createConnectionをオーバライドし、
通信して取得したデータを整形したり、DBと連携させたりする場合は
Request#parseNetworkResponseをカスタマイズすると良いと思います。

配布したコードについて補足

VolleyRequestHolder
講演の中で何回も使いましたが、これはVolleyの標準APIではありません。
RequestQueueはシングルトンにせよ。という話なので作成しました。
アプリ内共通でセッションCookieを扱ったり、オレオレ証明書を使う場合は、Volley#RequestQueueの第二引数にそれを行うHttpStackオブジェクトを渡します。
※sigletonなのにContextを渡しているので一瞬「おや?」と思うかもしれませんが、このContextはキャッシュディレクトリやパッケージ名を取得するために使うだけで、Context自体を保持するわけではないので問題ありません。

GsonRequest
こちらも今回の講演の主要コードですが、標準APIではありません。(元コード
通信が成功するとparseNetworkResponseが呼び出されます。その時にメソッド内でGSONを使ってオブジェクトに変換しています。
parseNetworkResponse内は非同期になっているので、通信とDBの連携などを行う際はこちらに記述すると良いかと思います。

ImageNoCache
サムネイルを表示する際に一瞬だけ登場したクラスです。
NetworkImageViewは画像のキャッシュを行うのですが、このコードは自分で作成する必要があります。
今回はキャッシュする必要性がなかったので、キャッシュについて何もしないクラスを作りました。
時間があれば試そうかと思ってたのですが、キャッシュのサンプルとして以下サイトのBitmapCache.javaを組み込んでいます。
Android Tips #51 ネットワーク通信・キャッシュ処理をより速く、簡単に実装できるライブラリ “Volley” を使ってみた


2013年7月31日水曜日

Support v7 の Action Barを使ったナビゲーションドロワー実装 (実装編)

チームEGGの赤峰です。

前回の「準備編」で開発の準備が整いました。
今回は自動生成された「Drawer」プロジェクトに修正を加え簡単なナビゲーションドロワーを作成します。




完成イメージ



1.マニフェスト変更

アクションバーをActivityに適応させるためにstyleの変更を行います。
  • Holoベースの場合…『Theme.AppCompat』
  • Holo.Lightベースの場合…『Theme.AppCompat.Light』
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.egg.drawer"
    android:versionCode="1"
    android:versionName="1.0" >
    <!--Android 2.2以上を指定 -->
    <uses-sdk
        android:minSdkVersion="8" 
        android:targetSdkVersion="17" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light" >
        <activity
            android:name="com.egg.drawer.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

2.レイアウトの変更

Activityに設定するレイアウトXMLの修正を行います。
  • android.support.v4.widget.DrawerLayoutを持つレイアウトを定義
    • idを定義
    • ドロワーの最初の子Viewにメインコンテンツ用のViewを定義
  • メインコンテンツViewの定義
    • layout_width, layout_heightにmatch_parentを指定
  • ドロワー表示用レイアウトをDrawerLayoutの子Viewとして加える
    • idを定義
    • ドロワーのlayout_widthは240dp~320dpを指定
    • 左から表示させる場合は、layout_gravityにstartを指定
    • 背景色の指定 (Lightスタイルを指定したので、白ベースのカラーコードを定義)
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <!-- メインコンテンツ領域 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <!-- ドロワー領域 -->
    <LinearLayout
        android:id="@+id/drawer"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#fafafa"
        android:orientation="vertical" >
        <Button
            android:id="@+id/button1"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:text="button1" />
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

3.Activityの変更

Activityでドロワーを制御するため、以下の修正を加えます。
  1. ActivityをActionBar対応する
  2. ドロワーを制御する
  3. アプリアイコンを変更する

1.ActivityをActionBar対応する

Actionbarに対応させるために継承クラスをActionBarActivityに変更します。
ActionBarActivityを利用するためandroid.support.v7.app.ActionBarActivityをインポートします。
ActionBarActivityを継承したことで、画面左端からスワイプすると
ナビゲーションドロワーが表示されるようになります。
package com.egg.drawer;

import android.support.v7.app.ActionBarActivity;

public class MainActivity extends ActionBarActivity {
   ....
}


2.ドロワーを制御する

ナビゲーションドロワー関連の処理はActionBarActivityで、
基本処理は実装されているため不足している処理を追加します。
ドロワー内のボタンが押された場合に、ドロワーを閉じる処理を追加します。
public class MainActivity extends ActionBarActivity {
    /** ドロワーレイアウト */
    private DrawerLayout mDrawerLayout;
    /** ドロワー用View */
    private View mLeftDrawer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mLeftDrawer = findViewById(R.id.drawer);
        // ボタンイベント
        mLeftDrawer.findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mDrawerLayout.closeDrawers(); // ドロワーを閉じる
              }
        });
    }
}

3.アプリアイコンを変更する

ActionBarDrawerToggle を利用しドロワー特有のアプリアイコンに変更します。
Drawer用アイコンは以下のリンクからダウンロードして下さい。


アプリアイコンのタップでドロワーのオープン・クローズを行うように実装します。
ActivityのonCreate()メソッドでActionBarDrawerToggleのオブジェクトを生成します。
ActionBarDrawerToggleのコンストラクターに指定する引数は以下の5つです。
  1. Activity
  2. DrawerLayout
  3. Drawer用アイコン(ダウンロードした画像)のリソースID
  4. オープン用のリソースID
  5. クローズ用のリソースID

アプリアイコンのクリックを有効化するためにActionBarに以下をセットします。
  • setDisplayHomeAsUpEnabled(true)
  • setHomeButtonEnabled(true)

Toggleを利用するためandroid.support.v4.app.ActionBarDrawerToggleをインポートします。
import android.support.v4.app.ActionBarDrawerToggle;
...

public class MainActivity extends ActionBarActivity {
    ...
    /** ドロワートグル */
    private ActionBarDrawerToggle mDrawerToggle;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // ドロワー用トグル生成
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_oepn, R.string.drawer_close) {
            @Override
            public void onDrawerClosed(View view) {
                supportInvalidateOptionsMenu();
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                supportInvalidateOptionsMenu();
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        // アプリアイコンのクリック有効化
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);

    }
}


Activityの通知の一部をActionBarDrawerToggleに通知しUp画像からドロワー画像に変更します。
...

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // 生成
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // 画面切り替え
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
}


アプリアイコンのタップをドロワーのオープン・クローズとして処理します。
...

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // アプリアイコンタップ
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}


以上で、Support v7を利用したナビゲーションドロワーが実装できます。

ナビゲーションドロワーを正しく実装するためには、
Androidデザインのナビゲーションドロワーを参考にしてください。


サンプルコード

今回ご紹介したサンプルコードをアップしました。
https://bitbucket.org/mobaegg/android_drawer

2013年7月26日金曜日

Support v7 の Action Barを使ったナビゲーションドロワー実装 (準備編)

チームEGGの赤峰です。

いよいよアクションバーが公式サポートされました。
Support v7での対応になるのでAndroid 2.2以上が対象となります。

まずは、Actionbarを使うための準備を行います。

1.サポートライブラリの更新

Android SDK Managerを起動し、
Extras > Android Support Libraryにチェックを入れインストールをします。



ダウンロードが完了すると『appcompat』フォルダーが生成されます。
『appcompat』がアクションバーを実装するのに必要なライブラリプロジェクトです。
SDKフォルダ > extras > android > support > v7

※『appcompat』をライブラリプロジェクトとして利用するため、任意のフォルダーにコピーしてください。




2.「appcompat」のライブラリプロジェクト化

アクションバーを利用するためには、「appcompat」をライブラリプロジェクトとして参照する必要があります。
Eclipseを起動し、 Appcompatを読み込みます。
File > New > Other > Android > Android Project from Existing Code





Import Projectsウィザードが起動したら「Browse...」を選択し、
1.でコピーした用意した『appcompat』フォルダを選択し、「Finish」を選択します。
 【注意】※SDK内の「appcompat」は利用しないようにしてください






この手順まで完了するとActionBar用のライブラリプロジェクトがワークスペースに生成されます。




3.「appcompat」のライブラリ読み込み

次は、作成するプロジェクトに「appcompat」をライブラリとして取り込みます。
今回はナビゲーションドロワーを作成するため以下のプロジェクトとして作成しています。

  • プロジェクト名:「Drawer」
  • パッケージ名:「com.egg.drawer」

この「Drawer」プロジェクトに先ほど作成した「appcompat」ライブラリを取り込みます。
「Drawer」プロジェクトのPropertiesを開き、Androidを選択します。

画面下のLibrary内にある「Add...」を選択し、「appcompat」プロジェクトを選択します。
「OK」を選択すると「Drawer」プロジェクトが「appcompat」プロジェクトを読み込むことができます。





ライブラリとして取り込んだプロジェクトにjarファイルが重複していると実行時にエラーが表示されます。
そのため、最後に「Drawer」プロジェクトのlibsに入っているサポートライブラリを削除します。




以上で「準備編」の完了です。
次回、「実装編」に続きます。

2013年7月24日水曜日

『マルチタイマー』をリリースしました。

チームEGGの赤峰です。

Androidアプリの『マルチタイマー』をリリースしました。
今回は新しいAndroid技術を取り入れたアプリになっています。

Google Play: 『マルチタイマー』

【機能】
・ストップウォッチ
・カウントダウン
・マルチ ストップウォッチ
・マルチ カウントダウン
・ランキングタイマー


【特徴】
・Android 3.0以降のHoloテーマ
・ナビゲーションドロワーの実装
・カードUI導入
・デザインガイドラインにそったアプリ開発

ナビゲーションドロワー

Holoテーマ

カードUI



今後も機能追加していく予定です。
欲しい機能やご要望があれば気軽に連絡ください。

Androidデザイン翻訳サイトもよろしく!
Android デザイン 翻訳 by チームEGG

2013年5月27日月曜日

Google I/O関連のリポジトリ

チームEGGの曽川です。

先日、Google I/Oで様々な発表がありました。
その中で、注目しておいたほうがいいリポジトリを紹介します。

InAppBilling Version3(アプリ内課金バージョン3)

https://code.google.com/p/marketbilling/
関連セッション

Google Play game service(リーダボードやアチーブメント)

https://github.com/playgameservices/android-samples
関連セッション1
関連セッション2
関連セッション3

Volley(非常に便利な通信API)

https://android.googlesource.com/platform/frameworks/volley
関連セッション

日々バグ修正や機能追加が行われているので、アプリ内に組み込むことを検討中であれば要チェックです。

2013年4月17日水曜日

Android Designを翻訳しました

チームEGGの曽川です。

Androidデザインガイドラインの翻訳を行いました。

Android Design 翻訳 by チームEGG


前回の講演でもちらっとお伝えしましたが、レイアウトや内容の修正を終えましたので公開します。
デザインも本家になるべく沿うように作っていますので、対応させながらご覧ください。
また、修正・指摘等あればぜひコメントをください。
今後は本家ドキュメントの更新に対応したり、本ブログでも触れていこうと思っています。

2013年3月17日日曜日

2013年1月27日日曜日

AndroidアプリをNexus 7へ対応させるTips

EGG曽川です。

Nexus7対応についての公式アナウンスを翻訳してみました。
原文は以下のURLからです。
Getting Your App Ready for Jelly Bean and Nexus 7

翻訳に誤りやさらに良い表現が有りましたら、お知らせください。


Jelly BeanとNexus7のためのアプリの準備

Android4.1のための完全なSDKを開発者が利用可能で、SDKマネージャからダウンロードできることをお知らせいたします。
現在、新しいJelly Bean APIを使用して、API16対象のアプリを開発しリリースすることができます。
また、SDK Tools revision 20.0.1とバグ修正のみが含まれているNDK revision 8bをリリースしています。

多くの人にとって、最初に味わうJelly Beanは美しいNexus7です。
ほとんどのアプリはNexus7上で正しく動作するでしょうが、アプリを最適化したくはありませんか?
ここデバイスを最大限活用するためにアプリケーションを最適化するいくつかのTipsを紹介します。

スクリーン
Nexus7という名前を与えられたのは、7インチ画面だからです。
開発者としては、約600*960のピクセル密度でtvdpiの密度として参照してください。
Dianne Hackbornが詳述したように、この密度は驚くかもしれませんが慌てることはありません。
私たちは、驚きとこの密度の新しいリソースの作成を防ぎます。
Androidは既存のリソースをスケーリングします。
実際には全てのJelly Bean OSはtvdpiリソースのみを含み、残りはhdpiリソースから縮小されます。
システムがhdpiのリソースをtvdpiに完全にスケーリングすることを確実にするために、有効に縮小させるために特別配慮した9-patch画像を作成します。
  • 伸縮領域は少なくとも2x2ピクセルサイズであることを確認してください。そうでなければ、縮小した際に消滅する危険性があります。
  • 画像の伸縮領域の前後に、余分で安全な1ピクセルを与えてください。そうでなければスケーリング時に変更する境界で色の補間が発生します。

7インチのフォームファクタは、内容の表示のために多くのスペースを与えます。
このサイズの画面レイアウトの代替を提供するために、sw600dpのリソース修飾子を使用できます。
例えば、あなたのアプリは起動アクティビティのレイアウトを含んでいるとします。
res/layout/activity_home.xml

7インチスクリーンの余分なスペースを活用するためには、別のレイアウトを提供してください。
res/layout-sw600dp/activity_home.xml

sw600dpの修飾子は、これらのリソースが短辺が少なくとも600dpの画面を持つデバイスで利用可能であることを宣言します。

さらに、10インチタブレット用の異なるレイアウトを提供するには
res/layout-sw720dp/activity_home.xml

このテクニックは、1つのアプリケーションでコンテンツの最適なレイアウトを示すために、デバイスの構成に応じて定義されている、スイッチングポイントとして使用することができます。

同様に、携帯電話のレイアウトは7インチの画面上でうまく動作しますが、少し大きめのフォントや画像のサイズを必要とするなら、あなたは、1つのレイアウトを使用してdimensionファイルで代替サイズを指定できます。
例えば、res/values/dimens.xml はフォントサイズのディメンジョンを含んでいるとします。
<dimen name="text_size">18sp</dimen>

しかし、res/values-sw600dp/dimens.xmlで7インチタブレットの代替テキストのサイズを指定することができます。
<dimen name="text_size">32sp</dimen>

ハードウェア
Nexus7は多くの携帯電話と異なるハードウェア機能を持っています。
  • 電話機能がない
  • 1つのフロントカメラ(android.hardware.cameraを要求するアプリはNexus7では利用できません。)

宣言した(または暗黙で)システムの機能は、アプリケーションの実行時に要求する、またはPlay StoreがNexus7ユーザに利用できないことを示すことに注意してください。
あなたのアプリにとって重要でないハードウェア機能は常にrequired="false"として宣言することで、機能が存在するかどうか実行時に検出し、機能的に広い人に使ってもらうようにします。
例えば、アプリがカメラを使用するが動作に必須でない場合、これを宣言します。



詳細については、Reto MeierのFive Steps to Hardware Happinessを参照してください。

結論
Nexus7はJellyBeanが付属しており、更新された一揃いのシステムアプリは新しいJellyBeanのAPIを活用するために構築されています。
これらのアプリは、あなたのアプリを判断にするにおいて標準のものです。これらのアプリに従っているか確認してください。

アプリが通知を表示する場合は、新しいリッチな通知スタイルの利用を考慮してください。
没入型コンテンツを表示している場合は、システムUIの外観を制御してください。
オプションメニューを使用している場合は、アクションバーのパターンを使用してください。

多くの作業がJellyBeanはバターのような滑らかな作りになっています。
アプリが同様になっていることを確認してください。
ハードウェアアクセラレーションレンダリングをオプトインしていない場合は、今すぐ実装しテストしてください。

Android4.1の詳細については、Android Developersサイトをご覧になるか、Liveに参加してください。

2013年1月12日土曜日

Verifying Back-End Calls from Android Apps 翻訳(Androidアプリからのバックエンド認証の呼び出し)

チームEGGの曽川です。

原文はVerifying Back-End Calls from Android Appsです。
Androidアプリとサーバが通信をする際に、誰と何の通信を行っているのか判別する方法です。
この記事では概要が書かれておりますので、実際の実装は各リンクをたどって進める必要がありそうです。
翻訳に誤りや良い表現があればご指摘をお願いいたします。


Verifying Back-End Calls from Android Apps
ほとんどのAndroidアプリは、データの永続化や共有のためにサーバ側のバックエンドのようなものを持っています。
もっとも基本的なゲームは、プレイヤーのハイスコアを覚えておく必要があります。
バックエンドを構築するとき、解決しなければならない1つの問題はどのようにバックエンドのコードが、アプリと何を話しており、誰が使っているのか知ることです。

クライアントアプリと通信するHTTPのエンドポイントを持っていると思いますが、サーバ側のコードがどのようにしてメッセージを送信している人を確認しますか?
結局のところ、誰もがどこからでもHTTPのPOSTリクエストを送信できます。
IDを推測できれば、ユーザを偽装することができます。

端末デバイス上でユーザ名とパスワードを入力をお願いすることは、本当に使い勝手が悪いです。
特に、もし誰かがアプリをインストールし、インターネットを使用して、IDを知るための許可を与えているならば、これ以上悩むことはありません。

GooglePlayサービスは、Googleアカウントの使用を基盤にするよい解決策の提供を開始しています。(Android2.2以上を実行する互換性のあるすべての端末上で現在利用可能です)

概要
複数のステップを完全に説明しますが、ここは短いバージョンです。
IDトークンと呼ばれる文字列を取得するためにお、GooglePlayを通じて利用可能なGoogleAuthUtilクラスを使用します。
バックエンドにトークンを送り、バックエンドはどのアプリから送られたものか誰がアプリを使っているのかを素早く容易に確認するために使用できます。



この機能は、単純なプログラミングモデルにアプリ/バックエンドIDを焼きこむ、App Engineの新しいクラウドエンドポイント機能のようなGoogleの機能に組み込まれています。

それでは、詳細を入手していきましょう。

アプリ登録
GooleAPIコンソールを使用するために多くの手順が必要です。
この目的のために、新しいプロジェクトを作成しなければなりません。
人間が読める形式の名前とグラフィカルブランドを与えることができますが、それらのリソースはこの特別なシナリオでは使用されていません。

また、多くの異なるGoogle APIにアクセスするために、このプロジェクトに権限を与えることができますが、このシナリオを2回行う必要はありません。
これらは重要な管理の役割であるため、プロジェクトのメンバーとして承認する人を真剣に考えなければなりません。

クライアントIDの作成
あなたのプロジェクトに、2つの異なるOAuth2.0の"クライアントID"が必要です。
1つ目は、Webアプリケーションの"クライアントID"です。
改めて、ラベリングやブランディングのものを無視することができ、9414861317621.apps.googleusercontent.comのようになるクライアントIDの文字列のみが必要です。

今、あなたはAndroidアプリのために、別のクライアントIDを作成する必要があるでしょう。
これを行うには、次の2つの情報を提供する必要があります。
アプリパッケージ名、証明書の署名です。
パッケージ名は、Java形式のDNSの逆順(AndroidManifest.xmlの一番上の「package」属性で与えられたもの)です。(例:com.example.identity)

アプリの証明書の署名を取得するには、次のシェルコマンドを実行してください。
$ keytool -exportcert -alias  -keystore  -v -list

"SHA1"とラベルされたオクテットをコピーし、デベロッパーコンソールのフィールドに貼り付けてアプリのクライアントIDを生成してください。
改めて、あなたが読み出したものから本当に必要なものはクライアントID文字列だけです。

Androidアプリ内
IDトークンを取得するために、GooglePlayサービスのGoogleAuthUtilクラスを呼び出す必要があります。
手順はObtaining an Access Tokenで説明されています。
魔法の余分な1ビットがあります。getToken(email, scope)メソッドのscope引数の値です。
文字列は、audience:server:client_id:Xとなり、Xは上で説明したWebアプリのためのクライアントIDです。
クライアントIDが上の例の値で与えられた場合、scope引数の値はaudience:server:client_id:9414861317621.apps.googleusercontent.comとなります。

魔法のようなことが起こります
通常OAuthトークンを要求すると、デバイスを利用する人はいくつかのリソースやその他の取得時にIDの使用してもかまわないかどうかを求める申し込みを見ます。
しかし、この場合システムはscope引数のサーバ側のクライアントIDを見て、あなたのAndroidアプリと同じプロジェクトだとわかると、ユーザを困らせることなくトークンを与えます。
(ユーザはプロジェクトを制御する開発者との関係にすでに同意しています。)

トークンの送信
サーババックエンドに話を開始する準備ができたとき、トークン文字列を送信する必要があります。
これを行うもっともよい方法はPOSTメッセージの本文に含むことです。
(URLパラメータに入れることもできますが、記録されることがあります。)
トークンの覗き見から中間者であることを保つために絶対にHTTPS通信を使用してください

トークンの使用
サーバがAndroidアプリからトークンを受け取るとき、それを確認することは非常に重要です。
2つの手順が必要です。
  1. 本当にGoogleからの署名であること確認します。
  2. 本当にあなたに宛てられたものであるか確認します。

署名の確認
Googleの公開/秘密鍵を使ってこれが署名されていることがわかったら、Googleはwww.googleapis.com/oauth2/v1/certsの公開鍵(定期的に変更する)を発行します。
(見に行ってください。)

実際にJSONウェブトークンであるIDトークンは、それらの証明書のいずれかを使用して署名されたことを確認しなければなりません。
幸い、これらを行うためのきちんとしたライブラリがあります。
(この記事ではJava、Ruby、PHPのための指針を与えます)

ライブラリは、Googleの証明書をキャッシュでき、必要な時にのみリフレッシュをおこなうので、確認は(ほとんどの場合)高速な静的呼び出しです。

トークンフィールドの確認
IDトークンがJSONペイロードを持っているとわかったら、署名を検証する多くのライブラリはハッシュや辞書または何かを与えます。
したがって、このようなaudやCIDやemailのような名前検索が可能となります。

まず、AUDという名前のフィールドを見て、あなたのクライアントID(Androidアプリのscope引数に含まれる文字列)と同一か確認します。
絶対にこの手順を省略してはいけません。
もしIDトークンを確認しなければ、ほかの開発者があなたのサービスへの要求を偽造することができます。

必要に応じて、CISという名前のフィールドを見てあなたのAndroidアプリのクライアントIDと同一か確認してください。
余談ですが、トップレベルプロジェクトそれぞれ独自のクライアントIDで複数の異なったAndroidクライアントアプリを持つことができます。

これらのこと3つを行ったと仮定します。その後、あなたは以下を知っています。

  1. Googleから発行されたトークン
  2. トークンが、ペイロードのemailフィールドで識別される人によって操作されたデバイスに送られました。

また、高い信頼性を持っています。
  1. トークンは、ペイロードのCIDフィールドのクライアントIDによって識別されたAndroidアプリによって得られました。

非互換性やルート化されたAndroidデバイスが情報を改ざんすることができるかもしれないので、クライアントIDは高い信頼性を持っています。
Google署名やGoogleへ、デバイスのユーザー認証の偽装をすることができません。

次は?
あなた次第です。
あなたが話している人とアプリを知って、その情報をどのように処理するかはあなた次第です。

コードの断片
GoogleのJavaライブラリを使用して、IDトークンチェッカーを実装するJavaクラスは次のとおりです。

import java.io.IOException;
import java.security.GeneralSecurityException;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;

public class Checker {

    private final List mClientIDs;
    private final String mAudience;
    private final GoogleIdTokenVerifier mVerifier;
    private final JsonFactory mJFactory;
    private String mProblem = "Verification failed. (Time-out?)";

    public Checker(String[] clientIDs, String audience) {
        mClientIDs = Arrays.asList(clientIDs);
        mAudience = audience;
        NetHttpTransport transport = new NetHttpTransport();
        mJFactory = new GsonFactory();
        mVerifier = new GoogleIdTokenVerifier(transport, mJFactory);
    }

    public GoogleIdToken.Payload check(String tokenString) {
        GoogleIdToken.Payload payload = null;
        try {
            GoogleIdToken token = GoogleIdToken.parse(mJFactory, tokenString);
            if (mVerifier.verify(token)) {
                GoogleIdToken.Payload tempPayload = token.getPayload();
                if (!tempPayload.getAudience().equals(mAudience))
                    mProblem = "Audience mismatch";
                else if (!mClientIDs.contains(tempPayload.getIssuee()))
                    mProblem = "Client ID mismatch";
                else
                    payload = tempPayload;
            }
        } catch (GeneralSecurityException e) {
            mProblem = "Security issue: " + e.getLocalizedMessage();
        } catch (IOException e) {
            mProblem = "Network problem: " + e.getLocalizedMessage();
        }
        return payload;
    }

    public String problem() {
        return mProblem;
    }
}


あなたがRubyでこれをやってみたい場合は、 google-id-token Ruby gemをインストールして、このように書きます

require 'google-id-token'
validator = GoogleIDToken::Validator.new
jwt = validator.check(token, required_audience, required_client_id)
if jwt
  email = jwt['email']
else
  report "Cannot validate: #{validator.problem}"
end

PHPプログラマは、Google APIs Client Library for PHPをチェックアウトしてください。
(apiOAuth2.phpのverifyIdTokenの関数)