Outsider's Dev Story: Mobile/Android 카테고리 글 목록https://blog.outsider.ne.kr/Stay Hungry. Stay Foolish. Don't Be Satisfied.2024-03-15T16:06:03+09:00Textcube 1.10.7 : Tempo primo[Book] 안드로이드 뜻밖의 역사 - 세상을 뒤흔든 모바일 OS에 담긴 숨은 이야기Outsiderhttps://blog.outsider.ne.kr/16212022-09-14T01:58:20+09:002022-09-14T01:58:20+09:00<div>
<fieldset style="padding: 20px 5px 5px 5px;">
<legend><a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=299230041">안드로이드 뜻밖의 역사 - 세상을 뒤흔든 모바일 OS에 담긴 숨은 이야기</a></legend>
<table>
<tbody>
<tr>
<td>
<a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=299230041"><img src="//blog.outsider.ne.kr/attach/1/7513793119.jpg" width="350" height="524" alt="책 표지" title="안드로이드 뜻밖의 역사" /></a>
</td>
<td style="vertical-align: top">
<a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=299230041">안드로이드 뜻밖의 역사 - 세상을 뒤흔든 모바일 OS에 담긴 숨은 이야기</a> - ⭐⭐⭐⭐
<br>쳇 하스 지음<br>송우일 옮김<br>인사이트
</td>
</tr>
</tbody>
</table>
</fieldset>
<br>
</div>
<p>지금은 iOS와 안드로이드의 세상이 된 게 자연스럽지만, 안드로이드가 어떻게 만들어졌는지를 다룬 책이다. 지금은 애플의 제품을 거의 다 쓰고 있는 관계로 안드로이드에서는 관심이 멀어진 지 오래되었고 안드로이드 개발자도 아니지만, 안드로이드 이전부터 모바일 제품에 관심 있어서 아이폰과 안드로이드가 등장할 때도 관심 가지고 보고 있었기에 책이 나오자마자 편한 마음으로 읽어봤다.</p>
<p>아는 내용도 있지만 몰랐던 부분도 있어서 꽤 재미있게 읽었다. 아마도 안드로이드 개발을 한다면 들었던 이름도 꽤 나올 가능성이 있어서 더 재미있게 읽었을 것 같다. 안드로이드의 개발되어서 성공까지 간 과정이 자세하게 정리되어 있고 이런 의미 있는 일이 기록으로 남게 된 것만으로도 큰 가치가 있다고 생각한다. <strong>안드로이드 하면 앤디 루빈을 떠올리기 쉽지만, 이 책은 한 명의 영웅이 아니라 안드로이드를 만드는 데 관여한 사람들의 업적을 모두 설명하고 있어서 원서의 제목이 왜 "Androids: The Team That Built the Android Operating System"인지 알 수 있었고 실제로 팀에 훨씬 집중하고 있다는 느낌이다. 그래서 더 좋았다.</strong><br />
<br></p>
<h1>1부 시작</h1>
<blockquote>
<p>2003년 후반 디지털 카메라용 운영 체제를 제공하는 포토팜을 창업하고 루빈이 CEO를, 화이트가 CTO를 맡았다.</p>
</blockquote>
<blockquote>
<p>화이트는 루빈에게 '포토팜'보다 더 나은 이름을 찾아야 한다고 말했다. 루빈이 android.com이라는 도메인을 가지고 있어서 그들은 회사 이름을 안드로이드로 바꾸고 캐릭터라는 디자인 회사를 고용해 로고와 명함을 비롯한 CI를 만들게 했다.</p>
</blockquote>
<p>앤디 루빈이 카메라 운영체제를 만들기 위해서 스타트업을 만들었다는 것은 모르고 있었다. 역시 도메인 드리븐인가!!</p>
<blockquote>
<p>루빈은 카메라 운영 체제를 만들지 못했다. 그러나 스마트폰에서 카메라가 얼마나 중요한지 감안한다면 그가 가장 널리 쓰이는 카메라 운영 체제를 만들었다고 주장해 볼 수도 있을 것이다. 단지 우회적인 방법으로 만들었을 뿐이다.</p>
</blockquote>
<p>이 문장은 나한테는 꽤 울림이 있었다. 카메라 OS를 만들고 싶었지만, 주위 반응도 별로여서 하기 싫었던(?) 모바일 운영체제를 다시 만들게 되었는데 돌고 돌아 결국은 카메라 운영체제라고 해도 틀리진 않아 보인다. 세상에서 가장 많이 사진을 찍는 운영체제 중 하나니까...</p>
<blockquote>
<p>2006년까지 안드로이드 팀에 합류한 사람들은 대부분 비-팜소스, 웹티비-마이크로소프트, 데인저 중 한 회사 또는 두세 군데 회사에서 일한 적이 있다.</p>
</blockquote>
<blockquote>
<p>비와 마이크로소프트 웹티비 팀에서 일했고 나중에 안드로이드 엔지니어링 팀을 관리한 스티브 호로위츠는 말했다. "그게 이 세계에서 중요한 부분이죠. 성공보다 실패에서 더 많은 걸 배울 수 있습니다."</p>
</blockquote>
<p>BeOS를 만들던 Be, PalmOS를 만들었던 <a href="https://www.palmsource.com/">PalmSource</a>, Microsoft가 인수한 WebTV, 그리고 앤디 루빈이 창업해서 초창기 스마트폰을 만들던 데인저까지 이 회사들의 이름은 책 전반에 걸쳐서 계속 나오고 안드로이드 초창기 개발자들은 대부분 이 회사들에서 같이 일한 적이 있는 사람들이다. 그리고 안드로이드를 만들기 위해 필요한 기술에 대한 경험이 있고 또 실패한 경험도 있었기에 그 경험을 바탕으로 안드로이드가 더 잘 만들어질 수 있었던 것 같다.</p>
<p style="text-align: center;"><img src="//blog.outsider.ne.kr/attach/1/3694290065.jpg" width="750" height="562" alt="Palm Tungsten T3, Palm Pre, Nexus One" title="" /></p>
<p>나는 1990년대 말부터 모바일 기기에 관심이 많았다. 폰도 그렇지만 당시엔 PDA라는 기기(책에도 나온다)를 무척 좋아하면서 포켓PC 등이 등장하면서 스마트폰으로 넘어갈 때까지 관심 있게 보고 있었다. 위 사진은 지금도 가지고 있는 당시 기기들인데 맨 왼쪽은 내가 제일 좋아했던 PalmSource의 palm Tungsten T3이다. 가운데는 안드로이드, 아이폰과 경쟁하기 위해 Palm이 막바지에 만들었던 Palm Pre인데 여기 들어간 WebOS가 당시 사용성에선 셋 중 가장 좋았다고 생각한다. 하지만 자금력이 없는 Palm Pre는 Palm을 재기시키지 못했고 HP에 인수되었다가 LG전자에 넘어가면서 지금은 LG 스마트TV에 들어가 있는걸로 알고 있다. 맨 우측은 책에도 나오는 안드로이드의 첫 레퍼런스폰 Nexus One이다. 그때는 iPhone보다 오픈 플랫폼을 지향하는 Android가 성공할 꺼라고 생각해서 미국에서 거금을 들여와서 한참 동안 사용했었다.(하지만 이후 아이폰으로 넘어갔다.)</p>
<blockquote>
<p>삼성 미팅은 휴대전화 사업부 대표인 이기택과의 만남으로 시작됐는데 이기택은 과거 데인저와의 기회를 놓쳤는데 같은 일이 다시 일어나는 걸 바라지 않는다면서 안드로이드와 함께하는 데 관심이 있다고 말했다. 시어스는 당시 미팅 상황을 설명했다. "이기택이 그의 팀에 성사시키자고 말해서 우리는 계약이 이뤄졌다고 생각했어요. 그런데 열 명이 넘는 중간 관리자가 있는 그의 팀을 만났는데 그중 누군가가 물어보더군요. '누가 운영 체제를 만드나요?' 우리가 '스웨트랜드라는 개발자입니다'라고 말하자 그들이 웃더군요. 삼성에서는 300명이 삼성 자체 운영 체제를 만들고 있다면서요."</p>
</blockquote>
<p>Android가 시장에서 성공했을 때 앤디 루빈이 삼성도 찾아왔다던 일화가 뉴스로 많이 돌아다녔고 삼성이 이 중요한 프로젝트를 놓쳐서 아쉽다는 얘기가 많았다. 그 이야기가 책에도 나오는데 루빈이 투자받기 위해서 한창 돌아다닐 때이다. 개인적으로는 삼성이 안드로이드를 놓친 게 별로 아쉽지 않다고 생각하는 편이고 삼성이 안드로이드에 투자하거나 인수했더라면 지금의 안드로이드의 위치에 못갔을 꺼라고 생각하는 편이다. 위 일화에서도 당시 삼성의 시선을 보여주고 있다고 생각한다.</p>
<blockquote>
<p>"우리는 시연 프로그램을 보여 주었고 앤디는 발표 자료를 넘겼죠. 루빈이 수익 창출 부분을 이야기하자 래리가 발표를 끊고 이야기했던 게 기억나요. '그건 걱정 말아요. 나는 여러분이 최고의 휴대 전화를 만들기를 바랍니다. 나머지는 나중에 궁리해 보죠."</p>
</blockquote>
<p>위는 안드로이드가 구글에 인수된 뒤에 회사에서 첫 발표를 할 때 얘기다. 지금은 안드로이드로 모바일 시장을 차지한 가치의 중요성이 당연하게 느껴지지만, 당시에는 어찌될 지 예상하기 어려운 상태에서 <strong>안드로이드라는 프로젝트 혹은 팀을 다루는 구글의 태도가 많은 것을 보여준다고 생각한다</strong>.<br />
<br></p>
<h1>2부 플랫폼 구축</h1>
<blockquote>
<p>"휴대 전화 제조사가 다른 누군가의 플랫폼에 흥미를 느끼게 하기는 정말 어려웠어요. 그들은 자기 회사만을 위한 소프트웨어를 만들었고 휴대 전화가 PC와 똑같아지는 걸 무서워했어요. PC 세계는 플랫폼을 소유한 소프트웨어 판매사가 하드웨어를 일상 용품으로 만들어 버리는 곳이었으니까요."</p>
</blockquote>
<blockquote>
<p>아이폰 출시를 계기로 운영 체제가 필요해진 회사들은 자신들이 만들 수 있는 것보다 더 복잡한 뭔가를 찾고 있었고 그에 따라 좀 더 기꺼이 안드로이드와 함께 일하려고 했다.</p>
</blockquote>
<p>당시 휴대폰 시장을 다시금 생각나게 했다. 우리나라는 좀 더 통신사가 힘을 가지고 있지만 휴대폰 제조사들은 어느 정도 경직되어 있었고 그런 요구사항을 받아들이느라고 힘들어했던 일화들도 책에 나오는데 아이폰은 아이폰 자체로도 대단했지만, 아이폰의 등장은 안드로이드에게도 중요한 기회가 되었다는 점이 재미있다.</p>
<blockquote>
<p>'다이앤, 구글로 와요. 여기 정말 멋진 일들이 있어요.' 그들이 내게 넌지시 말했죠. '플랫폼이고 오픈 소스에요.' 돈 걱정할 필요가 없는 구글에서 오픈 소스 모바일 플랫폼 일을 한다니? 어떻게 싫다고 말하겠어요? 완벽했죠.</p>
</blockquote>
<blockquote>
<p>팀은 액티비티 접근 방식을 받아들이기로 결정했다. 해밀턴이 어떤 식으로 그렇게 됐는지 설명했다. "다이앤에게는 그녀가 원하는 비전이 있었고 그냥 앉아서 타이핑했죠. 그렇게 된 거에요. 그녀가 생산적이고 일을 마무리 했기 때문이죠." 이 결정 모델은 오노라토가 구현한 초기 뷰 시스템 같은 다른 부분에서도 마찬가지였다. 팀은 일을 어떻게 해야 하는지에 관해 회의를 하거나 위원회를 열거나 논쟁을 벌이는 데 시간을 많이 쓰지 않았다. 그래서 누군가가 해법을 단숨에 만들어 내면 일이 거기서부터 진행됐다.</p>
</blockquote>
<p>나도 좋아하는 접근 방법이다. (현실에서는 말처럼 쉽진 않지만) 일을 하는 사람이 결정하게 되는 구조였고 안드로이드 팀에서는 잘 동작했다.</p>
<blockquote>
<p>시장에 안드로이드 기기가 몇 가지밖에 없을 때도 팀은 장기적인 게임을 생각했고 잠재적으로 거대하고 다양한 사용자와 기기 생태계를 예상했다.</p>
</blockquote>
<blockquote>
<p>리눅스가 이미 어느 정도 발전해 있었지만 내게는 이게 더 나은 기회였는데 특정 제품에 초점을 맞추고 있어서였어요. 안드로이드는 운영 체제 명세 또는 구상이었을 뿐 아니라 제품 개발이기도 했어요. 분명한 도전이었고 성공하지 못할 수도 있었지만 우리는 시도했죠. 비전을 실현하는 가장 좋은 방법은 그 일을 돕는 것이었습니다.</p>
</blockquote>
<p>지금은 당연한 안드로이드의 결과를 당시에도 꽤 꿈꾸고 있었고 그래서 더 성공할 수 있었던 거 같다.</p>
<blockquote>
<p>로봇을 자유롭게 사용하게 한 건 획기적이었다. 이리나는 좀 더 전통적인 브랜딩 접근 방식에 대해 이야기했다. "독자성이 브랜드 가이드라인에 도입되고 정말 엄청난 제약이 따라붙죠. '로고 주위에 빈 공간이 있어야 해요. 색상은 이렇고요. ...' 로고는 신성시되죠. 그런데 이 로고가 전통적인 관념을 완전히 산산조각 냈어요." 로고의 이러한 측면은 안드로이드 팀 자체에서 나온 게 아니라 안드로이드 오픈 소스화에 대응해 이리나의 브랜딩 그룹에서 나온 것이다. "이 방식은 그 문제를 해결하려는 우리의 창의적인 아이디어였어요. 디자이너로서 업무는 제품이 무엇을 상징하는지 소통하는 것이에요. 그건 당시로서는 획기적이고 창의적인 아이디어였어요. 오픈 소스는 우리에게 제약이 아니라 해법이었고 이 로고 작업 중에서 가장 잘한 일이라고 생각해요."</p>
</blockquote>
<p>여기서 로봇은 안드로이드 로고를 말한다. 로고를 자유롭게 변형할 수 있게 했다는데(사실 몰랐지만...) 이 부분도 안드로이드가 다른 팀과 다르게 일했던 것을 느낄 수 있었다.</p>
<blockquote>
<p>티모바일의 동의를 얻기 위해 안드로이드 팀은 두 가지 일을 해야 했다. 첫째는 티모바일 네트워크가 안전할 것이라고 안심시키는 일이었고, 둘째는 안드로이드 마켓과 함께 티모바일에서 관리하는 앱 스토어를 운영할 수 있게 하는 일이었다.</p>
</blockquote>
<blockquote>
<p>울타리 친 정원은 무너졌다. 그리고 안드로이드와 티모바일은 구글 플랫폼에서 애플리케이션 스토어를 운영하기로 합의했다. 이제 스토어를 제대로 만들어야 했다.</p>
</blockquote>
<blockquote>
<p>"우리는 팜소스에서 다른 사람들이 우리 플랫폼을 사용하게 하려고 애썼는데, 어려웠던 점 한 가지는 마이크로소프트가 PC 세계에서 했던 것과 똑같은 일을 누군가가 모바일 세상에서 하지 않을지 사람들이 몹시 두려워 한 것이었어요."</p>
</blockquote>
<p>아이폰이 흔든 시장에 나온 안드로이드는 빠르게(?) 스마트폰 플랫폼으로 자리 잡기 시작한다. 아마 그 이전에는 통신사와 하기 어려웠던 협상도 가능해졌다.</p>
<blockquote>
<p>다른 회사들은 사람들이 한 일을 보고 채용하고 그 일을 더 하라고 한다. 구글은 어떤 사람인지 보고 채용하고 그들에게 필요한 일은 뭐든 하라고 한다. 그 사람들이 과거에 한 일은 그들이 무엇을 할 수 있는지 보여 주는 훌륭한 예이지만, 구글이 보기에는 그들이 할 수 있는 일로 그들을 제한할 필요는 없었다. 그렇게 해서 뛰어난 글꼴 렌더링 전문가가 구글에서 에뮬레이터를 개발하게 됐다.</p>
</blockquote>
<p>이건 좋은 거 같기도 하고 아닌 거 같기도 하고... ㅎㅎ</p>
<blockquote>
<p>안드로이드의 '결과적인 오픈 소스'[^1] 모델 그 자체에 있다. 외부 개발자는 버그를 발견해서 고쳤을 때 그 버그가 그사이에 내부 또는 향후 버전 코드에서 고쳐졌는지, 심지어 자신의 시간 전부를 들여 작업한 코드가 존재 하기는 하는지 알 방법이 없다. 코드는 향수 요구 사항이나 변경 사항에 따라 옮겨지거나 재작성되는 경향이 있다.<br />
[^1]: 결과적인 오픈 소스는 당시 안드로이드 오픈 소스 모델에 내가 붙인 용어다. 안드로이드는 오픈 소스가 됐지만 오픈 소스로 개발되지는 않았다. 그보다는 팀이 몇 달간 내부적으로 개발하고 나서 코드를 공개했다.</p>
</blockquote>
<blockquote>
<p>"나는 오픈 소스 소프트웨어에 대한 확고한 믿음이 있습니다. 오픈 소스는 전혀 상상하지 못했던 걸 만들 힘과 스스로 뭔가를 만들어 볼 수 있는 자원을 사람들에게 주기 때문이죠. 안드로이드가 나왔을 당시 상황을 보면 OEM은 iOS 라이선스를 받을 수 없었습니다. 그리고 마이크로소프트는 획일적인 경험을 제공했어요. 그와 대조적으로 안드로이드는 OEM이 매장 진열대에서 스스로를 특화할 수 있도록 빠르고 손쉽게 기능을 만들 수 있는 기회를 주었어요."</p>
</blockquote>
<blockquote>
<p>"무언가를 오픈 소스로 만드는 게 중요하다고 생각하지 않아요. 오픈 소스로 만들지 않고도 공짜로 줄 수 있죠. 나는 오픈 소스 옹호자에요. 나는 우리가 하고 있는 것보다 더 오픈 소스를 해야 한다고 생각해요. 그런데 안드로이드의 강력함이 오픈소스라는 점에 있다고 단정할 수는 없을 것 같아요. 안드로이드를 오픈 소스로 만들지 않고 공짜로 제공했더라고 성공했을 거예요."</p>
</blockquote>
<p>오픈 소스로서의 안드로이드도 많이 나오지만 안드로이드는 "결과적인 오픈 소스"라고 하고 있다. 지금은 정확히 모르지만 한때 외부 기여를 안받기 때문에 구글의 안드로이드식 오픈소스를 비판하는 얘기도 많이 있었다. 그럼에도 오픈소스로 공개된 안드로이드는 충분히 효과를 본 것 같다.</p>
<blockquote>
<p>"그게 OR드로이드가 아니라 AND로이드라고 부른 이유에요. 두 가지 대안 중에서 결정해야 한다면 우리는 늘 둘 다 골랐거든요."<br />
- 팀에서 누군가가 한 말</p>
</blockquote>
<blockquote>
<p>초기에(그리고 이후 수년가) 팀에서 계속된 논쟁 한 가지는 그들이 만들고 있는 게 제품인가 아니면 플랫폼인가 하는 것이었다. 다시 말하면 휴대 전화(제품)를 만들고 있는가 아니면 다양한 제조사가 만드는 여러 가지 휴대 전화에서 현재와 미래에 사용할 운영 체제(플랫폼)를 개발하고 있는가 하는 토론이었다.</p>
</blockquote>
<blockquote>
<p>팀에서 벌어진 제품 대 플랫폼 논쟁은 사람들이 출신 회사에 따라 의견이 갈렸다. 바로 데인저 출신 대 비-팜소스, 웹티비-마이크로소프트 출신으로 나뉘었다. 데인저 출신 사람들은 단순한 해법을 선호했고 제품에 좀 더 중점을 두었다. 비-팜소스와 웹티비-마이크로소프트 출신 사람들은 좀 더 플랫폼적인 사고방식을 지녔고 안드로이드에서도 그러한 접근 방식을 선호했다.</p>
</blockquote>
<blockquote>
<p>브라이언 스웨트랜드는 양쪽을 다 알았는데 비와 데인저에서 일했기 때문이다. "둘 다 필요합니다. 내가 비에서 얻은 교훈이에요. 비는 당시 틀에 박혀 있었어요. 그래서 플랫폼이 되는 데 집중했죠. 제대로 된 앱이 없고 순수한 플랫폼만 만든다면 악순환을 끊지 못해요. 사람들이 필요로 하는 걸 만들지 않은 거고요."</p>
</blockquote>
<p>안드로이드처럼 대단한 프로젝트가 아니라고 하더라도 (내 취향일 수도 있지만) 비슷한 결정을 하게 되는 경우는 많은 것 같다. 잘못하면 둘 다 고른다는 것은 아무것도 안 고른 것과 다름없기도 해서 현실에선 쉽지 않긴 하다. 안드로이드 내에서도 출신에 따라서 선호가 달라진다는 것도 재미있었는데 성공 혹은 실패했던 경험에 따라 달라지는 걸로 보인다.<br />
<br></p>
<h1>4부 출시</h1>
<blockquote>
<p>당시 안드로이드 팀의 어떤 엔지니어가 한 말이 다양한 곳에서 인용됐다. "소비자로서 나는 반해 버렸어요. 당장 하나 갖고 싶네요. 그러나 구글 엔지니어로서 '우리는 처음부터 다시 시작해야만 해'라고 생각했어요."<br />
이 발언은 아이폰 때문에 안드로이드의 모든 게 바뀌고 개발 계획이 재작성됐음을 암시한다.</p>
</blockquote>
<blockquote>
<p>아이폰 발표는 모든 휴대 기기 제조사에 영향을 끼쳤는데 전체 모바일 산업에 파문을 일으켰으며 두려움을 야기함으로써 결국 다소 역설적으로 안드로이드가 시장에서 자리 잡는 주요한 이유가 됐다.</p>
</blockquote>
<p>아이폰은 발표 자체도 충격적이었지만(사실 난 그때 그렇게까지 아이폰의 위력을 알아채진 못했다.) 앞에서도 얘기했듯이 확실히 안드로이드에도 긍정적인 영향을 주었다. 마치 아이폰이 나오고 안드로이드가 만들어진 것처럼 보이지만 실제로는 비슷한 시기에 비슷한 목표를 가지고 두 프로젝트가 움직인 것이고 잘 모르는 성공하지 못한 프로젝트도 많이 있을거라고 생각한다. 당시 추억이 자꾸 생각나서 책을 보는 내내 재미가 있었는데 아이폰 이전의 PDA나 포켓PC 등은 대부분 스타일러스라고 부르는 얇은 팬을 통해서 화면을 터치했다. 나도 거기에 익숙했고 당시 대부분 기기의 화면 터치 성능은 좋지 않았기에(보통 손톱으로 터치했다 ㅋㅋ) 스티브 잡스가 아이폰을 시연하면서 QWERTY 키보드를 손가락으로 터치하는 걸 보고 놀랐다기보다는 말도 안 된다고 저렇게 동작할 리가 없다고 생각했었다.(안목이 없었지...)<br />
<br></p>
<h1>5부 안드로이드가 해낸 이유</h1>
<blockquote>
<p>우리는 적당한 때에 적당한 위치에 있었어요.</p>
</blockquote>
<p>수많은 안드로이드 팀이 비슷하게 얘기한다. 우리 팀이 엄청나게 잘했다고 얘기하는 게 아니라(실제로 잘했지만) 수많은 사람이 비슷하게 위처럼 얘기한다는 게 더 좋았다. 현실에선 한 명의 영웅적인 활동으로 되는 일도 많지 않고 미래를 다 예측하고 준비되어 있었다고 말하기 어려운 거니까...</p>
<p><strong><a href="https://blog.outsider.ne.kr/1621?commentInput=true#entry1621WriteComment">댓글 쓰기</a></strong></p>Android WebView의 페이지로딩 진행상황 Progress bar 표시하기Outsiderhttps://blog.outsider.ne.kr/4642010-05-03T04:09:10+09:002010-05-03T04:09:10+09:00기본적으로 웹뷰를 사용하여도 페이지의 로딩상태에 대해서 별도로 표시해주지 않습니다. 그래서 처음에 페이지를 띄우면 흰색화면에서 화면이 뜨게되는데 인터넷이 그리 빠르지 않으면 로딩중인것인지 앱이 죽은 것인지 판단하기가 어렵습니다. 사용자에게 로딩상태를 표시해 주는 것인 맞을 것입니다.<br><br>일반적으로 로딩상태를 표시해준다면 Ajax의 상징과도 같은 빙글빙글 도는 이미지인 spinner나 막대형태인 Progress Bar를 통해서 진행상태를 표시해 줄 수 있습니다. Progress Bar에 대해서는 <a href="http://developer.android.com/reference/android/webkit/WebView.html" target="_blank">안드로이드 WebView레퍼런스문서</a>에 아주 잘 나와있었습니다. <br><br><pre class="line-numbers"><code class="language-java">
getWindow().requestFeature(Window.FEATURE_PROGRESS);
myWebView.getSettings().setJavaScriptEnabled(true);
final Activity activity = this;
myWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
activity.setProgress(progress * 100);
}
});
myWebView.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String fallingUrl) {
Toast.makeText(activity, "로딩오류"+description, Toast.LENGTH_SHORT).show();
}
});
</code></pre><br>위의 코드를 onCreate안에 추가하면 프로그래스 바를 표시할 수 있습니다.<br><br style="color: rgb(204, 153, 0);"><span style="color: rgb(204, 153, 0);">1번라인의 requestFeature같은 경우는 content가 추가되기 전에 호출되지 않으면 오류가 나게 됩니다. 때문에 onCreate에 기본적으로 들어가게 되는 setContentView(R.layout.main);보다 상위에 1번라인을 추가하여야 정상적으로 동작하게 됩니다. </span><br style="color: rgb(153, 153, 102);"><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1185494503.gif" alt="DDMS 오류 메시지 " height="86" width="550" /></div><br>content추가 이후에 사용하게 되면 아래 Dalvik Debug Monitor에서 보이는 것처럼 "Caused by: android.utilAndroidRuntimeException:requestFeature() must be called before adding content"에러가 발생하고 프로그램
샐행시 오류메시지가 나타나면서 프로세스가 종료되게 됩니다.<br><br><span style="color: rgb(204, 153, 0);"><a href="http://developer.android.com/reference/android/webkit/WebChromeClient.html" target="_blank">WebChromeClient클래스</a>는 브라우저 UI에 progress변화나 Javascript alert같은 액션을 받아주는 역할을 합니다. <a href="http://developer.android.com/reference/android/webkit/WebViewClient.html" target="_blank">WebViewClient클래스</a>는 content의 랜더링에 대해서 받는 역할을 하고 에러메시지나 form submit을 받게 됩니다. 3번 라인은 WebView가 Javascript를 사용가능한 상태로 바꾸어줍니다.(기본은 false입니다.)</span><br>8번라인에서 레퍼런스문서에는 * 1000으로 되어 있었는데 이상하게 정상적으로 동작하지 않아서 100으로 고치니 정상적으로 동작하였습니다.<br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1126630313.gif" alt="프로그레스바가 포함된 웹뷰 실행화면 " height="500" width="340" /></div><br>이제 페이지를 로딩할때 상단 타이틀바에 프로그레스바가 잘 표시되는 것을 볼 수 있습니다.(Spinner로 보여주는 것은 아직 어떻게 하는건지 모르겠습니다 ㅠㅠ)<br><p><strong><a href="https://blog.outsider.ne.kr/464?commentInput=true#entry464WriteComment">댓글 쓰기</a></strong></p>Android WebView에서 Rotate시에 페이지 리로드(reload) 방지하기Outsiderhttps://blog.outsider.ne.kr/4632010-05-03T03:10:39+09:002010-05-03T03:06:27+09:00<a href="http://blog.outsider.ne.kr/463" target="_blank">웹뷰를 띄우는 부분에 대해서 포스팅</a>을 하였는데 여기서 기기를 가로로 회전시키면 화면이 가로보기로 바뀌면서 웹페이지가 다시 리로드가 되어버립니다. 이런저런 테스트를 해보니 정확히는 Reload가 발생하는 것이 아닌 액티비티가 호출되었을 때 발생하는 이벤트인 onCreate이벤트가 다시 발생하는 것으로 보입니다. 페이지를 이동하여도 기본으로 설정한 페이지로 다시 리로드가 되어버립니다.<br><br>이부분을 수정하려면 <span style="color: rgb(204, 153, 0);">AndroidManifest.xml</span>파일을 수정하여야 합니다.<br><br><div style="margin-left: 40px;"><span style="color: rgb(255, 118, 53); font-weight: bold;">android:configChanges="keyboardHidden|orientation"</span><br></div><br>Manifest파일의 Activity가 정의된 부분에 위의 설정부분을 추가해줍니다. <span style="color: rgb(204, 153, 0);"><a href="http://developer.android.com/guide/topics/manifest/activity-element.html#config" target="_blank">android:configChanges</a>는 이곳에 설정되지 않는 변화가 발생하면 액티비티를 셧다운하고 리스타트하게 되고 여기에 설정된 리스트의 변화는 <a href="http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged%28android.content.res.Configuration%29" target="_blank">onConfigurationChanged()</a>를 호출하게 됩니다. 여기서는 기기의 회전에 대한 orientation을 설정하였습니다. 실기기에서는 orientation만으로도 정상적으로 동작하였지만 <a href="http://www.androidpub.com/52338" target="_blank">에뮬에서는 keyboardHidden이 같이 발생</a>하는지 keyboardHidden도 추가해주어야 했습니다. 여러개를 적을 경우에는 파이프(|)로 연결을 합니다.</span><br><br><pre class="line-numbers"><code class="language-java">
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
</code></pre><br><span style="color: rgb(204, 153, 0);">액티비티 파일에서 onConfigurationChanged()을 위와같이 오버라이드</span>해주면 됩니다. 아직 안드로이드에 대해 절 모르면서 막 만들어보는 중이라 설명은 쉽지 않군요. 일단 저렇게 하면 로테이션시에 페이지가 리로드되지 않고 원하는대로 간단하게 화면회전만 됩니다.(웹뷰를 하면서 하기는 했는데 꼭 웹뷰에만 해당하는 문제는 아니군요. ㅡㅡ;;)<br><p><strong><a href="https://blog.outsider.ne.kr/463?commentInput=true#entry463WriteComment">댓글 쓰기</a></strong></p>Android WebView에 ZoomControls 사용하기Outsiderhttps://blog.outsider.ne.kr/4622010-05-03T02:32:31+09:002010-05-03T02:32:31+09:00안드로이드앱에서 <a href="WebView" target="_blank">WebView</a>를 사용할 일이 있어서(아직 책은 기본예제만 하고 있지만) 찾은 김에 정리해 봅니다. <a href="http://www.tutorialforandroid.com/2009/02/webview-with-zoomcontrols-in-android.html" target="_blank">WebView with ZoomControls in Android</a>의 내용을 다시 정리(?? 사실은 그대로 옮겨적기만)한 내용입니다. 이 예제는 줌컨트롤을 포함한 웹뷰를 생성하는 예제입니다. 줌 컨트롤은 안드로이드에서 웹브라우저등을 사용할때 화면상에 +/-버튼이 나오는 것을 의미합니다.<br><br><pre class="line-numbers"><code class="language-xml">
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</code></pre><br>AndroidManifest.xml 파일에 위의 내용을 추가합니다. 웹뷰를 사용하기 위해서는 인터넷에 대한 접근권한이 필요합니다. 이 부분이 추가되지 않으면 웹뷰를 추가하여도 인터넷이 연결안된 것처럼 페이지표시할 수 없음으로 나타나게 됩니다.<br><br><pre class="line-numbers"><code class="language-xml">
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView
android:id="@+id/webView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
</code></pre><br>layout/main.xml파일입니다. 웹뷰만 표시할 것이므로 간단히 WebView만 추가했습니다.<br><br><pre class="line-numbers"><code class="language-java">
package kr.ne.outsider;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class exwebview extends Activity {
private WebView myWebView;
final private String DEFAULT_URL = "http://blog.outsider.ne.kr";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myWebView = (WebView)this.findViewById(R.id.webView);
this.myWebView.loadUrl(DEFAULT_URL);
}
}
</code></pre><br>웹뷰만 띄우는 것은 간단합니다. 웹뷰의 객체를 가져오고 WebView의 loadUrl 함수를 이용해서 페이지를 호출합니다. <br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1385073001.jpg" alt="실행된 WebView 예제화면 " height="496" width="337" /></div><br>앱을 실행하면 정상적으로 웹뷰내에 지정한 웹페이지가 나타나게 됩니다.<br><br><pre class="line-numbers"><code class="language-java">
package kr.ne.outsider;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.FrameLayout;
public class exwebview extends Activity {
private WebView myWebView;
final private String DEFAULT_URL = "http://blog.outsider.ne.kr";
// new added
private static final FrameLayout.LayoutParams ZOOM_PARAMS = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM
);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myWebView = (WebView)this.findViewById(R.id.webView);
// new added
FrameLayout mContentView = (FrameLayout)getWindow().getDecorView().findViewById(android.R.id.content);
final View zoom = this.myWebView.getZoomControls();
mContentView.addView(zoom, ZOOM_PARAMS);
zoom.setVisibility(View.GONE);
this.myWebView.loadUrl(DEFAULT_URL);
}
}
</code></pre><br>줌컨트롤을 추가했습니다. <br>28번째 라인은 최상위(top-level) 윈도우의 DecorView를 가져옵니다.<br>29번째 라인은 WebView객체의 줌컨트롤을 얻어옵니다.<br>30번째 라인에서 최상위(top-level) 윈도우에 줌컨트롤을 추가합니다. 참고한 포스팅을 쓴 분이 BroswerActivity의 코드에서 추출해 낸 코드라고 합니다.<br>31번째 출은 시작할때 줌컨트롤을 숨기도록 합니다. 이는 사용자가 화면을 스크롤할때만 줌컨트롤이 나타나도록 하기 위해서입니다.<br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1039439746.jpg" alt="실행된 WebView 예제화면" height="496" width="337" /></div><br>평소엔 안보이다가 화면을 스크롤하면 줌컨트롤이 하단에 나타나고 +/-로 화면을 확대축소 할 수 있습니다. 제 생각에는 멀티터치를 이용한 줌이 기본으로 되어야 할 것 같은데 이유는 모르겠지만 멀티터치를 이용한 줌이 동작하지 않습니다. ㅠ..ㅠ<br><br>이렇게 웹뷰를 추가하게 되면 웹페이지의 URL을 클릭시에 웹뷰내에서 이동하지 않고 내장 브라우저가 호출되면서 내장 브라우저에서 링크된 페이지가 열리게 됩니다. <br><br><pre class="line-numbers"><code class="language-java">
package kr.ne.outsider;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
public class exwebview extends Activity {
private WebView myWebView;
final private String DEFAULT_URL = "http://blog.outsider.ne.kr";
private static final FrameLayout.LayoutParams ZOOM_PARAMS = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM
);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myWebView = (WebView)this.findViewById(R.id.webView);
FrameLayout mContentView = (FrameLayout)getWindow().getDecorView().findViewById(android.R.id.content);
final View zoom = this.myWebView.getZoomControls();
mContentView.addView(zoom, ZOOM_PARAMS);
zoom.setVisibility(View.GONE);
// new added
myWebView.setWebViewClient(new Callback());
this.myWebView.loadUrl(DEFAULT_URL);
}
// new added
private class Callback extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return(true);
}
}
}
</code></pre><br>웹페이지가 링크내에서 열리도록 하기 위해서 WebView객체에 새로운 WebViewClient객체를 추가했습니다. Callback에서 shouldOverrideUrlLoading메서드를 오버라이드해서 현재의 webview에서 다시 loadUrl을 하도록 처리했습니다. 이제 link를 클릭해도 웹뷰내에서 이동하게 됩니다.<br><p><strong><a href="https://blog.outsider.ne.kr/462?commentInput=true#entry462WriteComment">댓글 쓰기</a></strong></p>Ubuntu에서 안드로이드 디바이스 선택 안되는 문제Outsiderhttps://blog.outsider.ne.kr/4482010-04-01T03:51:08+09:002010-04-01T03:51:08+09:00Ubuntu에서 이클립스로 <a href="http://developer.android.com/resources/tutorials/hello-world.html" target="_blank">Hello World튜토리얼</a>을 AVD가 아닌 실제 디바이스에서 실행하려고(듣던대로 에뮬은 정말 느리더군요) 넥서스원을 실행하니까 AVD를 이용한 에뮬레이터가 자동으로 뜨는 대신 Android Device Chooser 화면이 나왔습니다.(윈도우에서는 디바이스를 연결하면 자동으로 디바이스에서 실행이 되었었습니다. <a href="http://blog.outsider.ne.kr/444" target="_blank">SDK를 설치</a>할때 윈도에서는 드라이버를 설치했었죠.) 물론 안드로이드 디바이스에서 USB 디버깅을 활성화해야 합니다.<br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1171735539.gif" alt="Eclipse의 Android Device Chooser화면 " height="435" width="550" /></div><br>Linux에서는 별도의 드라이버가 필요없다고 나와있었는데 기기가 연결이 되기는 했지만 Serial Number가 ???로 나타나면서 인식을 제대로 못했는지 OK버튼이 활성화되지 않아서 다음단계로 넘어갈 수가 없었습니다. <br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1293965643.gif" alt="adb devices 실행화면 " height="64" width="531" /></div><br>안드로이드 SDK안에 있는 tools부분의 Android Debug Bridge를 이용해서도 기기를 확인해 볼 수 있는데 adb devices를 실행해도 no permissions라고 나오면서 기기명이 제대로 표시되지 않았습니다. 문서를 찾아보니 <a href="http://developer.android.com/guide/developing/device.html#setting-up" target="_blank">Setting up a Device for Development</a>에 해당부분에 대한 설명이 나와있었습니다.<br><br><blockquote style="color: rgb(255, 118, 53);">/etc/udev/rules.d/51-android.rules</blockquote>root권한으로 위의 위치에 <span style="color: rgb(204, 153, 0);">51-android.rules 라는 파일을 생성하고 아래의 내용을 입력하고 저장</span>합니다.(Ubuntu 9.10입니다.)<br><br><blockquote style="color: rgb(255, 118, 53);">SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"</blockquote>Logout을 하고 온 뒤에도 정상적으로 되지 않으면 데몬을 재실행시켜주어야 정상적으로 됩니다.<br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1286802117.gif" alt="adb 서버 재실행 화면 " height="205" width="550" /></div><br>안드로이드 SDK의 Tools에서 <span style="color: rgb(204, 153, 0);">adb kill-server를 실행키셔 서버를 종료시킨되 sudo ./adb start-server로 데몬을 시작시켜줍니다. adb devices를 다시 실행하면 시리얼키가 정상적으로 나오는 것을 볼 수 가 있습니다.</span> 이제 이클립스에서 다시 안드로이드를 Run하면 정상적으로 Device를 선택할 수 있고 아래처럼 기기에서 실행된 Hello World를 볼 수 있습니다.<br><br><br><div class="imageblock center" style="text-align: center; clear: both;"><img src="//blog.outsider.ne.kr/attach/1/1382490734.gif" alt="사용자 삽입 이미지" height="173" width="480" /></div><br><p><strong><a href="https://blog.outsider.ne.kr/448?commentInput=true#entry448WriteComment">댓글 쓰기</a></strong></p>