Droidkaigiのリポジトリを参考に自分でGradle Pluginを作成してみる

Droidkaigiのリポジトリのように、マルチプロジェクトで設定ファイルを共有する仕組みを知りたいと思って幾星霜。

今まで重い腰が上がらなかったのだが、Wear OSのプロジェクトが設定をベタ書きにしており非常につらい思いをしていたので、必要に迫られてやることにした。誰かの参考になれば幸いである。

Read full post gblog_arrow_right

ライブラリのバージョン管理をしやすくするrefreshVersionsを試してみた

Gradleでライブラリの管理を便利にできそうなプラグインを見かけた。refreshVersionsというプラグインだ。

buildSrcを使って一括管理する方法は知っていたが、プロジェクトごとに用意するのも面倒くさい。なにか楽な方法はないかと思っていたが、これはその解の1つとなりそう。

Read full post gblog_arrow_right

テストを実行した跡にレポートを自動的に開く

gradle経由でテストタスクを実行すると、テスト結果のレポートがbuild/reportsディレクトリに出力される。このレポートファイルを確認するのに、毎回ProjectウィンドウをProject表示に切り替えて、ディレクトリを掘ってファイルをブラウザで開くようにするのは手間である。そこでテスト実行後に自動的に開くようにした。 もっとスマートにやる方法があるのではないかと思うのだが、Gradleがよくわからなくて私には無理だった。以下のタスクをapp/build.gradleに追加した。 task openReportJvmTest(type: Exec) { workingDir "build/reports/tests/testProdDebugUnitTest" commandLine 'open' args "index.html" } task openReportInstrumentedTest(type: Exec) { workingDir "build/reports/androidTests/connected/flavors/MOCK" commandLine 'open' args "index.html" } openReportJvmTest.onlyIf { !ciBuild && !travisBuild } openReportInstrumentedTest.onlyIf { !ciBuild && !travisBuild } tasks.withType(AbstractTestTask) { task -> if (task.name == "testProdDebugUnitTest") { task.finalizedBy openReportJvmTest } } tasks.withType(com.android.build.gradle.internal.tasks.AndroidTestTask) { task -> if (task.name == "connectedMockDebugAndroidTest") { task.finalizedBy openReportInstrumentedTest } } openReportXXXというのがテストレポートをブラウザで開くタスク。開くディレクトリを直書きしているが、がんばればタスクによって開くディレクトリを変えることはできるだろう。openコマンドを使っているが、Windowsだときっと動かない。 既存のテストタスクのFinalizerタスクとして実行するよう指定しているが、CI上ではopenコマンドが認識できないので失敗してしまう。そこでCI上では実行しないようにonlyIfで指定している。 pluginで定義されているテストタスクの後に実行させたいのだが、tasks.withTypeを使うことで各タスクの参照を得ている。直接タスクを指定すると「そんなプロパティはない」と言われたり、nullだったりしてうまくいかなくてこういう形に行き着いた。 取得したテストタスクそれぞれでfinalizedByを使ってレポートを開くタスクを指定している。dependsOnを使うとテストが全てパスしていればレポートが開くが、1つでもテストが失敗しているとopenReportタスクが実行されないので、finalizedByを使っている。 http://gradle.monochromeroad.com/docs/userguide/more_about_tasks.html 余談 そもそもRun configurationでテストを実行できるようにすればいいのではないかと思うかもしれない。というか私も最初はその方法をとった。 しかしAndroid Instrumented Testに関してはできたが、Android JUnitではできなかった。 個別のテストをクラスを指定して実行する分には問題ないが(テストコードを表示して実行するやり方)、プロジェクトに存在するテストコードをまとめて実行する方法が取れなかった。Javaで書かれたテストコードは実行されても、Kotlinで書かれたテストが漏れてしまうのである(このプロジェクトはJavaで書かれたテストコードとKotlinで書かれたテストコードが混在している)。 しょうがないのでCIでも実行するgradleのテストタスクを走らせる方法をとることにしたのだ。

Android Studio2.x時代のプロジェクトを3.0環境へ更新

ストアに公開しているアプリは2018年8月までにtargetSdkVersionを26以上にする必要がある。その関係で以前にリリースしたアプリを更新しているのだが、その際に最初のハードルとなるのが古いAndroid Studioで作ったプロジェクトを現在のバージョンに更新する作業である。 最近何回も同じことをやっているので、備忘録的に書いておく。 基本的には全部Migrate to Android Plugin for Gradle 3.0.0に書いてあるので、そのとおりにやるだけである。 書いている途中でAndroid Studio 3.1が正式版になった。が、3.0から3.1への更新はそんなに大きく変更しなくても済むので、基本は3.0へのマイグレーションガイドに書いてあることに対応すればよいはず。 Gradleのバージョン更新 まず始めにGradle(Gradle wrapper)のバージョン更新を行う。Android Studio3.0は最低でもGradle4.1以上が必要。(3.1はGradle4.4以上) gradle wrapperの更新はgradle-wrapper.propertiesファイルを書き換えてgradle syncを行うだけ。 私は./gradlew wrapper --gradle-version=<Gradleのバージョン>コマンドで更新している。これで更新したらシェルスクリプトの更新もかかる場合があるので、こっちのほうがいいのかなという雰囲気で選んでいるだけだったりする。 コマンドで更新した場合、distributionUrlで指定されるgradle wrapperが4.x-bin.zipといった感じでバイナリのみのものになる。Android Studioはallにしとけと変更を促してきて、結局手書きでdistributionUrlを書き換えることになるので、普通にマイグレーションドキュメントにあるようにgradle-wrapper.propertiesを書き換えるだけでいいと思う。 ちなみに利用するgradleのバージョンだが、私の場合Twitterで見かけたGradleのリリースツイートを見て覚えてるバージョンを利用している。今だと4.6。 使えるバージョンはhttps://gradle.org/releases/で確認できる。基本的には最新使っとけばいいんじゃないだろうか。 build.gradleの更新 android gradle pluginのバージョンを更新 repositoryに`google()`を追加する(先にGradle wrapperのバージョンを上げておく必要がある) 利用しているgradle pluginのバージョン更新 プロジェクトで利用しているgradle pluginのバージョンが古い場合、原因がよくわからないエラーが多発する。例えばNo signature of method: com.android.build.gradle.internal.scope.VariantScopeImpl.getGenerateRClassTask() is applicable for argument types: () values: []とか。こういうのは利用しているgradle pluginを最新のバージョンに更新すると解消されることが多かった。 基本的にAndroid Studioが利用しているプラグインの新しいバージョンがあれば教えてくれるはず(網掛けになって新しいバージョンがあることを示唆してくれる)ので、それに従ってgradle pluginのバージョンを上げてみると解決する場合が多いだろう。 エラーメッセージで検索してもこれといった解決策が見つからないという場合には、利用しているプラグインのバージョンを上げることを試してみよう。 ライブラリプロジェクトを利用している場合 昔はライブラリプロジェクトを利用している場合、publishNonDefault trueを設定して、アプリケーションモジュールをdebugビルドするときは、ライブラリプロジェクトもdebugビルドにするなんて指定をしている人もいただろう。 この設定をしている場合、Android Studio3.xにアップデートするにあたってちょっとした手直しが必要になる。 Android Studio3.0からはライブラリモジュールのビルド設定は、利用するアプリケーションモジュールのものと同じものが利用されるようになった。appモジュールでdebugビルドを選んだら、自動的に依存しているライブラリモジュールもdebugビルドでビルドされる。 そのため以下の手直しが必要。 ライブラリモジュール publishNonDefault trueの記述を削除する。 アプリケーションモジュール 例えば以下のように記述していたとする。 debugCompile project(path: ":library", configuration: "debug") releaseCompile project(path: ":library", configuration: "release") この場合、この2行は不要になるので削除。その後あらためてimplementation project(":library")とライブラリモジュールへの依存を記述する。 buildTypeを増やしている場合 追加でbuildTypeに手を加えている場合(デフォルトのdebugとrelease以外に定義している場合)、増やしたbuildTypeの定義にmatchingFallbacksという行を追加してやる必要がある。 これはそのbuildTypeが使われるときに、それが存在しないライブラリプロジェクトなどがどのbuildTypeを使えばいいかを指定するものだ。 Android Wearアプリを利用しているプロジェクト ライブラリモジュールと同様の問題と変更が行われている。publishNonDefault trueが要らなくなって、debugWearApp ...という記述群がwearApp(":wear")の1行で済むようになった。 プロダクトフレーバーを利用している場合 新しくflavorDimensionsを最低1つは定義しないといけなくなった。 productFlavorは何らかの基準で使い分けているはずなので、その基準を定義すれば良い。例えばhttps://github.com/gen0083/FilteredHatebuこのプロジェクトは、ネットワークのレスポンスという観点からmockとprodというプロダクトフレーバーを定義している。 ネットワークの観点で切り分けているので、flavorDimensions "network"という感じで定義してやる。 後はproductFlavorの定義の部分で、どのdimensionに属する定義なのかを指定してやればいい。flavorDimensionsが1つしかないのであれば省略可能である。 私は最初勘違いしていたのだが、これは決して各フレーバーごとに異なるdimensionを割り当てなければならないということではない。このプロジェクトでは最初mockにtest、prodにdefaultというdimensionを割り当てたのだが、そうするとプロダクトフレーバーはmockProdDebugという形になってしまい、mockとprodを切り替えられなくなってしまった。切り替えて使うものについては、同じdimensionを割り当てないといけない。 apt → annotationProcessorへの置き換え これは確かmustだったような気がする。(気がするというのは、最近更新したプロジェクトの中にはaptを使っているものがなかったので) 古いプロジェクトだとgradle pluginを使ってアノテーションによるコード生成ライブラリを使っていたと思うが、その機能は公式に取り込まれているので、gradle pluginの削除とaptをannotationProcessorに置き換えてやる。
Read full post gblog_arrow_right

Android Wearアプリを開発するときはversionCodeなどを一元管理すると便利

Android Wearアプリ(WatchFaceも)をGoogle Playで公開するときにbuild.gradleの共通化をやっておいた方がいいと思います。 Android Wearアプリプロジェクトを作成すると、標準ではmobileモジュールとwearモジュールが作成され、それぞれのモジュールにbuild.gradleが作成されます。 Google Playにアプリを公開する場合、build.gradleで指定するversionCodeとversionNameはmobile,wearモジュールで共通にしなければなりません。 初回アップロード時は両方同じ値なので問題ありませんが、アプリをバージョンアップする際に2つのファイルをいじらないといけないのは面倒くさいと思います。(というか絶対に忘れる) そのためversionCodeなどは、一箇所直せばmobileとwearのどちらにも適用されるようにしてやるといいと思います。 私はmobile,wearのbuild.gradleで共通して利用する部分を、別ファイルにして読み込ませるようにしてみました。 QiitaのAndroidの署名情報(signingConfigs)を外出しようを参考にさせていただきました。 /mobile/buildConfig.gradle defaultConfig {
applicationId "jp.gcreate.product.customphotowatch" minSdkVersion 18
targetSdkVersion 21 versionCode 3 versionName "1.0.2" } /mobile/build.gradle apply plugin: "com.android.application" android { apply from: "configBuild.gradle", to: android compileSdkVersion 21 buildToolsVersion "21.1.2" } 〜dependenciesは省略 /wear/build.gradle apply plugin: "com.android.application" android { apply from: "../mobile/configBuild.gradle", to: android compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig{ minSdkVersion 20 }
} 〜dependenciesは省略 上記では省略しましたが、buildTypeも外部ファイルに出して両者で同じ設定が適用されるようにしてます。 やってて未だに不安なのが、ちゃんと正しく設定できているのか、確認の仕方がいまいち分からず不安だということでしょうか・・・。 先日のDroidKaigiで発表のあった、つかえるGradleプロジェクトの作り方のやり方も参考になります。 こちらのスライドでの方法は、versionCode等の値を/build.gradleで定義し、各々のプロジェクトその値を参照することで共通化するやり方です。 こちらのやり方のほうが分かりやすいなぁって発表聞いてて思いました。 ちなみにAndroid Studioではルートのことをプロジェクト、mobileとかwearのことをモジュールと呼びますが、Gradleの世界ではどれもプロジェクトと呼ぶそうです。勉強になりました。

Android Studioの便利なところ〜Gradleが便利〜

Android Studioは、Gradleが便利だとよく言われています。 私がAndroid Studioを使い始めた頃は「Gradle便利っていうけど、どう便利なんだろう」とさっぱり分かりませんでした。むしろGradleが何をやっているか、何者なのかさっぱり分からず、逆によく分からない存在でした。(でしたというか、現在進行形でよく分かっていませんが・・・) 実際にGradleが便利というのが実感できたのは、外部ライブラリを簡単に取り込めることが分かってからです。 外部ライブラリの取り込み Androidではアプリ開発に便利なライブラリが多数公開されています。 自分で1から作るより、すでにある便利なライブラリのお世話になった方が、アプリ開発スピードも早くなりますしクオリティも高くなります。 Android Studioではそういったライブラリを、build.gradleに1行記述するという簡単な方法で自分のプロジェクトに取り込むことができます。 デフォルトではbuild.gradleは2つあるのですが、いじるのはプロジェクト直下にあるものではなく、appディレクトリにあるbuild.gradleです。 例えばcroutonというToastをカスタマイズして使える便利ライブラリを取り込む場合は、app/build.gradleのdependanciesにcompile 'de.keyboardsurfer.android.widget:crouton:1.8.4'と記述をするだけで取り込めます。 app/build.gradle dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:19.+' compile 'de.keyboardsurfer.android.widget:crouton:1.8.4' } Sync Project with Gradle Filesを実行すると、External Librariesに目的のライブラリが取り込まれます。 あらゆるライブラリがこの方法で使えるとは限りませんが、非常に便利です。 アプリ開発の始めの頃は外部ライブラリを利用するなんて発想がなかったものですから、Gradleが便利だぞと言われてもなんのこっちゃとさっぱり理解できませんでした。しかし、実際にこうやってライブラリが簡単に取り込めるのを確認すると、「なるほど、こりゃ便利だわ」とAndroid Studioを使うのが楽しくなってきました。