2011年1月10日月曜日

AndroidManifest.xml で宣言されていない Activity を動的に追加する (無理)

AndroidManifest.xml で宣言していない Activity を起動しようとしたが, ActivityNotFoundException が発生し, 「Unable to find explicit activity class ((Intent)intent).getComponent().toShortString(); have you declared this activity in your AndroidManifest.xml?」というエラーメッセージが出力されてしまった. エラーメッセージの内容は, 「AndroidManifest.xml 内で Activity を宣言してあるかい?」ということで, つまりは AndroidManifest.xml で宣言されていない Activity は起動できないよ, ということを示唆している. しかし, こっちはあくまで動的に Activity を追加したい (具体的には, 動的にインストールした OSGi バンドルに含まれている Activity を起動したい) わけなので, あらかじめ AndroidManifest.xml に宣言を書いておくなんていうことはできない. そこで, 動的に Activity を追加する方法があるかどうかを調べて見た.

Android のソースコードを読み込んでの結論は, 残念ながら「AndroidManifest.xml で宣言していない Activity を起動することはできない」である. Activity のクラス名を明示的に指定した Intent を用いて startActivity(Intent) を呼び出すと, その Activity の ActivityInfo を取得するために com.android.server.PackageManagerService クラスの getActivityInfo(ComponentName component, int flags) メソッドが呼ばれることになるが, このメソッドの実装が, 事前に AndroidManifest.xml から取得した情報しか扱えず, 情報の動的追加に対応していない. 動的追加に対応するように Android のソースコードを変更することはそんなに難しくは無い気もするが, 幾ら手元のソースコードを変更しても, 当たり前だが, 世の中に出回っている移動機内の Android の実装は変化しないので, Android のソースコードを変更するという手段を取ることはできない.


Dynamically add an Activity that is not declared in AndroidManifest.xml (impossible)

I tried to start an Activity that was not declared in AndroidManifest.xml, but an ActivityNotFoundException occurred and an error message "Unable to find explicit activity class ((Intent)intent).getComponent().toShortString(); have you declared this activity in your AndroidManifest.xml?" was shown. The error message implies that an Activity that is not declared in AndroidManifest.xml cannot be started. However, what I wanted to do was to dynamically add an Activity (to be concrete, to start an Activity that is contained in a dynamically-installed OSGi bundle), so it cannot be a choice to declare it in AndroidManifest.xml in advance. Therefore, I investigated whether there was a way to add an Activity dynamically.

The conclusion I got after reading Android's source code was, unfortunately, that an Activity that is not declared in AndroidManifest.xml cannot be started. When startActivity(Intent) is called with an Intent which explicitly specifies the class name of the target Activity, getActivityInfo(ComponentName component, int flags) method of com.android.server.PackageManagerService class is called to get the ActivityInfo of the Activity. However, the implementation of the method handles only information that has been obtained from AndroidManifest.xml in advance and has no mechanism to add information dynamically. It does not seem to be difficult to change the Android's source code to support dynamic addition, but I cannot take the option because implementations of Android in mobile terminals shipped around the world won't change however much I change the source code at my hand.