Rの二乗

先日のエントリでは外部のライブラリィプロジェクトをアプリケーションプロジェクトに取り込む際の解決策を書いた。

Androidの場合は、ライブラリィをAndroidプロジェクトとして作成したならば、プロジェクトではなく、ソースコードとして参照する必要がある。

しかし、この方法でも上手くいかないことが判った。それはライブラリィ・プロジェクト側でもAndroid リソースクラス(Rクラス)を使用している場合である。

以前のエントリで紹介した方法の場合、ライブラリィをソースコードとして取り込む場合、以下のようなディレクトリ構成になると思う。(順不同)

$PROJECT_ROOT
 |
 +--- gen (自動生成されたアプリケーションソース)
 |     |
 |     +-- R.java  ×
 |
 +--- src (アプリケーション・ソース)
 |
 +--- lib_src (ライブラリィ・ソース) ※LIB_PROJECT_ROOT\srcへのリンク
 |
 +--- lib_gen (自動作成されたライブラリィ・ソース) ※LIB_PROJECT_ROOT\genへのリンク
 |     |
 |     +-- R.java ×
 |
 +--- res (リソース)
 |     |
 |     +-- layout
 |           |
 |           +-- main_layout.xml

同一プロジェクト中に自動作成されたR.javaが二つ存在しているが、パッケージが違うため、存在自体に問題は無い。問題なのは、リソース(Rクラス)への参照がプロジェクト外に及ぶ場合だ。


例えば、ライブラリィ側では共通で使用する独自のコンポーネントを提供していたとしよう。
独自のコンポーネントは、標準のビューを拡張しており、属性 "guidance" が追加されている。

$LIB_PROJECT_ROOT
 |
 +--- gen (自動生成されたソース)
 |     |
 |     +-- R.java
 |
 +--- src (ライブラリィ・ソース)
 |     |
 |     +-- jp.hoge
 |           |
 |           +-- GuidanceView.java
 |
 +--- res (リソース)
 |     |
 |     +-- values
 |           |
 |           +-- attr.xml

拡張されたコンポーネントのための属性は attr.xml要素に記述することで、R.javaには属性をまとめる整数(ハンドル)の配列と、配列を参照するための序数が値となっている定数が生成される。(ここがわかりにくかった...)

    • attr.xml

     
        
    

    • R.java (attr.xmlにより追記された分)
public final class R {
    public static final class attr {
        public static final int guidance=0x7f010001;
    }
    :
    :
    public static final class styleable {
        public static final int[] GuidanceView = {
            0x7f010001
        };
        public static final int GuidanceView_guidance = 0;
    };
}

拡張されたコンポーネントはレイアウトにクラス名を明示することで、内部インフレータ(Inflator)により実体化される

    • main_layout.xml (拡張されたビューを抜粋)

     hoge:guidance="URLを入力してください">
        
     

ネームスペースhogeの指定は重要だ。この属性で指定されているURIの末尾が参照されるパッケージとなるからだ(これもわかりにくかった)。
この例の場合、xmlns:hoge="http://schemas.android.com/apk/res/jp.hoge" の末尾にあたる jp.hoge.R クラスがリソースとして参照されることになる。

インフレートされたコンポーネントは、コンストラクタ内で上記リソースを使って、レイアウトに指定された新たな属性を読み込むのである。(ここもわかりにくかった..)

    • jp.hoge.view.GuidanceView#GuidanceView
    public GuidanceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //attr.xml経由で拡張されたプロパティを取得
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GuidanceView);
        
        this.guidance = a.getString(R.styleable.GuidanceView_guidance);
	}


これで完璧なはずだったのだが、実際に上記のレイアウトを記述するとエラーになる。

ERROR No resource identifier found for attribute 'guidance' in package 'jp.hoge'

ならばとビルドし直すと、プロジェクト下のR.javaが消えてしまい、全ての参照がエラーとなってしまう。

R を解決できません

ということで、ADT Plugingで作成したプロジェクト、レイアウトからは外部プロジェクトのリソース(Rクラス)を参照できないのか、又は、プロジェクト中で管理できるリソース(R.java)は一つだけようである。

このままではやはり、共通ライブラリィを皆で共有して使う、という方法は採れないことになる。
一定の条件を満たしたアセンブリ同士ならば共有可能な、.NETのような仕様だと楽ちんなんだがなぁ。 今後に期待か。

解決(妥協する)方法はありそうなのだが、それは次回に。