Android Library ProjectでのSPI(Service Provider Interface)

ほぼメモ的な内容。

ライブラリプロジェクトを分割し、かつライブラリAに対し、ライブラリBが

プラグイン的に機能を提供する手段の一つとして検討した際のメモ。

あんまりAndroid自体は関係ない。


インターフェースとかの定義

まずサービス(Androidのサービスではないです)を定義するためにインターフェースとかをきる。


Service.java

package com.hoge;

public interface Service {
void onLoaded();
}



実装クラスを用意

機能提供側で実装クラスを作成


ServiceImpl.java

package com.hoge.impl;

public class ServiceImpl implements Service {
@Override
public void onLoaded() {
Log.d("test", "loaded " + getClass().getName());
}
}



META-INFを用意

src/{buildType}/resources/META-INF/services 以下に

サービス(インターフェース側)のFQNでファイルを生成

例: src/main/resources/META-INF/services/com.hoge.Service

実装クラスを提供するものがライブラリプロジェクトの場合は

これでaarファイルを生成した際にMETA-INFがjarファイルに含まれる。


上記ファイルにロードするクラスを記述する

上で作った src/main/resources/META-INF/services/com.hoge.Service に

ロードするクラスをFQNで記述する


com.hoge.Service

com.hoge.impl.ServiceImpl



クラスのロード

ServiceLoaderを使用してロード。(APIレベル9以降。流石に2.2とか対応している人はいないと信じたい)

以下はとりあえず定義されているやつをぐるぐるロードする例。


ServiceLoader<Service> loader = ServiceLoader.load(Service.class);
for (Service service : loader) { // loaderからはロードされたクラスへのiteratorが取得できる。
service.onLoaded(); // この例ではServiceImplの実体がnewされ渡される
}