자신이 개발한 앱이 많은 사람에게 오래도록 사랑받을 수 있도록 만드는 방법이 궁금하신가요? 효과적으로 사용자에게 ‘좋은 인상을 주고, 설치하고, 평가하게’ 하는 순환 고리를 만드는 방법은, 바로 “제품을 개선하는 것"입니다. 이는 오랜 시간에 걸쳐 입증된 확실한 방법입니다. 앱을 출시한 이후 어떻게 품질을 높일 수 있는지 앱 출시 이후 품질 개선하기에서 확인해 보세요!
앱의 품질은 설치 및 사용자 등급이나 평가, 참여, 사용자 보유 등의 측면에서 성공 여부에 장기적으로 직접적인 영향을 줍니다. 안드로이드 사용자는 고품질의 앱을 기대합니다. 핵심 앱 품질 가이드라인에서 다루는 핵심 앱 품질 기준 내용 및 관련 테스트를 통해서 기본적인 품질을 측정하실 수 있습니다. 모든 안드로이드 앱은 반드시 본 기준에 부합해야 합니다.
자기 소개를 시작으로, 오픈 소스의 장/단점과 현재 개발 관심 분야에 대해서 나누는 질의 응답시간을 가졌습니다. 학생들의 적극적인 질문과 다양한 분야에 대한 관심으로 엔지니어분들과 함께하는 Q&A 세션이 금세 지나가고, 다섯 개의 소그룹으로 나눠서 멘토와 함께 하는 점심 식사 시간을 가졌습니다.
*엔지니어 멘토들이 후배들에게 전해준 팁* 지금의 열정과 관심을 잃지 않고 지속적으로 자신의 관심분야를 찾아갈 것. 오픈 소스 커뮤니티에서 위축되지 말고 적극적으로 참여해 볼 것. 개발자로서의 기본적인 소양을 기르기 위한 노력을 할 것 - 소통 능력, 논리력, 수학 등 보다 깊이 있는 실력을 배양하기 위해서 기본에 충실할 것.
실제로 등록 이후에 과제 제출을 하기까지가 쉽지 않아 많은 학생이 과제를 완료하지 못했지만, 이번 참가 자체에 큰 의미가 있었다고 봅니다. 2013년에 있을 GCi 2013에서는 많은 한국 학생들이 등록과 함께 과제 제출까지 완료하는 더욱 적극적인 참여를 기대해 봅니다!
이를 위해서 여러 단계의 과정이 필요합니다. 전체 설명에 앞서, 짧은 버전으로 설명하자면 다음과 같습니다. > Google Play 서비스를 통해 사용 가능한 GoogleAuthUtil 클래스로 “ID Token”이라는 스트링을 받습니다. 해당 토큰을 벡엔드로 보내고 벡엔드에서는 토큰을 사용하여 빠르고 간단하게 어떤 앱이 보냈으며 사용자가 누구인지를 검증합니다.
이러한 기능은 App Engine의 새로운 Cloud Endpoints 기능과 같은 Google facilities에 내장되어 있는데, 앱/백엔드 아이덴티티를 간단한 프로그래밍 모델로 만든 것입니다. 이제 세부사항을 살펴 봅시다.
앱 등록
본 과정에서 Google API 콘솔을 꽤 많이 사용하게 될 것입니다. 이를 위해서 새로운 프로젝트를 만들어야 합니다. 하지만 읽기 편한 괜찮은 이름과 이미지로 브랜드화 한다고 해도, 해당 리소스는 본 시나리오 상에서는 사용되지 않습니다. 프로젝트가 다수의 다른 Google API에 접근할 수 있도록 승인할 수 있습니다. 하지만 해당 시나리오에서는 필요하지 않은 절차임을 거듭 말씀드립니다. 그리고 사람들을 프로젝트 멤버로 승인할 때, 관리자 기능을 부여하게 되기 때문에 신중하게 결정해야 합니다.
Client ID 만들기
프로젝트에 두 개의 서로 다른 OAuth 2.0 “Client ID”를 만들어야 합니다. 하나는 “웹 애플리케이션을 위한 Client ID”입니다. 이름 붙이기나 이미지 작업은 무시해도 됩니다. 필요한 것은 Client-ID입니다. Client ID는 9414861317621.apps.googleusercontent.com와 같은 형태를 가지고 있습니다.
그리고 다른 하나는 “안드로이드 앱을 위한 Client ID”입니다. 해당 Client ID를 만들기 위해서는 앱 패키지 이름과 인증 서명이라는 두 가지 정보를 제공해야 합니다. 패키지 이름은 AndroidManifest.xml에서 상위 “package” 속성에서 주어지는 대로 자바 스타일 리버스 DNS입니다. 예를 들면 com.example.identity와 같은 형태입니다.
앱의 인증 서명을 얻으려면, 다음과 같이 Shell 명령어를 사용하세요. $ keytool -exportcert -alias<your-key-name>-keystore <your-key-store-file>-v -list “SHA1”라고 표기된 부분을 복사해서, 개발자 콘솔 필드에 복사하고 Client ID를 생성합니다. 다시 말씀드리지만, 필요한 것은 Client ID 스크링 뿐입니다.
안드로이드 앱에서
Google Play 서비스 GoogleAuthUtil 클래스를 호출하여 ID 토큰을 받아와야 합니다. 해당 절차는 Access Token 토큰 받아오기에 설명되어 있습니다. 추가적으로 좋은 방법이 하나 있습니다. 바로 getToken(email, scope) 메소드에 scope 인자 값입니다. 해당 값은 스트링으로 audience:server:client_id:X 으로 표기되는데, X가 웹 앱을 위한 위에서 설명한 Client ID 값입니다. Client ID가 위에서 주어진 예제 값이라면 scope 인자 값은 audience:server:client_id:9414861317621.apps.googleusercontent.com가 되겠죠.
문제 해결
보통 OAuth을 요청할 때, 디바이스 사용자는 본인의 신원을 사용하여 어떤 리소스 등을 접근해도 괜찮은지 확인하는 절차를 접하게 됩니다. 하지만 이 경우에 해당 프로젝트를 제어하는 개발자와 관련 사항에 대해 사용자가 이미 동의한 상태이기 때문에 시스템에서는 scope 인자 안에 있는 서버측 Client ID를 보고, 안드로이드 앱과 동일한 프로젝트라는 것을 확인하여 사용자를 번거롭게 할 필요 없이 토큰을 주게 됩니다.
토큰 보내기
서버와 백엔드와 통신할 준비가 되면 토큰 스트링을 보내야 합니다. 가장 좋은 방법은 POST 메세지 안에 포함시켜서 보내는 것입니다. URL 파라미터로 넣을 수 있지만, 이 경우에 종종 느리게 동작할 수 있습니다. 중간 침입자가 토큰을 가로채지 못하도록 하기 위해서 반드시 HTTP 연결을 사용해야 합니다. 추가적인 통신을 주고 받을 필요가 없습니다. 백엔드에 게임 최고점을 보내는 것이라면, 추가 인자로 ID 토큰 스트링을 넣으면 됩니다.
토큰 사용하기 서버가 안드로이드 앱으로부터 토큰을 받을 때, 이를 검증하는 것이 매우 중요합니다. 이를 위해서 다음과 같은 두 단계가 필요로 합니다. 1. 실제로 Google에서 서명을 받았는지 검증한다 2. 실제로 의도된 것인지 검증한다.
ID 토큰(실제로 JSON 웹 토큰)이 앞서 말한 인증 중 하나로 서명되었는지 확인해야 합니다. 다행히 이를 위한 괜찮은 라이브러리들이 있습니다. 본 포스팅에서 Java, Ruby, PHP를 위한 설명을 해드리겠습니다. 라이브러리들은 Google 인증을 캐쉬하고 필요할 때만 리프레시할 수 있기 때문에 검증이 (거의 항상) 빠른 정적 호출입니다.
토큰 필드 검증하기
ID 토큰이 JSON 페이로드를 가지고 있으며, 서명을 인증하는 대부분의 라이브러리도 해시나 딕셔너리 등으로 전달해 준다고 밝혀졌습니다. 따라서 aud나 cid, email과 같은 지정된 필드를 검색할 수 있습니다.
첫째로, aud 필드를 보고 안드로이드 앱의 scope 인자에 포함된 스트링인 Client ID와 동일한지 확인해야 합니다. 이 단계를 절대 생략해서는 안됩니다. ID 토큰을 검증하지 않으면, 다른 개발자가 여러분의 서비스로 요청을 도용할 수도 있습니다.
선택적으로, cid라는 필드를 보고 안드로이드 앱 Client ID와 동일한지 확인할 수 있습니다. 참고로, 최상위 프로젝트에서 고유의 Client ID를 가진 여러개의 서로 다른 안드로이드 클라이언트 앱을 가질 수 있습니다.
세 가지 과정을 모두 완료했다고 가정해 봅시다. 그렇다면 다음과 같은 사항을 알 수 있습니다. 1. 토큰이 Google에서 발행되었다. 2. 페이로드의 이메일 필드에서 확인된 사용자의 디바이스로 토큰이 보내졌다.
그리고 다음 사항에 대해서 "고신뢰(high confidence)"를 가질 수 있습니다. 3. 페이로드의 cid 필드에서 Client ID로 확인된 안드로이드 앱으로 토큰을 얻었다.
비호환 및 루팅된 안드로이드 디바이스는 해당 정보를 조작할 수가 있기 때문에 Client ID만이 “고신뢰(high confidence)”를 가지고 있다. 하지만 해당 디바이스들이 가짜 Google 서명이나 디바이스 사용자 인증을 조작할 수 없다.
다음 단계는?
다음은 여러분의 손에 달려 있습니다. 어떤 사용자, 어떤 앱과 통신해야 하는지 알고 있기 때문에 해당 정보로 무엇을 해야할지는 본인에게 달려 있습니다.
코드 예제
다음은 Google 자바 라이브러리를 사용하여 ID 토큰 체커를 구현하는 자바 클래스입니다.
Daydream을 지원하는 앱은 어트랙트 모드에서 안드로이드 UI 툴킷 전체를 사용할 수 있습니다. 즉, 레이아웃, 애니메이션, 3D, 사용자 지정 뷰 등을 포함하여 앱이 현재 가지고 있는 컴포넌트를 쉽게 사용할 수 있고, 보다 잔잔한 프리젠테이션을 위해서 해당 컴포넌트들을 쉽게 조합할 수 있습니다. 또한 터치스크린 입력을 사용할 수 있기 때문에 원한다면 여러가지 인터랙티브한 경험을 제공할 수도 있습니다.
Daydream은 본인의 앱을 홍보할 수 있는 기회를 다소 제공합니다. 앱의 복잡한 면을 감추고 시각적으로 흥미있는 부분을 살려서 사용자가 앱 전체에 흥미를 느낄 수 있도록 합니다. 비디오 게임의 시선 끌기 모드 (attract mode) 처럼 말이죠.
그림 1. Google 세상보기(Google Currents)에서는 부드럽고 지속적으로 움직이는 뉴스 화면에서 화제거리를 스크롤한다.
구글 세상보기(Google Currents)는 이러한 방법으로 접근한 좋은 예입니다. Daydream으로서 시각적으로 흥미있는 화제거리를 선택하여 화면 슬라이딩으로 보여 줍니다. 화제거리를 터치하면 세상보기는 화면 전체로 해당 내용을 보여주며, 다시 터치하면 전체 실행 중인 앱에서 읽을 수 있습니다.
// Our content view will take care of animating its children. finalBouncer bouncer =newBouncer(this); bouncer.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); bouncer.setSpeed(200);// pixels/sec
// Add some views that will be bounced around. // Here I'm using ImageViews but they could be any kind of // View or ViewGroup, constructed in Java or inflated from // resources. for(int i=0; i<5; i++){ finalFrameLayout.LayoutParams lp =newFrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); finalImageView image =newImageView(this); image.setImageResource(R.drawable.android); image.setBackgroundColor(0xFF004000); bouncer.addView(image, lp); }
/** * Start the bouncing as soon as we’re on screen. */ @Override publicvoid onAttachedToWindow(){ super.onAttachedToWindow(); mAnimator.start(); }
/** * Stop animations when the view hierarchy is torn down. */ @Override publicvoid onDetachedFromWindow(){ mAnimator.cancel(); super.onDetachedFromWindow(); }
/** * Whenever a view is added, place it randomly. */ @Override publicvoid addView(View v,ViewGroup.LayoutParams lp){ super.addView(v, lp); setupView(v); }
/** * Reposition all children when the container size changes. */ @Override protectedvoid onSizeChanged (int w,int h,int oldw,int oldh){ super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; for(int i=0; i<getChildCount(); i++){ setupView(getChildAt(i)); } }
/** * Bouncing view setup: random placement, random velocity. */ privatevoid setupView(View v){ finalPointF p =newPointF(); finalfloat a =(float)(Math.random()*360); p.x = mMaxSpeed *(float)(Math.cos(a)); p.y = mMaxSpeed *(float)(Math.sin(a)); v.setTag(p); v.setX((float)(Math.random()*(mWidth - v.getWidth()))); v.setY((float)(Math.random()*(mHeight - v.getHeight()))); }
이 예제 코드로 본인이 원하는 것을 작업해서 화면에 넣어 줄 필요(간단한 그래픽이나 에러 메시지처럼) 없이 사용자에게 손쉽게 보여 줄 수 있습니다. 또한 더욱 복잡한 Daydream 프로젝트를 시작하기에도 좋은 샘플입니다.
기타 주의 사항
> 우선, 시스템에 피해를 주지 말라
Daydream은 디바이스가 충전될 때 실행된다. 하지만 Daydream이 지나치게 많은 CPU를 소모하게 되는 경우 충전이 매우 느리거나 전혀 진행되지 않을 수도 있다. 디바이스가 충전되고 있지 않음을 감지하면 시스템은 Daydream을 멈추게 만든다. 따라서 적절한 시간에 충전할수 있도록 코드에서 충분한 전력을 남겨 두도록 한다. > 화면 잠금을 준수하라
Daydream은 키가드(keyguard) 작동상에서 실행된다. 다시 말해, 민감한 콘텐츠를 보여줄 수 있는 경우라면, 사용자가 해당 콘텐츠를 제어할 수 있는 사용자 툴을 제공할 필요가 있다. 예를 들어, 포토 테이블과 포토 프레임에서는 사용자가 디스플레이될 사진을 앨범에서 선택할 수 있도록 해야한다. (당황스러운 슬라이드쇼를 피함) > 화면 밝기
Daydream에서 사용되는 장소를 판단하고 이에 따라 setScreenBright()를 사용하여 화면 밝기를 조정하라. 그리고 필요에 따라서 어둡거나 밟은 색상을 사용하라. 침대 머리맡 시계는 탁상 시계보다 어두워야 한다. 두 가지 모두에 쓰일 것이라고 판단되면 사용자에게 선택권을 주어야 한다. > 상태바 숨김 여부
많은 사용자들이 배터리 충전이나 날짜/시간 정보에 즉각적으로 접근할 수 있기를 원할 것이다. 따라서 setFullscreen() 사용을 피해야 한다. 특히 Daydream이 예술적인 측면보다 정보를 더 많이 가지고 있을 때 더욱 그렇다. Daydream은 요란스럽지 않으면서도 시간 정보와 충전 상태를 보여 줄 수 있게 “lights out”모드로 상태바를 시작할 것이다 (View.SYSTEM_UI_FLAG_LOW_PROFILE). > 언제 설정을 사용하나
일반적으로 어느정도 재량권을 가지고 Daydream 설정에 제어도구나 다이얼을 추가할 수 있다. 사실 이것은 개인화 기능이기에 사용자 편의대로 수정할 수 있도록 권장되어야 한다. 하지만 때로 심미적인 환경에서 더욱 설득력있는 경험이 나올 수 있기 때문에 소수의 세련되고 아름다운 구성 중에서 선택할 수 있도록 사용자에게 선택권을 주도록 하라 (비행기 조종석의 제어권을 모두 내어주기 보다). > 하나 이상이 될 수도 있다
설정에서 사용자에게 완전히 상이한 디스플레이 모드 사이에서 선택하도록 한다면, Daydream을 다중 DreamService 구현으로 나누라. 예를 들어 안드로이드 4.2에서 포토 갤러리는 포토 테이블과 포토 프레임 DayDream을 모두 제공한다. > 개발용 액티비티를 사용하라
대부분 안드로이드 개발 툴은 기존 안드로이드 앱 개발 및 디버깅에 최적화되어 있다. DreamService와 액티비티가 매우 흡사하기 때문에 DreamService과 동일한 콘텐츠 뷰를 호스트하는 테스트용 액티비티를 만드는 것이 유용할 수 있다. 다른 안드로이드 프로젝트처럼 IDE에서 코드를 런치하여 쉽게 테스트 할 수 있다. 자, 이제 충분히 설명 드린 것 같습니다. 여러분의 앱에 Daydream 지원을 개발할 도구가 있습니다. 여러분이 즐겁게 개발하면 사용자들도 즐길 수 있을 것입니다. 그리고 Google Play에 반짝이는 새 APK를 업로드할 때, 앱 설명을 추가하여 Daydream을 찾는 사용자들이 검색할 수 있도록 해주세요!
기타 문서 및 샘플 예제 DreamService API 문서 샘플 코드: BouncerDaydream (본 포스팅 코드 예제를 위해 완성된 프로젝트) 샘플 코드: WebView (HTML 페이지를 보여주는 Daydream) 샘플 코드: Colors (OpenGL ES 2.0 및 TextureView를 보여주는 Daydream)