他パッケージ(他のapk)のリソースを読む part2

ならば読み出すことは不可能なのだろうか? 否。

答えはAndroidマニフェストにある。

Androidにアプリケーションをインストールするには、インストールするアプリケーションを説明する、AndroidManifest.xmlという名前のマニフェスト(嫌な名前だ)ファイルを必ず作る必要がある。

  • Eclipse ADTがデフォルトで作成するAndroidManifest.xml
?xml version="1.0" encoding="utf-8"?>

    
        
            
                
                
            
        
    
    
 

肝はこの中の要素のsharedUserId属性だ。

android:sharedUserId - manifest Android Developers

android:sharedUserId

他のアプリケーションと共有するLinuxユーザIDを指定する。デフォルトではAndroidがアプリケーション独自のユニークなユーザID を割り当てる。
ちなみに、この属性に同じ名前を指定する複数のアプリケーションは、それらすべてが同じ証明書によって署名されているという条件の基に同じIDを共有する。
同じユーザID を持つアプリケーションは、それぞれが所有するデータにアクセスができ、必要であれば同じプロセスで実行することができる。(超意訳)

最初、これはAndroid上でメモリを節約するために同一グループ/プロセスで実行するための仕組みだと思ったのだが、それだけではなく、リソースを共有する条件でもあることが分かった。

上記jp.co.hoge.app.apk、jp.co.share.hogelib.apkで使用するマニフェストにandroid:sharedUserId属性を設定する。

  • AndroidManifest.xml

なお、パッケージ名同様、最低一つの"."ピリオドをユーザIDに含まなくてはならない。(そうしないとインストール時にエラーになる)

両方共にインストールする際のsharedUserIdを合致した後に実行(インストールし)アプリケーション側から、以下のコードを実行する。

//Activityクラスの実行中(コンテキスト)であることが前提
Context ctx = this.createPackageContext("jp.co.share", Context.CONTEXT_RESTRICTED);
Resources res = ctx.getResources();
Log.d("read resource from jp.co.share.hogelib.apk", res.getString(jp.co.share.R.string.guidance));

Context#createPackageContextにより、共有可能なapk内部のパッケージを対象としたコンテキストを取得することができるので、このコンテキストを使ってjp.co.share.hogelib.apkのリソースから該当の文字列を読込める。

なお、この例でjp.co.share.R.string.guidanceが解決されているのは、jp.co.share側のソースコード・パス(/srcと/gen)をEclipseからプロジェクトのビルドパスに追加しているためだ。

Androidアプリケーションのデバッグで注意しなくてはならないのは、通常のJavaアプリケーションがそうであるようにEclipse上でビルドできたからといって、それがEclipseから起動されるjavaw.exe上で動作している訳ではなく、他のO/S上(エミュレータだったとしても仮想のAndroid O/Sが動作している)でDalvik仮想マシンが動作しているということを理解することだ。(私自身、下手にjavaを知っているだけにこれを忘れてしまうことが多い)