2015/05/15

맥에서 이상한 한글 폰트가 보일때

가끔 웹 브라우징중에 이상한 한글 폰트가 보여질때가 있다.

요상한 한글 폰트의 정체는?
크롬 Developer Tools 에서 살펴보니 font-family 값이 Dotum,Arial,Helvetica,"Arial Unicode MS",sans-serif 로 되어 있다. 앞에서부터 하나씩 없애보자. "Arial Unicode MS"를 지우니 예쁜(?) 기본 폰트로 보여진다.

하지만 이런 글짜를 만날때마다 이렇게 조작 할 수 없으니 폰트를 아얘 비 활성화 해보자. Font Book을 실행시켜서  "Arial Unicode MS" 폰트 찾고 상단의 체크 버튼으로 비활성화 시켜준다.

"Arial Unicode MS" 는 원래 MS에서 만든 폰트인데 Mac 10.5 부터 기본 탑재 되어 있다. Office 문서 호환때문에 라이센싱 받아 넣은 것 같다. 하지만 한글 폰트가 구리므로 Out!

2015/01/08

VIM + FISH 사용시 "e484: can't open file" 발생

VIM에서 요상한 오류가 떴다.
E484: Can't open file /var/folders/wd/kj6dxg852k54q5tqmx8g46x00000gp/T
이런 식으로 $TMPDIR로 경로에 파일을 읽지 못한다는 에러가 나오면서 다양한 명령들(vim script들)이 제대로 동작하지 않았다.

검색을 하다보니 FISH 쉘을 사용하는 경우에 이런 문제가 발생한다고 한다. FISH쉘을 사용한지가 몇달째인데 그동안 VIM을 잘 안쓰고 있어서 문제를 빨리 발견하지 못했다.

 ~/.vimrc 에 vim에서 사용할 쉘을 명시해주면 해결된다.
set shell=/bin/sh

2013/12/04

Jenkins 에서 Genymotion 사용하기

Genymotion은 VirtualBox를 사용하여 안드로이드 단말의 이미지를 구동시키는 방식으로 제공되는 안드로이드 Emulator의 대체품입니다. 이를 사용하면 실제 단말에서 테스트를 돌리는 속도보다 최대 10배정도는 빠르게 테스트를 진행할 수 있어 최근 개발자들에게 급속도로 퍼지고 있는 중입니다.

http://cyrilmottier.com/2013/06/27/a-productive-android-development-environment/

보통 Jenkins에서 Android Emulator plugin를 사용하면 안드로이드 에뮬레이터를 이용해 테스트를 진행하게 됩니다. 이를 Genymotion으로 대체하여 테스트에 사용할 수 있습니다.


준비

이 글에서는 개발자가 Gradle를 사용하는 빌드를 구성하였다는 가정으로 설명합니다. Jenkins 에서 Gradle를 사용하기 위해서는 Jenkins Plugin 설정에서 Jenkins Gradle plugin 을 미리 설치해주어야 합니다. 또한 Jenkins가 설치되어 있는 기기에 Genymotion이 설치 되어있는것으로 가정합니다. Genymotion을 설치하는 방법은 이곳 을 참고하세요.

Genymotion VM 생성

Genymotion UI를 통해 테스트에 사용할 VM을 생성합니다.


콘솔에서 다음과 같이 입력하여 생성된 VM의 정확한 명칭을 확인합니다.
$ VBoxManage list vms
"Galaxy S4 - 4.3 - API 18 - 1080x1920_1" {c9cfec96-e28c-4ff5-bbb0-2dbe7dad9090}
VM의 명칭이 "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" 인것을 확인할 수 있습니다.
이 VM을 구동시켜 테스트 가능한 기본 상태로 만들어둡니다.

  • 앱내 NDK가 arm용 so만을 포함하고 있다면 여기에서 ARM Translation 를 설치해주세요.
  • 기본 설정시 +Sewon Ann 님이 작성하신  을 참고하면 매우 유용합니다.

이후 이 상태의 snapshot을 저장합니다.
$ VBoxManage snapshot "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" take "factory"
이렇게 하면 언제든 저장된 상태로 돌아올 수 있어 동일한 테스트 환경을  유지시킬 수 있습니다.

Jenkins Job설정

일반적인 프로젝트의 Job을 추가하는 방식으로 새로운 Job을 추가합니다. 저의 경우 free-style software project를 선택했습니다. 기존에 설정된 Job이 있으면 그걸 사용하면 됩니다.


VM띄우기 설정

Build항목에 Execute shell 항목을 추가 후에 아래 내용을 추가해서 빌드전에 VM이 초기화되고 구동되도록 설정합니다.



ps | grep "Genymotion\.app/Contents/MacOS/player" | awk '{print $1}' | xargs kill
VBoxManage snapshot "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" restore "factory"
/Applications/Genymotion.app/Contents/MacOS/player --vm-name "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" &

"/Applications/Android Studio.app/sdk/platform-tools/adb" wait-for-device
echo "sdk.dir=/Applications/Android Studio.app/sdk" > local.properties
각 항목에 대한 설명을 아래와 같습니다.
  • ps | grep "Genymotion\.app/Contents/MacOS/player" | awk '{print $1}' | xargs kill
    • 기존에 VM이 떠있는 경우 이를 종료시킵니다. 
  • VBoxManage snapshot "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" restore "factory"
    • 기존에 저장되있던 snapshot으로 상태를 복원합니다.
  • /Applications/Genymotion.app/Contents/MacOS/player --vm-name "Galaxy S4 - 4.3 - API 18 - 1080x1920_1" &
    • VM을 띄웁니다. player의 경로는 사용자의 설정에 맞게 수정해야합니다.
  • "/Applications/Android Studio.app/sdk/platform-tools/adb" wait-for-device
    • adb명령을 사용해서 VM이 뜨기를 기다립니다. adb의 경로는 sdk경로에 맞게 수정 되어야 합니다.
  • echo "sdk.dir=/Applications/Android Studio.app/sdk" > local.properties
    • sdk 경로가 Jenkins마다 다를 수 있으므로 이를 local.properties 에 저장해줍니다.

빌드 및 테스트 설정

이 글에서는 Gradle빌드를 사용하므로 Gradle 명령으로 빌드와 테스트를 수행합니다.
clean build connectedCheck

Report 설정 추가

connectedCheck의 결과는 build디렉토리내의 instrumentTest-results/connected/에 저장되므로 이를 junit repoter가 처리하도록 추가합니다.
**/build/instrumentTest-results/connected/*.xml


확인하기

빌드 후에 다음처럼 예쁘게 테스트 결과가 보이는것을 확인합니다.


이제 열심히 테스트 코드를 추가하면 됩니다. -_-;

요 글은 http://blog.genymobile.com/genymotion-jenkins-android-testing/ 을 기초로 작성되었습니다.

2013/01/24

안드로이드 오픈소스 라이브러리 활용하기

지난 2013년 1월 19일에 있었던  제2회 GDG Android Korea  안드로이드 미니 컨퍼런스 발표자료를 공유합니다.

안드로이드 앱 개발시 유용하게 사용할 수 있는 오픈소스 라이브러리에 관하여 발표를 진행했습니다. :) 


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들이 호출됩니다.
참 쉽죠? :)