'Gradle'에 해당되는 글 3건

  1. 2014.10.03 AndroidStudio Gradle + AspectJ
  2. 2013.11.08 Gradle + AndroidStudio + AndroidAnnotations with two different product flavor(diifferent packgename)
  3. 2013.10.22 Android Studio + Gradle 이용해서 apk빌드하기
2014.10.03 19:40

안드로이드 플젝을 하다가 반복되는 코드가 들어가야 할때가 있습니다.

예를들어 예외 처리시 다이얼로그를 띄워준다던가, 로그인 세션이 끊겼을때 다시 로그인을 시도하는등의 처리가 있는데, 로그인 세션이 끊겼을때의 경우, 


1. 서버로 리퀘스트 날림

2. 로그인 세션이 끊겨 리퀘스트가 실패(404 등등)

3. 예외를 잡고, 로그인을 시도

4-1. 성공시 다시 1 수행

4-2. 실패시 실패 다이얼로그 출력


이렇게 되는데 문제는 실패시 다시 해당 메소드를 호출해줘야 하는 문제가 있습니다.


그래서 처음 구현했을땐 각각의 리퀘스트를 날리는 메소드의 파라미터로 콜백을 줘서 처리를 했습니다.

그러다보니, 모든 코드들의 인덴테이션이 깊어 지는 현상을....



(fetcher는 rest call을 해주는 녀식입니다.)


여기서 먼저 rest call을 시도하는데, 실패하게 되면, callback의 failure 메소드를 호출해줍니다. 


그래서 미리 구현한 자동 로그인 처리 콜백을 대신 넣어주고, 이때 원래의 콜백을 생성자에 넣어 원래대로 성공시엔 원래의 콜백을, 그렇지 않고 실패시, 로그인을 시도하고 성공시 원래의 콜백을 다시 호출해 주는 형태입니다.


이것을 깔끔하게 할 방법이 없을까....하는 생각에 다이내믹 프록시를 써볼까도 생각해 봤지만 이왕 하는거 AspectJ를 사용해보기로 합니다. (다이내믹 프록시가 인터페이스에만 되는...? 이쪽은 좀 더 공부를 해봐야 할것 같아..)


stackoverflow에서 한참 뒤져보았지만... 제대로 되는게 없었는데,.,,,


https://github.com/uPhyca/gradle-android-aspectj-plugin


여기 간단하게 aspectj 를 사용할 수 있도록 해주는 플러그인이 이미 존재...허....바로 되네요...


자신의 프로젝트의 build.gradle을 아래와 같이 dependencies하고  configurations을 추가해줍니다.



build.gradle


repositories {

mavenCentral()

}


buildscript {

repositories {

mavenCentral()

}

dependencies {

classpath 'com.android.tools.build:gradle:0.12.2'

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.2+'

classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.+'

}

}


apply plugin: 'com.android.application'

apply plugin: 'android-aspectj'


android {

    compileSdkVersion 20

    buildToolsVersion "20.0.0"


    defaultConfig {

        applicationId "com.flask.aspectjtest"

        minSdkVersion 16

        targetSdkVersion 20

        versionCode 1

        versionName "1.0"

    }

    buildTypes {

        release {

            runProguard false

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }

    }

lintOptions {

abortOnError false

}

}


configurations {

ajc

aspects

ajInpath

}


ext.aspectjVersion = '1.8.2'


dependencies {

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

compile 'com.android.support:appcompat-v7:20.0.0'

}



굉장히 간단하게 되는지 테스트 해보기 위해, 



간단한 어노테이션을 먼저 만들고(런타임에도 유효한 메소드에 붙일 수 있는)




관점을 만들고 @Around 어노테이션으로 메소드 실행전/후에 하고싶은것을 넣어주었습니다. 




그리고 엑티비티 클래스에서 메소드에 정의한 어노테이션을 붙여줍니다.


실행을 하면 아래와 같은 결과가 나타납니다.




AspectJ 공부: http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte:fdl:aop:aspectj











저작자 표시 비영리 변경 금지
신고

'[+++ JAVA +++] > - - 작성중' 카테고리의 다른 글

AndroidStudio with Robolectric  (0) 2014.12.02
AndroidStudio Gradle + AspectJ  (0) 2014.10.03
AngularJs - 2  (0) 2014.08.05
Mocha - Javascript test framework  (0) 2014.07.23
Trackback 0 Comment 0
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 이 인자를 사용해서 고정해주게 됩니다.


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




저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 0
2013.10.22 15:54

안드로이드 스튜디오에서 프로젝트를 생성하게 되면 기본적으로 gradle이 적용된? 상태가 된다.


이때 프로젝트 구조가 기존에 알던 자바 프로젝트와 조금 다른데,


먼저 프로젝트폴더 안에 실제 어플리케이션의 root가 존재하게 되고, 프로젝트 폴더안에는 그 밖에 전체적인 셋팅을 담고 있다.

여기서 build.gradle이 여기도 존재하고, 어플리케이션폴더 안에도 존재하는데, 이는 밖에 위치한 build.gradle이 최상위란 뜻인거 같다.


우리가 작업해줘야 할것은 어플리케이션폴더 안의 build.gradle파일.


먼저 android gradle 참고할만한 문서 : http://tools.android.com/tech-docs/new-build-system/user-guide


먼저 나의 경우, Free 앱과 Paid앱을 따로 개발할 수는 없고, 단순히 앱 이름과 리소스만 변경하고자할때 이런 빌드 툴이 굉장히 편리하다. 알고 있으면.


그래서 한 일주일간 삽질 해가며 결국 이클립스를 버리고 안드로이드 스튜디오로 왔는데 옮긴 이유가 위에서도 언급했듯이 일단 프로젝트의 구조부터가 다르다. 그래서 gradle을 이용해서 뭔가 해보기가 애매했다. 그냥 옮기니 참 편하드라...?


일단 어플리케이션의 build,gradle을 보면 기본적으로 몇가지가 적혀있는데 gradle 버전 명시와 플러긴(여기서는 안드로이드) 그리고 안드로이드 버전정도가 있다.


gradle의 버전의 경우 현재 기준으론 1.8버전이 최신인데 이 버전은 0.6.+로 기재하면되고 그 이전버전의 경우 0.5정도 하면 될거 같다. 아직 완벽히 아는게 아니라서 왜 버전이 다른지는...



buildscript {

    repositories {

        mavenCentral()

    }

    dependencies {

        classpath 'com.android.tools.build:gradle:0.6.+'

    }

}



apply plugin: 'android'


repositories {

    mavenCentral()

}


// 사용할 안드로이드 sdk버전

android {

    compileSdkVersion 17

    buildToolsVersion "17.0.0"


    defaultConfig {

        minSdkVersion 9

        targetSdkVersion 17

    }




// 키스토어 설정 관련

// 내 경우 free, paid 두개를 동시에 빌드하기 위해서 서로 다른 키카 필요하다.(서로다른 키스토어가 필요하다는 뜻 아님.)

// 그리고 storeFile file() 에 키스토어의 경로를 기재해준다.

// 그리고 키 이름과 스토어 암호, 키 암호를 적어준다.

// 그런데 이렇게 하게 되면 build.gradle을 까보는것만으로도 비번을 알 수 있기에 위험한데 이걸 뭐 따로 저장한다던가 뭐 몇가지 대체하는 방법이 있었음. 여유가 생기면 찾아봐야지.

    signingConfigs {

        freeConfing {

            storeFile file(".../");

            storePassword "password"

            keyAlias "keyname_free"

            keyPassword "keypassword"

        }

        paidConfing {

            storeFile file(".../");

            storePassword "password"

            keyAlias "keyname_paid"

            keyPassword "keypassword"

        }

    }



// 이부분은 빌드를 진행할때 어떤 프로덕트를 생성할 것인지에 대한것을 기술하는거 같음.

// 보면 flavor이름이 paid, free이렇게 있다.

// 그리고 각각의 flavor에서 

// buildConfig -> BuildConfig.java에 대해서 한라인 수정 

// versionCode -> 버전 코드 - 빌드시에 AndroidMenifest.xml에 적용되서 빌드됨. 굳이 매니페스트 파일을 수정 할 필요 없음.

// versionName -> 버전 이름

// signingConfig -> 아까 위에서 정의한 사이닝컨픽. 반드시 이 위에 정의해줘야함...

    productFlavors {

        paid {

            packageName "com.example.myapp"

            buildConfig "public final static boolean isFullVersion = true;"

            versionCode 2

            versionName "1.1"

            signingConfig signingConfigs.paidConfing


        }

        free {

            packageName "com.example.myapp"

            buildConfig "public final static boolean isFullVersion = false;"

            versionCode 2

            versionName "1.1

            signingConfig signingConfigs.freeConfing

        }

    }

}


dependencies {

    compile 'com.android.support:appcompat-v7:+'

}



터미널에서   gradle을 빌드할땐 그냥 gradle build하면 빌드를 진행함.


기존의 apk등등 모두 지우고 새로 빌드할땐 gradle clean build해주면 됨.


일단 플래그 변경으로 어플리케이션 내부의 동작을 변경 할 수 있지만(이건 그냥 이클립스에서 할때도 됨.) 리소스의 경우는 조금 다르다.


먼저 src/main, src/res등의 폴더가 있는데 src폴더 하위에 free, paid폴더를 만들고 각각의 리소스를 경로에 맞게 넣어주면 빌드시에 해당 flavor을 찾아서 빌드한다.

따라서 각각 다른 리소스를 사용 할 수 있다. 



하다가 갑자기 com.example.myapp.R을 못 읽어온다고 할 수 있는데 이때는 프로젝트 설정에 들어가서 R.java가 포함된 폴더를 Source폴더로 설정해주면됨.


단점이 있다면 뭔가 용량이 늘어났다. 뭐때문인진 모르는데,,,기존 약 500kb에서 현재 1.2mb로 늘어났다.

라이브러리 포함도 안시켰는데도 이럼....ㅅㅂ


저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 0


티스토리 툴바