2012/11/18

Designing Beautiful Apps without Designer - Google HackFair 세션


어제 오늘(2012년 11월 17-18일) 구글 핵페어가 있었습니다. 많은 세션들이 있었는데 18일 세션중에 구글에서 근무하는 UX디자이너분 (Tony Kim)이 진행하신 세션이 기억에 남습니다.  세션을 들으면서 인상적인 내용만 메모차원에서 남겨봅니다. 추후에 비디오가 공개된다고 하니 한번 꼭 들어보세요!

[추가 2012/12/10]
발표자 분이 내용정리를 해주셨습니다. 아래 링크에서 확인하세요~
http://uxfactory.com/921

[추가]
프리젠테이션 파일이 공개되었습니다.

구글은 엔지니어의 천국, 아시아 ux 직군 직원수가 1자리수!!

디자이너가 참여하는 프로젝트를 럭셔리 프로젝트라고 부를 정도로 디자이너가 참여하지 않는 프로젝트가 많다.

구글이 실패한 플젝들을 보면
buzz, answers, dodgeball, wave,
google x, notebook 등등등..

이중 Wave를 보면 기능은 정말 많았다. 그래서 사용자들이 이걸 어떻게 활용해야할지 혼란스러워했다.
너무 많은 feature를 가진 앱은 실패하기 쉽다.



그럼 과연 좋은 앱이란?

제대로된 1개의 기능만 제공하는 것!

10가지의 구글 디자인 원칙
1. Useful
2. Fast :milisecond 단위의 가이드를 가지고 있다. 버튼 응답속도는 얼마 안에..
3. Simple
4. Engaging
5. Innovate
6. Universal
7. Profitable
8. Beautiful
9. Trustworthy
10. Pesonable ; Add a human touch.

Cafe studies : 구글 방문자들에게 테스트
Lab 
Field : 실 환경에서 테스트(가정방문)
AB테스트 : log data분석

앱이나 서비스의 응답속도
0.1초 : 잘돌아가고 있다고 느끼는 시간
1초 : 돌아가고  쓸만해
10초 : 애라이 못쓰겠다.

구글에서는 밀리세컨드 단위의 가이드 라인을 가지고 있다!!

그렇다면 과연 디자이너 없이 어떻게 개발해야할까?
1.  Tackle one use case only
2.. Kill all nice-to-have features - UX디자이너의 사명. 
3. one-bite 한입에 쏙 들어갈 정도로 기능을 축소하라?
4. show it to mother 엄마에게 보여줘라 -> 비IT 인에게 Feedback을 받는게 매우 효과적이다. 

엘리베이터 피치 - 60초안에 그 플젝을 설명할 수 있어야한다.
가족이나 친지에게 설명해본다. 

구체적인 실천 방법으로는
A. 디자이너랑 점심먹기. 밥을 사주면서 물어본다.
B. Shrink, Hide, Embody 작게, 안보이게, 상징적이게
C. 디자인 가이드 문서읽기 (안드로이드 디자인 가이드, 아이폰 디자인 가이드 필독!!)
D. 디자인 패턴을 사용해라. (많은 사이트들이 있다. http://www.mobile-patterns.com/ )

2012/09/18

안드로이드 개발자 간담회 - Definitive Android Design

9월 17일 저녁 안드로이드 개발자 간담회가 구글코리아에서 있었습니다. 이 간담회에는 아시아지역의 안드로이드 Developer Advocate들이 국내의 안드로이드 개발자들을 대상으로 여러 주제에 관해 세션을 진행했습니다.

그 중 Definitive Android Design 세션의 내용을 좀 자세히 정리해봅니다.

Definitive Android Design


이 세션은 안드로이드의 다양한 화면 구성에 대응하는 방법에 대한 전반적인 기술정보를 공유하는 자리였습니다. 이미 많은 내용들이 안드로이드 디자인가이드 문서에 공개되어 있고 커뮤니티에 의해 한글화된 문서 도 있어 많은 분들이 알고 계신 내용이지만 총정리를 해주더군요!

안드로이드 개발자들은 꼭 공부하고 기억해야할 내용입니다.

Devices and Displays

안드로이드는 이제 많은 기기에서 사용됩니다. 그 기기들은 매우 다양한 화면 크기와 형태를 가지고 있습니다. 각각의 단말에 일일히 대응하는것은 매우 어려운 일이 되겠지만 안드로이드 프래임웍에서는 이를 쉽게 만들어주는 많은 기능을 이미 가지고 있습니다. 


DIP(device independent pixel)를 사용하자.

초기에 안드로이드 개발되는 앱들이 dp단위 대산 px단위를 사용해 다양한 단말화면에서 화면이 엉망으로 표시되는 경우가 종종 있었습니다. dp단위를 사용하면 다양한 단말에서 동일한 크기의 버튼, 이미지를 기대할 수 있습니다. 아래 그림은 각각의 dpi 에서 Baseline안에 표시되기에 필요한 이미지의 크기를 나타내 주고 있습니다. 


안드로이드 프래임웍에서는 특정 dpi의 이미지가 다른 dpi 단말에서 보여지게 되는 경우 이미지를 자동으로 Scale up하거나 Scale down하여 화면에 보여줍니다. Scale up이되는 경우에는 아이콘이 좀 뭉개지는 현상이 발생하기도 하고 또 매번 사용시마다 단말상에서 Scaling 작업이 이루어지게되므로 이를 방지하기 위해 각각의 dpi 이미지를 넣어주는 것도 좋은 방법이라고 권고하였습니다. 성능이 낮은 단말에서 이미지 스캐일링 까지 해야 한다면 성능이 더 안좋겠죠~

Metrics

폰과 타블랫의 구분은 어떻게 할까요? 아래 그림을 한번 보세요.

안드로이드 3.2 이상에서는 Smallest width 600dp(sw600dp) 가 타블랫의 기준이 되고 Android 3.2 미만에서는 largexlarge가 타블랫의 기준이 됩니다.

터치가 가능한 UI요소를 화면상에 배치할때는 48dp 정도, 즉 실제 기기에서 ~9mm 정도의 영역을 사용하는것이 좋습니다.
또한 각각 요소들의 각격은 8dp정도가 적절합니다. (위 버튼에서는 상하에 4dp씩의 여백을 사용합니다.)

폰의 경우 한손으로 쥐는 경우가 있는데 이런 경우에 터치 오동장을 방지하기 위해 사이드에 16dp 정도의 빈 영역을 넣어주는것이 좋을 것이라고 합니다.


Action Bar

액션바는 안드로이드 3.0(허니콤) 이상에서 추가되 기존의 하드웨어 메뉴버튼을 대체하고 사용자에서 편리함을 주기위한 화면 구성요소입니다.


위 그림처럼 액션바는 크게 4가지로 구성됩니다.
  1. App icon
  2. View control
  3. Action buttons
  4. Action overflow
App icon은 앱의 특성을 아이콘을 통해 보여주는 공간이고 액션바에서는 Up동작을 위한 공간으로도 활용됩니다. Up버튼에 대한 설명은 탐색 패턴을 보시길 바랍니다.

View control은 앱이 가진 여러가지 뷰를 전환할 수 있는 컨트롤을 포함합니다. 드롭다운 메뉴나 탭 컨트롤등을 사용할 수 있습니다.

Action Buttons은 앱이 수행할 수 있는 중요한 액션들을 포함합니다. 공간이 없는 경우 자동으로 Action overflow쪽에 포함됩니다. 
Action overflow 는 자주 사용되지 않는 액션들이 표시됩니다. 위의 그림처럼 가로모드시에 공간이 충분할 때는 많은 Action item들이 나타나고 설정을 통해서 표시 유무를 지정할 수 있습니다.

Back button compatibility

하드웨어 메뉴버튼이 존재하는 경우(갤s3) Action overflow메뉴는 나타나지 않고 예전 Android단말을 대상으로한(targetsdk로 지정)앱에서는 가상의  메뉴버튼이 하단 시스템메뉴의 오른쪽 부분에 나타나게됩니다.

Expanded layout

JB에 들어오면서 Notification이 확장되어 다양한 레이아웃을 지원할 수 있게 되었습니다. 


이 알림을 이용할때는 지켜야하는 가이드라인도 설명해주었지만 너무 길어서 생략! 
하지만 꼭 읽어보세요~

Navigation

앞서 Action Bar에서 App icon이 Up 동작으로 사용할 수 있다고 했는데 Up동작은 다음과 같이 서로 다른 레벨로 탐색이 이용됩니다.
 Conversation 3 detail화면에서 Back버튼을 누르면 2 화면으로 가지만 Up버튼이 눌려진 경우 상위 리스트 화면으로 이동해야합니다.  또한 Back버튼은 앱을 벗어 날 수 있지만 Up버튼으로는 앱을 벗어날 수 없다는 것도 꼭 기억해두어야 할 특징입니다.

Fragment

Fragment는 재사용가능한 화면 구성요소로 각 영역별로 layout을 관리할 수 있는 장점이 있습니다. Support library를 통해 API 4 레벨부터 사용이 가능합니다. (자세한 정보는 제 블로그인 요기를 참고하시면 좋습니다. :)

Pure Android

안드로이드에서 제공하는 아이콘이나 버튼들을 아이폰이나 윈도우폰의 리소스를 사용하는 경우가 있습니다. 이렇게 되면 사용자들은 앱 사용시에 혼란이 오게됩니다. 익숙한 화면을 보여주는것이 앱을 쉽게 사용하게 하는 방법이 됩니다. 이와 더불어 하면 안좋은 것과 좋은 것에 대해서 다음과 같이 꼭집어서 설명해주었습니다.

하면 안되는 것들!
  • 다른 플래폼(아이폰, 윈도폰)의 UI를 차용한다.
  • 플래폼의 특성을 타는 아이콘을 사용한다.
  • 하단 탭바를 사용한다. (터치시 백버튼이 눌려질수 있다!!) 
  • 아이폰처럼 Labled 백버튼을 사용한다.
  • 아이폰처럼 설정에서 > 를 사용해 상세설정으로 들어가도록 한다.
해야 되는 것들!
  • 액션바를 쓴다.
  • Build intelligent context-aware app
  • 적절한 시점에 미리 데이터를 로딩해 놓는다.
  • Offline 모드를 지원한다.

여러 주제가 있었지만 개발자입장에서 가장 알찬 주제가 아니었을까 생각이 듭니다.
이런 기회가 자주 있었으면 참~ 좋겠습니다.

2012/08/14

Fragment는 왜 만들어졌을까요?

아래내용은 
"Google I/O 2012 - So You've Read the Design Guide; Now What"
세션에 나온 Fragment에 관한 정보를 정리한 것입니다.

Activity와 View를 가지고도 Dynamic한 UI를 만들 수 있습니다. View와 Activity를 아래와 같이 구성한다고 생각해봅시다. 화면 구성요소를 ListView와 DetailView로 구분하고 이를 담고 있을 Activity를 생성합니다.. Single-Pane화면에서는 두개의 Activity가 사용되고 Dual-Pane구성에서는 하나의 Activity를 사용합니다.
Activity+View를 사용한 구성

이렇게 구성되 있는 상태에서 카메라 기능을 사용한다고 생각해 봅시다.
카메라 기능을 사용하기 위해서는 아래와 같은 코드가 필요합니다.

Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);   startActivityForResult(camera, RESULT_PICTURE_RESULT);

이런 식으로 startActivityForResult를 호출해 onActivityResult를 통해서 받은 데이터를 처리하게 될것입니다.

Activity+View를 사용한 구성에서는 위와 같은 코드가 View의 내부에 위치하게 될겁니다.(View코드를 재활용한다고 했을때요!) 하지만 코드에서 필요한 중요 기능들은 Activity의 내부에 포함되어 있습니다. ( startActivityForResult나 onActivityResult함수)

위의 그림과 같은 구성에서는 그 기능들이 ListActivity와 DetailActivity 의 onActivity에서 View로 이벤트를 위임해주는 구현이 각각 들어가야합니다. 이것은 반복적이고 매우 귀찮은 작업입니다.

또 화면별 메뉴구성을 다르게하기 위한 코드(onOptionMenuXXX 들)나 Activity LifeCycle에 의존적인 기능들, 데이터를 가져오거나 저장하기 위한 코드들을 현재 화면구성에 맞춰서 동작하게 하기위해서는 이벤트를 위임해주는 기능을 구현해주어야합니다.(ListActivity와 DetailActivity모두에!!)

이렇게 Multi-pane화면을 지원하기 위해 구현을 하다보면 Activity에선 쉽게할 수 있는 작업들을 View쪽에서 해주기 위해 귀찮고 반복적인 작업이 반복됩니다. 이를 피하기 위해 Fragment는 만들어졌습니다.

위에서 구현해야했던 모든 기능들은 이제 Fragment내부에 구현하면 됩니다. 다음과 같은 구성이 되겠죠.
Fragment를 사용한 구성
이제 우리는 기능 구현코드들을 Fragment로 모으고 귀찮은 위임작업들을 하지 않고도 쉽게 Single-Pane, Dual-Pane화면을 지원할 수 있게 되었습니다. 야호!

Fragment는 Activity가 가진 많은 callback을 가지고 있고 Activity Lifecycle에 맞춰 그 callback들이 호출됩니다.
참 쉽죠? :)


2012/07/19

Nexus 7은 흥미로운 화면크기를 가졌습니다.

안드로이드 프래임웍의 어머니인 Dianne Hackborn
https://plus.google.com/105051985738280261832/posts/6eWwQvFGLV8 에 대한 번역글 입니다.

Nexus 7은 흥미로운 화면크기를 가졌습니다.


  • 7 인치.
  • 800x1280.
  • "tvdpi" density (수치로 보면 213).
  • dp단위로는 600 x 961


먼저 화면크기에 대해 이야기해보죠. raw해상도를 무시하면 이것은 보통의 7인치 타블랫과 마찬가지가지인 7" 타블랫입니다. 600x1024 화면을 가지는 몇몇 7"타블랫이 있긴한데 그것들은 다른 density(mdpi)를 가지고 있습니다. Density로만 따지면 우린 동일한 화면 공간을 가지고 있습니다. 600x961 또는 600x1024는 각각 16:10 또는 16:9 화면의 차이일 뿐입니다.



가장 크게보면, 최신 안드로이드 화면을 분류하는 기준인 "작은 화면 폭"의 정의의 측면에서 이들은 모두 -sw600dp입니다.

몇몇 분들이 Nexus 7인 10"UI의 화면 사이즈를 그져 화면 크기만 줄인게 아니다라는 글을 남기셨네요. 어느 정도 사실입니다. 물론 큰 화면의 phone UI도 아닙니다. 시스템과 앱에서는 각각 가장 최적으로 동작하는 UI를 사용합니다. 예를 들어 시스템 UI(Status bar나 Navigation bar, 설정화면)에서는 600dp화면에서 너무 조밀하기 때문에 Phone UI를 사용합니다. 다른 앱들은 타블랫 UI를 섞어 사용합니다. -- 예를 들면 Gmail앱은 대화목록에서는 타블랫 UI를 사용하고 메시지 화면에서는 가로모드, 세로모드에 따라서 각각 폰과 같은 단일 pane UI, 타블랫과 같은 dual-pane 을 사용합니다.

기존의 PhoneUI을 확대시켜 큰 화면을 지원하려는 개발자에게는 이것은 화면 구성의 큰 변혁이 일어나야 한다는 걸 의미합니다. 그리고 layout 담당자에게 모든 사이즈를 살펴보도록 해야합니다. 만약 UI가 600dp 화면에 적합한 크기라면 -sw600dp를 사용하세요. 만약 크거나 작은 공간이 필요하다면 다른 width를 사용하세요. 현재 실제 width에 맞춰서 동적으로 화면을 전환할 수(화면회전간에 변경되는) 있습니다. fragments가 그럼 화면 구성을 구현하는데 상당한 도움이 될껍니다.


이제 화면 density 에 대해 알아볼까요. 전 tvdpi 에 대해 많은 개발자들이 "이건 머지?!?"란 반응에 놀랐어요. 이 density는 이미 TV 화면 지원을 위해 작년에 소개되었어요. http://developer.android.com/reference/android/util/DisplayMetrics.html#DENSITY_TV

TV에서 xhdpi 는 1080p 출력을 위해 사용됩니다.(이것은 사용자가 TV에서 어느정도 떨어져있다는것을 가정에서 UI를 설계하게 합니다.) 그리고 tvdpi는 720p 화면에서 같은 UI크기를 표현하기 위해 추가되었습니다. 이미 알려진대로 이 density는 800x1280 7"화면과 같습니다. : 600x1024에 mdpi(160dp)이면 160*(800/600) = 약 213dpi 이죠.

앱개발자 들의 다음 리엑션은 아마도 "머? 또 다른 density를 지원해야한다고??" 일겁니다. 다행이도 그럴 필요는 없습니다. 우리는 tvdpi를 보조 density로 생각합니다. -- 호환 디바이스를 위해 중요하지만 개발자들이 이를 위한 리소르를 따로 만드는것을 장려하지 않습니다.이미 Android의 density scaling이 이러한 임이의 density를 지원하도록 설계되었기 때문에 모든 UI 설계에 density의 개념을 포함시키고 UI구성요소의 pixel-accurate 배치를 layout manager를  통하도록  함으로써 별도의 작업없이 이 해상도에 대한 지원이 가능합니다. 

물론 모든 가능한 density에 대해 bitmap을 각각 제공할 필요도 없습니다. Android는 bitmap을 현재의 density 에 맞도록 적절히 scaling합니다(보통 읽혀지는 시점에). 모든 layout의 단위 또한 scale 될수 있도록 dp단위로 제공되고 이를 화면상의 배치를 위해 layout manager가 pixel 단위를 사용합니다.(density에 따라 scaled된 이후에) 폰트크기 또한 간단히 scale되고 해상도에 맞춰 그려집니다. 레이아웃이 pixel로 처리된 후 문자의 크기는 hinting으로 인한 에러를 줄이기 위해 최종 pixel크기 기준으로 계산됩니다.


만약 bitmap이 의도하지 않았던 density로 scaled될지라도 테두리가 부드럽게 처리된 결과물을 얻을 수 있습니다. 안드로이드에서 이런 이슈를 완화시키는 몇가지 방법이 있습니다.


  • Nexus 7같은 화면의 기기는 상당히 높은 density 이기 때문에 scaling이 잘 눈에 띄지 않습니다.
  • 안드로이드는 Scale을 시킬 bitmap을 고를때 일반적으로 더 높은 density의 bitmap을 선택합니다. tvdpi 화면의 경우 보통 hdpi의 폰들을 지원하기 위해 대부분의 앱들이 포함하고 있는 hdpi 의 리소스들을 scale down시키게 됩니다.
  • 안드로이드 타블랫 UI에서는 일반 앱 아이콘보다 큰 사이즈의 아이콘을 사용합니다. 이를 위해 더 높은 density 의 아이콘을 사용하는 방식을 이용합니다. http://developer.android.com/reference/android/app/ActivityManager.html#getLauncherLargeIconDensity() 는 사용할 density를 리턴합니다. 앱의 아이콘은 산뜻한 화면의 핵심적인 요소이기고 디자인된 아이콘이 scaling없이 사용될수 있도록 density는 한단계 높은 density가 선택됩니다. (mdpi->hdpi, hdpi->xhdpi 등) 런처에서나 앱의 아이콘이 사용되는 곳에서 tvdpi 화면은 hdpi density로 지정되어 디자인된 크기가 사용됩니다.

Nexus 7 는 안드로이드 density scaling 이 얼마나 잘 동작하는지에 대한 큰 테스트였고 저는 이 결과에 매우 만족합니다. 사실 젤리빈 오픈소스 플래폼내에서 tvdpi 리소스가 사용되는 곳은 notification tray의 배경 이미지가 유일합니다. 또 그 리소스는 다른 화면 크기마다 각각의 버전이 있습니다. 이는 앱이 사용할만한 일반적인 접근법이 아닙니다. 화면에서 볼 수 있는 거의 모든것이 tvdpi 리소스 지정없이 scaling이나 기존의 hdpi 리소스를 그냥 사용하는 방식으로 충분히 처리가 가능합니다.

2012/06/18

android.support.v7.widget.GridLayout 사용하기

Android 4.0 에서 제공되기 시작한 GridLayout은 화면을 구성하는 데 매우 편리한 구성요소입니다. 하지만 사용할 수 있는 API 레벨이 14!!!
아마 왠만한 앱 개발자라면 그 아무도 GridLayout을 함부로 사용할 수는 없었을 겁니다. ㅠ.ㅠ

그런데 Support Library r7 부터 이 문제를 해결해줄 android.support.v7.widget.GridLayout 가 조용히 등장했습니다.  하지만 안드로이드 개발자 블로그에도, 개발자 사이트에서도 검색조차 잘 안되고 있는 슬픈 상황입니다.

Support라이브러리를 통해 GridLayout를 한번 사용해 볼까요?

기능

일단 기능은 http://android-developers.blogspot.kr/2011/11/new-layout-widgets-space-and-gridlayout.html 에서 말하고 있는 android.widget.GridLayout 완전히 동일합니다.

간단히 설명하면 화면을 Grid영역으로 나누고 각각의 자식요소들의 위치와 크기를 지정하는 방식으로 레이아웃을 구성하는 방법입니다.

GridLayout를 사용하면 기존에 Layout여러개를 중첩해서 구성해야했던 구조를 간단하게 구현할 수 있습니다.

내 앱 프로젝트에서 사용하기

1. ADT업데이트

먼저 ADT와 SDK Tools을 최신버전으로 업데이트 합니다. (현재 최신 버전은 r19로 GridLayout이용하기 위해서는 r17이상으로 업데이트되어야 합니다.)
(SDK가 설치된 경로는 ANDROID_SDK 라 칭합니다.)

$ANDROID_SDK/extras/android/support/v7/gridlayout/

위 경로에 안드로이드 라이브러리 프로젝트의 형태로 gridlayout support라이브러리가 자리잡고 있습니다.

2. 프로젝트 import

이클립스에서 이 경로에서 프로젝트를 import 하거나 이 디렉토리를 내 프로젝트의 적절한 경로에 복사후 import 합니다. (저의 경우 3rd-libs 라는 경로에 복사)

import 후 보여지는 내용

3. 라이브러리 프로젝트로 지정

다음과 같이 내 앱의 프로젝트 설정에서 Add 눌러 위의 library 프로젝트를 사용하도록 설정합니다.

라이브러리 프로젝트 사용설정

레이아웃 구성하기

위의 블로그 링크에서 설명하듯이 레이아웃을 구성했다면 xml에서 <GridLayout>  대신 <android.support.v7.widget.GridLayout> 을 사용하도록 변경합니다. <Space> 역시 <android.support.v7.widget.Space> 를 사용하도록 변경합니다.

그리고 GridLayout의 Attribute가 포함되어야 하기 때문에 다음과 같이 namespace를 지정하고
gridlayout과 관련된 attribute는 app:layout_column="1" 식으로 지정해줍니다.


<android.support.v7.widget.GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"


마치기

중첩된 LinearLayout으로 구성된 복잡한 구조를 GridLayout으로 쉽게 구성해 보세요. GridLayout의 소중함을 느끼실 수 있을겁니다~ :)


Ubuntu 10.04 에 sun-java6-jdk 설치하기

ubuntu에 jdk 패키지가 빠진 이후로 설치가 매우 어려워졌다.
다행히 debian쪽에는 패키지가 남아 있어서 그쪽을 사용하는 방법으로 시도해보기로 했다. 
sudo add-apt-repository "deb http://ftp.debian.org/debian squeeze main contrib non-free"
sudo apt-get update
sudo apt-get install sun-java6-jdk

이렇게 했는데 데비안 apt저장소 키가 등록이 안됬다고 나온다. 이럴땐 서버 gpg키를 받아서 등록해주자.
(AED4B06F473041FA는 위에서 나온 에러에 포함)

gpg --keyserver subkeys.pgp.net --recv-keys AED4B06F473041FA
gpg -a --export AED4B06F473041FA | sudo apt-key add -

이렇게게 했는데도 로컬 apt저장소 용량이 작다고 나온다. 좌절하지 말고 설명대로 아래와 같이 저캐시 용량을 늘려준다.

sudo vi /etc/apt/apt.conf.d/70debconf
맨 밑줄에 
APT::Cache-Limit "100000000";
추가 후에
sudo apt-get clean && sudo apt-get update --fix-missing

이렇게 삽질은 한 후에 누가 만들어 놓은 한방에 처리하는 스크립트를 찾았다. 하하하;;;


2012/05/14

Fragment 시작하기 - dfxkorea

DevFestX Korea 에서 안드로이드 Fragment에 관한 발표를 진행했습니다. 많은 분들이 관심을 보여주시고 발표후 직접오셔서 많은 질문 해주셨네요. 아주 재밌는 시간이었습니다.

특히 ViewPager에 대한 관심과 ActionBarSherlock에 대해서 많은 관심을 갖고 계신것 같았습니다. 몇몇 질문에 대해서는 추가 포스팅을 통해 자세히 공유하도록 하겠습니다. :)





2012/04/17

맥 파일시스템 확장 속성 변경하기

사내 공용 프린터 드라이버는 설치할때 마다 꼭 말썽을 피운다. 설치중에 항상 오류를 내는 것이다.

몇번 패키지 내부에 들어가서 preflight, postflight, VolumeCheck 파일에 실행권한을 주고 해결하곤 했는데 이번엔 제대로 동작하지 않았다.

직접 터미널로 들어가보니 평소에 보지 못하던 @ 표시가 눈에 띄었다.
이것은 무엇일까?  검색해보니 이것은 Extended file attribute 가 존재한다는 뜻! (http://en.wikipedia.org/wiki/Extended_file_attributes)

이 속성은 ls 옵션엔 -@를 추가하면 확인이 가능하다. 확인해보니
문제의 파일들에 대해서 com.apple.quarantine 속성이 걸려있었다.
$ xattr -p com.apple.quarantine preflight
0006;4f8cf8e5;Chrome;95741EED-A78B-4BC3-931A-B76D7486172A|com.google.Chrome
이 속성은 다운로드된 파일에 대해서 다시 한번 확인을 묻는데 사용되는 속성이다.
결국 이 속성 때문에 제대로 설치가 진행되고 있지 않았던 것이다.
$ xattr -d com.apple.quarantine *
위 방법으로 속성을 제거한 후 설치에 성공!

2012/04/01

ADT업데이트(r17)후 발생하는 NoClassDefFoundError 해결하기

ADT업데이트 후 혹은 이클립스 재설치후 빌드만 다시했을 뿐인데 갑자기 멀쩡하던 앱이 죽기 시작합니다.


난 아무것도 한게 없는데 왜 이런 시련이 왔을까요? 과연 무엇이 문제일까요?

원인

이름 그대로 Class가 패키지에 함께 포함되지 않아서 발생한 문제입니다. 무엇이 이 문제를 발생시켰을 까요?
ADT가 업데이트되면서 의존성을 체크하는 루틴이 크게 변경되었습니다.(자세한 내용는 요기 참고하세요. Android 프로젝트 의존성 처리 방식 변경)

기존 jar를 추가하면서 이클립스에서 build path를 추가했던것 기억하시죠?

수동 Build Path추가
일반적인 경우 libs 폴더에 jar프로젝트를 넣어두고 이렇게 수동으로 빌드패스를 추가해서 사용해 왔습니다. 그런데 이번 ADT업데이트 이후에 Android Dependencies가 만들어지면서 libs내의 jar를 자동으로  빌드패스에 추가가 됩니다. 이 jar들은 배포시에 함께 패키징 됩니다.

그럼 아무런 문제가 없지 않느냐?
맞습니다. libs폴더에 기존에 jar파일들을 넣어 두셨다면 문제가 발생하지 않습니다. libs 대신에 lib 폴더(또는 다른폴더)에 jar를 넣어두었기 때문에 NoClassDefFoundError가 발생하게됩니다.

해결방법


1) 가장 쉽고 옳은 방법

기존에 jar가 들어있는 폴더이름을 libs 로 변경하세요.


폴더를 libs로 변경하신후 기존 ADT r16이하를 사용하는 개발자 분들을 위해서 수동으로 빌드패스를 추가해주셔도 좋습니다. 하지만 공동 개발자들의 수가 그리 많지 않다면 ADT를 r17로 업데이트 하는게 더 좋은 방법입니다. (ADT r17버전은 기존 버전보다 개선사항이 매우 많습니다.
http://developer.android.com/sdk/eclipse-adt.html , SDK Tools업데이트도 꼭 함께 해주세요.)

2) 쉽지만 안좋은 방법

안드로이드 팀에서는 libs폴더를 기본 jar들의 경로로 정해두고 있기때문에 앞으로도 ADT가 업데이트 될때 마다 이러한 문제들이 계속 발생할 수 있습니다. 지금 바꾸는 것이 좋습니다. 사정상 libs 폴더를 사용하지 못한다면(그럴 이유가 있을지 모르겠지만) 다음과 같이 수동으로 추가한 jar 빌드패스를 패키징시에 포함되도록 export시켜주시면 됩니다.

하지만 이 방법은 절대 권하지 않습니다. 결국은 ADT를 업데이트 하게 될것이고 프로젝트가 매번 엉망으로 꼬이게 되는 경험을 하게 되실 겁니다.







2012/03/28

Android 프로젝트 의존성 처리 방식 변경

이 글은 아래 링크의 대한 번역글입니다.
http://tools.android.com/recent/dealingwithdependenciesinandroidprojects

이번(r17) Android SDK 부터 안드로이드 프로젝트에서 라이브러리 의존성을 체크하는 방식이 개선되었습니다.

먼저 Ant-based 빌드 시스템과 이클립스 플러그인이 동일하게 동작하도록 변경되었습니다.

프로젝트는 소스폴더와 라이브러리 프로젝트, jar파일 의존성을 갖습니다. 이제 라이브러리 프로젝트를 project.properties 에 넣기만 하면 자동으로 다음 경로들에서 의존성을 찾아 냅니다.

  • 프로젝트의 libs/*.jar
  • 라이브러리 프로젝트의 생성물
  • 라이브러리 프로젝트의 libs/*.jar 
위 항목들과 프로젝트 소스의 컴파일 결과물이 함께 dex에서 처리되어 APK를 생성하게됩니다.

프로젝트들간에 동일한 jar를 사용하는 여러 라이브러리를 포함할 수 있기 때문에 빌드시스템은 모든 경로에서 jar를 찾아내 중복되는 jar를 제거합니다. 이로 인해 흔히 보았던 문제인 "already added"가 더 이상 발생하지 않을 것입니다.

중요한 변경사항: 라이브러리 프로젝트가 R 클래스를 생성하고 패키징 하는 방식이 변경됨!
  • 더 이상 R 클래스가 라이브러리 프로젝트의 jar 에 포함되지 않습니다.
  • 라이브러리 프로젝트는 그들이 의존하는 라이브러리 프로젝트의 R클래스를 만들어 내지 않습니다. 메인 앱 프로젝트가 라이브러리에 포함된 R클래스를 그들 자체의 R클래스와 함께 만들어 집니다.
이것은 이제 라이브러리 프로젝트가 의존하는 다른 라이브러리 프로젝트의 R클래스를 가져오지 못함을 의미합니다. 이제는 앱의 R클래스가 모든 필요한 리소르를 모두 포함하고 있기 때문에 이는 더이상  필요하지 않습니다. (주 : 라이브러리 프로젝트에서 다른 라이브러리 프로젝트의 리소스를 참고가 더이상 불가능함을 의미합니다.)

이클립스에서의 변경사항
"Library Projects" 컨테이너의 동적인 classpath는 "Android Dependencies"로 변경되고 라이브러리 프로젝트 말고도 더 많은 걸 포함하게 되었습니다.

이 컨테이너는 라이브러리 프로젝트가 참조하고 있는 Java-only 프로젝트도 찾아내 앱 프로젝트에 포함 시켜줍니다. 또 그 자바 프로젝트가 다른 자바프로젝트를 참조할 경우에도 자동으로 그 프로젝트나 jar를 찾아서 추가합니다. (사용자 라이브러리에서 참조하는 jar역시 지원됩니다.)


중요 : 이는 참조하는 프로젝트에서 참조 프로젝트가 exported로 설정되어 있는 경우에만 설정됩니다. 이 동작은 프로젝트나 jar를 build path에 추가하는 경우 기본 동작이 아닙니다.
라이브러리 프로젝트(프로젝트 내부의 libs/*.jar를 포함)는 항상 exported 됩니다. 이 동작은 Java-only 프로젝트와 그 내부의 jar에만 해당됩니다.

물론 이 경우에도 중복되는 jar는 감지되고 제거 됩니다.

의존성 해결방법

프로젝트가 동일한 jar파일을 사용하는 두개 이상의 라이브러리 프로젝트를 포함하는 경우 빌드시스템은 이를 감지하고 중복문제를 해결해야합니다.

완전한 의존성관리 시스템은 각 jar파일을 quallified 이름과 버전 값으로 그들을 구분해 내야합니다. 하지만 불행이도 안드로이드 빌드시스템은 이를 지원하는 완전한 방법을 제공하지 않습니다. (아직!)

현재는 다음의 방법에 따르는 간단한 방식을 제공하고 있습니다.

Jar파일은 파일명에 의해 구분합니다.
mylib.jar는 mylib-v2.jar와 다른 파일로 인식되며 두 파일 모드 패키징 되고 두 버전이 동일한 라이브러리의 다른 revision인 경우 "already added" 라는 dx 에러를 내게됩니다.

같은 파일명인 jar의 경우 "same version"이라 함은  파일 내용이 동일할 경우를 말합니다.
현재의 감지 시스템은 매우 기초적인 구현이기 때문에  파일 사이즈와 sha1값을 가지고  파일이 동일하다는 판단을 합니다. 만약 동일한 파일명을 가졌지만 실제 내용이 다른 jar를 라이브러리 프로젝트들이 각각 가지고 있다면 빌드 시스템은 의존성관련 에러를 내게 됩니다.
android-support-v4.jar 와 android-support-v13.jar를 위한 처리
위의 두가지 라이브러리의 경우 -v13 은 -v4의 모든 구현을 포함하고 있기 때문에 특별하게 처리됩니다. 두개의 jar가 모두 발견되는 경우 -v13의 jar만 사용됩니다.
하지만 빌드시스템이 발견하는 -v4, -v13 라이브러리가 동일한 revision 이라는 것은 판단하지 못합니다. 그러기 때문에 support라이브러리를 업데이트 해주는 경우 모든 프로젝트의 -v4, -v13 jar를 동시에 업데이트 해주시기를 권합니다.