2010年12月16日木曜日

DDMSを改造して、logcatに日本語を出す!

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
なんだかんだで出したいじゃないですか、日本語。
という事で頑張りました。


目的

Logcatの日本語が文字化けするから直したい。気長にやる。
とりあえずWindows版を作る事を目的とする。
Linux版は改造部分だけ持っていけばすんなりいけると思う。っていうかそもそもちゃんと日本語出るんじゃね?

環境

SDKのビルド
OS:Ubuntu 8.04

前提として、Ubuntu8.04の中にAndroidのソースをrepo syncで持ってきてる状態とします。

DDMSのソース

ソースは
$ANDROID_SRC_ROOT/sdk/ddms
にある。
使用したソースはfroyo。ハッシュ値はわからず。多分あんま関係ない。

改造

以下のファイルを修正する。このクラスがログのオブジェクト受け取って実際に出しているっぽい。
$ANDROID_SRC_ROOT/sdk/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java

1121行目あたりが怪しい。
以下のコード
mc.msg = line.replaceAll("\t", "    ")
の下に
try{
mc.msg = new String(mc.msg.getBytes("shift_jis"), "utf-8");
}catch(Exception e){
e.printStackTrace();
}
を追加する。
ログはutf-8で来るのだけど、表示はshift_jisな為文字化けていたっぽい。
そこでshift_jisに文字コードを変換してあげる。と、いける。

追記-2010/12/18 10:54
・・・が!
コメントやTwitterで@androidzaurus @zaki50 @15myさんから色々指摘を頂きましたので色々追記します。

まず、
mc.msg = new String(mc.msg.getBytes("iso-8859-1"), "utf-8");
の方がいいのではなかろうか!とのこと。
そしてむしろ、
$ANDROID_SRC_ROOT/sdk/ddms/libs/ddmlib/src/com/android/ddmlib/MultiLineReceiver.java
でデータ受け取っている部分で
 s = new String(data, offset, length, "ISO-8859-1");
s = new String(data, offset, length, "UTF-8");
にしたら根本的に解決できるのでは、
という事。

全くそのとおりでした。
むしろなぜ
mc.msg = new String(mc.msg.getBytes("shift_jis"), "utf-8");
で正しく表示できていたのか自分でも不思議になってきました。

■LogPanelを改造する場合
$ANDROID_SRC_ROOT/sdk/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java
1121行目あたりの
mc.msg = line.replaceAll("\t", "    ")
の下に
try{
mc.msg = new String(mc.msg.getBytes("iso-8859-1"), "utf-8");
}catch(Exception e){
e.printStackTrace();
}
を追加する。

■MultiLineReceiver.javaを改造する場合
$ANDROID_SRC_ROOT/sdk/ddms/libs/ddmlib/src/com/android/ddmlib/MultiLineReceiver.java
54行目辺り
public final void addOutput(byte[] data, int offset, int length) 
の中の
s = new String(data, offset, length, "ISO-8859-1"); //$NON-NLS-1$
s = new String(data, offset, length, "UTF-8"); //$NON-NLS-1$
に修正する。

DDMSのビルド-実行

・Linux側でmake sdk

・以下の場所にddms.jar, ddmlib.jar, ddmuilib.jarなどがビルドされる
    $ANDROID_SRC_ROOT/out/host/linux-x86/sdk/android-sdk_eng.xx_linux-x86/tools/lib

・Windows側のAndroidSDKにddms.jar, ddmlib.jar, ddmuilib.jarをコピーする。(すでにddms.jar, ddmlib.jar, ddmuilib.jarが存在するので注意)
    $ANDROID_SDK/tools/lib
・あとはddms.batを実行

※ddms.batで起動しようと思ったらNoClassDefErrorが出た。(Windows7 64bit Home Premium使用)
その場合はddms.batの48行目辺りのjarpathをsetしている所を以下の様に修正する。
set jarpath=%frameworkdir%%jarfile%;%frameworkdir%ddmuilib.jar;%frameworkdir%ddmlib.jar;%frameworkdir%org.eclipse.jface_3.4.2.M20090107-0800.jar;%frameworkdir%sdkstats.jar;%frameworkdir%androidprefs.jar;%frameworkdir%org.eclipse.equinox.common_3.4.0.v20080421-2006.jar;%frameworkdir%org.eclipse.core.commands_3.4.0.I20080509-2000.jar;%frameworkdir%jfreechart-1.0.9-swt.jar;%frameworkdir%jfreechart-1.0.9.jar;%frameworkdir%jcommon-1.0.12.jar;%frameworkdir%osgi.jar
※ようするにクラスパス通ってないよ!という事です。↑はAndroid2.3が出た時に持ってきたSDKの場合のパスです。他バージョンや今後のバージョンでは異なる可能性があるので適宜書き換えてください。NoClassDefErrorに見つからなかったクラスのフルネームが出てくるので、なんとかエスパーしてjarを追加していって下さい。

できた・・・!


おまけ

■DDMSってフォント設定できるので、日本語出せるフォントにしておいて下さいね。

■MultiLineReceiver.javaに対する修正は既にパッチが上げられ議論されているようです。
「そう単純な話じゃねぇ!」とったコメントが入ってたりしてどうなるのかわかりませんが、
公式でマルチバイト文字の対応を実現してもられると助かりますね。

@androidzaurus @zaki50 @15myさんありがとうございました!


2 件のコメント:

  1. 前から日本語出したいなーと思っていたのでとても参考になります。

    書いてある内容を元にコードを見てみましたが、
    new String(mc.msg.getBytes("shift_jis"), "utf-8");
    としている部分(元のメッセージを shift_jis なバイト列にした物を utf-8として解釈して文字列にする)は
    new String(mc.msg.getBytes("ISO-8859-1"), "utf-8");
    (元のメッセージを iso-8859-1 なバイト列にした物を utf-8として解釈して文字列にする)ほうが正そうに思います(ビルド環境がないので試せていません)。

    根本的に直すのであれば、
    sdk/ddms/libs/ddmlib/src/com/android/ddmlib/MultiLineReceiver.java
    の addOutput(...) で s = new String(data, offset, length, "ISO-8859-1");
    としている部分を s = new String(data, offset, length, "UTF-8"); にするほうがよさそうに思いました。

    こちらでもビルド環境作って試してみますが、可能であれば確認していただけるとうれしいです。

    返信削除
  2. Twitterでは色々検証いただきありがとうございました!
    教えて頂いた情報含めて修正、追記します~

    返信削除