GraveDollの備忘録ブログ

勉強したことや捗るグッズの備忘録です。

ローカルaarファイルからサブモジュールを利用できない

Androidはかなり久しぶりの備忘録(投稿自体久しぶりですがw)。
Androidでライブラリ開発してるとき、そのライブラリ(Module)が依存するライブラリ(SubModule)のソースコードがプロジェクト内にあるとします。
このとき、メインのライブラリ(Moduleとします)のbuild.gradleで

dependencies  {
    api project(':Module:library:SubModule') //推移的依存
}

のように依存関係を設定してaarファイルを作成すれば良いかと思うかもしれません(ビルドも成功します)。
しかし、実際にアプリこのライブラリを組み込んでみると、アプリからSubModuleのメソッドなどにアクセスしようとするとClassNotFoundのエラーが発生してしまいます。
mavenリポジトリから依存させる場合はpomファイルで依存関係を参照できるのですが、ローカルのaarファイルではそれができないためです。

この場合どうすればよいのかというと、SubModuleをjarファイルで出力し、Moduleでそれを読み込むようにします。

//SubModuleのbuile.gradle
task copyJar(type: Copy) {
    from("${project.buildDir}/intermediates/aar_main_jar/release")
    into('../../libs')
    include('classes.jar')
    rename('classes.jar', 'SubModule.jar')
}

afterEvaluate {
    build.finalizedBy(copyJar)
}

ビルド処理終了時に、中間ファイルとして出力された.jarをリネームして、プロジェクトのlibsフォルダに保存しています。
中間ファイルの場所(${project.buildDir}/intermediates/aar_main_jar)ですが、AGPのバージョンによって突然変わってしまうことがあるので注意が必要です(この例では4.2.1を使用)。

上記の処理はメインのライブラリであるModuleのビルド前に完了させる必要があります。手動でSubModuleのgradleタスクを先に実行してしまえばいいのですが、面倒ですよね。
VisualStudioならこの辺のビルド順序は簡単に設定できるのですが、gradleは複数のタスクが並行して実行されているためなかなか難しいです。
私の場合はメインのModuleのbuile.gradleに以下の記載を追加し、Moduleのビルド処理前にSubModuleがビルド完了されるようにしています。

//メインModuleのbuile.gradle
preBuild.dependsOn ":Module:library:SubModule:build"

ModuleからSubModuleの参照は以下でOK。

//メインModuleのbuile.gradle
compileOnly project(path: ':Module:library:SubModule') //jarファイルが無い場合でもコンパイルエラーが起こらないように
api fileTree(dir: 'libs', include: ['SubModule.jar'])