LoginSignup
188
191

More than 5 years have passed since last update.

Androidでaptのライブラリを作るときの高速道路

Last updated at Posted at 2015-07-07

はじめに


Androidapt使aptAndroidapt

aptAnnotation Processing Tool


Jake WhartonDroidconAnnotation Processing Boilerplate DestructionJavaAST

apt使apt

apt使


apt使 Dagger  ButterKnife maven使Androidgradle使gradle


emilsjolander/IntentBuilder

jd-alexander/flender

airbnb/DeepLinkDispatch

Raizlabs/DBFlow

apt使


apt使2
コンパイル時 アプリから参照
IntentBuilder compier api
flender plugin runtime
DeepLinkDispatch processor -
DBFlow compiler -

- はプロジェクト名がそのままモジュール名になっているという意味で、DeepLinkDispatchであれば

apt 'com.airbnb:deeplinkdispatch-processor:x.y.z'
compile 'com.airbnb:deeplinkdispatch:x.y.z'

このようになります。好みの問題ではありますが、私はこの ライブラリ名ライブラリ名 + processor のペアが一番自然かなと思います。

プロジェクトを始めるときは、まずAndroidアプリケーションを選んで、作られたappモジュールをリネームして動作確認用のサンプルアプリにして、aptを行うためのJavaライブラリと、アプリから使うためのAndroidライブラリの合計3つのモジュールを作ります。

// settings.gradle
include ':sample' // サンプルのAndroidアプリ
include ':processor' // aptのJavaライブラリ
include ':library' // Androidライブラリ

Processorを定義する

javacがフックできるようにProcessorのエントリポイントを定義します。main/resources/META-INF/services に自分で定義する方法と、AutoService というライブラリを使って自動生成する方法があります。私はAutoServiceを使っていますが、大した作業ではないのでどちらでもいいと思います。
ちなみにAutoService自体もaptでマニフェストを生成しています。このようにaptはJava以外のファイルを生成することもできます。

Processorの定義はこのようにします。

@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
    ...

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        ...
    }
}

processRoundEnvironment

Java


Javasquare/javapoet 使
MethodSpec main = MethodSpec.methodBuilder("main")
    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
    .returns(void.class)
    .addParameter(String[].class, "args")
    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
    .build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
    .addMethod(main)
    .build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
    .build();

javaFile.writeTo(System.out);

基本的にはこれだけです。

gradleの小ネタ

Bintrayへのアップロード

BintrayへライブラリをアップロードするときにBintrayの公式のライブラリである bintray/gradle-bintray-plugin を使うと以下のようにする必要があります(READMEより)。

bintray {
    user = 'bintray_user'
    key = 'bintray_api_key'

    configurations = ['deployables'] //When uploading configuration files
    // - OR -
    publications = ['mavenStuff'] //When uploading Maven-based publication files
    // - AND/OR -
    filesSpec { //When uploading any arbitrary files ('filesSpec' is a standard Gradle CopySpec)
        from 'arbitrary-files'
        into 'standalone_files/level1'
        rename '(.+)\\.(.+)', '$1-suffix.$2'
    }
    dryRun = false //Whether to run this as dry-run, without deploying
    publish = true //If version should be auto published after an upload
    //Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
    pkg {
        repo = 'myrepo'
        name = 'mypkg'
        userOrg = 'myorg' //An optional organization name when the repo belongs to one of the user's orgs
        desc = 'what a fantastic package indeed!'
        websiteUrl = 'https://github.com/bintray/gradle-bintray-plugin'
        issueTrackerUrl = 'https://github.com/bintray/gradle-bintray-plugin/issues'
        vcsUrl = 'https://github.com/bintray/gradle-bintray-plugin.git'
        licenses = ['Apache-2.0']
        labels = ['gear', 'gore', 'gorilla']
        publicDownloadNumbers = true
        attributes= ['a': ['ay1', 'ay2'], 'b': ['bee'], c: 'cee'] //Optional package-level attributes
        //Optional version descriptor
        version {
            name = '1.3-Final' //Bintray logical version name
            desc = //Optional - Version-specific description'
            released  = //Optional - Date of the version release. 2 possible values: date in the format of 'yyyy-MM-dd'T'HH:mm:ss.SSSZZ' OR a java.util.Date instance
            vcsTag = '1.3.0'
            attributes = ['gradle-plugin': 'com.use.less:com.use.less.gradle:gradle-useless-plugin'] //Optional version-level attributes
            //Optional configuration for GPG signing
            gpg {
                sign = true //Determines whether to GPG sign the files. The default is false
                passphrase = 'passphrase' //Optional. The passphrase for GPG signing'
            }
            //Optional configuration for Maven Central sync of the version
            mavenCentralSync {
                sync = true //Optional (true by default). Determines whether to sync the version to Maven Central.
                user = 'userToken' //OSS user token
                password = 'paasword' //OSS user password
                close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
            }            
        }
    }
}

このような感じで長くなってしまいます。そこで私は最近 novoda/bintray-release に乗り換えました(READMEより)。

publish {
    userOrg = 'novoda'
    groupId = 'com.novoda'
    artifactId = 'bintray-release'
    publishVersion = '0.3.0'
    desc = 'Oh hi, this is a nice description for a project, right?'
    website = 'https://github.com/novoda/bintray-release'
}

bintray-release


IntentBuilder使


version.properties 
#Sun, 28 Jun 2015 19:01:31 -0700
major=0
minor=13
patch=0

ビルドファイルに以下のように書いておくと VERSION で参照することができて良さそうでした。

ext {
    VERSION = version()
}

task version << {
    println version()
}

def String version() {
    def versionPropsFile = file('version.properties')
    def Properties versionProps = new Properties()
    versionProps.load(new FileInputStream(versionPropsFile))

    return versionProps['major'] + "." + versionProps['minor'] + "." + versionProps['patch']
}

バージョンアップ

./gradlew bumpMajor
./gradlew bumpMinor
./gradlew bumpPatch

上のタスクを実行することでそれぞれ version.properties の数値をインクリメントしてくれます。bumpMajorbumpMinor は自分より小さい桁の数字をゼロに戻すので、たとえば 0.1.5 の状態で bumpMajor を実行すると 1.0.0 になります。

READMEの更新

ライブラリを使う人がコピペして使えるようにUsageに以下のように書くことがあると思います。

dependencies {
    compile 'se.emilsjolander:intentbuilder-api:0.13.0'
    apt 'se.emilsjolander:intentbuilder-compiler:0.13.0'
}

 x.y.z  latest-version 使調
IntentBuilder README.md.template  ./gradlew genReadMe bumpVersion => genReadMe => upload 使


Androidjar

: rejasupotaro/kvs-schema
SharedPreferencesSharedPreferences使

aptJavaWriter使processorcompiler
188
191
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

188
191