2011年12月27日火曜日

Android SDK r16にハマる

android sdk r16がリリースされましたので早速使ってみることにしました。違いは android 4.0.3対応のようです。いつものようにsdkをダウンロードして、次にsdk/tools/androidを実行して必要なファイルをダウンロードします。すべてダウンロードするには結構な時間が掛かりました。
ここまでは、問題ありません。ハマるのはこれからでした。
まず開発中のゲームをビルドしてみます。自分はantを使ってビルドしているので。

% ant clean
% ant debug とします。問題なくビルドできましたので、開発作業を再開します。
(% はマンドプロンプトです。csh系の場合は'%'、bashなどのsh系は'$'、rootシェルの場合は'#'と表記します。自分はcsh系が好きなので tcsh を使っています。因みに開発環境は Ubuntu 10.04)

ところが、プログラムを書き始めると「あれ?」、「何か間違えたかな?」... 5分ほど何が起きたのか
判りませんでしたが修正箇所が反映されていないようです。antの出力をよく見ると。

-dex:
      [dex] No new compiled code. No need to convert bytecode to dalvik format.
ソースコードを書き換えているのにdexファイルが作られていないようです。という事はapkファイルは?

-package:
[apkbuilder] No changes. No need to create apk.
やっぱりapkファイルも新しく作られていません。
一旦sdk 16を使うのを中止。r15に戻して作業を続ける事にしました。

さて、開発中のゲームが完成してリリース準備ができたので、放置していたr16でビルドできない問題を調べる事にします。
まず、ソースコードをダウンロードしておきます。リポジトリに android-4.0.3_r1 というのがあるのでこれを取ってきてビルドしておきます。

次にdexファイルを作るdxコマンドが動くかどうかチェックします。
% dx --dex --verbose --output bin/claases.dex bin/classes libs
問題ありません。ちゃんとclasses.dexができました。

次は ant関連を調べます。普段antを使っているのですが、いままでどのようにantでビルドされているのかちゃんと調べたことがなかったので調べる事から開始です。
sdkの下に tools/ant/build.xml というファイルがありました。これを見ると次のような記述があります。

<path id="android.antlibs">
    <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
    


これがandroidのビルドをする為のanttaskのjarファイルです。
androidのビルドをするためのanttask.jarがsdkに含まれているものとソースからビルドしたものが違うとソースを見ても意味がありませんから、同じかどうかチェックしておきます。
先ほどソースからビルドしたanttasks.jarと配布されているsdkのディレクトリのanttasks.jarのファイルサイズは同じなので同じ物のようです。

さらにbuild.xmlには、下記のような記述があります。
<taskdef name="dex"
        classname="com.android.ant.DexExecTask"
        classpathref="android.antlibs" />

名前からこのクラスがdexファイルを作るクラスのように見えます。先ほどダウンロードしておいたソースに DexExecTask.java ファイルがないか探します。
% find . -name DexExecTask.java
./sdk/anttasks/src/com/android/ant/DexExecTask.java
原始的な事をしましたけど、@checkelaさんがもっと便利なやり方を紹介しています。

DexExecTask.javaファイルに"No new compiled code. No need to convert bytecode to dalvik format."というメッセージを出している所がないかと探すと、ありますあります。すぐに見つかりました。(笑)
if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) {
    System.out.println(
             "No new compiled code. No need to convert bytecode to dalvik format.");
    return;
}

ここを直せばよいような気がします。
この調子でソースを追っていくと、 dexファイルを作る為の依存関係にあるファイルとして libs/ ディレクトリの下にあるファイルと bin/classesディレクトリをチェックしているのが分かります。そしてファイルの先頭にドットがあるファイルを無視したいように書かれています。そのファイルを無視する判定メソッドがInputPath.javaにあります。
ここが間違っています。 trueとfalseを逆にして返してしまうという単純なミス。
これでソースファイルを変更したのにdexファイルが作られない現象が直りました。
以前載せていたのはリバースド・パッチになっていました、訂正してあります。恥ずかしい...

InputPath.javaのパッチ。
diff -r -c source-4.0.3_r1/sdk/anttasks/src/com/android/ant/InputPath.java source/sdk/anttasks/src/com/android/ant/InputPath.java
*** source-4.0.3_r1/sdk/anttasks/src/com/android/ant/InputPath.java     2012-01-07 23:18:45.718828865 +0900
--- source/sdk/anttasks/src/com/android/ant/InputPath.java      2011-12-27 18:13:11.843712831 +0900
***************
*** 76,82 ****
       */
      public boolean ignores(File file) {
          // always ignore hidden files/folders.
!         return file.getName().startsWith(".") == false;
      }

      /**
--- 76,82 ----
       */
      public boolean ignores(File file) {
          // always ignore hidden files/folders.
!         return file.getName().startsWith(".");
      }

      /**

0 件のコメント:

コメントを投稿