Android

AndroidでマルチリンガルTTS(音声合成)アプリ

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - AndroidでマルチリンガルTTS(音声合成)アプリ
このエントリーをはてなブックマークに追加
はじめましてこんにちは
9月に入社しました、Androidアプリ開発者のたかなです。

今日はAndroidの搭載機能である「TTS(音声合成)」を用いた マルチリンガルTTSアプリを作ってみたいと思います!

20111228-171243



TTSとは


TTSは Text To Speech の略です。読んで字のごとく、音声合成を指します。

初音ミクなどのVocaloid、駅のアナウンス、ロボットに搭載されている音声を耳にしたことがある人も多いでしょう。棒読みちゃんを使っている人もいるかもしれませんね。

TTSは「動的に変化する情報をリアルタイムにしゃべってほしい」「状況に応じて素早くアナウンスしたい」「いつでも、どこでも、手間をかけずに情報を発信したい」といったニーズに対応するよう作られ、郵便局や病院の番号札の読み上げなどから、近年では肉声に近いなめらかな発音のモデルも増えてきました。


AndroidにTTSが標準搭載


Android 1.6から、TTS機能が標準搭載されています。
ただし、音声を合成するためにはボイスデータと呼ばれる音声のパーツの集合(アプリ形式)をインストールする必要があり、そのままでは使うことができません

今回のアプリではその点を加味して、ボイスデータの有無をチェック、なければマーケットの該当アプリへ遷移する、という機能も付加しています。


AndroidTTSの対応言語


現在、AndroidTTSの対応言語は「英語(イギリス英語を含む)」「フランス語」「ドイツ語」「イタリア語」「スペイン語」の5つです。 自分のAndroid端末がどの言語をしゃべれるかは、「設定」→「音声入出力」→「テキスト読み上げの設定」→「言語」で確認できます。

残念ながら日本語非対応とのことで、日本語の合成を実現するためには別のライブラリが必要です。


AndroidTTSを使ってみる


SDKの「TextToSpeech」クラスを使います。
リファレンスはこちら TextToSpeech - Android Developers

しゃべらせること自体はとても簡単で、 speakメソッドの引数に読んでほしいテキストを与えるだけです。
各言語の設定を行うにはsetLanguageメソッドでLocaleを指定します。
今の設定がどの言語か?を調べるためにはgetLanguage()しましょう。

また、自分以外の人の端末でアプリを使って欲しい場合は、その端末の対応言語を調べる必要があります。
これはisLanguageAvailableメソッドにLocaleを指定することで、ステータスがTextToSpeechの定数として返ってきます。

例)端末がアメリカ英語のTTSに対応可能かを判断するためには
if (mtts.isLanguageAvailable(Locale.US) >= TextToSpeech.LANG_AVAILABLE) {
   //対応可能だった時の処理
}

となります。 TextToSpeech.LANG_AVAILABLEは「言語が使用可能である」ことを指していて、 ステータスがLANG_AVAILABLE以上の状態であれば合成が可能です。

余談ですが、サポートされていないLocaleならLANG_NOT_SUPPORTED、必要なボイスデータがインストールされていないとLANG_MISSING_DATAが返ってくるので、必要に応じて処理を加えましょう。


作ってみよう


アプリの仕様です。

  1. はじめにボイスデータがあるかどうかチェックする

  2. ヘルプボタンを押すとガイド音声が流れる

  3. デフォルトはアメリカ英語

  4. テキストを入力して「TextToSpeech!」ボタンを押すと合成し再生

  5. 「Laguage」ボタンで言語の切り替えが可能



サンプルコード


TextToSpeechActivity.java

package jp.android;

import java.util.Locale;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class TextToSpeechActivity extends Activity  implements TextToSpeech.OnInitListener {

    private static final int CHECK_TTS = 682730935;
    private Button mSpeakButton;
    private TextToSpeech mTts;
    private EditText et;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.checkTTS();

        mTts = new TextToSpeech(this, this);

        this.mSpeakButton =
            (Button) findViewById(R.id.speak_button);
        et = (EditText)findViewById(R.id.inputText);
        mSpeakButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                startTTS(et.getText().toString());
            }
        });

    }

    /**
     * TTSエンジンがインストール済かどうかを判定
     */
    private void checkTTS() {
        Intent intent = new Intent();
        intent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(intent, CHECK_TTS);        
    }

    // チェックの結果を受け取る
    protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
        if (requestCode == CHECK_TTS) {
            if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
                //インストール済ならウェルカムメッセージを発話
                startTTS("Welcome to TTS application, Let`s start!");
            }
            else {
                //インストール無しなら
                Intent install = new Intent();
                install.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(install);
            }
        }
    }

    /**
     * 合成を実行
     * @param text 読み上げたいテキスト
     */
    private void startTTS(String text) {
        mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
    }

    /**
     * ヘルプガイドを読み上げる
     * @param v
     */
    public void startGuide(View v) {
        mTts.setLanguage(Locale.US);
        startTTS(getString(R.string.guide));
    }

    /**
     * 言語選択ボタン
     * @param v
     */
    public void onSelectLang(View v) {
        AlertDialog.Builder ab = new AlertDialog.Builder(this);
        String[] str = {"English","French","German","Italian","United Kingdom"};
        ab.setItems(str, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int i) {
                switch (i){
                    case 0:
                        mTts.setLanguage(Locale.US);
                        break;
                    case 1:
                        mTts.setLanguage(Locale.FRENCH);
                        break;
                    case 2:
                        mTts.setLanguage(Locale.GERMAN);
                        break;
                    case 3:
                        mTts.setLanguage(Locale.ITALIAN);
                        break;
                    case 4:
                        mTts.setLanguage(Locale.UK);
                            break;
                }
                
            }
        });
        ab.show();
    }

    public void onInit(int status) {        
        if (status == TextToSpeech.SUCCESS) {
            if (mTts.isLanguageAvailable(Locale.US) >= 
                    TextToSpeech.LANG_AVAILABLE) {
                //アメリカ英語に設定
                mTts.setLanguage(Locale.US);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        mTts.shutdown();
    }
}



20111228-171254

非常に簡単にマルチリンガルなTTSアプリが作れました。


注意点


speakメソッドは非同期なので、音声の合成処理・再生中はタスクの状態に応じた処理が必要です。特に長い文章を読ませたい場合(入力される文字数を制限しない場合)は注意しましょう。


サンプルプロジェクトのソース


スペースの関係で全部のソースは載せられないので、こちらに置いておきます。
https://www.assembla.com/code/texttospeech/git/nodes


まとめ


AndroidTTSを使うと、手軽に音読アプリが作れます。
合成から音声再生までのレスポンスが速いので、ちょっとした外国語のトレーニングに使えそうですね。
定型文をあらかじめ入力しておけば、海外旅行にも役立ちそうです。

また、今年1月から、全てのAndroid端末で 音声対話型コンシェルジュサービスnetpeople : aが利用可能になるとのことなので、TTSが日本語サポートされたら端末同士の会話が実現するかもしれません。


<おまけ>Androidで使える日本語TTSライブラリ


日本語で音声合成してみたい!という方向けに公開されているライブラリです。
有料のものがほとんどなので、気軽に試せないのが少し残念ですね。

音声合成エンジン "Galatea Talk"を用いたライブラリ

デザイナーに聞かれがちなAndroid UIの仕様

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - デザイナーに聞かれがちなAndroid UIの仕様
このエントリーをはてなブックマークに追加
開発部の井上(@inonb)です。12月に位置情報サービス・ロケタッチのAndroidアプリをリリースしました。ぜひお試しください。

さて、今回はAndroidアプリのUIまわりについて書いてみたいと思います。

iPhoneアプリに比べて、AndroidアプリのUI仕様は、わりとWebに近いところがあります。Webの仕事の経験があるデザイナーさんは入りやすいところもあるのですが、マルチディスプレイ対応など面倒なところもあります。

デザイナーさんに聞かれた質問について簡単にまとめてみたいと思います。

1. iPhoneアプリのデザインって流用できますか?


流用はできるだけ避けたいです。

たとえばTwitterやFacebookのアプリなど、両プラットフォームに多くのユーザーを持つアプリを見ても、iPhoneとAndroidではデザインが変わっているのが分かると思います。

Androidのデザインは、OSの標準UIが、iPhoneと比べてフラットでシャープな感じなので、アプリのデザインの方もできればそれに合わせたいところです。

アプリのナビゲーションも、「戻る」「メニュー」ボタンがあることでだいぶ変わってきます。

具体的な違いについては、iPhoneとAndroid両方でているアプリをたくさん見比べるのがいいと思いますが、まとまった資料としては、Google UIチームが昨年5月に行った「Android UI design patterns」というセッションのビデオ・スライドがおすすめです。

iPhoneには「iOS Human Interface Guidelines」というドキュメントがあって、デザイン全体の要点をまとめていますが、このセッションでは同じように、Googleの開発チームによるAndroidデザインの考え方に触れることができます。

それに加えて、使い回しのきく5つのデザインパターンと、そのケーススタディとして、Twitterアプリが紹介されています。

2. pxは使えないんですか?


Androidではアプリのビュー(見た目)はXMLで記述します。WebアプリがビューにHTMLのテンプレートを使うのと似た感じで、記述もHTMLとよく似ています。

このXMLで、フォントや画像、コンテナの大きさを指定するときには、おもにdpという単位を使います。

正式名はdensity independent pixelといって、ピクセルに解像度の高さを掛けたものです。ややこしいですが、こうすると解像度が異なる端末でも見かけの大きさが揃うようになります。

逆にいえば、pxでサイズ指定すると、解像度によって表示される大きさがばらばらになってしまいます。



こんな感じです。そこで大きさの単位にはdpを使うことが推奨されています。

Androidはディスプレイの解像度の高さを3段階(最新ドキュメントでは4段階)に分けています。中解像度、160dpiが基準で、このとき1dp=1pxとなります。240dpiでは1dp=1.5pxです。

インチ数100dp
低解像度120dpi75px
中解像度160dpi75px
高解像度240dpi150px

現行機種では、次のようにディスプレイは高解像度のものが多いです。

インチ数ドット数解像度
Galaxy S4型480×800240dpi
IS033.5型640x960320dpi
Lynx 3D3.8型480×800240dpi
Xperia4型480×854240dpi
Galaxy Tab7型600×1024240dpi

3. 素材の画像はどう出力すればいいんですか?


dpはAndroid独自の単位なので、素材の画像はpxで書き出します。そのとき何pxで出力すればいいのか、という点が問題ですが、大きくふたつの方法があります。

オートスケール
Androidには、解像度に合わせて画像を拡縮する機能があります。
ひとつの画像でも、低解像度向けには小さく、高解像度向けには大きく、サイズを調整して表示してくれます。

この方法の問題は、拡大された画像が粗くなって見える場合があることです。
そこで、アイコンやロゴなど、どの解像度向けにもきれいに表示させたい場合には、次のプレスケールと呼ばれる方法を使います。

プレスケール
プレスケールは、こちら側で解像度別に素材を用意する方法です。たとえば、100dp × 30dpのロゴを、中解像度と高解像度向けに用意する場合、100px × 30px(中)、150px × 45px(高)の画像を2つ書き出すことになります。

それを解像度別のフォルダに入れます。

drawable

drawableというフォルダが、画像などリソース場所の置き場ですが、その下に-hdpi、-mdpiなどがついたフォルダがあります。これが解像度別のフォルダになるので、高解像度用は-hdpiに、中解像度用は-mdpiに入れます。するとそれぞれの環境で使い分けがされます。

このオートスケール、プレスケールを使い分けて、画像の素材を準備していくことになります。

Androidはディスプレイがさまざまなので、それを考慮したデザインが必要ですが、解像度やディスプレイサイズの違いを吸収するしくみもありますので、それをうまく利用したUI設計をしたいですね。

Androidを「貧血チェックガジェット」化する!

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - Androidを「貧血チェックガジェット」化する!
このエントリーをはてなブックマークに追加
はじめまして。今回のTechブログを担当する@ianim4です。
まだ、本当の名前はありません。


今回のお題

Tech ブログ、スマフォシリーズもだいぶ回を重ねて参りました。今回は、そろそろ何か作ってみましょうと言う事で技術のライブドアとして何がいいかなと、考えてみます…

思いつかないときは、逆立ちをして、数秒待ちます。

はっちゃけた!(古
貧血チェックガジェットを作ることになりました。

どういったものかと言うと、貧血になった人がいた場合に、Androidが知らせてくれると言う画期的なものです。これは、夏の体育館、校長先生のありがたいお話の時にはまず間違いなく必要とされるガジェットでしょう。

実装に向けて

貧血は、「血液中の赤血球が乏しくなること」とのことなので、血液中の赤血球濃度を測ればいいですね。Androidには、いろいろなセンサーがあるらしいのでこの中に役に立ちそうなものがあるのか確認してみました。

え〜と。

加速度センサー
明るさセンサー
ジャイロセンサー。

へ〜。

地磁気センサー
傾きセンサー

ふむふむ。

圧力センサー

近傍センサー


あれ?

温度センサー。

これで、最後か…



今回の企画は、方向性が不確かなものとなったため一時休止となりました。
ご迷惑をおかけします。申し訳ありません。



追記

「貧血チェックガジェット」の企画を休止とさせて頂いたわけですが、ちゃんとやりなさい、と、言う事なので、この記事を追記させて頂きます。

今回は、完成しました!

用意したものは、Android本体、アイマスク、セロテープ、Androidの加速度センサーを使用した自己流貧血判定アルゴリズム!? です。


作り込み


hinketsu_pic1
自己流貧血判定アルゴリズム搭載のガジェットアプリはこんな感じ


hinketsu_pic2
そして、アイマスク。


hinketsu_pic3
検証機のAndroidと、アイマスクをセロテープで固定する。


hinketsu_pic4
頭に装着できる様になった。


検証

hinketsu_pic5
あ! このガジェットを装着したままの人が貧血で倒れている。


BlogPaint
近くに寄ってみると、アプリ上になにかトーストが


BlogPaint
もっと寄ってみる。わかりずらい…


hinketsu_pic8
エミュレータのスクリーンショットで。


プログラムについて

自己流貧血判定アルゴリズム!? ということで加速度センサーを使用しました。まあ検索してもらえばわかりますが、加速度センサーについては沢山実装方法が載っています。ここで、あえて私が書くのも恐縮ではありますが、解説させて頂きます。

加速度センサーは、以下の様な感じで利用してみました。

public class Main extends Activity {
  static final String TAG = "Main";
  private float[] mPoolValues;

  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mPoolValues = null;
    //-------------------
    // 加速度センサーを定義        
    //-------------------
    SensorManager sensorManager =
        (SensorManager)getSystemService(Context.SENSOR_SERVICE);
    // 機種に加速度センサーがあるか確認し存在していた場合、
    //イベントリスナーを定義する
    List<Sensor> sensors =
        sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if(sensors.size() > 0){
      sensorManager.registerListener(
        new SensorEventListener() {
          public void onAccuracyChanged(Sensor arg0, int arg1){}
          public void onSensorChanged(SensorEvent ev){
            // 初回 加速度の3軸値それぞれをとっておく
            if(mPoolValues == null){
              mPoolValues = new float[]{
                                ev.values[0],
                                ev.values[1],
                                ev.values[2],
                            };
              return;
            }
            // 前回と今回の加速度差分の大きさを取得。
            float ac0 = ev.values[0] - mPoolValues[0];
            float ac1 = ev.values[1] - mPoolValues[1];
            float ac2 = ev.values[2] - mPoolValues[2];
            float d = (float) Math.sqrt(
                                  ac0 * ac0 + 
                                  ac1 * ac1 + 
                                  ac2 * ac2);
            // 加速度の差分の大きさが15を超えたら、この人貧血。
            if(d > 15){
              Toast.makeText(Main.this,
                             "貧血になりました。",
                             Toast.LENGTH_LONG).show();
            }
            // 今回の加速度を保持
            mPoolValues[0] = ev.values[0];
            mPoolValues[1] = ev.values[1];
            mPoolValues[2] = ev.values[2];
          }
        },
        sensors.get(0),
        SensorManager.SENSOR_DELAY_NORMAL// Sensorの通知感覚→標準
      );
    }
  }
}


加速度センサーは、下記の様にSenserManager#getSensorListメソッドで取得します。
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
この、メソッド。その他センサーの取得も出来ます。
Sensorクラスの定数で指定します。
Sensor.TYPE_ACCELEROMETER加速度センサー
Sensor.TYPE_LIGHT明るさセンサー
Sensor.TYPE_GYROSCOPEジャイロセンサー
Sensor.TYPE_MAGNETIC_FIELD地磁気センサー
Sensor.TYPE_ORIENTATION傾きセンサー
Sensor.TYPE_PRESSURE圧力センサー
Sensor.TYPE_PROXIMITY近傍センサー
Sensor.TYPE_TEMPERATURE温度センサー

戻り値はList型なので、同一センサーで複数存在するのもあるし、ないのもあるということなのでしょうか。検証機のAndroidでは、温度センサーやジャイロセンサーはありませんでした。

次に、SensorManager#registerListenerメソッドでイベントリスナーを登録します。今回は、onSensorChangedのコールバックメソッドで貧血判定ロジックを実装です。

コールバックが来るたびに加速度の前回との差分を計算しその値が指定の閾値より大きい時、つまりは貧血で転倒したときの反動をトリガーとして、アラートを出しています。

加速度の3軸の値それぞれ、前回の差分を求め
その差分で構成されているベクトルの大きさを求めます。
二乗の和のルートをとり、これを加速度の前回との差分としました。
※回転による遠心力等については、今回特に考えていません。

※今回のサンプルプロジェクト一式です。
ダウンロードはこちら!


まとめ


倒れた勢いを検知して、貧血状態をチェックできた。優れものだな、このガジェット。

社内のスマフォ開発用ライブラリの管理方法を公開しちゃいます!

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - 社内のスマフォ開発用ライブラリの管理方法を公開しちゃいます!
このエントリーをはてなブックマークに追加
こんにちは!こんにちは!
最近JavaやObjective-Cで開発をしていて、やっぱりPerlって使いやすい言語なんだなぁと改めて感じている栗原です。
#と言いつつもJavaもObjective-Cも好きだったりします。

今回は「スマフォのライブラリなどの管理をどげんかせんといかん」とCTOに言われたために考えた、弊社のスマフォ開発チームが行なっているAndroid、iPhoneそれぞれの社内用ライブラリやスニペットの管理方法についてご紹介したいと思います。

ソースの管理方法

まずソースの管理についてですが、現在弊社のスマートフォン系のアプリはGitを使って管理しています。
通常のアプリも含めて「android」と「iphone」というプロジェクトを作成し、その中でそれぞれのプラットフォーム毎にリポジトリを作成しています。
以下のようなイメージですね。

git://example.com/iphone/app01.git
git://example.com/iphone/app02.git
git://example.com/android/app01.git
git://example.com/android/app02.git
共通ライブラリに関しても、アプリと同レベルの階層にAndroidであれば「common」、iPhoneであれば「ldtouch」という名前でリポジトリを作成し、その中にライブラリやスニペットをつっこんでいます。(なぜ名前が違うかは気にしないでくださいw)

git://example.com/iphone/ldtouch.git
git://example.com/android/common.git

ガイドライン

リポジトリを作ったら、その中になんでもつっこめばいいってもんじゃないですよね。
のちのち「ほげほげするライブラリがあった気がするけどどこだっけな…」とか「このライブラリちゃんと動くんかな」とか「このライブラリどう使うかわかんねーYO、まぁソース読みゃーいいけどさ」とかなるのは目に見えています。

そこで現在スマフォ開発チームでは、共通ライブラリやスニペットを管理する上で以下のようなガイドラインを設けています。

  • なんでもできる1つの大きな便利ライブラリは作らない
  • ライブラリを作成するときはユニットテスト必須(作れないものナシでもOK)
  • ライブラリにもならないようなものは簡単にコピペして使えるようにスニペットとして管理する
  • ドキュメントを書く(JavaDoc形式)
  • 可能な限り(常識の範囲内で)下位互換性を保つ(@Deprecatedを付けるとか)

プラットフォーム別の管理方法


Androidのライブラリ管理


まずAndroidについてですが、common/以下のディレクトリ構成は下記のようになっています。

common/
+ android-common-lib01/
    + AndroidManifest.xml
    + res/
    + src/
    + pom.xml
+ android-common-test-lib01/
    + AndroidManifest.xml
    + res/
    + src/
    + pom.xml
+ android-common-lib02/
    + AndroidManifest.xml
    + res/
    + src/
    + pom.xml
+ android-common-test-lib02/
    + AndroidManifest.xml
    + res/
    + src/
    + pom.xml
+ android-common-snippet01/
    + AndroidManifest.xml
    + res/
    + src/
    + pom.xml
+ pom.xml
ライブラリは「android-common-ライブラリ名」というフォーマットでディレクトリを掘っていくと同時に、そのライブラリのテストも「android-common-test-ライブラリ名」というフォーマットでディレクトリを掘っています。

各ディレクトリの中には、そのライブラリとそのライブラリを使ったサンプルプログラムが含まれており、どのように使うのかがすぐにわかるようになっています。

上図をよく見るとそれぞれのディレクトリにpom.xmlというファイルがあります。これはビルド管理ソフトウェアであるMavenの設定ファイルになっています。各ライブラリのビルド管理はこのMavenを使用して行なっており、ビルドフェーズの中でユニットテストもできるような形になっています。なお、トップ階層にもpom.xmlがありますが、これはライブラリ全体でも個別でもビルド管理をできるようにしているからです。

また、スニペットに関してもライブラリと同じ位置付けで「android-common-スニペット名」みたいな形で個別のスニペットとサンプルプログラムを同梱させていたりします。

iPhoneのライブラリ管理


iPhoneのldtouch/以下の構成は下記のようになっています。

ldtouch/
+ Classes/
   + LDFooView/
      + LDFooView.h
      + LDFooView.m
   + NSArray+Bar/
   + NSData+Baz/
   + QuxAuth/
+ Externals/
+ GHUnitOSTestMain.m
+ LDTouch-Info.plist
+ LDTouch-.xcodeproj/
+ LDTouch_Prefix.pch
+ Scripts/
   + RunTest.sh
+ Tests/
   + LDFooView/
      + LDFooViewTest.m
   + NSArray+Bar/
   + NSData+Baz/
   + QuxAuth/
+ UISample/
   + Classes/
iPhoneのライブラリですが、現状フレームワーク(foo.framework)のような形は取っていません。基本的にはldtouch/Classes/にあるライブラリのファイル(foo.mとfoo.h)を自分のプロジェクトにコピーして使うようになっています。

この方法はのちのちライブラリがバージョンアップした際に追従できないなど、いろいろと問題もありますが、現状ライブラリとしてまとめられるほどの数もないため、一旦はこの形式を取っています。この管理方法については今後変わっていく可能性があると考えています。

テストに関しては、ライブラリと同じ名前でldtouch/Tests/の中に入れています。テストフレームワークはGHUnitというものを使っています。GHUnitを使うと以下のようなGUIを使ったテストができます。なんかカッコイイ!

ldtouch_ghunit


また、UISampleというアプリも同梱されています。このアプリはView系のライブラリのサンプルアプリになっていて、そのライブラリを使うとどういう動きが作れるのかを見ることができるサンプルアプリになっています。起動すると以下のような感じになっています。
これを見ることによってぐっとそのライブラリの動作がイメージしやすくなりますね!

uisample

ということで、現在スマフォ開発チームで進めている社内用ライブラリをどのように管理しているかのご紹介しましたがいかがだったでしょうか。
今回ご紹介した管理方法については、このようにライブラリをまとめること自体始めたばかりですし完璧なものではないと考えていて、今後もブラッシュアップしていこうと考えていたり、有用なライブラリができたら公開等も考えていますので、ぜひ楽しみにしていてください。



あ、あと余談ですが、最近弊社スマフォ開発グループではFacebookのグループで日報を書くのが流行っています(他のグループでもやっているらしい)。

「普段あまり話さないあの人はこんなこと考えてたのか」とか「この人が紹介しているこのライブラリ、あまり興味なかったけど確かに面白いな」とか、いつも自分の頭の中だけで考えていることだったり、やっているプロジェクトには直接関連しないから話さないけど仕事自体には関連する事柄や意見などを共有しようとしています。

普段面と向かって話す時間はあまりないけど、こんなこと思ってるんだ考えてるんだというのを共有できたりするとコミュニケーションの幅が広がりそうですね!興味のある方はやってみては如何でしょうか。

facebook_group


ということで、今回はこの辺で。
ではでは。

Eclipse苦手者がAndroid開発する際に押さえるべきこと

カテゴリ
ブックマーク数
このエントリーを含むはてなブックマーク はてなブックマーク - Eclipse苦手者がAndroid開発する際に押さえるべきこと
このエントリーをはてなブックマークに追加

こんにちは! スマートフォンアプリ開発チームのfaultierです! 得意な口説き文句は「君のprotocolにconformしたい」ですが、今のところ使ったことはありません。

みなさん、普段の開発ではエディタは何を使ってますか? きっとvimかemacsかメモ帳か念力による直接入力を使っていると思います。ちなみに僕はvim派です。出社したらまずはブラウザ・ターミナル・IRCクラインアント・Twitterクライアント・iTunesを立ち上げ、可能な限りその中から出ないことを心がけています。

前回は同じチームのgaoohさんがEclipseによるAndroid開発環境の作り方を解説していましたが、今回はそれに便乗して、出来るかぎりターミナルから出たくない不精者のためのEclipseを使わないAndroid開発環境を作るときに押さえておくべきことを、リーダーに言われてもいないのにまとめてみました。

AndroidSDKのツール群を使う

AndroidSDKをインストールすると、Androidを作るのに必要なフレームワークやAndroidエミュレータだけでなく、コマンドラインから使うツール郡も一緒にインストールされます。なにはともあれ、$SDK_HOME/toolsや$SDK_HOME/platform-toolsにパスを通して、これらのツールを使えるようにしておきましょう。

android

そのものずばり、androidコマンドです。AVD(Android Virtual Device、エミュレータで動かすAndroidの仮想デバイス)やSDKの管理、Androidプロジェクトの雛形を作ったりできます。特に覚えておく必要があるサブコマンドを以下に挙げますが、他にできることやそれぞれのサブコマンドのオプション等は-hオプションを付けて確認してください。

list|create|move|delete|update avd
AVDの管理をするサブコマンドです。EclipseやAVDマネージャからGUIで作ることもできますが、androidコマンドを使えばCUIで管理することもできます。
create (test-)project
Androidプロジェクトの雛形を作ります。バージョンや環境によって変わると思いますが、僕の手元のSDKでは、AndroidManifest.xml、メインのActivityとレイアウト、アイコン、string.xml、ant用のbuild.xml、ProGuard用のproguard.cfgなどを用意してくれました。
update sdk
Eclipse+ADT環境であればEclipseから各バージョン向けのライブラリやエミュレータを取得/更新できますが、Eclipseを使わない場合はandroidコマンドから行ないます。実行するとSDK and AVDマネージャが立ち上がり、SDKの更新があればダウンロードできます。また、サードパーティのAdd-onもいくつか(この記事を書いた時点ではGoogle API Add-onとSamsung GALAXY TAB Add-onが利用可能です)ここからインストールできます。

emulator

エミュレータを起動するコマンドです。android list avdでAVDを確認して、emulator @AVD_NAMEでエミュレータ起動です。こちらも細かい起動オプションを付けることができ、回線速度や遅延、プロキシやリダイレクトの設定などもできます(エミュレータでデバッグしているとついつい3G回線の遅さを見過してしまうので、起動オプションで3G回線の設定にしておきましょう)。なお、エミュレータはtelnet接続して起動後に設定を変更することもできます。

adb

エミュレータやデバイスを制御するコマンドです。アプリケーションのインストール/アンインストール、ログの表示、仮想デバイスに接続してのshell起動など、CUIでAndroid開発をするときにはこれを使わないことには始まりません。

-eオプション、-dオプション、-sオプション
-eオプションを付ければ起動中のエミュレータを、-dオプションを付ければUSBデバッグモードの実機を制御するようになります。それぞれ複数接続している場合は、adb devicesでデバイスのシリアルナンバーを確認して、-sオプションで指定することでそのデバイスを制御することができます。
install/uninstall
アプリケーションのインストール/アンインストールをするサブコマンドです。インストールするときはapkファイルのパスを、アンインストールをするときはパッケージ名を指定します。
pull/push
直接デバイスに、もしくはデバイスからファイルをコピーするサブコマンドです。
logcat
端末のログを表示します。android.util.Logを使って出力したログはこれで見ることができます。
shell
端末に接続してadbシェルを起動します。SDカード内のファイルを直に操作したり、amコマンドでインテントを送ったり、sqlite3コマンドでDBの中身をいじったりできます。
forward
ローカルのソケットをデバイスに転送できます。TCPやUnixドメインソケットだけでなく、JDWPにもフォワードできます。

ddms

前回の記事でも出てきたDDMS、これはEclipseやADTの機能ではなくAndroidSDKに付属しているツールですので、ddmsコマンドで単体で起動できます。

keytoolとjarsignerを使う

Eclipse+ADTで開発している場合は、鍵を作ったり署名したりもEclipse上でできますが、Eclipseを使わない場合はkeytoolとjarsignerというtoolを使って自分でやる必要があります。keytool -keygenで鍵を作って、jarsignerでapkファイルに署名です。鍵の作り方や署名方法はドキュメントを参考にしてください。

jdbを使う

デバッガが無いとデバッグプリントでも仕込んでlogcatで見るくらいしか手段が無くて大変面倒ですが、ちゃんとjdbを繋いでデバッグすることができます。adb shellからamコマンドで-e debug trueオプションを付けてインテントを送ってアプリを起動し、adb jdwpで一覧表示してJDWPのPIDを探し、adb forward tcp:PORT jdwp:PIDで転送の設定をして、jdb -attach localhost:PORTで接続できるようになります。

mavenを使う

普通にJavaファイルをコンパイルして、dxコマンドでclassファイルをバイナリに変換、apkbuilderでapk作成、という手順で作ることもできますが、面倒なだけなのでそこは自動化してしまいましょう。androidコマンドでcreateすればant用のbuild.xmlなども生成されますが、mavenの方が便利そうだったので僕はmaven-android-pluginを使っています。

一つ一つ説明していくとそれだけで一記事書けそうなボリュームだったので、サンプルプロジェクトを用意してみました。Hello worldアプリケーションのプロジェクトとそのテストプロジェクトをandroidコマンドで作り、二つのプロジェクトをmavenのマルチプロジェクトの形で一つのプロジェクトにしてあります。チェックアウトしたら、(mavenをインストールして)親ディレクトリでmvnコマンドを実行すると、依存ライブラリのインストール、エミュレータの起動、アプリケーションのビルド、apkファイルの生成、インストール、テストの実行までコマンド一発でやってくれます。

テスト用のプロファイルとディストリビューション用のプロファイルを用意してあるので、(署名用のキーの生成などを事前に行なって)mvn clean package -Pdistributionを実行すると、今度はテストは行なわず、ProGuardによる最適化・難読化、署名などを行なったapkファイルがsample-app/targetの下に生成されます。

vimを使う

最初に僕はvim派だと宣言したので、ここではvimでコードを書くときに便利なものをいくつか紹介します。emacsでも同じように便利なものがあると思うので、emacs派の方はここは読み飛ばしてもらって自分で便利ツールを探して下さい。

taglist

ソースコード中のクラスやメソッドをアウトライン表示してくれるプラグインです。Eclipseのアウトラインビューみたいになります。

FuzzyFinder

ファイル名やクラス名、メソッド名などから簡単にファイルを探して開けるようにしてくれるプラグインです。探す対象も、開いているバッファ、タグ、最近開いたファイルなどから選ぶことができ、部分一致や曖昧な補完などもしてくれるので、恐しく便利です。特にJavaだとsrc以下の階層が深くなりがちですが、いちいちパス打ってられっか、とイライラしたりする必要はありません。

neocomplcache+snipMate

普段PerlやRubyを書いてるWebエンジニアから見ると、Javaは所謂「おまじない」多い言語に見えますが、あんなものをいちいちタイプしてたら日が暮れます。Eclipseを使っている同僚のディスプレイをこっそり後ろからのぞいて見ると、コード補完やスニペットを活用して自分で書かずにEclipseに書かせていました。当然ですがvimで書くときも、自分で書かずにvimにやらせてしまうのが正しい怠け者の生き方です。

neocomplcacheはコード補完を便利にするプラグインで、snipMateはスニペットを簡単に使えるようにしてくれるプラグインです。neocomplcacheを入れておけば、何か打てば補完候補が出てくるので、あとはその中から適切なものを選ぶだけの簡単なお仕事になります。それだけだとクラス名やメソッド名を補完してくれるだけなので、よく書くコードはスニペットにしてしまいましょう。neocomplcache自体にもスニペット機能が付いていますが、snipMateの方が個人的には書き易く、を連携させることもできるので、そっちを使っています。

最後に

色々紹介してきて最後に全部ひっくりかえすようでなんですが、Javaを書くなら正直なところEclipse(や他のIDE)の方がずっと便利です。Javaに関してなら、コード補完や整形、リファクタリングやテスト、デバッガとの連携など、賢くやってくれますし。なので例えば、

  • Androidアプリに集中したいのに、iPhoneアプリのためにObjective-CやCを書いたり、サーバサイドのアプリのためにPerlやRubyを書いたり、WebインターフェースのためにHTMLやJavaScriptを書いたりすることが稀によく頻繁に毎日ある
  • 上司や嫁/旦那に泣きついてみたものの、設備投資の予算が獲得できなかった
  • 「この人と、添い遂げたい」と心に決めたエディタがいる
  • 文字しか表示されてない画面を見ていると心が落ち着く
  • テンキーは隣村にあり、マウスは地の果てにあると思っている

みたいな項目に心当たりがあるような人だったら、非Eclipse環境に手を出してみてもいいんじゃないかなと思います。逆に、

  • 当面Androidアプリしか作らない
  • あるいは、普段からJavaのお仕事をしている
  • 画面に文字しか表示されてないと精神が不安定になる
  • 「えーマジメモリ不足!?」「キモーイ」「Eclipse起動した程度で重くなるPCが許されるのは小学生までだよねー」「キャハハハハハハ」と思っている

みたいな項目にいくつかあてはまるような人は、普通にEclipseを使ってもいいんじゃないかな、と思います。とは言え、好みの環境を組み合わせられたり、自動化したりすることもできるので、普段はEclipseを使う人も知っていても損は無いんじゃないでしょうか。ということで、EclipseとADTだけがAndroid開発環境じゃないんだよという紹介でした!