본문 바로가기

TechLog

개발일기.20120121

#. 얼마 전 BITNA 앱의 안드로이드 버전 배포가 끝났다.

이로써 케냘은 [3대 앱 마켓에 동일한 앱을 혼자서 개발해 올린 개발자] 타이틀을 획득하였습니다!

ㅜㅜ 

관련 링크 : BITNA의 3대 모바일 플랫폼 진출을 자축하며(?)

일단 저지르고 보니 한편으로는 대체 내가 무슨 깡으로 이런 일을 시작한건가 ... 싶은 생각이 들긴 하는데; 시도해볼만한 가치가 있는 일이었다는 생각이 든다. 개발 지식 면에서는 일단 어떤 플랫폼이든 UDP 패킷과 계층적인 화면 요소에 대한 그리기 기능에 관련된 작업을 능숙하게 처리할 수 있게 되었다는 점에서 그 가치를 찾을 수 있었다. 하지만 그것보다도, 딱히 어떤 개발자가 무슨 모티베이션이 있다고 위 3대 모바일 플랫폼의 스타일을 모두 경험해보겠는가. -_-; 일시적이긴 하지만 시간적 여유가 있었던게 다행이라면 다행이었다.

덕분에 지난 40여일간 일정이 없는 날은 이들 앱 개발하는데 모든 시간을 쏟았는데, 초기에 UI를 다시 디자인하고 플랫폼간 호환을 위한 메시지 표준과 UDP 통신 샘플 프로그램을 만드는데 소요한 시간을 제외하면, 실제 개발 자체는 그렇게 오래 걸리지 않은 것 같다. 전자의 작업에 대충 10일 정도의 시간이 소요되고, 아이폰/윈도우 폰/안드로이드 버전을 개발하는데 대략적으로 각각 1주, 1주, 2주 정도가 소요된 것 같다.

 

#. 사실 안드로이드 버전은 그렇게 오래 걸릴 일이 아니었는데 중간에 삽질을 워낙 많이 했다.

예를 들어보자면 뭐 이런 문제들이 있었다 :

  • webview; 투명색을 배경으로 사용할 수 없는 버그, div 태그의 텍스트를 변경할 때 이미 그려진 글자가 지워지지 않아 계속 겹쳐 출력되는 버그
  • Animation 클래스를 사용해 특정 객체의 애니메이션을 수행하고 난 후, 해당 객체가 애니메이션이 끝난 위치에 실제로 존재하지 않는 것 (버그는 아니지만 뭔가 이상하다)
  • framelayout을 이용한 레이아웃 방법; view 자체에 left, top 등의 프로퍼티가 있는게 아니라 각자 레이아웃을 담당하는 클래스마다 자신만의 LayoutParams 클래스를 갖고 있고, 그 파라미터 값을 사용해서 레이아웃을 수행한다.
  • ViewGroup(=container), View, Drawable이 별도로 존재하는 당황스러운 구조; 지금은 각자 기능이 다르다는 것을 인지하고 있지만, 코드는 지저분하더라도 좀 단순한 구조를 만드는게 낫지 않았을까. 참고로 iOS에서는 View 클래스가 저 역할을 다 처리한다.
  • View가 화면에 표시되고, 다른 View에서 Invalidation이 일어나면 실질적으로 갱신이 필요없는 View에서도 invalidation 영역이 겹치면 onDraw가 반복적으로 호출된다; 이게 웬 Win32 시절 모델이여 걍!
  • 이미지 버튼을 사용하는 방식; state별로 버튼 이미지를 할당할 수 있는 기능이 있는건지 없는건지 모르겠다. 게다가 button 전체에 입힐 이미지를 사용하려면 background 프로퍼티에 값을 할당해야 한다는 것도 알고 나면 괜찮지만 모를때는 알 수가 없다.
  • visibility가 VISIBLE이 아니면 onDraw가 아예 호출되지 않는다는 걸 몰라서 한참 헤맴
  • 직접 만든 View 클래스를 UI를 구성하는 xml 파일에 추가할 때 Class(Context context), Class(Context context, AttributeSet attrs), Class(Context context, AttributeSet attrs, int defStyle) 세 가지 형태의 생성자를 구현해야 하는 점; 이것도 전혀 힌트가 없어서 ... 구현하지 않으면 inflateLayout에서 터져버린다.
  • 요소의 회전 애니메이션이 일어났을 때, 회전한 부분이 원래 요소의 사이즈 영역을 벗어날 경우(예를 들어 가로로 긴 이미지를 90도 회전해서 세로가 긴 이미지가 되었을 경우, 원래 가로로 되었을 때의 이미지 영역을 벗어나서 세로 모양이 된 부분) 해당 부분이 제대로 갱신되지 않는데 ... 이게 기기마다 갱신이 잘 되는 기기도 있고 아닌 경우도 있다. 이 뿐만이 아니라 한 요소에 setTextColor, setText, setLayoutParam(요소의 위치를 변경하기 위해) 함수를 동시에 호출했을 때, 적용되는 타이밍이 조금씩 다르기도 하다. 게다가 이것도 디바이스마다 작동이 다르다! 이를테면 옵티머스 원에서 버그를 일으키는 코드가 디자이어HD에서는 잘 돌고 막 ...
  • 모토롤라 계열 안드로이드 폰은 wifi의 MAC 주소를 얻으려고 시도할 때 wifi가 꺼져 있으면 null을 리턴하기도 한다. 사실 MAC 주소는 wifi가 켜져있는지 꺼져있는지에 상관 없이 항상 동일한 값을 갖기 때문에 굳이 이럴 필요가 없을텐데... 다른 폰들은 wifi가 꺼져 있을 때도 정상적으로 MAC 주소를 리턴한다.

... 그냥 생각난 것들만 언급해도 이 정도. 으으으 ...

 

#. 현재 아이폰, 안드로이드 버전에는 광고가 붙어 있다.

처음에 광고를 붙일 때는 수익보다도 '실제로 광고 수익이란게 얼마나 나는걸까'하는게 궁금해서 붙여 봤는데, 사실 결과는 처참하다:

루시드 폴 <사람이었네>의 가사 일부가 떠오른다.
나는 방안에 갇혀 한 달에 3달러 버는 개발자 ...

하지만 그와는 별개로, 앱의 이용 상황을 빠르게 파악할 수 있다는 점은 무척 마음에 든다. 앱을 배포하고 난 다음에 실제로 앱 다운로드 수가 늘었는지 어떻게 되었는지를 확인하려면 며칠을 기다려야 각 앱 마켓 사이트에 다운로드 수가 반영되는데, 광고를 달아놓으면 그와 관련된 통계를 금방 얻을 수 있다. (약간의 시간 지연이 있긴 하지만, 앱 마켓에 반영되는 것보다는 훨씬 빠르다) 그리고 앱을 다운받고 나서 잠깐 살펴보고 그냥 꺼버리는 경우가 있고 계속 살펴보는 경우가 있는데, 광고 노출 수는 그런 숫자까지도 반영한다고 볼 수 있기 때문이다.

사실 이런 종류의 통계를 내기 위해 코드를 삽입할 수도 있겠지만(구글 어널리틱스 모바일 버전이 있다고 들은 것 같기도?) 번거롭기도 하고, 명시적으로 뭔가 화면에 보여주질 않으면서 백그라운드에서 뭔가 하는 것도 내 성미에 안 맞고 ... 그냥 대놓고 광고 보여주는 쪽이 사용자가 '아 광고 보여주느라 뭐가 왔다갔다 하는구나'라고 인지하는데 좋을거라고 생각하고 있다. 물론 광고가 불편한 사용자도 있긴 하겠지만, 그래도 최대한 노출 안 되게 하고 있는데 좀 봐줘요 ㅜ

 

#. 아직도 할 일은 많고.

어제 StopWatch K를 디버깅해서 다시 제출했다. 치명적인 버그를 두 개나 안고 있었는데도 7개월 씩이나 업데이트를 안 하고 있었던 내 자신이 원망스러울 뿐이고 (...) 혹시나 멀티트랙 스톱워치가 필요하신 분들은 일주일 쯤 후에 배포 완료되면 받아서 한 번씩 써 보세요. 외관은 허접하지만 기능은 좋아요 'ㅅ')a

그리고 Mug 리팩토링도 해야겠고 ... 으어어