안드로이드 응용프로그램은 Application 객체와 안드로이드4대구성요소인 액티비티, 서비스, 브로드캐스트리시버, 콘텐트 프로바이더입니다.


Application 객체

 자바프로그램에서 실행중인 응용프로그램의 표현은 android.app.Application 객체입니다. 이 객체는 응용프로그램이 시작할 때 instance 화됩니다. 또한 중지할때는 소멸됩니다. 참고로 Application 클래스의 인스턴스는 응용프로그램의 리눅스 프로세스 수명동안 지속됩니다. 프로세스가 종료되고 재시작할때 새로운 Application 의 인스턴스가 생성됩니다.


구성요소

 정말 중요합니다. 안드로이드응용프로그램의 기본조각은 RunTime에 의해 관리되는 구성요소(액티비티, 서비스, 브로드캐스트리시버, 콘텐트 프로바이더)가 있습니다. 이들 구성요소는 서로 다른 책임과 LifeCycle(생명주기)를 갖습니다. 

 모두 응용프로그램을 시작할 수 있는 진입점이됩니다. 구성요소가 시작되면 응용프로그램의 LifeCycle를 통해 다른 구성요소들을 시작시킬 수도 있습니다. 구성요소는 응용프로그램 내에서 또는 응용프로그램 간에 intent를 사용하여 다른 구성요소를 시작시킬 수 있습니다. 

 인텐트는 동작하는 수신자의 동작을 지정하기도하며(사진찍기와 이메일전송, 문자전송도 가능합니다.), 송신자에게 수신자로 데이터를 제공할 수 있기도합니다. 인텐트는 명시적 인텐트와 임시적 인텐트가있습니다.


명시적 인텐트

컴파일 시 응용프로그램에서 알 수 있는 4대구성요소의 이름을 분명하게 나타내는 인텐트입니다.


암시적인텐트

 IntentFilter 블록안에 여러개의 특성으로 정의한 구성요소에 런타임(실시간) Binding 합니다. 만약 해당 Intent가 어느 구성요소의 IntentFilter 특성과 일치하게된다면 그 구성요소가 시작되게 됩니다.


안드로이드 응용프로그램은 SubClass를 이용하여 구성요소를 구성하고, 응용프로그램의 모든 구성요소는 AndroidManifest.xml 파일에 등록되어야 합니다.



Activity 액티비티

 언제가 디바이스의 스크린을 차지하여 사용자에게 보인을 화면을 말합니다. 정보를 표시하거나 사용자의 입력받는부분을 담당합니다. UI구성요소를 포함하며, 모든 뷰계층구조에 대한 객체 참조를 담고있습니다. 사용자가 화면 사이를 옮겨 다닐 때 액티비티 인스턴스는 스택을 형성하게 됩니다.



Service 서비스

서비스는 사용자의 직접 상호작용은 없고, BackGround에서 눈에 띄지않게 뒷단에서 실행할 수 있습니다. 일반적으로 동작이 자신의 수명보다 오래 살 수 있을때 다른 구성요소에 실행을 떠넘기기 위해 사용되는 편입니다. 서비스는 started 또는 bound 모드로 실행될 수 있습니다. 2가지 실행방법이 있습니다.


시작서비스(started service)

 명시적 또는 암묵적 인텐트로, Context.startService(intent)가 호출될 때 시작됩니다. 그리고 Context.stopService(Intent)가 호출될때 종료됩니다.


바운드 서비스(bound service)

 명시적 혹은, 암묵적 인텐트 매개변수와 함께 Context.bindService(Intent, ServiceConnection, int)를 호출하여 여러 구성요소를 서비스에 바인딩할 수 있게됩니다. 바인딩 후, 구성요소는 ServiceConntection 인터페이스를 통하여, 그 Service와 Interaction 할 수 있고, Context.unbindService(ServiceConnection)을 통해 그 서비스로부터 바인딩을 해제할 수 있게됩니다. 마지막 구성요소가 서비스로부터 바인딩 해제되면 서비스는 소멸되게 됩니다.



Content provider 콘텐트 프로바이더

 안드로이드 응용프로그램 내부 혹은 응용프로그램 사이에서 상당한 양의 Data를 공유하려는 응용프로그램은 Content 프로바이더를 활용할 수 있습니다.


 콘텐트 프로바이더는 어떤 데이터 소스에도 접근을 제공하지만, 응용프로그램 안에서 사용하는 SQLite DB를 다른 응용프로그램과 공유할때 주로 사용됩니다. 이런 콘텐트 프로바이더의 도움으로 안드로이드 응용프로그램은 원격 프로세스에서 실행되는 응용프로그램에 Data를 공개할 수 있게 됩니다.



BroadCast receiver 브로드 캐스트 리시버

 BroadCast receiver는 응용프로그램 내, 원격 응용프로그램, 또는 Platform으로부터 보내진 Intent를 듣는 매우 제한된 기능을 가지고 있습니다. 

어떤 Intent가 BraodCastReceiver로 보내진 것인지 가리기 위해 수신되는 intent Filteriing을 합니다. 인텐트 수신을 시작하려면, 브로드캐스트 리시버를 동적으로 동록해야합니다. 

수신을 종료하려면 등록을 해제해야 합니다. 만약 AndroidManifest.xml에 정적으로 등록되어있다면, 응용프로그램이 설치되어있는 동안 계속해서 Intent를 수신할 수 있게 됩니다. 따라서 어떤 Intent가 필터에 일치할 때 브로드캐스트 리시버는 연결된 응용프로그램을 시작할 수 있게 됩니다.


포스팅에 앞서

안드로이드 스레드를 알기에 앞서 플랫폼, Applicatioin 아키텍처, 응용프로그램의 실행먼저 알아보겠습니다.

 

안드로이드 SoftWare Stack

 안드로이드의 응용프로그램은 리눅스 커널, native C++ 라이브러리, 응용프로그램 코드를 실행하는 run time을 기반으로 소프트웨어 스택 위에서 동작하게 됩니다.

 

4층 응용프로그램 계층이 있습니다.

3층 애플리케이션프레임워크, 코어자바가 있습니다.

2층 네이티브 라이브러리, 런타임이 있습니다.

1층 리눅스 커널이있습니다.

 

응용프로그램 == 어플리케이션 = 앱 = Application

자바언어로 구현된 안드로이드 응용프로그램을 지칭합니다. 안드로이드 응용프로그램은 자바와 Android Framework 라이브러리를 사용합니다. 우리가 흔히아는 안드로이드 앱을 일컷는 용어라 할 수 있습니다.

 

Core JAVA

 안드로이드 응용프로그램과 안드로이드 프레임워크에서 사용된 Core java 입니다. 코어자바는 완벽한 JAVA SE나 ME구현을 따르지 않고, JAVA 5기반의 중단되버린 Apache의 부분집합 혹은 집합입니다. 코어자바는 기초 자바 스레딩 메커니즘인 java.lang.Thread클래스와 java.util.concurrnet Package를 제공중입니다.

 

Application Framework

Window system, UI ToolKit, 리소스(자원) 등 기본적으로 자바에서 안드로이드 애플리케이션(응용프로그램)을 작성하기 위해 요구되는 모든것을 다루는 Android Class의 집합이라 생각하시면 되겠습니다. 프레임워크는 안드로이드 구성요소의 생명주기, LifeCycle간의 상호통신을 정의하고 관장, 관리하며 애플리케이션이 스레드 관리를 단순화하기 위해 활용되는 안드로이드 비동기 메커니즘 스레드를 제공합니다. HandlerThread, AsyncTask, IntentService, AsyncQueryHandler, Loaders가 있습니다.

 

 

Native Library

그래픽, 미디어, 데이터베이스, 폰트, OpenGL등 빠른 속도가 요구되므로, C/C++로 구현된 라이브러리입니다. 안드로이드 프레임워크 Native Code를 위한 자바래퍼를 제공하기 때문에 자바응용프로그램은 기본적으로 네티이브 라이브리와 직접 상호작용을 하지 않습니다. 보통 프레임워크를 거쳐서 사용하게 되는 구조입니다.

 

Run time

 내부바이트 코드표현으로, 가상 머신환경에서 컴파일된 안드로이드 애플리케이션(응용프로그램) 코드를 실행하는 Sand Box 화된 런타임 환경입니다. 모든 응용프로그램은 자신만의 달빅또는 아트 런타임에서 동작합니다. 아트는 킷캣, API 19단계 이상 부터 사용자가 활성화할수있는 선택적 런타임이며, 지금은 달빅이 기본 런타임입니다.

 

Linux Kernal

 많은분들이 아는 리눅스의 커널부분을 지칭합니다. 리눅스 디바이스드라이버가 관장하는 하드웨어기능을 사용하기 위한 하부 운영체제입니다. 덕분에 응용프로그램에서 소리, 네트워크, 카메라 등 기기의 HW를 사용할 수 있게됩니다. 모든 응용프로그램은 자신고유의 프로세스를 시작하고, 모든 프로세스는 실행되는 응용프로그램과 함께 RUN Time을 가집니다. 프로세스 내의 여러스레드가 응용프로그램 코드를 실행할수 있게 됩니다. 커널은 스케줄링을 통해 프로세스와 스레드가 사용하는 CPU실행시간을 나눕니다. 리눅스를 배워보셨다면 무슨말인지 이해하기가 더 수월하실 겁니다.

 

 

스팅 시작하기 앞서

 Gradle을 도입한 목표중 하나는 단일 소스 코드로 목적에 맞는 다양한 APK 생성입니다. 모듈 내부에서 디버그, 릴리즈와 같은 빌드 타입별로 세부사항을 변경하거나, lite, full 버전 과 같이 기능 일부를 비활성화 할 수 있습니다.(feature 변경) 

 빌드 변형은 빌드타입과 제품특성을 합한 개념입니다. 어떤 모듈에 3가지 빌드타입과 4가지 제품 특성이 존재한다면 빌드 변형은 3*4=12가지 경우입니다. 이번 포스팅에서 빌드타입에 대해 살펴보도록 하겠습니다.


빌드타입

build type 에는 debug와 release가 존재합니다. 디버깅이 포함된 apk이냐 마켓에 배포할 apk냐에 따라 구분되어집니다. 

debug build는 default대로 진행하면 되고, release 빌드때는 pro guard 를 비활성화 하였습니다.

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

다음과 같이  minifyEnabled true로 하면 프로가드가 활성화됩니다. 소스코드난독화하여 역컴파일을 방지하게 됩니다.

프로젝트 폴더에들어가서 gradlew :app:assemble 명령을 치면 빌드가 완료되고나서 debug, release apk 가 생성됨을 확인하실 수 있습니다.

또한, 그렇게 하기 귀찮으시면 gradle 콘솔(안드로이드 프로젝트)을 열어서 assemble 태스크를 실행하시면 되겠습니다. app모듈에 build 그룹에 있습니다.


다음과 같이 assemble task를 실행시키고나면, debug용도와 release용도의 apk가 생성됨을 확인하실 수 있습니다.




앱 서명 첨부하기

release 용을 빌드할떄는 앱서명(siging)에 관한정보를 직접 지정하여 등록하셔야 합니다. signing을 할때 module build.gradle을 수정하는데, android 블록아래에 signingConfigs를 입력합니다. 물론 siginingConfigs는 buildTypes 블록보다 먼저 정의되어야 합니다.


signingConfigs{
release{
storeFile file('app.keysave')
storePassword 'keypass'
keyAlias 'key'
keyPassword 'mypassword'
}
}


buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

그런데 문제는, 앱서명에 관한정보를 직접 썼다는게 보안상의 문제로 될수있습니다. 그러므로 담당자 서버의 환경변수에 별도로 지정하는게 좋겠습니다.

signingConfigs{
release{
storeFile file('app.keysave')
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
}

그리고 환경변수를 윈도우에서 설정해줍시다. 예로들어 KEYSTORE_PASSWORD라는 환경변수를 읽어오기 위해서는 ORG_GRADLE_PROJECT_KEYSTORE_PASSWORD 라고 환경변수 이름을 짓고, 변수값을 넣어서 생성하면 gradle에서 환경변수로 값을 얻어오실 수 있습니다.


제품 특성

빌드타입이 빌드의 속성을 변경하는것이라고 앞서 설명드렸습니다. 제품 특성은 리소스 교체 혹은 특정 feature를 활성화 또는 비활성화 시킬 수 있습니다. module build.gradle에 기술하시면 되겠습니다.



제품 특성 생성 해보기

제품 특성 생성하려면 android 블록에 productFlavor 블록을 추가합니다. lite와 full이라는 제품 특성 추가해보겠습니다.


productFlavors{
lite{
applicationId 'com.lite.HelloWorld'
}
full
}

.



제품 특성 확인


추가된 제품 특성을 확인하려면 Android Studio IDE 좌측 하단에 세로방향으로 위치한 Build Variants 창을 활용합니다. app모듈에 build Varient를 선택해보시면, full,lite 조합 release, debug로 나오는것은 확인하실수있습니다. 2*2 =4가지경우가있네요. 원하시는 값을 선택후 build apk를 하였더니 아래그림처럼, app-gull-release apk가 생성됨을 확인할 수 있었습니다.





제품 특성 활용

제품특성을 간단히 적용하려면 AndroidManifest.xml 을 변경한후 재빌드 하면 되긴합니다. 엄청 번거롭죠. 그러나 제품특성을 활용하면 더욱 쉽고 간편하게 적용시킬 수 있습니다. 예를든다면 lite 버전의 로고와 app label을 변경합니다.  app 모듈의 src폴더 아래 lite 폴더를 만들고 AndroidManifest.xml 파일을 추가합니다. Project View로 진행하시면 됩니다.



프로젝트뷰로 다음과 같이 lite폴더에 AndroidManifest.xml 파일을 추가하였습니다.

그리고 Android 뷰로 돌아오면 lite버전의 AndroidManifest.xml 파일이 추가된것을 확인하실 수 있습니다. 추가된 파일에는 (lite)라고 추가됨을 확인하실 수 있습니다. 

제품특성은 module build.gradle의 android.defaultConfig블록의 속성값을 공유하게 됩니다. defaultConfig블록은 간단히 요약하면 AndroidManifest.xml 의 내용 중 gradle로 재정의할 수 있는 속성들입니다. 또한 제품특성은 소스 코드를 재정의할 수 있습니다. 변경량은 최소화 하는게 좋습니다.




제품 특성으로 특정기능 활성화 (Feature On)

 제품특성을 활용하면 전체 app,의 기능 중 일부를 활성화 또는 비활성화 할 수 있습니다. 예를들어 full 제품 특성에서는 현재 시간 표시 기능을 활설화 하고 demo제품 특성에서는 현재시간을 보여주지 않게 합니다. 모듈 build.gradle에서 BuildConfig변수를 활용하면 됩니다.


productFlavors{

   full{

  buildConfigField "boolean", "SHOW_CURRENT_TIME", "true"

  }

   lite{

   buildConfigField "boolean", "SHOW_CURRENT_TIME", "false"

  }

}


SHOW_CURRENT_TIME이라는 boolean 변수를 추가했습니다. 내용을 입력하고 SYNC NOW버튼을 누르면 변수가 자동으로 생성되어 소스코드에서 참조할 수 있습니다.


 if(BuildConfig.SHOW_CURRENT_TIME){

  

}


실제확인하려면 app/build/generated/source/buildConfig/lite/debug/com/프로젝트 폴더에 BuildConfig클래스를 열어봅니다. applicationid등 빌드스크립트가 생성한 다양한 변수가 있는것을 확인하실 수 있습니다.


+ Recent posts