Android Things SDK 개요


이 글은 Android things의 공식 홈페이지에 있는 Overview를 번역한 것이다. 크게 보자면 Android Things가
embedded 기기에 대한 core Android의 확장이며 그에 따른 Android Things의 이점과 제약을 설명하고 있다.


개인적으로는 다른 어떤 이점보다도 단일 app 기반이라는 점과 UI의 부재라는 제약이 더 크게 보인다.
사실 라즈베리파이는 아두이노나 다른 embedded 기기에 비한다면 상당히 고사양의 기기이다. multi tasking이
가능한 CPU와 HDMI라는 고사양의 display 인터페이스를 가지고 있음에도 불구하고 그 것을 활용하지 못한다는
것은 하드웨어 리소스의 낭비로 보여진다. 


이런 측면으로 보자면 아두이노를 지원해야 할 것 같지만 그 또한 여의치 않은 것이 아두이노같은 저수준의 디바이스는
작은 크기의 소프트웨어와 빠른 속도, 저사양의 기기이므로 메모리 관리가 효율적으로 이루어져야 한다는 점에서 
VM 기반의 Android 플랫폼이 썩 어울려 보이지는 않는다.


이렇게 쓰고보니 Android Things가 마치 쓸모없는 것 처럼 표현이 되었는데…아직 개발자 프리뷰이니 조금 더
지켜보아야 할 것 같다.



Android Things는 동일한 Android 개발 툴, 동급 최고의 Android 프레임워크, 모바일에서 개발자들의 성공을 
보장하는 Google API를 제공함으로써 embedded 기기와 관련된 개발을 쉽게 할 수 있도록 한다.



embedded 기기를 위한 app들은 개발자로 하여금 폰이나 태블릿보다 하드웨어 주변 장치나 드라이버에 더 익숙하게
한다. 또한 일반적으로 embedded 기기는 사용자들에게 단일 app 환경을 제공한다. 이 문서는 core Android 
개발과 Android Things 사이에 추가된 것, 빠진 것 등 중요한 차이점을 설명한다.


Android Things는 Things Support Library를 통해 추가적인 API를 제공하는 Core Android 프레임워크의
확장이다. 이런 추가된 API들은 기존의 모바일 기기에서는 찾아볼 수 없었던 새로운 유형의 하드웨어를 통합시킬 수 
있는 app을 개발할 수 있도록 해준다.


또한 Android Things 플랫폼은 단일 애플리케이션 사용을 위해 간소화 되어있다. 시스템 app이 존재하지 않고
기기의 시작과 동시에 개발자가 개발한 app이 자동으로 실행됨으로써 사용자가 app 환경에 집중할 수 있도록 해준다.


Things Support Library


주변장치 I/O API

주변장치(Peripheral) I/O APIs는 개발한 app이 산업 표준의 프로토콜과 인터페이스를 통해 센서들이나 액츄에이터
들과 통신할 수 있도록 해준다. 다음의 인터페이스들을 지원한다 : GPIO, PWM, I2C, SPI, UART.

APIs의 사용 방법에 대한 추가적인 정보는 다음 링크에서 확인하라. Peripheral I/O API Guides


User Driver API

사용자 Drivers는 기존 Android 프레임워크 서비스를 확장하고 다른 app들이 표준 Android APIs를 통해 접근
가능한 프레임워크에 하드웨어 이벤트를 주입할 수 있도록 해준다.

APIs의 사용 방법에 대한 추가적인 정보는 다음 링크에서 확인하라. User Driver API Guides


동작의 변화


Core application packages


Android Things 는 시스템 apps와 content providers등 표준 API 모음은 포함하지 않는다. 앱을 개발할 때
common intents와 아래 목록의 content provider APIs는 사용을 하면 안된다.

  • CalendarContract
  • ContactsContract
  • DocumentsContract
  • DownloadManager
  • MediaStore
  • Settings
  • Telephony
  • UserDictionary
  • VoicemailContract


화면 출력은 선택 사항

Android Things는 전통적인 Android 애플리케이션과 마찬가지로 UI toolkit을 이용하여 그래픽 사용자 
인터페이스를 제공할 수 있다. 그래픽 모드에서는 애플리케이션의 Window가 전체 화면을 모두 차지하게 된다.
Android Things는 시각적인 사용자 환경을 완벽하게 제어할 수 있는 시스템 상태바라든지 네비게이션 버튼이
포함되어있지 않다. 


따라서 Android Things는 디스플레이가 필요하지 않다. 그래픽 디스플레이가 제공되지 않는 기기상에서도
여전히 Activity들은 Android Things app의 중요한 컴포넌트이다. 그렇기 때문에 프레임워크는 모든 입력 
이벤트를 포커스가 주어진 foreground Activity로 전달한다. 이렇게 개발된 앱은 service와 같은 다른 애플리케이션 
컴포넌트로부터 키 이벤트나 모션 이벤트 등을 수신받지 못한다.


Home activity 지원

Android Things는 부팅 시 자동으로 실행될 수 있도록 애플리케이션의 manifest에 주요 진입점으로 home
activity
를 노출하도록 하고 있다. 이 activity는 CATEGORY_DEFAULT와 IOT_LAUNCHER 두 개의 intent
filter를 반드시 포함시켜야 한다.


개발의 편의를 위해 이 activity는 CATEGORY_LAUNCHER 또한 포함시켜야 하므로 Android Studio를 통한
배포 또는 디버깅시에 이 activity를 기본 activity로 실행시킬 수 있다.

<application
    android:label="@string/app_name">
    <activity android:name=".HomeActivity">
        <!-- Launch activity as default from Android Studio -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>

        <!-- Launch activity automatically on boot -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.IOT_LAUNCHER"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
</application>


Google service들의 지원

Android Things는 Google APIs for Android의 일부를 지원한다. 아래의 목록은 Android Things에서의 
API 지원 여부를 보여준다.


Supported APIs


Unavailable APIs

주의 : 일반적으로 사용자의 입력이나 인증 절차가 필요한 APIs는 app에서 사용할 수가 없다.


Android Things의 각 배포버전은 Google Play Services의 최신 안정화 버전을 번들로 제공하며 적어도 
클라이언트 SDK 10.0.0 이상의 버전이 필요하다. Android Things는 기기의 Play 서비스를 자동으로 업데이트
해주는 Google Play Store를 포함하고 있지 않다. 기기의 Play 서비스 버전은 정적으로 고정되어있기 때문에
app은 대상 배포판에 번들로 제공되는 것 보다 큰 버전의 클라이언트 SDK를 대상으로 할 수 없다.


주의 : 개발자 프리뷰 상태인 동안 각 배포판의 번들 버전은 release notes에 그 목록이 표시되어 있다.


Permissions

embedded 기기에서는 app 실행 시에 대화상자에 접근할 수 있는 UI를 제공하지 않기 때문에 app 실행 시의 권한 
요청
은 지원되지 않는다. 필요하다면 app의 manifest 파일에 권한을 선언해야 한다. app의 manifest에 선언된 
정상적이고 워험한 권한들은 설치 시에 부여된다.


Notifications

Android Things에는 시스템 전반적으로 상태표시줄이나 창이 없으므로 notification은 지원되지 않는다.
따라서 NotificationManager APIs의 호출은 피해야 한다.






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^


Big을 했으니 Small도 해야지~ 

얼마전 페북을 열심히 보다가 유명 개발자께서 새로운 무언가를 소개한 글을 잠깐 보았다. 바로 구글에서 자사의
안드로이드를 기반으로 추진하는 IoT 프로젝트인 Android Things라는 프로젝트였다. 구글의 개발자 사이트를
가보면 HOME 메뉴 아래 Android, Wear, TV, Auto에 이어 5번째로 자리잡고있다.


마침 작년부터 아두이노에 관심을 갖게 되었고 또 올해 추진하고 있는 아두이노로 스마트 미러를 만드는 계획에
차질을 빚고 있던 차에 이런 정보를 접하니 관심이 안갈 수 없다. 아쉽게도 Android 자체가 고수준 언어인 JAVA에
기반을 하고 있다보니 아두이노는 지원 기기에 없지만 라즈베리 파이를 지원한다고 하니 안그래도 기웃거리고 있던
라즈베리 파이를 시작해 볼 좋은 핑계가 생긴 셈이다.


그래서 오늘은 이 Android Things에 대해 간단하게 알아보고자 한다.
이 글은 Android Things의 메인 페이지를 정리한 것이다.

참조 링크 : https://developer.android.com/things/index.html


예정된 수순?

뭐 애초에 전방위적으로 손을 안뻗친 곳이 없는 구글이다보니 IoT에 눈을 돌렸다 해도 이상할 것도 없고 또 자율
주행 차를 연구하고 있었다 하면 당연히 그 과정에서 IoT가 빠져있었을리가 만무하다. 더군다나 이미 모바일 OS인
Android를 통해 소형 기기에 대한 생태계를 확실하게 굳히고 있는 마당에 사실상 일반 개발자에게 공개된 시점이
최근일 뿐 이미 오래 전에 준비는 다 되어 있었다고 봐야 할 것이다(그렇다면 곧 애플도?).


결국 올 것이 온 것이니 우리는 아~주 자연스럽게 이용만 하면 된다 ^^. 그러기 위해서는 차근 차근 하나씩 그 속을
들여다 보아야겠지.


Android Things 소개

그래서인지 Android Things의 소개에는 Android가 가지고 있는 장점들을 활용할 수 있다는 점을 유독 강조하고
있는 느낌이다. 이름 자체가 Android로 시작하니 두말하면 잔소리인가? 어쨌든 메인 페이지의 표제어가 바로
‘안드로이드의 용이성과 힘’이다. 


여기서 강조하고 있는 것은 기존에 구축된 Android의 개발 툴, API들, 리소스들과 개발자 커뮤니티를 마음껏 이용할
수 있다는 것, 새로운 IoT 기기들을 위해 저수준의 I/O와 라이브러리를 제공하는 새로운 API가 추가되었다는 것,
마지막으로 IoT의 가장 큰 약점인 보안 부분을 Android OS 수준에서 제공할 수 있다는 것 등이다.



다음으로 강조하는 것은 프로토타입의 개발에서부터 실제 상품 개발까지의 과정을 빠르게 진행할 수 있다는 것이다.
기존에 생산된 많은 디바이스들에 대해 인증 받았고 이러한 기기들 덕분에 커널 개발, 펌웨어 개발, 보드 자체의
개발 등 어려운 과정을 거치지 않고도 바로 프로토타입 제품을 생산할 수 있으며 이렇게 개발된 프로토타입 자체가
이미 상용 제품의 수준이기 때문에 상용제품 개발에도 큰 힘이 들지 않는다는 것이다.



그리고 마지막으로 기존에 구굴이 이루어 놓은 많은 것들을 사용할 수 있다는 것이다. 구글 플레이를 이용한 앱의 
배포라든지 Weave라는 IoT 프로토콜을 이용할 수 있다는 것, 각종 시스템 이미지나 업데이트 혹은 버그 픽스등을 
안정적으로 제공받을 수 있다는 점, 그리고 OS와 앱의 업데이트를 OTA 인프라를 이용해 진행할 수 있다는 것 등이
그것이다.



정리

길게 늘어놨지만 요점은 안드로이드 생태계를 기반으로 이미 구축된 구글의 다양한 서비스와 인프라들을 마음껏
이용할 수 있다는 것이다. 그럼 과연 이 것이 구체적으로 무엇을 의미하는가? 하는 것은 Android Things 사이트에
있는 내용을 차근차근 정리하면서 알아보도록 하자 (사실 가장 먼저 손대고 싶은 것은 샘플 프로젝트 중 텐서플로우를
이용하여 이미지 처리를 하는 예제인데 천리길도 한 걸음 부터…차근차근 나가자~^^).



블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^


GCM으로 전환 후 C2DM이 적용된 단말 처리


현재 일하고 있는 곳에서 운영하고 있는 모바일 시스템이 아직도
C2DM을 사용하고 있다.


최근 다른 PUSH 솔루션을 이용할 계획이 수립됨에 따라 GCM을
사용하는 PUSH 솔루션에 맞추어서 우리도 GCM으로 migration을 해야하는데
모바일 기기를 일괄로 GCM으로 업데이트 못할 경우 서버는 GCM으로 모바일 기기는
C2DM으로 서로 안맞는 경우가 발생을 할 것 같으니 혹시 C2DM을 통해 받은 
auth token을 GCM에서 바로 사용할 수는 없는지 확인해 달라고 한다.


진작에 구글 개발자 사이트로 갔어야 하는데 괜히 여기저기 기웃거리느라 
시간만 뺐겼다…-.-


결론은 다음과 같다.


GCM의 API key와 C2DM의 token을 파라미터로 
https://android.apis.google.com/c2dm/migrate API를 호출하면
응답이 오는데 이 응답에 새로은 auth token이 포함되어있으니 이 auth token을
이용하여 push를 전송하면 된다.

출처 : https://developers.google.com/cloud-messaging/c2dm#supporting-legacy-client-apps


이게 뭔 뻘짓거리인가…-.-
어차피 GCM 등록은 해야 하고…새로운 토큰을 별도로 받아서 처리를 해야 한다니…-.-
그냥 GCM이 설치된 버전의 앱을 일괄 배포하고 강제 업데이트 하도록 진행하는 것이
백번 낫겠다…


암튼 별로 권장할만한 방법이 아닌 것은 분명하다…

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

일단 기본적인 세팅으로는 화면 회전을 할 경우 onSaveInstanceState, onCreate 등이 모두 다시 호출이 된다.

이러한 동작을 막고 onConfigurationChanged를 호출하여 끝내고 싶을 경우 해당 Activity에 

onConfigurationChanged (Configuration newConfig)를 오버라이드하여 구현하고 AndroidManifest.xml의 

Activity 설정에 다음 내용을 추가해주어야 한다.


android:configChanges="orientation|keyboardHidden|screenSize"


단, 이 때 안드로이드 펌웨어 구버전에서는 screenSize가 없어도 가능했던 모양인데

최근 버전에서는 screenSize도 같이 적어줘야 이 내용이 반영이 되므로 주의해야 한다.

자세한 내용은 API 참고...^^;;;



블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

일단 이 내용은 공식적인 기술 문서에 의한 것이 아니라

전적으로 개발상의 경험으로 정리한 내용이니 착오 없으시길 바랍니다.


문제의 발단은

현재 회사에서 운영 중인 앱의 안드로이드 버전에서

이전 버전은 홈버튼을 놀러 앱을 종료한 후 재실행 할 경우 바로 직전 화면으로 들어가는데

가장 최근 배포한 버전은 위와 같은 경우 다시 처음 로그인 화면부터 뜬다는 것이다.


로그를 확인해보니 이전 버전에서는 홈 버튼을 누른 후 재실행시 onCreate(), onResume() 어느 함수도

실행되지 않았는데 최근 배포버전은 onCreate()와 onResume()을 차례로 호출하고 있었다.


계속 검색하고 소스 코드 분석 하고 하던 중 마지막으로 확인하게 된 것이 AndroidManifest.xml 파일의

메인 Activity에 설정되어있는 android:launchMode 속성...


이전 버전 소스와 비교를 해보니 이전 버전은 이 설정 값이 singleTop으로 되어있는데

최신 배포버전에는 이 설정값이 singleTask로 되어있었다.


검색한 내용으로는

singleTop의 경우 이 값이 설정된 Activity는 호출되면 호출된 것 만큼 생성을 하는데 

다만 기존에 생성된 것이 있다면 이 것을 재활용 하게 된다고 한다. 

따라서 이 경우에는 기존에 떠있는 프로세스를 그대로 사용하기에 onCreate()가 호출되지 않는 것이다.


하지만 singleTask의 경우 이 값이 설정된 Activity는 호출되면 기존 Activity를 죽이고 새로 instance를

생성하기 때문에 항상 onCreate()부터 시작하게 되는 것이다.


이렇게 홈 버튼으로 앱 종료 후 재실행 할 때 onCreate()의 호출 여부로도 singleTop과 singleTask의 차이를

확인할 수 있다.

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

최초 작성일 : 2013/02/08 18:03 


긴 글 싫어하시는 분들을 위한 3줄 요약

1. ADT Errors running builder 'Android Pre Compiler' on project 문제 발생
2. Android SDK Tool 21.0.1에는 버그가 있으므로 Android SDK Tool 21.1 rc 설치
3. Android SDK Tool 21.1 rc 설치 후 반드시 https://dl-ssl.google.com/android/eclipse-preview/에서
관련 패키지들 업데이트

=============================================

현재 맥북 프로에서 이클립스를 이용하여 안드로이드를 개발(사실은 운영)하고 있다.
이클립스 버전은 JUNO를 사용 중인데...얼마전 뭔가를 잘못 업데이트 했는지
이클립스를 실행시키면 항상 Loading Workbench에서 이클립스가 멈춰버리는
문제가 생겼다.

이 문제에 대해 이것 저것 검색도 하고 검색한 것을 적용도 해보았지만
완전한 해결책은 찾지를 못했고 이클립스를 실행하기 전에 항상 metadata 디렉토리를
삭제한 후 실행을 시켰다. 물론 프로젝트 설정은 다 날아가서 늘 프로젝트를
새로 import해야 하는 문제가 있었지만...ㅠ.ㅠ

오늘 이 문제를 제대로 고쳐보고자 맘먹고 전체 세팅을 바꾸기로 했다.

그런데...빈대 잡다가 초가삼간 태운다고...몇가지 업데이트를 하는 과정에서
더 심각한 문제가 발생을 하였다.

프로젝트를 import한 후 clean이나 build를 수행하니 에러가 발생을 하는 것이었다.
아래의 메시지를 출력하면서 빌드가 되지 않았는데 증상은 aidl 파일들이 java 파일로
변화되지 않는 것이었다.

ADT Errors running builder 'Android Pre Compiler' on project

역시 구글링을 통해 문제를 해결하고자 열심히 검색하고 몇가지 해법을 찾았으나
요지부동...

그 과정에서 얻은 것은 Android SDK를 새로 받았더니...
오호라! 이클립스가 ADT라는 이름의 번들로 추가되어 있는 것이었다.
이제는 번거롭게 이클립스 다운받고 또  ADT 설정하고 할 필요가 없어졌다.
그냥 SDK 하나 다운로드 받으면 만사 땡~

암튼...
이렇게 까지 했는데도 문제가 해결되지 않았다.
가장 확실해보이는 해법은 현재 적용된 Android SDK Tool 21.0.1 버전에 버그가
있기 때문에 아직 Preview 단계인 Android SDK Tool 21.1 rc 버전을 받아야 한다는
것이었다.

다음은 stackoverflow에 달린 답변 전문이다.

I always hate answering my own questsions, but this is a genuine solution.

The 21.0.1 version of the ADT tools has a bug that prevents a project building if you have any files without extensions in them. This is a particular problem for users (like me) using subversion with has extenion-less files.

One recommended solution is to install these 'subversive' Eclipse plugins (Help > Install new Software > Work with your Eclipse version site > Expand 'Collaboration' > Choose 'Subversive SVN JDT Ignore Extensions' and 'Subversive SVN Team Provider') but this didn't work for me (I'm on Indigo, perhaps on Juno it works).

The solution is to install the 21.1 preview version of the ADT tools and SDK manager from Google. Clear instructions can be found here and you can read all the background add your voice to the angry mob of developers here.


그래서 시키는대로 했는데도 불구하고 이번에는 SDK를 못찾는 문제가 생겼다.
분명 설정 화면에서 SDK 위치를 지정을 해 주었는데도 불구하고 SDK를 인식하지
못하는 것이었다.

요기서 얼마간 삽질이 있었다.
결국 생각해보면 Android SDK Tool 21.1 rc이라는 새 버전을 사용하게 된만큼
관련된 다른 패키지들도 업데이트를 해주어야 하는 것이 당연지사인데 그것을
생각지 못한 것이다.

그리고 드디어 새로운 소프트웨어 설치를 통해 아래 링크를 이용하여 다른 패키지를
모두 업데이트한 이후에야 모든 문제가 해결되었다.


정말 힘든 하루였다...ㅠ.ㅠ

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

최초 작성일 : 2012/10/08 15:10





직찍사

12일 배송이라고 들어서 아무 생각 없이 기다리고 있었는데
오늘 떡하니 도착을 했다.

현재 일하고 있는 곳에서는 Wi-Fi가 차단되어있어서 달리 만져볼게 없었고
1층 커피숍 Wi-Fi를 이용하여 구글 계정 등록하고 몇가지 설치를 해보았다.

외형만으로 봤을 때 일단 7인치도 만만한 사이즈가 아니라는 것.
(역시 휴대 기기의 맥시멈 사이즈는 5인치대인 것 같다.)

화면이 정말 깨끗하다는 것.

재질은 아이패드를 만지다 봐서 그런지 그리 고급스럽지는 못하다는 점.

Wi-Fi 전용 기기는 정말 Wi-Fi 없으면 그냥 게임기라는 점...ㅠ.ㅠ
(그나마도 설치된 게임이 없다면 그냥 깡통이라는 거...-.-)

하지만 뭐니뭐니해도 새 기계는 정말 마음을 즐겁게 해준다는 점~

일단 첫인상은 이정도.

생각나는대로 사용기를 올려보도록 하겠다~

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

최초 작성일 : 2012/07/20 16:05


현재 송해 아저씨 광고하는 모 은행에서 모바일 관련 운영 업무를 맡고있다.


최근 아이폰은 괜찮은데 안드로이드쪽의 푸시가 잘 안온다는 고객측의 클레임이 있어
조치를 하다가 C2DM 계정이 이전 개발당시의 테스트용 계정인 것 같아 새 계정을
만들어 다시 테스트를 해보기로 결정하고 C2DM 계정을 등록하려는데...

이게 웬일...

2012년 6월 26일자로 기존의 C2DM 서비스는 deprecated 되었단다...ㅠ.ㅠ
다음은 구글의 개발자 페이지에 있는 안내문이다.




위 내용 하단에 링크되어있는 GCM 서비스가 C2DM을 대체한다.
아이폰 개발이 메인이다보니 안드로이드쪽 정보에 너무 둔감했나보다.

그나저나 기존 소스를 GCM에 맞춰 수정해야 하나...
일거리가 늘어버렸다...ㅠ.ㅠ

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

최초 작성일 : 2012/06/13 14:31 



Jenkins를 이용한 Android 및 iOS 앱 자동 빌드 시스탬 구축


예전부터 개발의 생산성과 품질을 높이기 위한 모든 방법에 관심이 많았다.

다만 기회가 많지 않아 사용해 본 것이라고는 CVS + CruiseControl의 CI나

Trac + SVN의 이슈 트래커 정도가 다였다.


그러다가 스마트폰의 중흥기에 발맞춰보고자 아이폰 앱 개발을 시작하게 되었고

어찌어찌하다보니 운영 업무로 안드로이드와 아이폰을 모두 관리해야 하는 입장에

처하게 되었다.


더구나 하이브리드 형태다보니 모바일 웹 개발자들이 개발을 하고나서

테스트를 하려면 내가 항상 새로 앱을 빌드해주어야 하는 상황이 되어버렸다.

(원래 하이브리드 형태로 웹 리소스들을 웹서버쪽에 두었더랬는데 성능상의 이슈로

웹 리소스를 아예 단말의 앱쪽에 밀어넣는 우스운 형태가 되어버렸다.)


결국 이러한 상황을 타개하고자 jenkins를 이용한 CI 환경을 구축하게 되었다.

아래 내용은 그 과정에 대한 정리이다.


*** 이 작업에 영감을 주신 맥부기의 '뱅리'님께 감사드립니다 ***


1. 환경


서버 : 맥미니 서버

OS : MAC OSX Lion Server (10.7.3)

소프트웨어 : Jenkins(iOS 앱 빌드를 위해서 Xcode plugin 사용), android_sdk, Xcode(4.2.1)


2. 프로세스 설명


현재 자동으로 빌드하고자 하는 앱은 하이브리드 형태로 대다수의 기능적인 부분은 js, css, html로 구성되어있다.

다만 네트워크의 부하와 성능적인 문제로 인해 불가피하게 리소스들을 웹서버에 두지 못하고 앱 내에

포함을 하게 되었다. 따라서 다음 프로세스에 따라 최종 앱을 빌드하게 된다.


1) SVN 서버로부터 웹 리소스(js, css, html 등)을 checkout(update)하여 jenkins의 workspace에 저장

   * 이 부분은 jenkins를 설치한 후 job을 생성하고 빌드를 수행하면 기본적으로 이루어지는 프로세스이다.


2) 역시 SVN으로부터 단말쪽 앱 소스를 checkout(update)하여 jenkins의 workspace에 저장


3) 1)에서 받은 웹 리소스를 2)쪽에 있는 단말 소스의 적당한 위치에 복사


4) 앱 빌드


5) 빌드된 패키지를 웹페이지에서 다운로드 받을 수 있도록 SVN의 다른 위치에서 commit


이후 단계는 배포서버에 설치된 Hudson (jenkins의 이전 버전)에서 자동으로 빌드된 앱 패키지 파일을 불러와

웹페이의 다운로드 링크 위치에 저장을 한다.


이러한 프로세스를 위해 1), 3)의 프로세스를 수행하기 위한 job(Project)을 하나 만들고

다음으로 안드로이드 앱 빌드를 위한 job과 아이폰 앱 빌드를 위한 job 이렇게 총 3개의 job을 생성하게된다.


잡을 생성한 후에는 웹 리소스를 받아와 앱 소스쪽으로 복사해주는 job을 상위에 놓고

단말 앱을 빌드하는 2개의 job을 서브 프로젝트로 놓아 상위 프로젝트의 빌드를 수행하면 자동으로

하위 프로젝트까지 수행되도록하면 한번의 빌드로 전 과정이 수행되게 된다.


3. 상세 설명


3-1 소프트웨어 설치


우선 이 내용은 아이폰 앱 빌드를 포함하고 있기 때문에 MAC을 기반으로 설명을 한다.

jenkins는 맥용으로 다운로드받아 설치할 수도 있다.(jenkins 홈페이지에 가면 각 OS별 네이티브 바이너리를

다운로드 받을 수 있다.)

하지만 여기서는 jenkins.war를 다운로드 받아 설치하였다.


다운로드 위치 : http://jenkins-ci.org/

jenkins 실행 : 가단하게 standalone으로 실행하였으며 실행 방법은 다음과 갘다.

java -jar jenkins.war --httpPort=[port번호]


이렇게 설치하게 되면 jenkins의 root 디렉토리는 /Users/[사용자 계정]/.jenkins가 되며

SVN으로 부터 checkout한 소스들은 /Users/[사용자 계정]/.jenkins/workspace 아래 jenkins에서 생성한

프로젝트명으로 디렉토리를 생성한 후 그 아래 저장된다.


3-2 웹 리소스를 SVN으로부터 checkout(update)하여 앱 소스쪽으로 복사하는 job 생성


- jenkins의 메인 화면에서 '새로운 job' 선택

- job 이름 입력 (이 곳에 입력된 이름으로 workspace아래 디렉토리가 생성되므로 가급적 영문으로 입력)

- 프로젝트 형태는 기존 job 복사를 제외하면 4가지가 있는데 무난하게 첫번째 free-style로 선택한 후 OK 버튼 클릭





- OK 버튼을 누르면 바로 새로 생성된 job의 설정 화면으로 이동한다. 이 job은 SVN에서 소스를 가져와 다른 위치로 복사하는 프로세스를 수행하므로

   관련된 설정만 정리한다.


소스 코드 관리 항목

* Subversion 선택

* Repositary URL에 SVN repositary 주소 입력

Local module directory (optional) 항목은 소스를 저장할 위치인데 디폴트인 .으로 놔두면 위에서 언급한대로jenkins 설치 위치의 workspace아래 job이름의

  디렉토리 아래로 소스들이 저장된다.


Build 항목

* Add build step 선택. 선택할 수 있는 항목은 아래와 같은데 웹 리소스를 카피하기 위한 build.xml 파일이 기존 소스에 포함되어 있었기 때문에

  여기서는 Invoke Ant를 선택하였다. 단순 카피만 수행한다면 Execute shell을 선택하여 shell script로 처리해도 될 것이다.





* Ant의 빌드 파일(build.xml)에서 수행할 Target의 이름을 적어준다. Target이 여러개일 경우 공백으로 구분하여 적어준다.


* Invoke Ant를 선택하면 jenkins는 기본적으로 현재 job 경로의 root에서 build.xml 파일을 찾는다. 즉 TEST라는 프로젝트라면

  /Users/[사용자 계정]/.jenkins/workspace/TEST/build.xml을 수행하게 되는 것이다. 만일 build.xml이 다른 경로에 있거나 빌드 파일이

  다른 이름이라면 '고급…'버튼을 클릭 후 Build File 항목에 빌드파일의 경로와 이름을 적어준다.





Post-build Action 항목

* 앞서 프로세스에서 설명한 바와 같이 소스 카피 후 바로 앱을 빌드하는 job을 수행해야 하므로 Add post-build action에서 'Build other project'를 선택한다.

* Project to build에 앞으로 추가할 앱을 빌드하는 job의 이름을 입력한다. 2개 이상의 job을 수행하려면 ,로 구분하여 적어준다.





마지막으로 저장 버튼 클릭 후 프로젝트 메인 화면으로 돌아오면 최초로 Build Now를 수행하여 SVN으로부터 소스를 Checkout한다.

물론 설정에서 등록한 모든 작업들이 진행된다.


3-3 안드로이드 앱 빌드 job 생성


job 생성에서부터 소스 코드 관리 항목까지의 작업은 3-2와 동일하다.


빌드 트리거 항목

* 3-2의 job 수행 후 바로 수행되도록 설정하기 위해 '다른 프로젝트가 빌드된 후 빌드함' 항목에 체크

* Project names에 선행할 프로젝트 이름을 입력한다. 2개이상의 프로젝트 이름은 ,로 구분하여 입력한다.





Build 항목


*** 사전 준비 ***

먼저 로컬에서 안드로이드 프로젝트의 빌드를 수행하는 Ant 빌드파일을 생성하고 이 빌드 파일을 함께 SVN에 커밋한다.

빌드 파일 생성은 [android sdk]/tools로 이동하여 다음 명령어를 수행하면 된다.


 ./android update project -p [안드로이드 프로젝트 경로] -n [프로젝트 이름]


이 명령을 수행하면 프로젝트 root 아래에 다음 2개의 파일이 생성된다.


build.xml

local.properties


이 중 build.xml은 수정할 것이 없고 local.properties에 android sdk 경로가 기록되는데 jenkins를 통해 자동 빌드를 해야 하므로

이 경로를 jenkins 서버의 환경에 맞춰 수정해주어야 한다.


이렇게 생성된 2개의 파일을 모두 SVN에 commit한다.


* 3-2와 마찬가지로 Invoke Ant를 선택하고 수행할 Target을 적어주는데 'clean debug' 이렇게 적어주면 된다(따옴표 없이 적음)

* 여기까지 하면 Build Now를 수행했을 때 .apk 파일이 생성되어 프로젝트 root 밑에 bin 디렉토리에 저장된다.

* 나는 여기서 배포용 서버까지 올리는 작업을 추가로 진행하였기 때문에  Add build step을 추가하고 (Execute shell) shell script를 통해

생성된 .apk 파일을 또 다른 SVN의 working copy(SVN 서버에서 checkout한 위치)로 복사를 한 후 그 위치로 이동하여 commit을 수행하는 내용을 추가하였다.

참고로 아래와 같은 코드이다.


# 기존 .apk 파일 삭제

rm [svn working copy]/[앱 패키지명].apk


# jenkins 프로젝트에 생성된 앱 패키지를 svn working copy로 복사

cp [jenkins 프로젝트 root]/bin/[앱 패키지명].apk [svn working copy]/[앱 패키지명].apk


# svn working copy로 이동

cd [svn working copy]


# 빌드번호 부여를 위해 날짜값을 구함

buildDate=`date +%Y%m%d%H%M%s`


# SVN 서버로 commit

svn commit -m "앱 이름 Android build$buildDate" [앱 패키지명].apk


마지막으로 '저장'버튼 클릭 후 3-2와 마찬가지로 Build Now를 클릭하여 최초 빌드를 수행해준다.



3-4 iOS 앱 빌드 job 생성


사전 준비로 jenkins에 Xcode plugin을 설치해야 한다.

다운로드 위치 : https://updates.jenkins-ci.org/download/plugins/xcode-plugin/ 1.3.1 버전 다운로드


jenkins 메인 화면의 'jenkins 관리'->'플러그인 관리'로 이동한다.

상단 탭 버튼 중 '고급'으로 이동하여 중간 부분에 있는 '플러그인 올리기'에서 다운로드 받은 xcode-plugin.hpi 파일을 선택하고

'올리기' 버튼을 클릭하면 설치된다.


아니면 '설치 가능' 탭에서 바로 플러그인을 선택하고 설치해도 된다.


빌드 트리거 항목까지는 3-3과 동일하게 진행한다.


Build 항목

* Add build step에서 Xcode를 선택합니다. 상당히 많은 입력항목이 나오는데 대부분 디폴트로 둔다.(비어있는 항목도 그대로)

  직접 설정해야 할 것은 'Clean before build?'와 Build IPA?', 'Keychain password'정도만 입력해주면 된다.


* 3-3과 마찬가지로 배포용 서버로 업로드 해야 하므로 Add build step에서 Execute shell을 선택하고 shell스크립트를 작성하는데

  내용은 경로와 앱 이름을 제외하고는 3-3과 동일하다.


'저장'버튼을 눌러 저장하고 최초로 Build Now를 눌러준다.

기존에 Xcode에서 정상적으로 빌드되는 프로젝트라면 jenkins의 설정만으로도 정상적으로 빌드가 된다.




블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

최초 작성일 : 2012/02/13 09:32 


그동안 프로가드를 이용하여 난독화를 진행해왔는데 최근 신규 라이브러리를

추가하면서 아래와 같은 에러가 발생하였다.

[2012-02-13 09:27:14 - IBKLauncher_Dev] Proguard returned with error code 1. See console

[2012-02-13 09:27:14 - IBKLauncher_Dev] Note: there were 993 duplicate class definitions.

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find superclass or interface java.awt.Frame

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find superclass or interface java.awt.event.ActionListener

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find superclass or interface java.awt.event.WindowListener

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.SocksDialog: can't find superclass or interface java.awt.Dialog

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.SocksDialog: can't find superclass or interface java.awt.event.WindowListener

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.SocksDialog: can't find superclass or interface java.awt.event.ItemListener

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.SocksDialog: can't find superclass or interface java.awt.event.ActionListener

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.UDPRelayServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.UDPRelayServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.UDPRelayServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.UDPRelayServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find referenced class java.awt.Frame

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find referenced class java.awt.image.ImageProducer

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find referenced method 'java.awt.Image createImage(java.awt.image.ImageProducer)' in class net.sourceforge.jsocks.SocksEcho

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.SocksEcho: can't find referenced method 'void setIconImage(java.awt.Image)' in class net.sourceforge.jsocks.SocksEcho

.

.

.

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.ProxyServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.ProxyServer: can't find referenced class org.apache.commons.lang.RandomStringUtils

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: net.sourceforge.jsocks.socks.ProxyServer: can't find referenced class org.apache.log4j.Logger

[2012-02-13 09:27:14 - IBKLauncher_Dev]       You should check if you need to specify additional program jars.

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: there were 241 unresolved references to classes or interfaces.

[2012-02-13 09:27:14 - IBKLauncher_Dev]          You may need to specify additional library jars (using '-libraryjars'),

[2012-02-13 09:27:14 - IBKLauncher_Dev]          or perhaps the '-dontskipnonpubliclibraryclasses' option.

[2012-02-13 09:27:14 - IBKLauncher_Dev] Warning: there were 14 unresolved references to program class members.

[2012-02-13 09:27:14 - IBKLauncher_Dev]          Your input classes appear to be inconsistent.

[2012-02-13 09:27:14 - IBKLauncher_Dev]          You may need to recompile them and try again.

[2012-02-13 09:27:14 - IBKLauncher_Dev]          Alternatively, you may have to specify the options

[2012-02-13 09:27:14 - IBKLauncher_Dev]          '-dontskipnonpubliclibraryclasses' and/or

[2012-02-13 09:27:14 - IBKLauncher_Dev]          '-dontskipnonpubliclibraryclassmembers'.

[2012-02-13 09:27:14 - IBKLauncher_Dev] java.io.IOException: Please correct the above warnings first.

[2012-02-13 09:27:14 - IBKLauncher_Dev]  at proguard.Initializer.execute(Initializer.java:308)

[2012-02-13 09:27:14 - IBKLauncher_Dev]  at proguard.ProGuard.initialize(ProGuard.java:210)

[2012-02-13 09:27:14 - IBKLauncher_Dev]  at proguard.ProGuard.execute(ProGuard.java:85)

[2012-02-13 09:27:14 - IBKLauncher_Dev]  at proguard.ProGuard.main(ProGuard.java:499)


안드로이드 개발 경험이 일천한지라 무지 당황하였다.
답은 역시 구글링~
그러 문제가 발생한 패키지에 -dontwarn 옵션을 주면 해결되는 문제였다.

-dontwarn net.sourceforge.jsocks.**

어렵지 않게 해결되어 다행이다...ㅠ.ㅠ

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^