アプリケーションパッケージ(.apk)中のクラスを列挙してロードする

一つ前のエントリでclasses.dex中のクラス名を列挙できた訳だが、これですぐにクラスがロードできる訳ではない。
通常のJavaアプリケーションではよくある、以下のコードでは、クラスをロードしようとしても失敗するだろう。

  • Activity中にて
//スレッドのコンテキストクラスローダを使う
ClassLoader loader = Thread.currentThread().getContextClassLoader();

Enumeration enumeration = enumClassNames(this);
while (enumeration.hasMoreElements()) {
    String className = enumeration.nextElement();
    //クラスをロードする
    Class.forName(className, loader);
    //ClassNotFoundExceptionがスローされる
}

ならばどうする?

Contextクラスに属したクラスローダ(Context#getClassLoader()で取得できる)階層には、DexClassLoaderというdex形式ファイル(classes.dex)からクラスをロードできるクラスローダがクラスローダチェインに挿入されているので、ロードにはそれを使う必要がある。

  • Activity中にて
//アクティビティから取得できるコンテキストクラスローダを使う
ClassLoader loader = this.getClassLoader();

Enumeration enumeration = enumClassNames(this);
while (enumeration.hasMoreElements()) {
    String className = enumeration.nextElement();
    Class.forName(className, loader);
    //OK
}

これで、classes.dexからクラス名の一覧を列挙して、好きなクラスをロードしてインスタンスを生成することができるようになった。