前置き
以前、こんなエントリーを書いたのですが、もう少し調査して簡単な方法や複雑なライブラリ構成のときにどうすればいいか等が分かったので、書き直しました。
GitHubのPrivateリポジトリのライブラリを参照する
上記の方法だと、publishNonDefault=trueに対応出来ていませんでしたが、こちらは対応出来る方法になっています。
A. 1ライブラリ1プロジェクトの場合
プロジェクト内に1ライブラリモジュールしかない、シンプルな構成のプロジェクトの場合です。
ライブラリ側
1. ライブラリプロジェクト下にgradle.propertiesを配置して以下を記述
# mavenリポジトリ名
mavenRepository=maven-repo
# maven出力フォルダのプロジェクト相対パス(最後が必ず”mavenリポジトリ名”と一致していること)
mavenPublishDir=../maven-repo
# maven groupId
mavenGroupId=jp.co.sample.group
もちろん、上記の値は全て適宜、変更して下さい。
2. ライブラリプロジェクト下にmavenupload.gradleを配置して以下を記述
def repo = new File(rootDir, mavenPublishDir)
def groupId = mavenGroupId
def libName = project.name
def versionName = android.defaultConfig.versionName
// maven push
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository url: "file://${repo.absolutePath}"
pom.version = "${versionName}"// version
pom.groupId = "${groupId}" // グループ名
pom.artifactId = "${libName}" // ライブラリ名
}
}
}
3. ライブラリプロジェクトのbuild.gradleに追記
- 先頭に追加。(ライブラリプロジェクトの作成方法によってはすでに記述されている場合も有り)
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
- android{}内に追記。
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
...
defaultPublishConfig 'release' // 任意
publishNonDefault true // 任意
}
publishNonDefault=true
がtrueかどうかは関係が無いので、自由に設定して下さい。
- 末尾に追加。
apply from: '../mavenupload.gradle'
参考:最終build.gradle
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
publishNonDefault true
}
dependencies {
compile 'com.android.support:support-v4:23.3.0'
}
apply from: '../mavenupload.gradle'
4. mavenにpublishするタスクを実行する
必要があればバージョンアップすること(依存している全てのプロジェクトが影響を受けるので要注意!)
GradleTasksの中から、uploadArchivesというタスクを見つけてダブルクリックするか、ライブラリプロジェクト下で以下を実行する。
$> ./gradlew uploadArchives
5. GitHubにcommit & Pushする
コマンドなら以下。
$ git add -A
$ git commit -m 'libA build' // コメントは随時変更してください
$ git push
アプリ側(ライブラリ使用側)
git-repoを使います。
1. GitHubにSSH Key(公開鍵)を登録する
個人アカウントのSettingsでやります。
SSH Keyの作り方や、設定方法はあちこちにあるのでググって下さい。
2. アプリのルートプロジェクトのbuild.gradleに追記
app/下のbuild.gradleではなく、その上の階層にあるファイルです。
repositories {
mavenCentral()
}
dependencies {
classpath group: 'com.layer', name: 'gradle-git-repo-plugin', version: '2.0.2'
}
3. アプリのbuild.gradleに追記
app/下のbuild.gradleです。
- dependenciesの上に追加。
apply plugin: 'git-repo'
repositories {
github("GitHubユーザー名", "リポジトリ名", "ブランチ", "mavenディレクトリ名")
}
- dependenciesを追加。
ライブラリ側がpublishNonDefault=true
にしているかどうかで変わります。
publishNonDefault=false(または未設定)の場合
dependencies {
...
compile 'グループID:ライブラリ名:1.0.0'
}
参考:最終build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "sample.jp.co.cy.samplelib"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
apply plugin: 'git-repo'
repositories {
github("myGitHubName", "libRepositoryName", "master", "maven-repo")
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
testCompile 'junit:junit:4.12'
compile 'jp.co.sample.group:libA:1.0.0'
}
publishNonDefault=trueの場合
アプリ側の設定だけ、false(または未設定)の場合と異なり、dependencies部分を以下のようにします。
dependencies {
...
debugCompile('グループID:ライブラリ名:1.0.0:debug@aar')
releaseCompile('グループID:ライブラリ名:1.0.0:release@aar')
}
参考:最終build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "sample.jp.co.cy.samplelib"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
apply plugin: 'git-repo'
repositories {
github("myGitHubName", "libRepositoryName", "master", "maven-repo")
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
testCompile 'junit:junit:4.12'
debugCompile('jp.co.sample.group:libA:1.0.0:debug@aar')
releaseCompile('jp.co.sample.group:libA:1.0.0:release@aar')
}
B. 1プロジェクトに複数のライブラリがある場合
プロジェクト内にライブラリモジュールが複数ある場合です。それぞれ単独で参照されるだけのライブラリを寄せ集めただけのプロジェクトなら、Aの方法で出来ます。
今回は、以下のような構成で、libAがsubA,subBに依存しているような場合を検討します。
+ Root(checkout フォルダ)
+ MyLibraries
+ subA
+ subB
+ libA
+ sampleApp
- sampleAppは、ライブラリ開発のための動作確認用サンプルアプリモジュール。
- sampleAppは、libAに依存します。
- libAは、subAをbuildTypeに依存して参照します。
- sampleAppは、libAをbuildTypeに依存して参照します。
通常、同一プロジェクト内のモジュール参照だと、dependenciesは以下のような記述になっているかと思います。
dependencies{
developDebugCompile project(path: ':subA', configuration: 'debug')
developReleaseCompile project(path: ':subA', configuration: 'release')
developCompile project(':subB')
}
dependencies{
developDebugCompile project(path: ':libA', configuration: 'debug')
developReleaseCompile project(path: ':libA', configuration: 'release')
}
ライブラリ側
一筋縄ではいきません。libAやsampleAppのdependenciesをいじることが出来ないからです。
git-repoを使用した書き方に変えてしまうと、ライブラリ内をデバッグ実行が出来ないのと、subAやsubBを編集して動作確認したいときに、maven-repoディレクトリを、いちいちコミット・pushする必要が生じてしまうからです。
productFlavorsでdependenciesを切り替える方法も試しましたが、成果物の名称がかなりアレな感じになったのでやめました。
ということで、今回は、以下の手段を執ることにします。
開発用のプロジェクトと、publish用のプロジェクトを分ける
少し手間ですが、この方が最終的に効率が良いと感じました。
1. publish用のフォルダを作成する
まず、subA,subB,libAをフォルダごとコピーして、以下のようなフォルダ構成にします。
ただし、MyLibraries自体がGradleプロジェクトですが、MyLibrariesForPublishは単純にフォルダを作成しただけで、Graldeプロジェクトとしては扱いません。AndroidStudioでMyLibrariesForPublishを直接開かないように要注意です。
また、この方法だと、開発プロジェクトの方でいくらversionCode/versionNameを上げても、こちらのpublish用プロジェクトの方を変更しないと反映されないので、そこが要注意ですね。
+ Root(checkout フォルダ)
+ MyLibraries
+ subA
+ subB
+ libA
+ sampleApp
+ MyLibrariesForPublish
+ subA
+ subB
+ libA
2. publish用のプロジェクトを作成する
subA, subB, libAの各srcフォルダをごっそり削除します。
その後、各build.gradleのsourceSetのrootを、開発用プロジェクトのフォルダに指定してやります。
android {
// 開発用プロジェクトのソースコードを参照させる
sourceSets {
main.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/subA/src/main")
debug.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/subA/src/debug")
release.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/subA/src/release")
}
...
}
android {
// 開発用プロジェクトのソースコードを参照させる
sourceSets {
main.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/subB/src/main")
}
...
}
android {
// 開発用プロジェクトのソースコードを参照させる
sourceSets {
main.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/libA/src/main")
debug.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/libA/src/debug")
release.setRoot("${project.rootDir.getAbsolutePath()}/../MyLibraries/libA/src/release")
}
...
}
3. publish用ディレクトリ下にmavenupload.gradleを配置して以下を記述
内容はAの時と同じです。
def repo = new File(rootDir, mavenPublishDir)
def groupId = mavenGroupId
def libName = project.name
def versionName = android.defaultConfig.versionName
// maven push
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository url: "file://${repo.absolutePath}"
pom.version = "${versionName}"// version
pom.groupId = "${groupId}" // グループ名
pom.artifactId = "${libName}" // ライブラリ名
}
}
}
4. 各ライブラリプロジェクト下に、gradle.propertiesを配置する
内容はAの時と同じなので、割愛します。
subA,subB,libA全て同じ内容になるはずなので、ファイルのコピペで済むはずです。
5. 各ライブラリのbuild.gradleを書き換える
subA, subB, libAの各build.gradleの末尾に以下を追記。
apply from: '../mavenupload.gradle'
いったんこの時点で、AndroidStudioで各ライブラリプロジェクトを開いて、GradleSyncが通るか確認して下さい。
続いて、libAのdependenciesを書き換えます。ただし、Syncが最初は通らなくなるので注意して下さい。(maven-repoディレクトリをpushしないと、当然ですね・・・)
dependencies{
debugCompile('jp.co.sample.group:subA:1.0.0:debug@aar')
releaseCompile('jp.co.sample.group:subA:1.0.0:release@aar')
compile 'jp.co.sample.group:subB:1.0.2'
}
6. 各ライブラリのuploadArchivesを実行する
まず、subA, subBのuploadArchivesを実行します。
コマンドラインでやる方が楽です。
$ cd subA
$ ./gradlew uploadArchives
$ cd subB
$ ./gradlew uploadArchives
続いてそれをcommit & pushします。
$ git add -A
$ git commit -m 'subA/subB build' // コメントは随時変更してください
$ git push
その後で、libAのuploadArchivesを実行します。
$ cd libA
$ ./gradlew uploadArchives
最後にlibAの成果物をcommit & pushします。
$ git add -A
$ git commit -m 'libA build' // コメントは随時変更してください
$ git push
これで、他のアプリプロジェクトからlibAを参照出来るようになりました。
この項目の流れは、うまくbashスクリプトとかにしておけば、一気に出来るなと思ったので、この手法をとることにしました。
ここにさらにsubCがあって、libBはlibAとsubCを参照してて・・・なんて複雑な構成になっても、スクリプトに追記していけばpublishする手間はさほど変わらずに済むかな、という点で有効かなと考えています。(試してはいません)
アプリ側
単純な1ライブラリ参照と異なって、dependenciesを以下のように書く必要があります。
(以下はpublishNonDefault=trueの場合)
dependencies{
debugCompile('jp.co.sample.group:libA:1.0.0:debug@aar'){
transitive=true
}
releaseCompile('jp.co.sample.group:libA:1.0.0:release@aar'){
transitive=true
}
}
transitive=trueがミソですね。
これは、「libAの依存も順次解決してね」という指定みたいです。