連載
» 2013年02月18日 18時00分 公開

Androidで動く携帯Javaアプリ作成入門(40):動的クラスローディングでAndroidアプリ“裏”開発 (3/3)

[緒方聡,イーフロー]
前のページへ 1|2|3       

JARをDEXに変換

 「AndroidでJavaのJARファイルを直接使いたい」という需要は、それなりにあるのではないかと思います。通常、そうした使いたいJARは、「libs」ディレクトリに入れておくだけで、ADTが良きに計らってくれます。ただし、動的に使用したい場合、そのJARはDEX形式でなければなりません。どうすればよいのでしょうか。

 ここで使用するのが「dx.jar」です。

注意! 「dx.jar」のライセンス

 AndroidがApache Licenseであることは有名ですが、Android SDKはApache Licenseではありません。「Terms and Conditions」の3.3には以下のように記載されています。

3.3 You may not use the SDK for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.

 これを意訳します。

 あなたは、本使用許諾契約で許可されていない、いかなる目的のためにもSDKを利用できません。該当するサードパーティのライセンスで必要とされる範囲を除き、以下は行えません。

  • (a)バックアップを除くコピー、変更、改作、再配布、リバースエンジニアリング、逆アセンブル、またはSDKやSDKの一部の派生物の作成
  • (b)パーソナルコンピュータを除く携帯電話またはその他のハードウェアデバイス上でSDKの任意の一部をロードし、他のソフトウェアとSDKの一部を結合するか、SDKの一部を組み込んだ任意のソフトウェアまたは装置の配布

 SDKの一部を再配布したりアプリに組み込んだりするのは、Android SDKの使用許諾契約違反になります。

 一方でdx.jarのソースコードはApache LicenseのAndroidソースツリーに含まれており、ソースコードにもApache Licenseであることが明記されています。


 dx.jarはAndroid SDKに含まれるSDKの一部でありながら、そのソースコードはApache Licenseで自由に利用できる、ダブルスタンダードとなっているため、自身でビルドしたdx.jarなら大丈夫なのか、ソースコードを取り込めば大丈夫なのかが、はっきりしない状態です。本記事では、自身でビルドしたdx.jarを取り込む前提で話を進めますが、ライセンスは読者自身で、しっかりと確認するようにしてください。


 dx.jarは、Java形式のJARをDEX形式のJARに変換してくれるJavaプログラムです。JavaプログラムでJAR形式なら、「libs」に入れればアプリから使えるようになります。dx.jarは配布するサンプルアプリには含まれていません。読者自身で「libs」フォルダに入れてアプリをビルドしてください。

 dx.jarはコマンドラインで以下のように使用します。

java -jar --dex --output={出力先} {変換対象}

 メインエントリクラスは「com.android.dx.command.Main」です。つまり、以下のように実行することで、アプリ内でJARのフォーマット変換が行えることになります(サンプルアプリ内ではリフレクションを使用しています)。

String jarPath = Environment.getExternalStorageDirectory().getPath() + "/Hello.jar";
File converted = new File(mDexOutputDir, "Hello_converted.jar");
mDexPath = converted.getAbsolutePath();
mJarPath.setText(mDexPath);
if (converted.exists()) {
    append("Convert skipped");
} else {
    String[] params = new String[] {
        "--dex",
        "--output=" + mDexPath,
        jarPath
    };
    com.android.dx.command.Main.main(params);
    append("Convert finished");
}

 必要な引数を配列に組み立てて、mainメソッドを呼び出します。これでDEX形式に事前に変換しておくことなく、動的クラスローディングが行えるようになります。

動的クラスローディングする際の4つの注意点

 今回はAndroidプラットフォームで動的クラスローディングについて解説しました。本文で触れていなかった注意点をいくつか補足しておきます。

【1】生成した最適化されたDEXファイルを消したり書き換えたりしてはならない

 そのDEXファイルを使用している最中に、ファイルを削除したり書き換えたりすると、「libc」というネイティブライブラリでエラーが発生します。エラーの発生個所は、おそらく「DexFile#finalize()」から呼び出される「closeDexFile(int)」というネイティブメソッドの先でしょう。

 出力されたファイルを消したり書き換えたりしなければ大丈夫なので、出力先はアプリのプライベート領域を指定するようにしましょう。

 なお、BaseDexClassLoader、DexClassLoader、DexFileでは出力先ファイルが存在するかどうかを事前にチェックする必要はありません。あればそれが使用され、なければ生成されます。つまり、初回だけ変換の時間を要することになります。

【2】変換後のJARから生成したDEXを使用中にJARフォーマット変換でJARを書き換えてはならない

 これも同様にlibcでエラーが発生します。これは本サンプルが行っているように変換前にファイルが存在するかどうかをチェックすることで防ぐようにしてください。

【3】クラスファイルの形式は1.5にする

 コンパイルするJDKのバージョンが新しい、特にJava 7の場合、dx.jarで変換できない可能性があります。以下は今回使用したHelloクラスをコンパイルした際のjavacのオプションです。

mkdir out
javac -source 1.5 -target 1.5 -bootclasspath "%JAVA_HOME%\jre\lib\rt.jar" -d out com\example\hello\Hello.java
jar cf Hello.jar -C out .

 上記のように「-source」「-target」に1.5を指定すれば安全です。

【4】動的クラスローディングするJARの出所に注意

 動的クラスローディングは危険性もはらんでいます。特に、インターネット上からJARをダウンロードするようなケースで細心の注意を払ってください。ダウンロードしたJARが悪意を持って作られたものであった場合、アプリと同じ権限で悪意あるコードが動作します。情報を盗まれたり消されたり、アプリを勝手にインストールされたり、やろうと思えば権限内で何だってされてしまいます。

 こうした悪意あるコードを防ぐのは動的クラスローディングでは難しい課題です。「権限のないサービスなどでコードを実行し、本体アプリとはプロセス間通信で結果を受け取る」「信頼のおける開発者(同じ組織や自分自身のみ)のJARしか動作させない」などが解決方法だと思います。

「Androidで動く携帯Javaアプリ作成入門」バックナンバー
前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。