2012年7月13日金曜日

Lion上でAndroidビルド

OSXでJCROMが、LionではできねーYO! とご指摘をいただきました。
Lionの載ったMBAで試してみたけど、、できるよ?
今回はAOSPの android-4.1.1_r1 をビルドしてみました。
基本的にJCROMの手順と同じです。

2012年7月12日木曜日

自動回転の固定

というわけでJCROMビルド環境が整ったので、さっそく何か実装してみたいな、と。
今週に入ってからWDFとかINFファイルとか、Windowsのドライバ開発周りの調査と確認ばかりでコードを書けていないので昨夜ちょろっとやってみました。

OSXでJCROM

ちょっとしたブームになったJCROM、遅ればせながら手元でビルドしてみました。
確認されている開発環境はUbuntuだけですが、手元のiMac(Show Leopard)でそのままビルドします。ビルド自体がそこそこ時間がかかる負荷の大きな作業なのでVMとかで(メモリやCPUに)余計な負担を増やしたくないな、と。

2012年6月17日日曜日

本番環境とテスト環境の切り替え

#むおおおお に「本番環境とテスト環境で接続先サーバが違うときどう管理してますか?」と聞かれました。
リリース時にいちいちソースやリソースを書き直すのは手間だしミスがあるといけないし、VCSでの管理的にビミョー…みたいな。

Windowsアプリを作ってる頃は、変わりうる設定は全部INIファイルから読み込めるようにしていました。
[server]
Host=hoge.tamac.jp
Port=80
のような.iniファイルを.exeと同じ名前で同じディレクトリに置いて ::GetPrivateProfileString() 的な(Win32 SDKを直で使ってたので)。
デフォルト値(本番環境用)はアプリ内に持っておいて、INIファイルがない時はその値を用います。

Androidでも同じ考え方で、外部ストレージから特定のファイルを読み込んで設定値を取得します。
例えばmicroSDのルートディレクトリに パッケージ名.conf というファイルがあればそれを読み込んで通信先URLを取得。同ファイルが無ければアプリ内に持っている(本番環境用の)デフォルト値を用いる、みたいな。

これだと、複数の対向サーバがあるような状況(例えば開発サーバ(ローカルPCとか)、テストサーバ、ステージングサーバ、本番サーバ)でも、同一のバイナリで実行時に通信先を切り替えることができます。
SDK(adbやDDMS)がない環境でもmicroSDにアクセスできれば通信先を変更できるので、例えばクライアントにテストサーバを見てもらうような場合でも割とハードルが低くてすみます。

見ようによっては余計なデバッグ機能を残したままアプリをリリースする形になるのでクライアントやプロジェクトリーダーとネゴっておく必要はあると思いますが、何かの参考になれば(o'ヮ'o)

public class Configuration
{
    /** 設定ファイル */
    private static final String CONF_FILENAME = "CONF_FILENAME";
    /** 接続URL設定 */
    private static final String CONF_CONNECTION_URL = "CONNECTION_URL";
    /** 接続URL設定 組み込み値 */
    private static final String CONF_CONNECTION_URL_DEFAULT = "http://hoge.tamac.jp";

    /** コンテキスト */
    private final Context mContext;
    /** 設定ファイル */
    private final Properties mProperties = new Properties();

    /**
     * コンストラクタ
     * @param    context    コンテキスト
     */
    public Configuration(Context context) {
        mContext = context;

        // 設定ファイル読み込み
        String filename = getMetaData(CONF_FILENAME);    // "jp.tamac.hoge.conf"
        if (filename != null) {
            if (filename.startsWith("/")) {
                // フルパス
                loadProperties(filename);
            } else {
                // XOOMの外部SDカード → 内部(エミュレート)SDカード → getExternalStorageDirectory()の返すパス
                boolean result =
                    loadProperties("/mnt/sdcard-ext/" + filename) ||
                    loadProperties("/mnt/sdcard/" + filename) ||
                    loadProperties(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + filename);
            }
        }
    }

    /**
     * プロパティ読み込み
     * @param    filepath    設定ファイルパス
     * @return    結果
     */
    private boolean loadProperties(String filepath) {
        if (!new File(filepath).isFile()) {
            // ファイルがない
            return false;
        }

        try {
            mProperties.load(new FileInputStream(filepath));
        } catch (Exception e) {
            android.util.Log.e("Configuration#loadProperties()", e.toString());
            return false;
        }

        // 読み込み成功
        return true;
    }

    /**
     * 接続先URL取得
     * @return    接続先URL
     */
    public String getConnectionURL() {
        String url = null;

        if (url == null) {
            // 設定ファイルから
            url = mProperties.getProperty(CONF_CONNECTION_URL);
        }

        if (url == null) {
            // AndroidManifestから
            url = getMetaData(CONF_CONNECTION_URL);
        }

        if (url == null) {
            // 組み込みデフォルト値 ※お好みでリソースから読むのでも
            url = CONF_CONNECTION_URL_DEFAULT;
        }
        return url;
    }

    /**
     * AndroidManifestからMETAデータ取得
     * @param    name    パラメタ名
     * @return    METAデータ
     */
    private String getMetaData(String name) {
        try {
            PackageManager manager = mContext.getPackageManager();
            ApplicationInfo info = manager.getApplicationInfo(mContext.getPackageName(),
                                                              PackageManager.GET_META_DATA);
            return info.metaData.getString(name);
        } catch (Exception e) {
            // 無ければ無いで問題ないのですりつぶす
            return null;
        }
    }
}

設定ファイルサンプル。先頭が # の行はコメント行として無視されます。
# 開発環境
CONNECTION_URL=http://192.168.1.20:8080/
# テスト環境
#CONNECTION_URL=http://test.hoge.tamac.jp/
# 本番環境
#CONNECTION_URL=https://hoge.tamac.jp/

2012年5月21日月曜日

Poke bits

Facebookで延々 “あいさつ” を送ってくる方がいて、あいさつを受けたら無視するわけにはいかないので、気付く限りあいさつを返していたのですが、そうするとまたすぐ新しいあいさつが届いて、エンドレスです。終わりがありません。あぁ戦争に巻き込まれちゃったなぁ…って感じ。画面の片隅にブラウザを開いておけば割とすぐあいさつ返しはできるのですが、席を外しづらいとか、ちょっと打合せをしていて目を離してるスキにあいさつされたりとか、気になっちゃうんです。なんとなく。

自動的にあいさつを返すChrome Extensionもいくつかあるようですが(これとかこれとか)、そんなツールに頼るのでは愛がないし失礼ですよね。
やっぱり自分の手で、ていねいに、コードを書かないと

2012年5月7日月曜日

プログラマ35歳定年説

まだ35歳ではないけれど(ここ大事。テストに出ます)、35歳になるまでに考えたい問題。最近機会があってこの言葉の意味を再考するに至りました。

よく聞く「35歳定年」の理由は
  • 新しい技術を覚えられなくなる。柔軟な発想ができなくなる。
  • 徹夜や長時間勤務が体力的にできなくなる。
  • PG単価では給料が上がらないのでPM、SEへの転向を迫られる。
  • 会社がー
  • 家族がー
などがあります。
どれも本人次第、場合によっては移籍(転職)することで解決できる気もしますが、一理あるとは思います。

でもそれとは別に、35歳って、ひとつの絶望の淵に直面しているのかなと。
入社してプログラムを覚えて/あるいは学生時代に身につけたプログラミングスキルを活かして「プログラムを作る」ということを生業にして十数年。お客さんと話をしたり、理不尽な仕様変更やデスマを何度も経験して。少しでも改善しようと、よい仕様・よい仕事にしようと、お客さんに喜んでもらえるシステムにしようともがいて、がんばって。でも変わらない現実。全てのお客さんが同じ意識を共有してくれるわけじゃないし、だんだんワガママになっていくエンドユーザー(コンシューマーでもエンタープライズでも)。
そうして溜った鬱憤を晴らすことができず、結局自分ががんばったところで環境を変えられない・この仕事を続けていって幸せになれるの?と絶望に負けそうになる35歳。
同業他社に転職しても境遇は変わらないことも見えてくる、そんな歳なんじゃないかと思うのです。(昨日まどマギ第11話・第12話を観ました←)

あたしは同年代の人より早くからこの業界にいて、立場柄プログラマ以上にいろんなコトを見てきてしまったので、35歳までまだまだ時間があるけれど(重要。テストにry)、それでも限界というか、気持ちが耐えられないと、そう感じる昨今です。

プログラマは35歳で終わりなんてことはない。プログラムは作り続けられるし技術的にもまだまだ伸びる。現にCodeJamの成績は上がっているしあんなに楽しいんだもの。
でも仕事としては。
職業としてのプログラマは、35歳よりだいぶ前だけれど、そろそろ厳しい…かもね?

2012年1月31日火曜日

AndroidManifest.xml file missing!

これまでAndroidアプリの開発でも Emacs + ant を使っていたのですが、今年はいろいろ新しいことも始めるゾ!という意気込みでどうもみんなが使ってるらしい Eclipse + ADT を使いはじめました。宣言

旧来Emacs + ant でビルドしていたプロジェクトディレクトリを丸ごとそのまま Eclipse にインポートしようとしたら AndroidManifest.xml file missing! と言われてしまって完了できなかったので対策メモ。