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

2012年9月1日土曜日

ZXing QRコードスキャナーをWebから使う

ちょっと ZXing(バーコードライブラリ)のAndroid版アプリ(QRコードスキャナー)のソースを追いかけていたらちょっと気になる <intent-filter> を見つけまして。

ん、、これって?
  private static final String[] ZXING_URLS = { "http://zxing.appspot.com/scan", "zxing://scan/" };
  private static final String RETURN_CODE_PLACEHOLDER = "{CODE}";
  private static final String RETURN_URL_PARAM = "ret";
おおおおおー!?

ブラウザで表示するWebページ上で
zxing://scan/?ret=(戻り先URL)
にリンクするとQRコードスキャナーが起動する。のはよいとして、スキャンが終わると戻り先URL)に戻ってきてくれる。このときURLに {CODE} があるとその部分がスキャンした文字列になってくる。
例えばこんな感じ → zxing://scan/?ret=http%3A//tes.to/zxing.html%3Fcode%3D%7BCODE%7D

つまりWebアプリや例えば業務系のサイトなんかで、QRコードスキャナーを使ってバーコード(JAN/EANでもQRコードでもISBNでも)を読み込んでその結果を持ってページに戻ってきてもらうようなことが可能なわけです。わざわざ専用のWebViewアプリを作らなくても!

zxing://scan/ のかわりに http://zxing.appspot.com/scan を使うこともできます。

URLQRコードスキャナー
未インストールインストール済み
zxing://scan/エラーQRコードスキャナー自動起動
http://zxing.appspot.com/scanインストール案内ページ表示ブラウザで開くかQRコードスキャナーで開くか問い合せ

動作確認できるテストページも作ったので気になる方はAndroid端末実機でアクセスしてみてください。
http://tes.to/zxing.html


で、例によっていろいろ実験してから解説ページを見つけてるわけです(´・ω・`)
http://code.google.com/p/zxing/wiki/ScanningFromWebPages

2012年7月30日月曜日

HTTP logging

Android上で行われるHTTP通信のログを取りたいことがあります。主にデバッグとか。動作確認とか。
カスタムROMを作ればアプリのコードに手を入れなくてもヘッダくらいはロギングできます。
(ストリームに手を入れれば送受信データもロギングできますが、サイズが大きかったりバイナリデータだったりするのでファイル出力するなどの対応が必要でしょう。今回はリクエストヘッダだけをlogcatに出力します)

2012年7月22日日曜日

最初からADBデバッグON

初回起動時のデフォルト言語を日本語にしたのと同様、最初からUSBデバッグが有効だったらいちいち設定画面でチェック入れなくていいから楽になる…
という思いでサクッと対応差分を作ってみたのですが、、、
frameworks/base/services/java/com/android/server/usb/UsbDeviceManager.java
                         setAdbEnabled(false);
                     }
                     SystemProperties.set("persist.service.adb.enable", "");
+                } else if (Settings.System.getInt(mContentResolver, "jcrom_adb_inited", 0) == 0) {
+                    // first boot
+                    setAdbEnabled(true);
+                    Settings.Secure.putInt(mContentResolver, Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED, 1);
                 }
+                Settings.System.putInt(mContentResolver, "jcrom_adb_inited", 1);
 
                 // register observer to listen for settings changes
                 mContentResolver.registerContentObserver(

build/core/main.mk とか調べてみたら、 full_maguro-user のかわりに full_maguro-userdebug 使えばデフォルトでADBデバッグ有効になるぽいorz
そんなわけでビルドに使ってるシェルスクリプトを少し書き換えただけでこの差分は破棄 ( ゚∀゚)ノボーイ

初回起動時のデフォルト言語を日本語に

JCROMの JC は Japanese Custom らしいです。
だったら初回起動時から日本語表示して欲しい…!
(選択するだけなんだけど wipe するたびに設定し直すの面倒くさいんだもの)

というわけで調べてみました。
JCROM でも AOSP でも同じはずです。

結論だけ知りたい方は build/target/product/full_base.mk
PRODUCT_LOCALES := en_US

PRODUCT_LOCALES := ja_JP
にしてください。

2012年7月21日土曜日

AndroidでアニメGIF表示

AndroidでアニメGIF表示と言えば明日の鍵さんがブログ記事にしてみえましたが
もっと短いコードでそれなりに動くものを作りました。

ソースはこれ。使い方はこんな感じサンプルプロジェクト
リソースや外部ファイルのアニメGIFを android.graphics.drawable.AnimationDrawable にします。各フレームをDrawableに展開してメモリに持つので、大きな画像やフレーム数が多いファイルはOOMになるかもしれません。

アニメーションの途中で pause したり resume したりする場合はこちらのブランチを使ってください。ただし AnimationDrawable の privateメンバにアクセスするためにリフレクションを使っています。

無保証ですがちょっとした用途なら使える、、カナ? 自己責任でご自由にお使いください。(Galaxy Note と Galaxy Nexus でしか確認していませんが API Level 4(1.6)でも動くと思います)

2012年7月13日金曜日

Lion上でAndroidビルド

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

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年1月31日火曜日

AndroidManifest.xml file missing!

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

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

2012年1月29日日曜日

TextViewのワードラップ

AndroidのTextViewは、英単語が途中で改行されてしまわないようにワードラップ処理をしてくれます。
日本語の禁則処理もしてくれているようなのですが、どうにも不自然で納得できません。(句読点の直後に改行が入らず次の1文字も巻き込んで計算されるなど)

ソースを追うと、TextViewのプライベートメンバ mLayout で保持される StaticLayout がワードラップ処理をしているようです。(setText()に Spannable を渡すと mLayout自体は DynamicLayout になりますが、DynamicLayout が内部で StaticLayout を作ります)
うまいことワードラップする Layoutクラスを作ってリフレクションで mLayout に設定する方法もあると思うのですが、StaticLayoutはそこそこボリュームがあって手を出すのは心が折れるので、InputFilter を使う方法でワードラップ処理を改造してみました。

2012年1月4日水曜日

ActionBarCompat

GALAXY NEXUS が発売されてAndroid 4.0(ICS)端末が市場に出てきました。
Honeycombで搭載されたActionBarがいい具合にスマホ化されていてカックイイです(*゚∀゚)

Android SDKのサンプルに、ActionBarCompat という、バージョン差を吸収してActionBarを表示する(Honeycombより前のAndroidではActionBarモドキを表示する)アプリがあったので、Toroくんのブログを参考に拙作 あとでよむ twiccaプラグイン に組み込んでみました(Ver.1.2)。

ところが直後から「IS01で起動できなくなった」「SH-10B(LYNX)で動かない」というコメントが…orz
おかしいな、エミュレータで Android 1.6 でも動くことを確認したのに。。
実機を借りて確認したら AbstractMethodError で落ちてました。ぐぬぬ…