'androidannotations'에 해당되는 글 1건

  1. 2013.11.08 Gradle + AndroidStudio + AndroidAnnotations with two different product flavor(diifferent packgename)
2013.11.08 20:12

Gradle + AndroidStudio + AndroidAnnotations with two different product flavor(diifferent packgename)


안드로이드에서 제일 짜증나고 불편하고 반복적인 작업이 바로 R 클래스, 그러니까 리소스 사용에 관련된 모든것을 R.java 에 접근해서 사용하는 것입니다.


이때 이것을 자동화? 또는 좀더 가독성이 좋고 유지보수하기 좋게 해주는것이 바로 AndroidAnnotations, Roboguice 등이 있습니다. 물론 저런 뷰 Injection 말고도 다른 기능들 rest, async, event처리등 굉장히 많은 편리한 기능들을 내포하고 있습니다.


http://androidannotations.org/

https://github.com/excilys/androidannotations

https://code.google.com/p/androidannotations/wiki/FAQ

https://github.com/excilys/androidannotations/issues/690

https://github.com/excilys/androidannotations/issues/517

https://github.com/excilys/androidannotations/issues/676

http://stackoverflow.com/questions/17910603/android-studio-gradle-android-annotations/17999249#17999249

어노테이션 프로세서관련 stackoverflow 답변

http://stackoverflow.com/questions/19351168/gradle-annotations-flavors-wont-run-annotations-processor

메이븐 셋팅

https://github.com/excilys/androidannotations/wiki/Maven


이번에는 AndroidStudio에서 gradle로 빌드할때 아래와 같은 조건일때 빌드하는 방법을 포스팅 하려고 합니다. 한 4일? 간 삽질해서 알아낸...멍청하네요.ㅋㅋ


1. AndroidAnnotations 를 사용한다.

2. Gradle 빌드에서 두가지 서로다른 product flavor가 존재한다.

3. 각 product flavor에는 pckage name이 조금씩 다르다.

(ex, free버전에는 패키지네임 뒷부분에 **.**.**.free가 붙는다)


먼저 AndroidAnnotations는 컴파일 시간에 미리 관련 뷰들을 바인딩 해줘서 런타임에서 속도 저하 없이 사용할 수 있고, Roboguice는 런타임에? 하는걸로 알고 있습니다. (이 부분에 대해서 자세히 아시는 분은 지적해 주시면 감사하겠습니다.)


따라서 컴파일 타임에 뭔가를 하는데 이름에서도 나타내듯이 어노테이션을 사용하게 됩니다.

즉, @~~~~~뭐 이런것을 사용한단 말이죠. JUnit 에서 @Test 처럼 미리 정의된 어노테이션을 가지고 뷰를 바인딩 하게 됩니다. 

그리고 컴파일시에 자바의 어노테이션 프리프로세서를 통해서 어노테이션을 사용한 클래스를 상속받아 새로 클래스를 만들게 되고 여기서 바인딩이 이뤄지게 됩니다.


첫번째 문제는 새로 클래스(엑티비티)를 생성하기 때문에 기존의 이름을 사용할 수 없습니다. 따라서 AndroidAnnotations에서는 이름 뒤에 언더스코어, '_' 이것을 붙여서 구분하게 됩니다.

즉, AndroidManifest.xml 에서 엑티비티를 정의할때 '_' 를 추가해야합니다.

Intent를 사용할때도 위와 같습니다.


두번째 문제는, 이 바인딩이 이뤄질때 onCreate에서 바로 뷰들을 사용할 수 없습니다. 이때 사용하게되면 바인딩이 아직 이뤄지지 않았기 때문에 NullPointerException 이 나게 됩니다.

따라서 바인딩이 다 된 시점에야 뷰들을 초기화 하고 사용할 수 있는데 이것을 콜백으로 받아오는 어노테이션이 바로 @AfterViews 입니다. 즉 이 어노테이션이 붙은 매소드에서 바인딩이 다 된후에 호출하게 되고 뷰에 대해서 접근할 수 있습니다. 따라서 onCreate 매서드에는 거의 바디가 조촐합니다.


첫번째 링크에서 보다시피 굉장히 매소드들, 필드들이 굉장히 가독성이 좋게 되고 유지보수 펴하게 되어있으며 코드 또한 간결하게 됩니다. 이렇게 뷰에 대한 반복적인 작업만 없앴는데도 상당히 편해졌다는것을 알 수 있습니다.


이정도만 AndroidAnnotations 설명을 마치고 이제 본격적인 Gradle 과의 연동?에 대한 내용입니다.


먼저 메이븐으로 의존성 관리를 하고 있으면 좋습니다. 따라서 AndroidStudio에서 의존성을 추가해주는데 이때 중요한것이 최신버전이 아닌 스냅샷 버전을 사용할것입니다.

현재 최신버전이 2.7.1 인거 같은데 최신버전에 없는 컴파일 인자를 사용하기에 3.0 SNAPSHOT을 사용하도록 합니다. (여기서 굉장히 삽질한것이, build.gradle에 정의한 AA버전과 메이븐의 AA버전이 안맞아서....이틀간....-_-)


그런뒤 build.gradle에 아래와같이 추가해줍니다.


ext.daggerVersion = '1.0.0';

androidAnnotationsVersion = '3.0-SNAPSHOT';

repositories {

mavenCentral()

maven {

url 'https://oss.sonatype.org/content/repositories/snapshots/'

}

}

android {

productFlavors {

paid {

packageName "com.my.app"

}

free {

packageName "com.my.app.free"

}

}

}

android.applicationVariants.all { variant ->

aptOutput = file("${project.buildDir}/source/apt_generated/${variant.dirName}")

println "****************************"

println "variant: ${variant.name}"

println "manifest:  ${variant.processResources.manifestFile}"

println "aptOutput:  ${aptOutput}"

println "****************************"


variant.javaCompile.source = variant.javaCompile.source.filter { p ->

return !p.getPath().startsWith(aptOutput.getPath())

}


variant.javaCompile.doFirst {

println "*** compile doFirst ${variant.name}"

aptOutput.mkdirs()


variant.javaCompile.options.compilerArgs += [

'-classpath', configurations.compile.asPath,

'-processorpath', configurations.apt.getAsPath(),

'-AandroidManifestFile=' + variant.processResources.manifestFile,

'-AresourcePackageName=com.my.app',

'-s', aptOutput

]

}

}

configurations {

apt

}

dependencies {

compile "com.android.support:support-v13:13.0.0"


apt "org.androidannotations:androidannotations:${androidAnnotationsVersion}"

compile "org.androidannotations:androidannotations-api:${androidAnnotationsVersion}"


apt "com.squareup.dagger:dagger-compiler:${daggerVersion}"

compile "com.squareup.dagger:dagger:${daggerVersion}"

}

* androidannotations.jar 은 딱 컴파일 할때 필요한, 즉 어노테이션 프로세서가 있는 jar이고,
실제 우리가 써야 하는건  androidannotations-api 인듯. 이틀간 이거때문에 삽질 함


여기서 스냅샷을 사용하는 이유가 바로 free버전의 패키지 네임이 다르기 때문입니다.

만악 스냅샷이 아닌 최신버전을 사용하게 되면(물론 나중의 최신버전엔 기 인자가 포함될 수 있겠죠), 


*** compile doFirst FreeDebug

Note: Starting AndroidAnnotations annotation processing

Note: AndroidManifest.xml file found: */build/manifests/free/debug/AndroidManifest.xml

warning: The AndroidManifest.xml file was found, but not the compiled R class: com.my.app.free.R

/SettingViewPagerActivity.java:30: error: Resource id value not found in R.id: 2131165208

@ViewById(R.id.pager)

^

Note: Number of files generated by AndroidAnnotations: 1

Note: Generating source file: com.my.app.activity.SettingViewPagerActivity_

Note: Time measurements: [Whole Processing = 135 ms], [Process Annotations = 63 ms], [Validate Annotations = 31 ms], [Extract Annotations = 13 ms], [Generate Sources = 12 ms], [Find R Classes = 9 ms], [Extract Manifest = 5 ms],

Note: Time measurements: [Whole Processing = 0 ms],

warning: The following options were not recognized by any processor: '[androidManifestFile, resourcePackageName]'

1 error

1 warning

:MyApp:compileFreeDebug FAILED


처럼 실패하게 됩니다. 이유는 R.class를 찾아야 하는데 못찾아서 해당 리소스를 가져오지 못해 에러가 납니다.

그러면 어떻게 R.class를 찾아야 하나...? 보면 R을 com.my.app.free.R 인줄 알기 때문입니다.

즉 product flavor에서 package name을 정의한대로 찾아가기 때문입니다.

그래서 -AresourcePackageName=com.my.app 이 인자를 사용해서 고정해주게 됩니다.


이 인자가 얼른 최신버전에 반영이 되기를 바랍니다.




저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0


티스토리 툴바