한 건의 데이터를 입력하는 테스트는 개발자가 손으로 디바이스에 직접 틱틱 입력하면서 금방 테스트할 수 있습니다. 그러나 1000 건의 데이터를 입력하는 행위를 재현해야 한다면 이건 도저히 사람이 수동으로 할 일이 아니게 됩니다. 얼마전 저한테 그런 일이 닥쳤습니다. -.-;

시나리오는 이렇습니다.

대기 화면 -> 목록 화면 -> 입력 화면 -> 여러가지 값 입력 -> 저장 버튼 -> 목록 화면 -> back 버튼 -> 대기 화면

이 시나리오를 1000 번, 2000 번 반복해야 합니다.

처음엔 JUnitPerf를 참조해서 테스트케이스 안에서 코딩을 통해 반복을 구현하려고 했지만, 답이 안나오더군요. 제가 안드로이드 테스트 프레임워크를 아직 잘 이해를 못한 탓인거 같습니다. 그래서 결국은 그냥 1 건 입력하는 테스트케이스를 만들고 am instrument를 1000번 반복해서 실행하는 것으로 구현했습니다. ^^;

아래처럼 배치파일을 만듭니다. 

@rem 반복횟수. 첫번째 파라미터로 받음.
set REPEAT=%1

@rem 실행할 명령(my.app.test는 테스트케이스가 포함된 패키지명, my.app.test.InsertTest는 테스트케이스 클래스)
set TEST=adb shell am instrument -w -e class my.app.test.InsertTest  my.app.test/android.test.InstrumentationTestRunner

@rem FOR /L %variable IN (start,step,end) DO command [command-parameters]
FOR /L %%A IN (1,1,%REPEAT%) DO %TEST%

배치파일이 TestInsert.bat라면 반복횟수를 파라미터로 주어 실행합니다.

C:\TestInsert.bat 1000

와우! 성공했습니다. 밥먹으러 가기 전에 돌려놓고 나는 맛있게 밥만 먹으면 됩니다. ^^
Posted by 에코지오
,

안드로이드 테스트 기본

am instrument 명령어 자세한 사용법

테스트케이스 차이점

2개의 핵심 테스트케이스
 isolated testing of a single activity
- 시스템 인프라와 약한 연결
- 일부 시스템 자원을 Mock으로 대체

- functional testing of a single activity
- 시스템 인프라 그대로 이용
- 실제 환경과 동일

테스트케이스 작성 샘플

안드로이드용 다른 테스트 프레임워크
(1) Robotium
- 블랙박스 테스트용
- 하나의 테스트케이스에서 여러 액티티비 사이를 이동 가능
- 뷰 요소를 화면상의 index(몇 번째로 나타나는가)로 참조 : 블랙박스 테스트라면 뷰의 ID를 알 수 없기 때문. 
- 그냥 뷰의 ID(R.id.xxx)로 참조하는 API도 제공하면 더 좋을 듯.

(2) Calculon
- 화이트박스 테스트용
- DSL 개념도입 : Watij와 비슷한 방식으로 테스트 코드 작성
- 다른 액티비티로 이동시 해당 액티비티를 참조하기가 어려움

* Robotium과 Calculon을 잠깐 써본 바로는 둘다 아직은 부족한 점이 많아 보입니다.

Posted by 에코지오
,
SQLite DB 테이블 조회할 때 한글과 영어가 섞인 컬럼에 대해서 정렬을 하게되면, SQLite는 기본적으로 기타문자(특수문자,숫자), 영어, 한글 순서로 정렬을 합니다. 보통 ORDER BY 절에 COLLATE LOCALIZED 키워드를 사용하는데, (사실 이게 뭔지는 저도 잘 모르지만) 사용자 로케일이 ko_KR이더라도 우리가 원하는대로 한글 - 영어 - 기타 순으로 정렬되지는 않더군요. 

ORDER BY name COLLATE LOCALIZED ASC; // 기타 - 영어 - 한글 순으로 정렬됨

1. 구분 컬럼을 이용한 방법
우리나라 사용자에게 좀더 자연스러운, 한글 -> 영어 -> 기타 순서로 정렬하기 위해 고민하다가 검색해보니 역시 유용한 팁이 있네요.


해당 컬럼 값이 한글인지, 영어인지, 기타인지 구분해주는 구분컬럼을 두어서 1, 2, 3 식으로 할당을 합니다. 그리고 ORDER BY 절에 이 구분컬럼으로 먼저 정렬을 하면 조회목록에서 한글이 영어보다 먼저 나오게 됩니다. 위 링크에 나오는 것처럼 구분컬럼을 TAG라고 하면,

ORDER BY tag, name COLLATE LOCALIZED ASC; // TAG 컬럼으로 먼저 정렬하므로 한글 - 영어 - 기타 순으로 정렬됨

그러나 TAG와 같은 구분컬럼을 이용하는 경우에는 복잡성이 증가하고 유연성이 떨어집니다. 
우선 테이블 컬럼이 늘어나게 되고, NAME 컬럼에 값이 추가/수정될 때마다 이게 한글인지 영어인지 기타 인지 판단하여 TAG 컬럼 값 역시 적절히 추가/수정해줘야 합니다(이런 일에는 트리거가 유용하겠죠). 우리에게 테이블에 컬럼을 추가할 수 있는 권한이 없을 수도 있습니다. 만약 언어 로케일 설정 또는 화면별로 정렬 순서를 다르게 가져가야 한다면 TAG 컬럼을 활용하기 어려울 수도 있습니다.

2. ORDER BY 절에서 CASE 문을 이용하는 방법
이런 구분컬럼을 추가하지 않아도 우리가 원하는대로 정렬할 수 있습니다. ORDER BY 절에서 CASE 문을 사용해서 동적으로 한글/영어/기타로 구분하면 됩니다.

ORDER BY (CASE WHEN substr(name ,0, 1) BETWEEN 'ㄱ' AND '힣' THEN 1 
                           WHEN substr(name, 0, 1) BETWEEN 'A' AND 'Z' THEN 2
                           WHEN substr(name, 0, 1) BETWEEN 'a' AND 'z' THEN 2
                           ELSE 3 
                 END), 
                 name COLLATE LOCALIZED ASC

제가 SQL 전문가가 아니기 때문에 더 좋은 쿼리가 있는지는 모르겠습니다. 이 방법은 테이블을 고칠 필요가 없으며, 언어 로케일이나 화면 등 상황에 따라서 ORDER BY 절에서 정렬 순서를 수정하면 되므로 유연합니다. 동일한 CASE 구문이 여러 곳에서 쓰인다면 SQL 함수로 만들거나 자바 메소드로 만들어두면 됩니다. 다만 구분컬럼을 두는 1번 방법보다는 성능면에서 안 좋습니다. 그러나 테스트해 본 바로는 생각보다 그리 느려지지 않았습니다.

ps. 위 2가지 방법 모두 완벽한 정렬은 아닙니다. 첫글자 이후로는 기타 - 영어 - 한글 순으로 소팅됩니다. 즉 아래와 같이 정렬됩니다.
 - 가나다123
 - 가나다abc
 - 가나다라마바

ps2. SQLite가 COLLATE LOCALIZED 키워드를 어떻게 해석하는지 low level의 소스를 분석해보면 좀더 근본적인 해결 방법이 있을것 같습니다.

Posted by 에코지오
,
안드로이드 애플리케이션 소스를 디버깅하는 최선의 방법은 이클립스에서 [Debug As > Android Application]을 실행하는 것입니다. 그러나 어떤 경우에는 이 메뉴를 이용할 수 없거나 또는 이용할 필요가 없는 상황도 생깁니다.  
예를들어 Debug As 메뉴를 실행했더니 바빠 죽겠는데 어디가 꼬였는지(?) 계속 아래와 같은 에러가 발생한다면?

[2010-04-12 11:33:41 - Contacts]Installing Contacts.apk...
[2010-04-12 11:34:19 - Contacts]Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE
[2010-04-12 11:34:19 - Contacts]Please check logcat output for more details.
[2010-04-12 11:34:19 - Contacts]Launch canceled!

또는 로컬의 애플리케이션 소스가 타겟에 설치된 버전과 소스가 동일해서 재설치하거나 덮어쓸 필요가 없는데, 소스는 디버깅하고 싶다면?
이럴 때는 Debug As 메뉴를 고집하지 말고 임시로 수동으로 디버깅하면 됩니다. 

수동으로 프로세스에 디버거 붙이기
디버깅하고자 하는 애플리케이션 프로세스에 디버거를 여러분이 직접 수동으로 붙여서(attach) 디버깅할 수 있습니다. 다음 과정을 따릅니다.

  1. 타겟(에뮬레이터)에서 해당 애플리케이션을 시작시킴 
  2. 이클립스 DDMS에서 해당 프로세스를 선택
  3. 미리 만들어둔 리모트 디버그 실행설정을 실행함 
  4. 이제 소스에 중단점 존재시 디버그 퍼스펙티브로 전환됨

* 이클립스에 리모트 디버그 실행 설정 만들기
  • 프로젝트 오른 클릭 > Debug As > Debug Configurations 실행
  • Remote Java Application 타입으로 새로운 launch 설정 생성
  • Port를 8700번으로 수정
  • Apply 클릭 (Debug 클릭하면 바로 실행됨)


프로세스에 디버거 붙이는 작업을 자동화하기

만약 수동으로 디버거를 붙이는 작업을 자꾸 반복해야 한다면, 이것은 당연히 비효율적인 일이 되고 맙니다. 

또한 디버거를 붙이는 작업을 사람이 수동으로 처리하다보니, 애플리케이션 시작부터 리모트 디버거를 붙이기까지 다소 시간이 걸릴 수 있습니다. 이렇게 되면 디버거가 연결되기 전에 액티비티의 onCreate() 같은 메소드에 찍어둔 중단점은 지나쳐 버릴 수가 있습니다 (아 물론, 이 문제는 에뮬레이터의 Dev Tools 애플리케이션의 Development Settins에서 아래처럼 Wait For Debugger 옵션을 체크하여 방지할 수 있습니다).



어쨋든 디버거 붙이는 과정은 가급적 스크립트로 만들어두고 자동으로 실행시키는 것이 좋습니다.


▶ 타겟(에뮬레이터)에서 해당 애플리케이션을 시작

am(Activity Manager) 명령어를 이용합니다. 타겟에서 지정된 액티비티를 디버그 모드로 시작하는 명령형식은 다음과 같습니다.

am start -D -n <package-name>/<package-name>.<class-name> 

자동으로 해당 액티비티 프로세스의 디버깅 포트가 8700 포트로 포워딩되며 만약 8700 포트로 붙는 디버거가 없으면 액티비티는 디버거가 붙을 때까지 대기합니다. 다음은 Contacts 네이티브 애플리케이션의 주소록 목록화면 액티비티 띄우는 예제입니다.

$ adb shell am start -D -n com.android.contacts/.ContactsListActivity


▶ 이클립스 DDMS에서 해당 프로세스를 선택 

이클립스 DDMS를 보지 않고 방금 띄운 프로세스의 디버깅 포트를 알아내는 것이 핵심입니다. 디버깅 포트는 이렇게 알아낼 수 있습니다.

(1) 해당 프로세스가 마지막에 뜬 프로세스인 경우

adb jdwp | tail -1

(2) 프로세스의 이름을 알고 있는 경우

# ps| grep 프로세스명 | awk '{print $2}'
# 다음은 프로세스명이 android.process.acore인 경우 예제
$ adb shell ps | grep android.process.acore | awk '{print $2}'

이제 리모트 디버깅 실행설정에서 설정해둔 8700 포트를 이렇게 알아낸 포트로 포워딩하면 됩니다.

# 먼저 위에서 알아낸 디버깅 포트를 $DEBUG_PORT 변수에 저장합니다
$ adb forward tcp:8700 jdwp:$DEBUG_PORT


▶ 이클립스 리모트 디버그 실행설정을 실행
이클립스에 만들어둔 '리모트 디버그 실행설정'도 스크립트을 통해서 실행하는 방법이 있으면 좋겠네요. 이 부분은 좀더 찾아봐야겠습니다.

Posted by 에코지오
,

지난 글에서는 로컬의 네이티브 애플리케이션 소스를 이클립스를 통해 쉽게 디버깅할 수 있도록, 에뮬레이터에 내장된 것과 동일한 키로 서명하는 방법을 알아봤습니다. 그러나 굳이 내장된 것과 동일하게 서명하지 않고(즉 Custom Debug Keystore를 만들지 않고) 로컬 네이티브 애플리케이션을 디버깅할 수 있습니다. 

(1) 내장된 애플리케이션을 설치 제거하거나(uninstall)

(2) 내장된 패키지(apk) 파일을 내가 빌드한 apk 파일로 덮어쓴 후(overwrite)

그러고 나서 이클립스에서 Debug As로 디버깅하면 됩니다.

1. 네이티브 애플리케이션 uninstall하기

에뮬레이터에서 기존 네이티브 애플리케이션을 설치제거(uninstall)합니다. 

# 그냥 언인스톨하면 안됩니다
$ adb uninstall com.android.calculator2
Failure

# 아직 rm으로 파일을 삭제할 수 없습니다
$ adb shell rm /system/app/Calculator.apk
rm failed for /system/app/Calculator.apk, Read-only file system

# remount는 /system 파티션을 ro(read-only)에서 rw(read-write)로 바꿉니다
$ adb remount

# 이제 rm으로 apk를 삭제하고 uninstall합니다
$ adb shell rm /system/app/Calculator.apk
$ adb uninstall com.android.calculator2

Success

# 기존 데이터를 보존하고 uninstall하려면 -k 옵션 추가
$ adb shell pm uninstall -k com.android.calculator2

▶ 네이티브 애플리케이션 제거 순서 요약 : remount => remove apk => uninstall 


2. 또는 네이티브 패키지 파일을 덮어쓰기

내장된 애플리케이션 패키지 파일(apk)을 로컬에서 빌드된 파일로 강제로 덮어씌우고 디버깅할 수 있습니다.

# remount는 /system 파티션을 ro(read-only)에서 rw(read-write)로 바꿉니다
$ adb remount

# 내장된 apk를 로컬 apk로 overwrite합니다
$ adb push C:\Calculator\bin\Calculator.apk /system/app


이클립스에서 Debug As 실행

내장된 애플리케이션을 언인스톨하거나 로컬 패키지 파일로 덮어쓴 후에 이클립스에서 [프로젝트 오른 클릭 > Debug As > Android Application]을 실행합니다. 이제 로컬에서 빌드된 네이티브 애플리케이션이 타겟에 새롭게 설치되면서 소스를 디버깅할 수 있습니다. (이 경우 apk는 /data/app에 설치됩니다. /system/app에 설치되지 않습니다)


별거 없네요. 어때요? 참, 쉽죠? ^^

Posted by 에코지오
,
이클립스(+ ADT 플러그인) 환경에서 애플리케이션을 개발하고 소스(*.java)를 디버깅하는 방법은 무척이나 쉽습니다. 소스에 중단점을 찍고나서 [프로젝트 선택 > 오른클릭 > Debug As > Android Application]을 실행하는게 전부이죠.



개발자가 Debug As > Android Application을 실행했을 때 이클립스가 무슨 일을 하는지 알아볼까요?

1. 에뮬레이터가 런치되면서 기본 액티비티가 시작됩니다.

2. DDMS의 Devices 뷰에서는 해당 애플리케이션 프로세스가 선택되어 있고 초록색 벌레가 붙어있는 것을 볼 수 있습니다.



3. 소스에 중단점(break point)이 있으면 디버그 퍼스펙티브로 전환됩니다.

이 모든 걸 이클립스가 알아서 자동으로 실행해줍니다. 한편 Console에는 아래와 같은 메시지가 출력됩니다.

[2010-03-30 11:08:56 - ActivityLifecycleProject]------------------------------
[2010-03-30 11:08:56 - ActivityLifecycleProject]Android Launch!
[2010-03-30 11:08:56 - ActivityLifecycleProject]adb is running normally.
[2010-03-30 11:08:56 - ActivityLifecycleProject]Performing my.andr3.life.MyActivity activity launch
[2010-03-30 11:08:56 - ActivityLifecycleProject]Automatic Target Mode: launching new emulator with compatible AVD 'myavd'
[2010-03-30 11:08:56 - ActivityLifecycleProject]Launching a new emulator with Virtual Device 'myavd'
[2010-03-30 11:09:05 - ActivityLifecycleProject]New emulator found: emulator-5554
[2010-03-30 11:09:05 - ActivityLifecycleProject]Waiting for HOME ('android.process.acore') to be launched...
[2010-03-30 11:11:24 - ActivityLifecycleProject]HOME is up on device 'emulator-5554'
[2010-03-30 11:11:24 - ActivityLifecycleProject]Uploading ActivityLifecycleProject.apk onto device 'emulator-5554'
[2010-03-30 11:11:24 - ActivityLifecycleProject]Installing ActivityLifecycleProject.apk...
[2010-03-30 11:11:59 - ActivityLifecycleProject]Success!
[2010-03-30 11:12:00 - ActivityLifecycleProject]Starting activity my.andr3.life.MyActivity on device
[2010-03-30 11:12:09 - ActivityLifecycleProject]ActivityManager: Starting: Intent { cmp=my.andr3.life/.MyActivity }
[2010-03-30 11:12:13 - ActivityLifecycleProject]Attempting to connect debugger to 'my.andr3.life' on port 8615

콘솔 로그를 분석해보면 생각보다 많은 작업들이 벌어지는 것을 알 수 있습니다.
  1. 에뮬레이터가 떠있지 않다면 에뮬레이터를 띄움
  2. 프로젝트/bin에 빌드된 패키지 파일(.apk)을 디바이스에 업로드함 : adb push
  3. 업로드된 apk 파일을 /data/app에 설치(or 재설치) : adb install -r 
    - LogCat 로그를 보면 에뮬레이터 내부적으로 무슨 일이 더 벌어지는지 상세히 알 수 있음
  4. 애플리케이션 프로세스(Dalvik VM)가 생성되면서 기본 액티비티를 시작시킨다. : am start
  5. DDMS는 해당 VM의 디버그 포트(JDWP)를 8700 포트로 포워딩(DDMS에서 해당 프로세스가 선택됨) : adb forward
  6. 이클립스 디버거가 8700 포트에 연결(Dalvik VM과 이클립스가 통신시작) : DDMS에서 해당 프로세스에 초록색 벌레 아이콘 나타남
  7. 소스 중단점 존재시 이클립스 디버그 퍼스펙티브로 전환됨

* 'Dalvik VM - DDMS - Eclipse' 사이의 연결관계에 대한 자세한 내용은 ekwang님의 글 참조 : http://ekwang.tistory.com/4

Posted by 에코지오
,

네이티브 애플리케이션 소스를 수정하여 컴파일, 테스트, 디버깅해야 할 경우가 있습니다. 주로 제조사에서 그런 작업을 합니다. 네이티브 애플리케이션 커스터마이징을 위해 제일 먼저 할 일은 당연히 이클립스에 네이티브 애플리케이션 프로젝트를 구성하는 것입니다. 이클립스 환경에서 네이티브 앱을 빌드하는 방법을 알아보죠.

1. 일단 안드로이드 소스 저장소(http://android.git.kernel.org/)에서 해당 네이티브 애플리케이션 소스를 다운받습니다. snapshot 링크를 클릭하면 압축파일로 한번에 쉽게 다운로드 받을 수 있습니다. 



2. 압축을 풀고 이클립스에서 새로운 Android Project로 구성합니다. 생성 마법사에서 Android Project 선택 후 Create project from existing source 선택하여 소스 경로를 설정합니다.



3. 다행히 Calculator 처럼 공개된 안드로이드 프레임워크 API(android.jar)만 사용하는 애플리케이션이라면 일반적인 유저 애플리케이션처럼 큰 문제 없이 잘 빌드됩니다.


4. 그러나 Contacts 처럼 숨겨진 프레임워크 API에 의존하는 경우 android.jar 만으로는 컴파일 자체가 안됩니다. Contacts는 안드로이드 풀소스 빌드 과정에서 중간 결과물로 생성되는 classes.jar 등에 의존하고 있는데, 이런 경우는 짤없이 안드로이드 전체 소스를 다운받아 몇 십분~몇 시간 걸리는 full 빌드를 우분투 환경에서 한번은 해줘야 합니다. 


android.jar 외에 어떤 jar 파일을 빌드패스에 추가할 지는 Android.mk 파일 등을 참조하여 판단하면 됩니다.

좀 더 자세한 설명은 다음 링크를 참조하세요.


* 전체 네이티브 패키지(애플리케이션, 프로바이더 등)를 이클립스를 이용하여 한꺼번에 빌드하기 위한 세팅은 다음 링크를 참조합니다.

http://source.android.com/using-eclipse
http://blog.naver.com/jang2818?Redirect=Log&logNo=20078863663



Posted by 에코지오
,
안드로이드 애플리케이션 패키지(apk)를 설치하기 위해서는 반드시 서명(signing)을 해야합니다. 
서명되지 않은 애플리케이션을 설치하려고 하면 아래처럼 [INSTALL_PARSE_FAILED_NO_CERTIFICATES] 에러가 발생하게 됩니다.

$>adb install ActivityLifecycleProject.apk
178 KB/s (8585 bytes in 0.046s)
        pkg: /data/local/tmp/ActivityLifecycleProject.apk
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]

애플리케이션 서명 여부 확인하기
그럼 어떤 애플리케이션이 서명되었는지 여부는 어떻게 알 수 있을까요? 우선은 JDK에 포함된 jarsigner 명령을 통해서 확인할 수 있습니다.

## 서명안된 apk
$>jarsigner -verify ActivityLifecycleProject.apk
no manifest.
jar is unsigned. (signatures missing or not parsable)


## 서명된 apk
$>jarsigner -verify ActivityLifecycleProject.apk
jar verified.

(좀더 자세한 서명 정보는 -verfiy -verbose -certs 옵션을 추가하면 볼 수 있습니다.)

또는 간단히 apk 파일을 알집 등으로 풀어서 META-INF 폴더 안에 CERT.SF 와 같은 파일이 있으면 서명된 패키지로 볼 수 있습니다. 서명되지 않은 apk에는 이러한 파일이 없습니다.



이클립스를 통한 자동 디버그 모드 서명
앞서 애플리케이션은 반드시 서명되어야 한다고 했습니다. 그런데 우리는 이클립스(+ADT) 환경에서 안드로이드 애플리케이션을 개발하면서, 서명 작업을 의식하지 않고 자연스럽게 타겟에 애플리케이션을 설치하고 테스트합니다. 이렇게 개발자가 직접 서명을 하지 않아도 되었던 이유는 이클립스가 애플리케이션을 빌드하면서 자동으로 apk에 서명까지 함께 해주었기 때문입니다.

apk 서명에는 debug 모드와 release 모드가 있는데, 이클립스는 debug 모드로 서명을 해줍니다. 이클립스가 apk를 디버그 모드로 서명하기 위한 키/인증서(key/certificate)는 "$HOME/.android/debug.keystore" 파일에 저장되어 있습니다. 'debug.keystore' 파일은 이클립스가 필요시 자동으로 생성해줍니다. 이클립스 Preferences 창의 Android > Build 메뉴를 보면, 이 파일이 기본 디버그 키저장소(Default debug keystore) 파일로 설정되어 있는 것을 확인할 수 있습니다.



네이티브 애플리케이션은 좀 다르다
그럼 네이티브 애플리케이션도 이클립스가 자동생성한 debug.keystore 파일로 서명해서 설치가 될까요? 일단 debug.keystore 파일로 서명된 네이티브 Calculator 애플리케이션을 설치해보죠. 

D:\Android\Calculator\bin>adb install Calculator.apk
789 KB/s (88433 bytes in 0.109s)
        pkg: /data/local/tmp/Calculator.apk
Failure [INSTALL_FAILED_ALREADY_EXISTS]
 
이미 동일한 패키지가 존재한다며 에러가 떨어집니다. -r 옵션을 추가해서 재설치를 시도해봅니다.

D:\Android\Calculator\bin>adb install -r Calculator.apk
425 KB/s (88433 bytes in 0.203s)
        pkg: /data/local/tmp/Calculator.apk
Failure [INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES]

일치하지 않는 인증서 에러가 발생하면서 설치되지 않네요. 그러면 우리가 원래 하던대로 이클립스에서 [Run As > Android Application]을 실행해보겠습니다.

[2010-04-02 16:54:10 - Calculator]Android Launch!
[2010-04-02 16:54:10 - Calculator]adb is running normally.
[2010-04-02 16:54:10 - Calculator]Performing com.android.calculator2.Calculator activity launch
[2010-04-02 16:54:10 - Calculator]Automatic Target Mode: using existing emulator 'emulator-5554' running compatible AVD 'myavd'
[2010-04-02 16:54:10 - Calculator]WARNING: Application does not specify an API level requirement!
[2010-04-02 16:54:10 - Calculator]Device API version is 7 (Android 2.1)
[2010-04-02 16:54:10 - Calculator]Uploading Calculator.apk onto device 'emulator-5554'
[2010-04-02 16:54:10 - Calculator]Installing Calculator.apk...
[2010-04-02 16:54:13 - Calculator]Re-installation failed due to different application signatures.
[2010-04-02 16:54:13 - Calculator]You must perform a full uninstall of the application. WARNING: This will remove the application data!
[2010-04-02 16:54:13 - Calculator]Please execute 'adb uninstall com.android.calculator2' in a shell.
[2010-04-02 16:54:13 - Calculator]Launch canceled!

역시 애플리케이션 시그너쳐가 다르다며 재설치가 실패합니다. 이로부터 우리는 타겟에 내장되어 있는 네이티브 애플리케이션은 이클립스가 생성하는 debug.keystore를 통해 서명된 것이 아니라 다른 인증서로 서명되었음을 알 수 있습니다. 

네이티브 애플리케이션 서명용 테스트 키
MYDROID/build/target/product/security/ 에는 시스템 패키지(네이티브 애플리케이션)들을 '디버그 모드'로 서명하기 위한 4가지의 준비된 표준 테스트 키가 있습니다. 이것들은 개발 단계에서 사용되며, 에뮬레이터에 내장된 네이티브 애플리케이션은 안드로이드 소스 full 빌드 중에 이 중 한가지 키로 서명이 됩니다.

- media.pk8 , media.x509.pem
- platform.pk8 , platform.x509.pem
- shared.pk8 , shared.x509.pem
- testkey.pk8 , testkey.x509.pem

4가지 키에 대한 간략한 설명은 다음과 같습니다(README 파일 참조).
  • testkey -- a generic key for packages that do not otherwise specify a key.
  • platform -- a test key for packages that are part of the core platform.
  • shared -- a test key for things that are shared in the home/contacts process.
  • media -- a test key for packages that are part of the media/download system.

네이티브 애플리케이션이 어떤 테스트 키로 서명되는지는 해당 애플리케이션 소스 루트의 Android.mk를 보면 알 수 있습니다. 네이티브 Contacts 애플리케이션의 Android.mk 파일을 보면 LOCAL_CERTIFICATE := shared 로 설정돼있습니다. 즉 shared 테스트 키로 서명을 한다는 것이죠.

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
LOCAL_PACKAGE_NAME := Contacts
LOCAL_CERTIFICATE := shared
include $(BUILD_PACKAGE)
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

Calculator의 Android.mk를 보면 LOCAL_CERTIFICATE 변수가 정의돼 있지 않은데, 그러면 기본적으로 testkey 키로 서명하게 됩니다.

네이티브 애플리케이션 자동 서명용 디버그 키저장소 만들기
에뮬레이터에 내장된 네이티브 애플리케이션이 어떤 키/인증서로 서명되었는지 알았으니, 커스텀 디버그 키저장소(Custom debug keystore) 파일을 만들고, 이것을 이클립스에 등록하여 이클립스가 자동으로 네이티브 애플리케이션에 서명하도록 할 수 있습니다.
키저장소를 만들기 전에 알아둘 사항이 있는데, 생성된 java keystore 파일을 이클립스에서 사용하기 위해서는 반드시 alias는 androiddebugkey, password는 android이어야 한다는 겁니다. 그리고 openssl 과 JDK(1.6 권장)가 설치돼 있어야 합니다.
자 그럼, testkey.pk8 및 testkey.x509.pem 파일로부터 testkey.jks 파일을 만들어봅시다. 

  • 키 파일 : testkey.pk8
  • 인증서 파일 : testkey.x509.pem
  • 키 알리아스 : androiddebugkey
  • 키 패스워드 : android
  • 키저장소 패스워드 : android
  • 생성할 키저장소 파일 : testkey.jks

1. PK8 유형의 키 파일을 PEM 유형 키로 변환

$ openssl pkcs8 -inform DER -nocrypt -in testkey.pk8 -out testkey.pem

2. 키와 인증서를 포함하는 PKCS#12 포맷의 저장소 생성

$ openssl pkcs12 -export -in testkey.x509.pem -inkey testkey.pem -out testkey.p12 -password pass:android
-name androiddebugkey

3. PKCS#12 포맷 저장소 파일을 자바 키저장소 포맷으로 변환
(1) JDK 1.5인 경우 jetty 라이브러리에 포함된 PKCS12Import 클래스를 이용

$ java -classpath jetty-core-6.1.14.jar org.mortbay.jetty.security.PKCS12Import testkey.p12 testkey.jks 

(2) JDK 1.6인 경우 JDK에서 제공하는 keytool을 이용

$ keytool -importkeystore -deststorepass android -destkeystore testkey.jks -srckeystore testkey.p12
-srcstoretype PKCS12 -srcstorepass android

* 참고로 위의 1 ~ 3까지의 작업을 단순화시킨 keytool-importkeypair라는 스크립트가 있습니다. 아래와 같이 사용합니다

$ keytool-importkeypair -k testkey.jks -p android -pk8 testkey.pk8 -cert testkey.x509.pem -alias androiddebugkey

드디어 네이티브 애플리케이션을 이클립스를 통해 자동으로 디버그 모드 서명하기 위한 키저장소 파일을 만들었습니다.

이클립스에 커스텀 디버그 키저장소 파일 설정하기
생성한 키저장소 파일 testkey.jks를 적당한 곳에 두고 이클립스 Preferences 창의 Android > Build 메뉴에서 커스텀 디버그 키저장소(Custom debug keystore) 필드에 설정해줍니다.



OK 버튼을 누르고 아까 설치 실패했던 Calculator 프로젝트에 대해서 [Run As > Android Application]을 다시 실행합니다.

[2010-03-29 13:30:31 - Calculator]Uploading Calculator.apk onto device 'emulator-5554'
[2010-03-29 13:30:32 - Calculator]Installing Calculator.apk...
[2010-03-29 13:30:36 - Calculator]Success!
[2010-03-29 13:30:36 - Calculator]Starting activity com.android.calculator2.Calculator on device
[2010-03-29 13:30:41 - Calculator]ActivityManager: Starting: Intent { cmp=com.android.calculator2/.Calculator }

성공이네요. 이제 우리는 (이클립스 환경에서) 네이티브 애플리케이션도 평범한 유저 애플리케이션처럼 서명 작업을 의식하지 않고, Run As 또는 Debug As > Android Application을 실행하면서 자연스럽게 개발/디버깅/테스트할 수 있게 되었습니다.

Posted by 에코지오
,


네이티브 애플리케이션(Native Application)

  • 내장 애플리케이션(Built-in Application) 또는 시스템 애플리케이션(System Application) 등으로 불림
  • 주로 제조사에서 개발되어, 디바이스(or 에뮬레이터)에 내장된 상태로 제공됨
  • Contacts, Browser, Phone, Camera, Email, Gallery 등(전체 목록은 안드로이드 풀소스의 packages 디렉토리 참조)
  • 디바이스의 /system/app에 설치됨 : ex) /system/app/Contacts.apk
  • 보통 안드로이드 full 소스 빌드시 함께 빌드되며 이 과정에서 별도의 인증서로 서명됨
  • 네이티브 애플리케이션을 디버그 모드로 서명하기 위한 인증서들은 MYDROID/build/target/product/security에 있음


유저 애플리케이션(User Application)

  • 일반적으로 이클립스 IDE 환경에서 새로운 Android Application 프로젝트로 개발되는 애플리케이션들임
  • 사용자에 의해 다운로드되어 설치됨
  • 디바이스의 /data/app에 [패키지명].apk 형태로 설치됨 : ex) /data/app/com.mycompany.myapp.apk
  • 대개 개발/테스트 단계에서는 이클립스 ADT플러그인이 생성해주는 Default Debug Keystore로 서명됨
  • Default Debug Keystore 파일 : USERHOME/.android/debug.keystore
Posted by 에코지오
,

애플리케이션에서 사용하는 SQLite DB의 table 구조나 data를 확인하는 3가지 방법을 정리해봅니다.

1. sqlite 프롬프트 이용
명령어 날리는게 귀찮지만 sqlite 활용의 기본이니 알아두면 좋습니다. 이 방법은 직접 디바이스 내부 DB에 접속하여 작업 가능하므로 DB 파일을 로컬로 복사할 필요가 없습니다.

자세한 이용 방법은 커니님의 글 참조 : http://androidhuman.tistory.com/entry/테이터베이스-그-속이-궁금하다

2. SQLite 클라이언트 툴 이용
SQLite Database Browser 같은 SQLite DB 전용 클라이언트 소프트웨어를 이용하여 DB 내용을 볼 수 있습니다.

(1) 클라이언트 SW 설치
- SQLite Database Browser : UI가 수수함. 주로 데이터 조회 기능 제공.
- SQLite Developer Lite : UI가 세련됨. 테이블/인덱스 외에 뷰/트리거도 조회. 테이블 관리 등 여러가지 기능 제공.

(2) DB 파일 꺼내기
디바이스 or 에뮬레이터의 내부 DB 파일(*.db)을 로컬로 꺼냅니다. 예를들어 Contacts Provider가 사용하는 DB파일을 C:\로 복사해보죠.

$ adb pull /data/data/com.android.providers.contacts/databases/contacts2.db C:/contacts2.db

(3) 꺼낸 DB 파일을 클라이언트 툴로 오픈
SQLite 클라이언트 툴로 오픈하여 DB 구조와 데이터를 확인합니다.





* 타겟 시스템의 바뀐 DB 내용을 확인하고자 한다면, DB 파일 꺼내는 작업을 반복해서 해주어야 하므로 DDMS의 File Explorer보다는 파일 꺼내는 명령을 배치파일로 만들어두고 실행하는 것이 편리합니다. 보통은 DB 파일을 꺼내고 툴로 오픈하는 명령을 하나의 배치파일로 만들어두고 활용합니다.

3. 이클립스 DB 클라이언트 플러그인 이용
SQLite 클라이언트 툴을 설치하는게 귀찮거나 이클립스 외에 다른 프로그램을 띄우는게 싫다면, 이클립스 안에서 SQLite DB를 볼 수 있게 세팅해주면 되겠습니다. 개인적으로 이 방법을 선호합니다.(그러나 이런 이클립스 플러그인들은 JDBC를 이용하기 때문에 전용 SW보다는 DB 관리 기능이 부족합니다.)

(1) DB 클라이언트 플러그인 설치
SQL Explorer나 Quantum DB 같은 DB 클라이언트 플러그인을 설치합니다.

(2) JDBC 연결 세팅
JDBC 드라이버 : http://www.zentus.com/sqlitejdbc/ 에서 구할 수 있습니다.
JDBC URL 형식 : jdbc:sqlite:/[로컬 DB파일 경로] (예를들어, jdbc:sqlite:/C:/contacts.db )

(3) DB 플러그인에서 DB 연결하여 내용조회
DB 파일을 JDBC URL에 설정된 고정된 경로로 꺼내고, DB 플러그인에서 DB에 연결하여 내용을 확인합니다.



* 2번 방법과 마찬가지로 내부 DB 변경시마다 로컬로 DB파일 꺼내는 작업을 반복해야 하므로, 파일 꺼내는 배치파일 or 명령을 이클립스 외부프로그램(External Tools)으로 등록시켜서 실행하면 편리합니다.



참고 : SQLite 데이터베이스의 DDL 쿼리 덤프 뜨기
sqlite에서 제공하는 .dump 명령어를 사용합니다. (table/index/trigger CREATE 문과 data INSERT 문이 출력됨)

$ sqlite3  C:/contacts.db  .dump > C:/contacts.ddl
Posted by 에코지오
,