Edited at

【Android】「自作ライブラリ」を「GitHub」に置いて「Gradle」でビルドするだけで利用できるようにする(1)

More than 1 year has passed since last update.


背景

アプリをいくつも開発していると、同じクラス、同じモジュールを実装しなくてはならなくて、煩雑に感じることが多々ある。

例えば、Aアプリにも、Bアプリにも、Cアプリにも、「ある条件下でユーザにレビューをお願いする機能」が搭載されているが、いつも開発時にコピペして搭載している、などの場合、この地味な作業が煩雑で仕方がない、キーッてなる。

それを解消する為に「Android ライブラリ」という共通化モジュールが存在するわけだが、このライブラリモジュールを更新する度に手動で各アプリに「AAR(後述)」ファイルを配置していたら、やはりそれはとても煩雑である。

なので、Googleの「Support ライブラリ」みたいに、Gradleにバージョンを記載するだけで新しいライブラリをビルドできるように実現できたら、相当、楽でしょ。

↓こんな風に書くだけでさ。

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.google.firebase:firebase-core:11.6.2'
implementation 'com.google.firebase:firebase-crash:11.6.2'
implementation 'com.google.firebase:firebase-ads:11.6.2'
implementation 'cutboss.support:boss:1.1.1'
implementation 'cutboss.support:review:1.1.4'
}

じゃあ、やろうぜ。


やりたいこと


  1. Android ライブラリ」を自作する(公式「Android ライブラリの作成」の内容を見る限り、難しくなさそう)

  2. 自作した「Android ライブラリ」を「GitHub」にアップロードする(無料開発をモットーにしているので、「有料のprivate」ではなく、「無料のpublic」で登録して、ライブラリは全世界に公開することを前提とする)

  3. Gradle」に記載すれば全世界のどこの誰でもビルドしてライブラリを参照できるようにする


(1)「Android ライブラリ」を作成する

公式「Android ライブラリの作成」の内容を読めば、大体のことは理解できる。

・・・が、それでも疑問に思って手が止まったので、そのことを中心に補足的に解説する。


(1.1)プロジェクトを作成する

これは、普段、「Android アプリ」を作成する手順とまったく同じ。

ここが個人的第一ハマりポイント。

「ライブラリ専用プロジェクト」というものは存在しない!!!

いつもの「Android アプリ」と同じように、新規プロジェクトを作成すればいい。

 File▶

  New▶

   New Project...

こうだよね。

このときに設定する「プロジェクトの名前」や「パッケージ」は、ライブラリには何の関係もないので、適当で構わない(個人的第二ハマりポイント)。

また、アプリを作成するのではないので、画面は勿論不要、「Add No Activity」を選択すること。

どうせ削除するので(直後述)。

create_new_project.png

(※執筆時「Android Studio 3.0.1」を使用)


(1.2)「app/」を削除する

アプリを作成するのではないので、プロジェクトの作成ができたら、まず、不要な「app/」一式を削除する。

その方法は、、、「Android Studio」左サイドのプロジェクト内に「app/」があるので(普段アプリ作成している場所)、その「app/」の上でコンテキストメニューを表示(マウスの右クリック)して、「Open Module Settings」を選択する(個人的第三ハマりポイント)。

すると「Project Structure」が表示され、「Modules」以下に「app」があるので、「app」を選択(ハイライト)した状態で、「DEL」キーを押下するなどして、完全に「app」を削除する。

project_structure_modules.png

これで削除はOK。

(※執筆時「Android Studio 3.0.1」を使用)


(1.3)「module」を作成する

ここからやっと本題、ライブラリを作成する。

ライブラリは、「module」という単位で呼ばれる。

 File▶

  New▶

   New Module...

こうして、「Android Library」を選択する。

create_new_module.png

configure_the_new_module.png


(1.3.1)「Application/Library name」の決定は適当に

Application/Library name」の入力については、ホントどうでもいい、適当で構わない。

strings.xml」に、

<resources>

<string name="app_name">Util</string>
</resources>

このように入力した内容が自動で定義されるだけだし、この定義は不要なので、削除してしまおう。

<resources>

</resources>

後ほど、こうしてしまって構わない。


(1.3.2)「Module name」は配布される

次、「Module name」だが、「AAR(後述)ファイルの名前」になるので、これはよく考えて。

例えば、


util-1.0.0.aar

review-1.1.4.aar


こういったファイル名にして全世界に配布したいと考えた場合は、「Module name」を「util」「review」とすればいい。


${Module name}-1.0.0.aar


ということだ。


(1.3.3)「Package name」は世界中のコードに残る

そして、次、「Package name」、これまた、とても重要だ。

このパッケージ名が、ライブラリ利用先でのパッケージになるので、世界に恥じないように、よく考えなければらない。

例えば、私の場合は、このパッケージ名のところですごく熟考して、


import cutboss.support.util.Utils;

import cutboss.support.review.Review;


最終的にこうしたのだが、全世界の人にこうやって使ってほしいってのを、ホントによく考えて決めた方が後々悔いがないと思うし、何より、パッケージ名が競合するライブラリ同士はビルドできず片方は利用できなくなってしまうので、世界の誰とも競合しないオリジナリティ溢れる美しいパッケージ名を生み出そう(そう考えてやってたら凄い楽しくなってきてた)。

そう、なので、「util」「review」というモジュールをそれぞれ作成したとき、これらを両方とも、


import cutboss.support.Utils;

import cutboss.support.Review;


「cutboss.support」という同一パッケージ名にしては絶対にいけない。

プロジェクトは同じであっても、「util」「review」は別のそれぞれ独立したモジュールとして作成されているので、プロジェクトが同じだからといってパッケージ名を同一にしてしまうと、「異なるモジュール同士が同一のパッケージ名を有している」ということで、競合が発生してビルドが失敗する(個人的第四ハマりポイント)。


(1.3.4)「パッケージ名」と「Gradle上の記載」を混同しない

ここで混同してほしくない注意点があるのだが、「パッケージ名」と「Gradle上の記載」に、関連性はない(個人的第五ハマりポイント)。

例えば、私は「Gradle上の記載」を以下のようにして使ってほしくて、このように定義した(後述)のだが、

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'cutboss.support:review:1.1.4'
implementation 'cutboss.support:util:1.0.0'
}

これは「Package name」や「Module name」と一致させなければならないというような制約があったわけではない

単に、個人的に、「パッケージ名」と「Gradle上の記載」が近しい方が利用者が混乱しないだろうなって思って、勝手に私がパッケージ名とGradle上の記載を似た感じにしたに過ぎない

とにかく、「Gradle上の記載」は自由に定義できる(後述)ので、パッケージ名とGradleの関連をごっちゃにしてはいけない。

(※執筆時「Android Studio 3.0.1」を使用)


(1.4)クラスを作成する

普通にアプリでクラスを作成するのと全く同じ。

ライブラリとして機能させたいクラスをパッケージ下に作成するだけなので、さすがに割愛する。


(1.5)「AAR」を作成する

モジュールが完成したら、世界に配布するために、「AAR」を作成する。

AAR」ファイルとは、「Android プロジェクト用のライブラリをまとめたフォーマット」で、「AAR」には「Android リソース」や「Manifest ファイル」を含めることができる(←公式「Android ライブラリの作成」にそう書いてある)のだが、「AAR」はそもそも「Android Studio 専用のライブラリ」なので、「Android Studio」以外の環境でライブラリを使いたい場合は、「AAR」ではなく「jar」を作成するということになる。

勿論今回は「AAR」を作成するので、「jar」は作成しない。


(1.5.1)「AARファイル名」を細工する

ところで、以下が私作モジュールの最終的な(全世界に配信済みの)「build.gradle」の全内容なのだが、

apply plugin: 'com.android.library'

android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 21
targetSdkVersion 26
versionCode 2
versionName "1.0.1"
version = android.defaultConfig.versionName
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'assets/*'
}
libraryVariants.all { variant ->
variant.outputs.all { output ->
output.packageLibrary.exclude("libs/*")
if (variant.name == android.buildTypes.release.name) {
outputFileName = output.outputFile.name.replace(("-release.aar"), "-${version}.aar")
} else if (variant.name == android.buildTypes.debug.name) {
outputFileName = output.outputFile.name.replace((".aar"), "-${version}.aar")
}
}
}
}

dependencies {
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
}

「AAR」ファイルを前述の、


util-1.0.0.aar

review-1.1.4.aar


という形式にしたくて、以下を追記して実現している。

    libraryVariants.all { variant ->

variant.outputs.all { output ->
output.packageLibrary.exclude("libs/*")
if (variant.name == android.buildTypes.release.name) {
outputFileName = output.outputFile.name.replace(("-release.aar"), "-${version}.aar")
} else if (variant.name == android.buildTypes.debug.name) {
outputFileName = output.outputFile.name.replace((".aar"), "-${version}.aar")
}
}
}

デフォルトでは「バージョン名」がファイル名に付与されないので、今、どのバージョンを利用しているか明確にする為の配慮として、上記は、「-${version}.aar」としてある。


(1.5.2)「難読化」すると参照できなくなるので要注意

普段アプリをリリースするときに「難読化」していると、癖でライブラリも「難読化」してしまうので、気をつけよう。

やってみればアーッて当然のことなのだが、難読化してしまうと、クラス名が訳の分からん名前にされてしまうので、そのクラスは本来のクラス名でインポートできなくなる(個人的第六ハマりポイント)。

    buildTypes {

release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

こうして「minifyEnabled true」にしたらマズイということなのだが、こうしたとして、「public以外を難読化する」ということも可能だ。

proguard-rules.pro」ファイルに、以下の1行を追記しよう。

-keep public class cutboss.support.util.** { public *; }

こうすることで、publicだけが難読化されず、インポート先で参照できるようになる。

執筆時点では私のモジュールは全てこうなっているのだが、「宣言に(直接)移動」操作(Control+B)で私のソースコードを参照したときに、public以外が難読化されていて参照できないのは、不親切かなあと、思うところもある。

今後、私は難読化を全て解除するかもしれない。


(1.5.3)依存関係に含めたくないライブラリの指定方法

ライブラリを作成していて、その自作ライブラリからさらに外部ライブラリを参照しているようなことは、少なからずあると思う。

そういった場合で、コンパイルでは使用するけど依存関係には含めたくない、という場合、「compileOnly」という指定方法だけで、解決できる(個人的第七ハマりポイント)。

dependencies {

compileOnly fileTree(dir: 'libs', include: ['*.jar'])
}


(1.5.4)おまけ「exclude 'assets/*'」について

以下「exclude 'assets/*'」を私は追記しているが、

    packagingOptions {

exclude 'assets/*'
}

ライブラリで「assets/」配下を参照する必要があれば、勿論、この追記は必要ない(というか追記したら機能しなくなるでしょ)。


(1.5.5)「Terminal」でリリースビルド

「Android Studio」下部の「Terminal」にて、以下のコマンド「gradlew assembleRelease」を実行する(個人的第八ハマりポイント)。


C:\Job\svn\trunk\barber\maid\android\SupportBoss>gradlew assembleRelease


何も操作していなければ、プロジェクトルート(この例なら「C:\Job\svn\trunk\barber\maid\android\SupportBoss」)がデフォルトで表示されているはずなので、そこでそのままこのコマンドを実行しよう。

terminal.png

以下が表示されれば成功だ。

terminal_success.png

以下に「AAR」ファイルが生成されている。


プロジェクトルート > モジュール名 > build > outputs > aar


aar.png

次回は、ライブラリを「GitHub」にアップロードする為の前準備を行う。

(※執筆時「Android Studio 3.0.1」を使用)


サンプルアプリ

以下アプリの「フィードバック」項目の動作や、「ある条件下でユーザにレビューをお願いする」機能は、本記事記載の方法で作成したライブラリで動作しているので、良かったら参考にしてみてほしい。

勿論のことであるが、ライブラリ経由だからといって、動作が不自然だったりはしていないと思う。

ic_launcher.png

シンプルなメモ帳は文字数もカウントする-カラーラベルや並べ替えを搭載した無料ノート-NOTEBOSS

【動作環境】

Android OS 5.0以上

Made in Japan.

© CUTBOSS

Producer & Director, Boss of the Barber.

Lead Programmer & Designer, Boss of the Barber.

header_2_ja.png


参考記事