하이브리드앱 아키텍쳐 및 개발 사례

64
(푸딩얼굴인식 앱을 통해서 본) 하이브리드앱 아키텍쳐 및 개발 사례 앱스프레소팀 | 장동수 1

Upload: dongsu-jang

Post on 30-Oct-2014

52 views

Category:

Technology


8 download

DESCRIPTION

2011.11.30 H3에서 발표했던 "(푸딩얼구인식앱을 통해서 보는)하이브드리앱 아키텍쳐 및 개발 사례"의 발표 자료입니다.

TRANSCRIPT

Page 1: 하이브리드앱 아키텍쳐 및 개발 사례

(푸딩얼굴인식����������� ������������������  앱을����������� ������������������  통해서����������� ������������������  본)

하이브리드앱아키텍쳐����������� ������������������  및����������� ������������������  개발����������� ������������������  사례

앱스프레소팀����������� ������������������  |����������� ������������������  장동수

1

Page 2: 하이브리드앱 아키텍쳐 및 개발 사례

index

1. 하이브리드앱����������� ������������������  아키텍쳐����������� ������������������  개요

2. 하이브드리앱����������� ������������������  유형����������� ������������������  및����������� ������������������  특징

3. 푸딩얼굴인식����������� ������������������  앱����������� ������������������  개발����������� ������������������  사례����������� ������������������  공유

4. 앱스프레소����������� ������������������  플러그인����������� ������������������  활용

5. Lessons����������� ������������������  Learned

6. References

2

Page 3: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드앱����������� ������������������  아키텍쳐����������� ������������������  개요

이런����������� ������������������  거...아님����������� ������������������  -_-;

3

Page 4: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드앱����������� ������������������  아키텍쳐����������� ������������������  구성����������� ������������������  요소

웹����������� ������������������  표준����������� ������������������  기술

플랫폼����������� ������������������  SDK

iOS����������� ������������������  SDK

하이브리드

HTML5 CSS 자바스크립트

비표준����������� ������������������  Device����������� ������������������  APIs

안드로이드����������� ������������������  SDK

윈폰7����������� ������������������  SDK …⋯

웹����������� ������������������  UI����������� ������������������  툴킷 자바스크립트����������� ������������������  프레임웍/라이브러리

표준����������� ������������������  Device����������� ������������������  APIs

웹네이티브

웹브라우져����������� ������������������  “앱”

프레임웍

네이티브����������� ������������������  라이브러리

UI����������� ������������������  툴킷

개발����������� ������������������  도구 웹브라우져����������� ������������������  “엔진”

4

Page 5: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드앱의����������� ������������������  꿈

Development����������� ������������������  Cost

Application����������� ������������������  Quality

네이티브

BEST

WORST

하이브리드

5

Page 6: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드라는����������� ������������������  이름의����������� ������������������  “짬뽕”...

난,물~����������� ������������������  H2O~

O

H H

6

Page 7: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브

웹 웹

내가,하이브리드~

앱����������� ������������������  개발자들을����������� ������������������  유혹하는����������� ������������������  “파란”����������� ������������������  짬뽕~

7

Page 8: 하이브리드앱 아키텍쳐 및 개발 사례

웹����������� ������������������  개발자들을����������� ������������������  유혹하는����������� ������������������  “빨간”����������� ������������������  짬뽕~

네이티브 네이티브

나도,하이브리드~

8

Page 9: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브와����������� ������������������  웹의����������� ������������������  결합

웹네이티브Native-WebBridge

Java����������� ������������������  Applet?Active-X?

Flash/Flex?

문제는....다리!!

9

Page 10: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브와����������� ������������������  웹의����������� ������������������  결합

WebView

WebViewClient����������� ������������������  &����������� ������������������  WebChromeClient

loadUrl

addJavascriptInterface

UIWebView

UIWebViewDelegate

loadRequest

stringByEvaluatingJavascriptFromString

10

Page 11: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브와����������� ������������������  웹의����������� ������������������  결합

그림 출처: http://petticoatsandpistols.com/2010/05/12/

URL

자바스크립트

쿠키

캐시그래봤자,문자열~

어차피,꼼수

그리고...HTTP!

11

Page 12: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드앱����������� ������������������  유형����������� ������������������  및����������� ������������������  특징

12

Page 13: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브����������� ������������������  지향����������� ������������������  하이브리드앱

사실상����������� ������������������  네이티브,

웹은����������� ������������������  거들����������� ������������������  뿐...

·제한적이고����������� ������������������  직관적인����������� ������������������  네이티브와����������� ������������������  웹의����������� ������������������  결합·웹브라우져����������� ������������������  as-a����������� ������������������  UI����������� ������������������  컴포넌트·도움말,����������� ������������������  앱/개발사����������� ������������������  소개,����������� ������������������  공지사항/새소식...·웹����������� ������������������  기반����������� ������������������  사용자����������� ������������������  인증(OAuth)...

13

Page 14: 하이브리드앱 아키텍쳐 및 개발 사례

웹브라우져����������� ������������������  as-a����������� ������������������  UI����������� ������������������  컴포넌트

14

Page 15: 하이브리드앱 아키텍쳐 및 개발 사례

웹����������� ������������������  기반����������� ������������������  사용자����������� ������������������  인증

15

Page 16: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(안드로이드)

<<웹서버 컨텐츠 불러오기>>public class NoticeActivity extends Activity { ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); WebView webView = (WebView)findViewById(R.id.webView); webView.getSettings().setJavaScriptEnabled(true); webView.setWebChromeClient(new WebChromeClient()); ... webView.loadUrl(“http://m.pudding.kr/pud/mNotice.kth”); ... } ...}

<<앱에 포함된 정적 컨텐츠 불러오기>>public class HelpActivity extends Activity { ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); WebView webView = (WebView)findViewById(R.id.webView); webView.getSettings().setJavaScriptEnabled(true); webView.setWebChromeClient(new WebChromeClient()); ... webView.loadUrl(“file:///android_asset/www/help.html”); ... } ...}

16

Page 17: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(iOS)

<<웹 서버 컨텐츠 불러오기>>@interface NoticeViewController : UIViewController { IBOutlet UIWebView *webView;...@end

@implementation HelpViewController...- (void)viewDidLoad { ... NSURL *url = [NSURL URLWithString:@”http://m.pudding.kr/pud/mNotice.kth”]; NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; [webView loadRequest:requestObj]; ...}...@end <<앱에 포함된 정적 컨텐츠 불러오기>>

@interface HelpViewController : UIViewController { IBOutlet UIWebView *webView;...@end

@implementation HelpViewController...- (void)viewDidLoad { ... NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; NSString *path = [bundlePath stringByAppendingPathComponent:@”/www/help.html”]; NSURL *url = [NSURL fileURLWithPath:path]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request]; ...}...@end

17

Page 18: 하이브리드앱 아키텍쳐 및 개발 사례

웹은����������� ������������������  아니지만����������� ������������������  네이티브도����������� ������������������  아닌,

그러나����������� ������������������  웹스러운...

·광범위하고����������� ������������������  일관성없는����������� ������������������  네이티브와����������� ������������������  웹의����������� ������������������  결합·웹브라우져를����������� ������������������  내장한����������� ������������������  네이티브����������� ������������������  클라이언트·기존����������� ������������������  웹����������� ������������������  서버����������� ������������������  “조금����������� ������������������  손����������� ������������������  봐서...”����������� ������������������  재활용·기존����������� ������������������  웹����������� ������������������  컨텐츠����������� ������������������  “조금����������� ������������������  손����������� ������������������  봐서...”����������� ������������������  재활용

“한����������� ������������������  지붕����������� ������������������  두����������� ������������������  가족”����������� ������������������  하이브리드앱

18

Page 19: 하이브리드앱 아키텍쳐 및 개발 사례

여기도����������� ������������������  하이브리드~

19

Page 20: 하이브리드앱 아키텍쳐 및 개발 사례

저기도����������� ������������������  하이브리드~

20

Page 21: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(안드로이드)

<<링크 클릭 가로채기>>...WebView webView = (WebView)findViewById(R.id.webView);webView.getSettings().setJavaScriptEnabled(true);webView.setWebChromeClient(new WebChromeClient());webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView webView, String url) { if(!url.startsWith(“http://m.pudding.kr/pud/”) { new AndroidDialog.Builder(NoticeActivity.this) .setMessage(“딴데로 갈라구?? -_-+”) .setPositiveButton(“아니... 여기 있을께 ㅠㅠ”, new DialogInterface.OnClickListener() { dialog.dismiss(); }) .setNegativeButton(“갈꼬얌!”, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int witch) { dialog.dismiss(); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); NoticeActivity.this.startActivity(intent); } }).show(); return false; } else if ... ...이러쿵 저러쿵... } else if ... ...어쩌구 저쩌구... } else if ... ...구시렁 구시렁... } view.loadUrl(url); return true; }});webView.loadUrl(“http://m.pudding.kr/pud/mNotice.kth”);...

21

Page 22: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(iOS)

<<링크 클릭 가로채기>>@interface NoticeViewController : UIViewController<UIWebViewDelegate, UIAlertViewDelegate> { IBOutlet UIWebView *webView; NSString *externalUrl;...@implementation HelpViewController...- (void)viewDidLoad { NSURL *requestUrl = [NSURL URLWithString:@”http://m.pudding.kr/pud/mNotice.kth”]; [webView loadRequest:[NSURLRequest requestWithURL:requestUrl]]; [webView setDelegate:self]}- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url = [[request URL] absoluteString]; if(![url hasPrefix:@”http://m.pudding.kr/pud/mNotice.kth”]) { self.externalUrl = url; UIAlertView *alertView = [UIAlertView alloc] initWithTitle:nil message:@”딴데로 갈라구?? -_-+” delegate:self cancelButtonTitle:@”아니... 여기 있을께 ㅠㅠ“ otherButtonTitles:@”갈꼬얌!”, nil]; [alertView show]; [alertView release]; return NO; } else if ... ...이러쿵 저러쿵... } else if ... ...어쩌구 저쩌구... } else if ... ...구시렁 구시렁... } return YES;}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex == YES && self.externalUrl) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.externalUrl]; }}...

22

Page 23: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(안드로이드)

<<URL을 이용한 네이티브와 웹의 통신>>webView.loadUrl(“javascrpt:getFieldValue(‘userName’)”); // 결과는 나중에... 비동기!! -_-;...webView.loadUrl(“javascrpt:setFieldValue(‘userName’, ‘“ + userName + “‘“);...

webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView webView, String url) { if(!url.startsWith(“custom://getFieldValue”) { Uri uri = Uri.parse(url); String fieldId = uri.getQueryParameter(“fieldId”); String fieldValue = uri.getQueryParameter(“fieldValue”); if(fieldId.equals(“userName”)) { userName = fieldValue; // 결과가 도착했다! 이제 어떡하지? 비동기!! OTL } else if ... } else if ... } else if ... // 나는 엘시프가 씨러요! ㅠㅠ } return false; } else if ... } else if ... } else if ... // 나는 엘시프가 씨러요! ㅠㅠ } view.loadUrl(url); return true; }});...

<<URL을 이용한 네이티브와 웹의 통신::자바스크립트>>function getFieldValue(fieldId) { var fieldValue = document.getElementById(fieldId).value; location.href = ‘custom://getFieldValue?fieldId=’ + fieldId + ‘&fieldValue=’ + fieldValue;}function setFieldValue(fieldId, fieldValue) { document.getElementById(fieldId).value = fieldValue;}

23

Page 24: 하이브리드앱 아키텍쳐 및 개발 사례

예제����������� ������������������  코드(iOS)

<<URL을 이용한 네이티브와 웹의 통신>>NSString *script = [NSString stringWithFormat:@“getFieldValue(‘%@’)”, fieldId];[webView stringByEvaluatingJavaScriptString:script];...

NSString *script = [NSString stringWithFormat:@“setFieldValue(‘%@’, ‘%@‘)“, fieldId, fieldValue];[webView stringByEvaluatingJavaScriptString:script];...

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *url = [[request URL] absoluteString]; if(![url hasPrefix:@”custom://getFieldName”]) { NSDictionary *params = [HttUtils decodeQueryString:[[request URL] query]]; NSString *fieldId = [params objectForKey:@”fieldId”]; NSString *fieldValue = [params objectForKey:@”fieldValue”]; if(fieldId isEqualToString:@”userName”) { self.userName = fieldValue; } else if ... } else if ... } else if ... // 나는 엘시프가 씨러요! ㅠㅠ } [paramArray release]; return NO; } else if ... } else if ... } else if ... // 나는 엘시프가 씨러요! ㅠㅠ } return YES;}...

24

Page 25: 하이브리드앱 아키텍쳐 및 개발 사례

웹����������� ������������������  지향����������� ������������������  하이브리드앱

사실상����������� ������������������  웹,

네이티브는����������� ������������������  거들����������� ������������������  뿐...

·광범위하지만����������� ������������������  일관성있는����������� ������������������  네이티브와����������� ������������������  웹의����������� ������������������  결합����������� ������������������  ·클라이언트����������� ������������������  사이드����������� ������������������  “웹앱”·기존����������� ������������������  웹����������� ������������������  서버����������� ������������������  +����������� ������������������  RESTful����������� ������������������  API����������� ������������������  서버·기본적인����������� ������������������  웹����������� ������������������  컨텐츠는����������� ������������������  앱에����������� ������������������  포함

25

Page 26: 하이브리드앱 아키텍쳐 및 개발 사례

하이브리드����������� ������������������  모바일����������� ������������������  앱����������� ������������������  프레임웍

26

Page 27: 하이브리드앱 아키텍쳐 및 개발 사례

이것도����������� ������������������  하이브리드!

27

Page 28: 하이브리드앱 아키텍쳐 및 개발 사례

푸딩얼굴인식앱����������� ������������������  개발����������� ������������������  사례����������� ������������������  공유

28

Page 29: 하이브리드앱 아키텍쳐 및 개발 사례

“푸딩얼굴인식����������� ������������������  앱”����������� ������������������  소개

����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  푸딩얼굴인식����������� ������������������  앱은...

·600만+����������� ������������������  다운로드!·@iolothebard����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  와����������� ������������������  @seti222·5500+����������� ������������������  줄의����������� ������������������  자바스립트·2700+����������� ������������������  줄의����������� ������������������  CSS·200+����������� ������������������  줄의����������� ������������������  네이티브����������� ������������������  코드·앱스프레소����������� ������������������  0.9+����������� ������������������  내부����������� ������������������  개발����������� ������������������  버전

29

Page 30: 하이브리드앱 아키텍쳐 및 개발 사례

단일����������� ������������������  페이지����������� ������������������  인터페이스

index.html

ActivePage

show/hide

#pageId

pageId.css

pageId.js

30

Page 31: 하이브리드앱 아키텍쳐 및 개발 사례

단일����������� ������������������  페이지����������� ������������������  인터페이스

웹앱도����������� ������������������  MVC가����������� ������������������  필요해!

자바스크립트가����������� ������������������  컨트롤러!

·웹����������� ������������������  서버도����������� ������������������  없는����������� ������������������  데...����������� ������������������  페이지����������� ������������������  이동은����������� ������������������  왜?!· (GUI)����������� ������������������  애플리케이션����������� ������������������  스타일의����������� ������������������  “상태”����������� ������������������  관리·빠른����������� ������������������  화면����������� ������������������  전환����������� ������������������  &����������� ������������������  화면����������� ������������������  전환����������� ������������������  효과·체감����������� ������������������  성능����������� ������������������  UP!·메모리����������� ������������������  사용량����������� ������������������  UP!·그런데...����������� ������������������  공동����������� ������������������  작업은����������� ������������������  어떻게?����������� ������������������  -_-;

31

Page 32: 하이브리드앱 아키텍쳐 및 개발 사례

단일����������� ������������������  페이지����������� ������������������  인터페이스

<<HTML마크업: section#faceFoundPage>><section id=”faceFoundPage” class=”jj-page”> <header> <button class=”jj-left jj-back”><span data-nls=”common.back”>이전</span></button> <button class=”jj-right jj-home”><span data-nls=”common.home”>홈</span></button> <h1><span data-nls=”faceFoundPage.title”>얼굴인식 결과</span></h1> </header> <article> ... </article> <footer> ... </footer></section>

<<CSS스타일:faceFoundPage.css>>#faceFoundPage { background-color:rgb(255,255,255);}#faceFoundPage > article, #faceFoundPage > footer { background-color:rgb(138,135,136);}...

<<자바스크립트:faceFoundPage.js>>var jj.ui = jj.require(‘jj.ui’);export.FaceFoundPage = new jj.defclass(jj.ui.Page, { onInit: function() { $(this.pageNode).bind(‘onpagebeforeshow’, function() { … }); $(this.pageNode).bind(‘onpageaftershow’, function() { … }); $(this.pageNode).bind(‘onpagebeforehide’, function() { … }); $(this.pageNode).bind(‘onpageaftershow’, function() { … }); ... }, ...});

<<자바스크립트를 이용한 화면 전환>>// 화면을 수동으로 초기화var faceFoundPage = new FaceFoundPage( $(‘#faceFoundPage’), // 화면을 구성하는 DOM 노드 facePickerPage, // 화면내의 .jj-back 노드를 클릭할 때 전환될 페이지 mainPage); // 화면내의 .jj-home 노드를 클릭할 때 전환될 페이지// 화면 표시에 필요한 상태 정보를 전달faceFoundPag.setFaceInfo(faceInfo);// 현재 화면이 왼쪽으로 사라지면서, 새 화면이 오른쪽에서(slideleft) 나타남faceFoundPage.show(‘slideleft’);// 현재 화면을 유지한 채, 새 화면을 아래에서 위로(slideup) 나타남(modal)//faceFoundPage.show(‘slideup’, true);

32

Page 33: 하이브리드앱 아키텍쳐 및 개발 사례

“Placeholder”����������� ������������������  HTML����������� ������������������  Markup

HTML

TemplateData

API����������� ������������������  서버

+

웹����������� ������������������  서버

이름 클래스 레벨

<<foreach>><<foreach>><<foreach>>

★ ♥ ♦<<end>><<end>><<end>>

★ ♥ ♦iolo bard 만렙

장동수 개발자 쪼렙

... ... ...

캐시 앱

Placeholder

자바스크립트

이름 클래스 레벨

iolo bard 만렙

장동수 개발자 쪼렙

... ... ...

캐시 로컬스토리지Static����������� ������������������  HTML����������� ������������������  Fragment

33

Page 34: 하이브리드앱 아키텍쳐 및 개발 사례

“Placeholder”����������� ������������������  HTML����������� ������������������  Markup

웹앱도����������� ������������������  MVC가����������� ������������������  필요해!

뷰와����������� ������������������  모델의����������� ������������������  분리

·HTML����������� ������������������  마크업을����������� ������������������  위한����������� ������������������  “변수”·웹����������� ������������������  서버����������� ������������������  개발에서����������� ������������������  널리����������� ������������������  쓰이는����������� ������������������  템플릿(velocity,����������� ������������������  smarty,����������� ������������������  ...)을����������� ������������������  웹����������� ������������������  클라이언트에����������� ������������������  적용

·서버����������� ������������������  부하는����������� ������������������  DOWN!·데이터����������� ������������������  전송량도����������� ������������������  DOWN!·캐시����������� ������������������  히트율은����������� ������������������  UP!

34

Page 35: 하이브리드앱 아키텍쳐 및 개발 사례

“Placeholder”����������� ������������������  HTML����������� ������������������  Markup

<div id=”faceFound_starTemplate” class=”jj-template”> <div class=”face” data-fastclick=”true”></div> <div class=”rank”></div> <p class=”rate”><span class=”rateText”></span><small>%</small></p> <p class=”nameText” data-fastclick=”true”></p> <p class=”info”></p> <p class=”descriptionText”></p></div>

<div id=”faceFound_star_wrapper”><div id=”faceFound_star_scroller”> <ul> <li class=”nomatch”> <div id=”faceFound_star_nomatch”> <h5 data-nls=”0ah002”>닮은 연예인을 찾지 못했습니다.</h5> <p data-nls=”0ah003”>얼굴이 가까이 나온<br />정면 사진으로 다시 시도해 보세요.</p> <div> <button id=”faceFound_retryBtn” class=”y” data-fastclick=”true”> <span data-nls=”0ah005”>다시 찾기</span> </button> </div> </div> </li> <li> <div id=”faceFound_star1” class=”jj-placeholder” data-template=”#faceFound_starTemplate”></div> </li> <li> <div id=”faceFound_star2” class=”jj-placeholder” data-template=”#faceFound_starTemplate”></div> <div id=”faceFound_star3” class=”jj-placeholder”></div> </li> <li> <div id=”faceFound_star4” class=”jj-placeholder” data-template=”#faceFound_starTemplate”></div> <div id=”faceFound_star5” class=”jj-placeholder” data-template=”#faceFound_starTemplate”></div> </li> </ul></div><!-- star_scroller --></div><!-- star_wrapper -->

35

Page 36: 하이브리드앱 아키텍쳐 및 개발 사례

“Marker”����������� ������������������  CSS����������� ������������������  Class

웹앱도����������� ������������������  MVC가����������� ������������������  필요해!

뷰와����������� ������������������  컨트롤러의����������� ������������������  분리

·CSS����������� ������������������  스타일시트를����������� ������������������  위한����������� ������������������  “조건문”·프론트엔드����������� ������������������  UI����������� ������������������  개발자와����������� ������������������  자바스크립트����������� ������������������  개발자의����������� ������������������  약속·화면의����������� ������������������  동적인����������� ������������������  변화를����������� ������������������  자바스크립트없이����������� ������������������  확인����������� ������������������  &����������� ������������������  제어·HTML/CSS는����������� ������������������  “쬐끔”����������� ������������������  복잡해지고...����������� ������������������  -_-;·자바스크립트는����������� ������������������  “쬐끔”����������� ������������������  단순해지고...����������� ������������������  -_-;·함께����������� ������������������  일하기는����������� ������������������  더����������� ������������������  좋아지고~����������� ������������������  ^O^

36

Page 37: 하이브리드앱 아키텍쳐 및 개발 사례

“Marker”����������� ������������������  CSS����������� ������������������  Class

<<스타일시트>>/* 일치하는 연예인이 하나라도 있으면 안내문을 표시하지 않는다 */#faceFoundPage .nomatch { display:none;}/* 일치하는 연예인이 없으면 그에 따른 안내문을 표시한다 */#faceFoundPage.nomatch .nomatch { display:block;}/* 일치하는 연예인이 없으면 carousel 페이지 인디케이터를 숨긴다 */#faceFoundPage.nomatch ul > li { display:none;}/* 일치하는 연예인이 없으면 하단의 공유 버튼들을 비활성화 */#faceFoundPage.nomatch footer button { opacity:0.5;}/* 일치하는 연예인 숫자에 따라 carousel 영역(iscroll)의 너비를 조절한다#faceFoundPage.nomatch #faceFound_star_scroller, #faceFoundPage.match_1 #faceFound_star_scroller { width:320px;/*320*1pages*/ } #faceFoundPage.match_2 #faceFound_star_scroller, #faceFoundPage.match_3 #faceFound_star_scroller { width:640px;/*320*2pages*/ }#faceFoundPage.match_4 #faceFound_star_scroller,#faceFoundPage.match_5 #faceFound_star_scroller { width:960px;/*320x3pages*/}

<<자바스크립트>>if(matchingCelebs < 1) { $(‘#faceFoundPage’).addClass(‘nomatch’);} else { $(‘#faceFoundPage’).removeClass(‘nomatch’).addClass(‘match_’ + matchingCelebs);}

37

Page 38: 하이브리드앱 아키텍쳐 및 개발 사례

단말����������� ������������������  해상도별����������� ������������������  최적화

Responsive����������� ������������������  Web����������� ������������������  Design?

지금은����������� ������������������  곤란하니,����������� ������������������  기다려����������� ������������������  달라~

·<HTML>����������� ������������������  태그에����������� ������������������  마커����������� ������������������  CSS����������� ������������������  클래스����������� ������������������  추가/활용·기본적으로����������� ������������������  해상도에����������� ������������������  자유로운����������� ������������������  프론트엔드����������� ������������������  UI����������� ������������������  개발·널리����������� ������������������  쓰이는����������� ������������������  해상도는����������� ������������������  꼼꼼하게����������� ������������������  “미세”����������� ������������������  조정·특이한����������� ������������������  해상도는����������� ������������������  최소한의����������� ������������������  “미세”����������� ������������������  조정·이����������� ������������������  한����������� ������������������  몸����������� ������������������  희생해서...����������� ������������������  모두가����������� ������������������  행복할����������� ������������������  수����������� ������������������  있다면...����������� ������������������  ㅠㅠ

38

Page 39: 하이브리드앱 아키텍쳐 및 개발 사례

“Marker”����������� ������������������  CSS����������� ������������������  Class

<<단말 해상도 마커 클래스를 활용한 스타일 최적화>>/* 해상도 독립적인 레이아웃 */section { width:100%; height:100%; }header, footer { height:10%; }article { height:80%; }article.noheader, article.nofooter { height:90%; }article.noheader.nofooter { height:100%; }.../* 아이폰 해상도에 맞춰 미세 조정 */.screen320x480 header { height:44px; }.screen320x480 footer { height:49px; }.screen320x480 article { height:387px;/*480-44-49*/ }.screen320x480 article.noheader { height:436px;/*480-44*/ }.screen320x480 article.nofooter { height:431px;/*480-49*/ }.../* 갤러시탭에 해상도에 맞춰 미세 조정 */.screen600x1024 header { height:80px; }...

<<단말 플랫폼/해상도 마커 클래스 초기화 스크립트>>var platformCls = (/iOS/.test(navigator.userAgent)) ? ‘ios’ : (/Android/.test(navigator.userAgent) ? android : ‘generic’);var screenCls =‘screen’, screen.width, ‘x’, screen.height).join(‘’);var orientationCls = (screen.width < screen.height) ? ‘portrait’ : ‘landscape’;$(window).addClass(platformCls, screenCls, orientationCls);

<<단말 플랫폼 마커 클래스를 활용한 스타일 최적화>>/* 플랫폼 고유의 체크박스(on/off 스위치) 이미지를 사용 */input[type=”checkbox”] { background-repeat:no-repeat; background-size:100%;}.ios input[type=”checkbox”] { background-image:@url(‘img/ios/check.png’);}.android input[type=”checkbox”] { background-image:@url(‘img/android/check.png’);}...

39

Page 40: 하이브리드앱 아키텍쳐 및 개발 사례

다국어����������� ������������������  처리

I18N?����������� ������������������  L10N?����������� ������������������  A11Y?

이제는����������� ������������������  선택이����������� ������������������  아닌����������� ������������������  필수!

·<HTML>����������� ������������������  태그에����������� ������������������  마커����������� ������������������  CSS����������� ������������������  클래스����������� ������������������  추가/활용· “그림����������� ������������������  글자”����������� ������������������  사용����������� ������������������  최소화����������� ������������������  :����������� ������������������  국제화����������� ������������������  &����������� ������������������  접근성·일관성있는����������� ������������������  번역어����������� ������������������  식별자·언어별����������� ������������������  어순����������� ������������������  /����������� ������������������  길이����������� ������������������  /����������� ������������������  너비����������� ������������������  차이����������� ������������������  고려·언어별����������� ������������������  UI����������� ������������������  “미세”����������� ������������������  조정

40

Page 41: 하이브리드앱 아키텍쳐 및 개발 사례

다국어����������� ������������������  처리

41

Page 42: 하이브리드앱 아키텍쳐 및 개발 사례

다국어����������� ������������������  처리

<<다국어 지원 초기화 스크립트>>var lang = navigator.language.substring(0, 2);if(lang !== ‘en’ && lang !== ‘ja’ && lang !== ‘zh’) { lang = ‘en’; }$.get(‘locales/’ + lang + ‘/messages.json’, function(messages) { $(document.documentElement).addClass(‘jj-nls-’ + lang);//언어 식별 마커 클래스 추가 $.each(document.body).find(‘*[data-nls]’).each(function(index, node) { var key = node.attr(‘data-nls’); var message = messages[key]; if(message) { node.html(message); } else { console.error(’missing nls message:’ + key); }});

<<다국어 번역 텍스트 파일(locales/언어/messages.json)>>“common.back”: “Back”,...“setupTwitterPage.title”: “Setup - Twitter”,...

<<다국어 지원 자리 잡기 태그>><button><span data-nls=”common.back”>이전</span></button>...<h1><span data-nls=”setupTwitterPage.title”>설정 - 트위터</span></h1>...

<<다국어 번역 텍스트 치환 결과>><button><span data-nls=”common.back”>Back</span></button>...<h1><span data-nls=”setupTwitterPage.title”>Setup - Twitter</span></h1>...

<<마커 클래스를 활용한 언어별 스타일 최적화>>.jj-nls-zh #intro_title { /*locales/zh/img/intro_title.png*/ background-image:@url(‘../img/intro_title.png’);}.jj-nls-zh #find_cameraBtn > .text,.jj-nls-zh #find_albumBtn > .text {! width:70px; display:inline-block;}...

42

Page 43: 하이브리드앱 아키텍쳐 및 개발 사례

Ant를����������� ������������������  이용한����������� ������������������  빌드����������� ������������������  자동화

1.����������� ������������������  verify:����������� ������������������  jslint

2.����������� ������������������  merge:����������� ������������������  ant����������� ������������������  concat

3.����������� ������������������  compress:����������� ������������������  YUICompressor

4.����������� ������������������  preprocess:����������� ������������������  ant����������� ������������������  filter

5.����������� ������������������  test:����������� ������������������  JSTestDriver

6.����������� ������������������  docs:����������� ������������������  JSDocToolkit(v2)

43

Page 44: 하이브리드앱 아키텍쳐 및 개발 사례

Ant를����������� ������������������  이용한����������� ������������������  빌드����������� ������������������  자동화

<target name=”verify_js” depends=”init”> <jslint jslint=”${jslint.js}” encoding=”${js.encoding}” options=”${jslint.options}” haltOnFailure=”${jslint.haltOnFailure}”> <predef>${jslint.predef}</predef> <formatter type=”plain”/> <filelist refid=”js.src.files”/> </jslint> </target>

<target name=”merge_js” depends=”verify_js” if=”build.release”> <!-- pudface --> <concat destfile=”${js.out.merged}” encoding=”${js.encoding}” outputencoding=”${js.encoding}” fixlastline=”no” eol=”unix”> <filelist refid=”js.src.files”/> <filterchain> <deletecharacters chars=”&#xFEFF;”/> </filterchain> </concat> <echo message=”merged into ${js.out.merged}”/> </target>

<target name=”compress_js_yuicompressor” depends=”verify_merged_js” if=”build.release”> <!-- pudface --> <java classname=”${yuicompressor.mainclass}” classpathref=”yuicompressor.classpath” fork=”true” failonerror=”true”> <arg value=”--verbose”/> <arg value=”--charset”/> <arg value=”${js.encoding}”/> <arg value=”--type”/> <arg value=”js”/> <arg value=”-o”/> <arg file=”${js.out.compressed}”/> <arg file=”${js.out.merged}”/> </java> <delete file=”${js.out.merged}”/> <echo message=”compressed into ${js.out.compressed}”/> </target>

44

Page 45: 하이브리드앱 아키텍쳐 및 개발 사례

Ant를����������� ������������������  이용한����������� ������������������  빌드����������� ������������������  자동화

<target name=”build_debug” depends=”clean,copy_apis” if=”build.debug”> <copy todir=”${out.dir}” verbose=”true”> <fileset dir=”${src.dir}”> <exclude name=”index.html”/> </fileset> </copy> <copy todir=”${out.dir}” encoding=”${html.encoding}” outputencoding=”${html.encoding}” verbose=”true” overwrite=”true”> <fileset dir=”${src.dir}”> <include name=”index.html”/> </fileset> <filterchain> <linecontains negate=”true”><contains value=”@@RELEASE”/></linecontains> </filterchain> </copy> </target>

<target name=”build_release” depends=”clean,compress_js,compress_css” if=”build.release”> <copy todir=”${out.dir}” verbose=”true”> <fileset dir=”${src.dir}”> <exclude name=”index.html”/> <exclude name=”js/pudface/**”/> <exclude name=”css/**”/> </fileset> </copy> <copy todir=”${out.dir}” encoding=”${html.encoding}” outputencoding=”${html.encoding}” verbose=”true” overwrite=”true”> <fileset dir=”${src.dir}”> <include name=”index.html”/> </fileset> <filterchain> <linecontains negate=”true”><contains value=”@@DEBUG”/></linecontains> </filterchain> </copy> </target>

45

Page 46: 하이브리드앱 아키텍쳐 및 개발 사례

네이티브와의����������� ������������������  결합

사용한����������� ������������������  앱스프레소����������� ������������������  플러그인

·deviceapis.filesystem:����������� ������������������  파일����������� ������������������  입출력·deviceapis.deviceinteraction:����������� ������������������  화면����������� ������������������  꺼짐����������� ������������������  방지����������� ������������������  /����������� ������������������  진동·ax.ext.media:����������� ������������������  카메라����������� ������������������  /����������� ������������������  포토����������� ������������������  앨범����������� ������������������  /����������� ������������������  효과음·ax.ext.net:����������� ������������������  업로드����������� ������������������  /����������� ������������������  다운로드·ax.ext.ui:����������� ������������������  네이티브����������� ������������������  UI����������� ������������������  /����������� ������������������  차일드����������� ������������������  브라우져·ax.ext.ga:����������� ������������������  구글����������� ������������������  통계·ax.ext.admob:����������� ������������������  애드몹����������� ������������������  광고· kth.puddingface:����������� ������������������  푸딩얼굴인식앱����������� ������������������  전용����������� ������������������  *^^*

46

Page 47: 하이브리드앱 아키텍쳐 및 개발 사례

앱스프레소����������� ������������������  플러그인����������� ������������������  활용

47

Page 48: 하이브리드앱 아키텍쳐 및 개발 사례

Android����������� ������������������  Native����������� ������������������  Module(Android����������� ������������������  Library����������� ������������������  Project)

iOS����������� ������������������  Native����������� ������������������  Module(Xcode����������� ������������������  Static����������� ������������������  Library����������� ������������������  Project)

Appspresso����������� ������������������  Plugin����������� ������������������  Project

����������� ������������������  앱스프레소����������� ������������������  플러그인����������� ������������������  구조

export&����������� ������������������  share

link&����������� ������������������  run

Appspresso����������� ������������������  Application����������� ������������������  Project

Appspresso����������� ������������������  Plugin����������� ������������������  Archive����������� ������������������  (*.axp)

axplugin.xml axplugin.js

res overlay

lib*.a *.jar

48

Page 49: 하이브리드앱 아키텍쳐 및 개발 사례

앱스프레소����������� ������������������  플러그인����������� ������������������  API

AxPlugin

1

2

2

4

/*����������� ������������������  YOUR����������� ������������������  CODE����������� ������������������  HERE����������� ������������������  */activate(AxRuntimeContext)deactivate(AxRuntimeContext)execute(AxPluginContext)

...

AxRuntimeContext

getWebView()getWidget()

...requirePlugin(pluginId)executeJavaScript(script)

...

AxPluginContext

int����������� ������������������  getId()String����������� ������������������  getMethod()Object[]����������� ������������������  getParams()

...sendResult([result])

sendError(code[,����������� ������������������  message])

자바스크립트����������� ������������������  API

플랫폼����������� ������������������  확장����������� ������������������  API

Android iOS

49

Page 50: 하이브리드앱 아키텍쳐 및 개발 사례

앱스프레소����������� ������������������  플러그인����������� ������������������  플랫폼����������� ������������������  확장����������� ������������������  API

·안드로이드����������� ������������������  전용·Activity·ActivityListener·WebViewListener·WebViewClientListener/WebChromeClientListener·iOS����������� ������������������  전용·UIViewController·UIApplicationDelegate·UIWebViewDelegate·AxViewControllerDelegate

50

Page 51: 하이브리드앱 아키텍쳐 및 개발 사례

앱스프레소����������� ������������������  플러그인����������� ������������������  자바스크립트����������� ������������������  API

·AxPlugin의����������� ������������������  자바스크립트����������� ������������������  “stub”· function����������� ������������������  execSync(method,����������� ������������������  params)· function����������� ������������������  execAsync(method,����������� ������������������  successCallback,����������� ������������������  errorCallback,����������� ������������������  params)

· params:����������� ������������������  array����������� ������������������  of����������� ������������������  arguments

· successCallback:����������� ������������������  function(result)����������� ������������������  {����������� ������������������  ...����������� ������������������  }

· errorCallback:����������� ������������������  function(error)����������� ������������������  {����������� ������������������  ...����������� ������������������  }

·ax,����������� ������������������  ax.error,����������� ������������������  ax.util,����������� ������������������  ax.console,����������� ������������������  ax.request,����������� ������������������  ax.bridge,����������� ������������������  ax.plugin,����������� ������������������  ...

51

Page 52: 하이브리드앱 아키텍쳐 및 개발 사례

앱스프레소����������� ������������������  플러그인����������� ������������������  개발����������� ������������������  실습

네이티브����������� ������������������  주소록����������� ������������������  UI����������� ������������������  플러그인

·deviceapis.pim.contact����������� ������������������  는...·너무����������� ������������������  어려워����������� ������������������  +����������� ������������������  너무����������� ������������������  느려����������� ������������������  +����������� ������������������  뽀대도����������� ������������������  안나...����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  x3·그래서,����������� ������������������  @bluenmad ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  가����������� ������������������  만들었습니다~

·어떻게?

ax.ext.contact.pickContact(function(contact) { if(contact && contact.phoneNumbers) { var firstPhoneNumber = phoneNumbers.split(‘,’)[0]; if(confirm(contact.firstName + ‘에게 전화걸까요?’)) { location.href = ‘tel:’ + firstPhoneNumber; } }}, function(error) { ... })

52

Page 53: 하이브리드앱 아키텍쳐 및 개발 사례

axplugin.xml

<?xml version=”1.0” encoding=”UTF-8”?><axplugin id=”ax.ext.contact” version=”1.0”>! <description>Contact Extension API Appspresso Plugin! </description>! <url>http://appspresso.com</url>! <author>Appspresso Dev. Team</author>! <license>Copyright (c) 2011, KT Hitel Co., LTD. All Rights Reserved.! </license>

! <feature id=”http://appspresso.com/api/ax.ext.contact“! ! category=”Extension” />

! <module platform=”android” platform-version=”8”! ! min-platform-version=”7” max-platform-version=””! ! class=”com.appspresso.screw.contact.ContactPlugin”>! ! <property name=”permission” value=”android.permission.READ_CONTACTS” />! </module>

! <module platform=”ios” platform-version=”4.1”! ! min-platform-version=”4.0” max-platform-version=””! ! class=”ax_ext_contact_MyPlugin”>! ! <property name=”framework” value=”AddressBook.framework, AddressBookUI.framework” />! </module></axplugin>

53

Page 54: 하이브리드앱 아키텍쳐 및 개발 사례

axplugin.js

/*jslint browser:true, confusion:true, debug:true, devel:true, nomen:true, plusplus:true, vars:true *//** * @fileOverview Contact Extension API * @author blueNmad * @version 1.0 */(function () { “use strict”;

var NS_CONTACT = “ax.ext.contact”; var PREFIX_CONTACT = “ax.ext.contact”;

/** * Contact Extension API * * @namespace * @name ax.ext.contact */

/** * @class * @name ContactOpts * @memberOf ax.ext.contact */

/** * native callback for pickContact. * * @param result * @memberOf ax.ext.contact * @private */ var onPickContactCallback = undefined;

/** * pick a contact * * @param {function} callback * @param {function} errback * @param {ax.ext.contact.ContactOpts} opts * @return AxRequest * @methodOf ax.ext.contact */

function pickContact(callback, errback, opts) {

onPickContactCallback = callback;

return this.execAsync(‘pickContact’, ax.nop, errback, [opts || {}]);

}

function onPickContact(contact) { if ( !! onPickContactCallback) { onPickContactCallback(eval(contact)); }

onPickContactCallback = undefined; }

ax.plugin(PREFIX_CONTACT, { ‘pickContact’: pickContact, ‘onPickContact’: onPickContact }, NS_CONTACT);})();

54

Page 55: 하이브리드앱 아키텍쳐 및 개발 사례

com...contact.ContactPlugin.java

package com.appspresso.screw.contact;

import android.app.Activity;import android.content.Intent;import android.provider.ContactsContract;

import com.appspresso.api.AxPluginContext;import com.appspresso.api.AxRuntimeContext;import com.appspresso.api.DefaultAxPlugin;...<<중간생략>>...

/** * Appspresso Plugin Android Module * * id: ax.ext.contact * version: 1.0.0 * */public class ContactPlugin extends DefaultAxPlugin { private static final int

REQ_PICK_CONTACT = 62000;

private ActivityListener activityListener = new ActivityAdapter() {

public boolean onActivityResult(Activity activity, int requestCode, int

resultCode, Intent data) { if (ContactPlugin.REQ_PICK_CONTACT ==

requestCode && data != null) { return ContactUtils.onPickContact(

runtimeContext, data); }

return super.onActivityResult(activity, requestCode, resultCode, data);

} }; public void activate(

AxRuntimeContext runtimeContext) { super.activate(runtimeContext);

runtimeContext.addActivityListener(activityListener);

}

public void deactivate(AxRuntimeContext runtimeContext) {

runtimeContext.removeActivityListener(activityListener);

super.deactivate(runtimeContext); }

public void pickContact(AxPluginContext context) {

Intent intent = new Intent(Intent.ACTION_PICK,

ContactsContract.Contacts.CONTENT_URI); runtimeContext.getActivity()

.startActivityForResult(intent, REQ_PICK_CONTACT);

context.sendResult(); }}

55

Page 56: 하이브리드앱 아키텍쳐 및 개발 사례

com...contact.ContactUtils.java

package com.appspresso.screw.contact;

import java.util.ArrayList;import java.util.List;

import org.apache.commons.logging.Log;import org.json.JSONArray;import org.json.JSONObject;

import android.app.Activity;import android.content.Intent;import android.database.Cursor;import android.provider.ContactsContract;...<<중략>>...import android.webkit.WebView;

import com.appspresso.api.AxLog;

class ContactUtils { private static Log L =

AxLog.getLog(“ContactPlugin”);

private static final String JS_CALLBACK_ONPICKCONTACT =

“ax.ext.contact.onPickContact”;

public static boolean onPickContact(RuntimeContext runtimeContext,

Intent data) { if (data == null) { return false; }

String contactId = data.getData().getLastPathSegment();

JSONObject contact = ContactUtils.getContactWithContactId(

activity, contactId);

if (contact != null) { runtimeContex.invokeJavaScriptFunction(

JS_CALLBACK_ONPICKCONTACT, contact); } return true; }

static JSONObject getContactWithContactId(Activity activity, String contactId) {

JSONObject contact = new JSONObject(); ... Cursor cursor = null; Cursor rawContactIdsCursor = null; try { String[] rawContactIds = null; rawContactIdsCursor = activity .getContentResolver().query( RawContacts.CONTENT_URI, new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + “ = ?”, new String[] { contactId }, null); ... <<중략>> ... }}

56

Page 57: 하이브리드앱 아키텍쳐 및 개발 사례

ax_ext_contact_MyPlugin.h

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import <AddressBook/AddressBook.h>#import <AddressBookUI/AddressBookUI.h>#import “AxPlugin.h”

@protocol AxContext;@protocol AxPluginContext;

@interface ax_ext_contact_MyPlugin : NSObject<AxPlugin, ABPeoplePickerNavigationControllerDelegate> {@private NSObject<AxRuntimeContext> *_runtimeContext;}

@property (nonatomic,readonly,retain) NSObject<AxRuntimeContext>* runtimeContext;

- (void)activate:(NSObject<AxRuntimeContext>*)runtimeContext;- (void)deactivate:(NSObject<AxRuntimeContext>*)runtimeContext;- (void)execute:(NSObject<AxPluginContext>*)context;

- (IBAction)presentABPeoplePickerNavigationController;

// ABPeoplePickerNavigationControllerDelegate method- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person;

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier;

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;

@end

57

Page 58: 하이브리드앱 아키텍쳐 및 개발 사례

ax_ext_contact_MyPlugin.m

//// ax_ext_contact_MyPlugin.m//// Copyright 2011 none. All rights reserved.//

#import “AxRuntimeContext.h”#import “AxPluginContext.h”#import “AxError.h”#import “AxLog.h”#import “ax_ext_contact_MyPlugin.h”

#define JS_CALLBACK_ONPICKCONTACT @”ax.ext.contact.onPickContact”

@implementation ax_ext_contact_MyPlugin

@synthesize runtimeContext = _runtimeContext;

- (void)activate: (NSObject<AxRuntimeContext>*)runtimeContext {

_runtimeContext = [runtimeContext retain];}

- (void)deactivate:(NSObject<AxRuntimeContext>*)runtimeContext {

[_runtimeContext release]; _runtimeContext = nil;}

- (void)execute:(id<AxPluginContext>)context { NSString* method = [context getMethod]; AX_LOG_TRACE(@”ContactView_ios_method : %s”, method); if([method isEqualToString:@”pickContact”]){

[self presentABPeoplePickerNavigationController]; [context sendResult]; } else { [context sendError:AX_NOT_AVAILABLE_ERR]; }}

- (IBAction)presentABPeoplePickerNavigationController { dispatch_async(dispatch_get_main_queue(), ^{ ABPeoplePickerNavigationController *picker = [[[ABPeoplePickerNavigationController alloc] init] autorelease]; picker.peoplePickerDelegate = self; [[self.runtimeContext getViewController] presentModalViewController:picker animated:YES]; // [picker release]; });}...<<중략>>...- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { [[self.runtimeContext getViewController] dismissModalViewControllerAnimated:YES];}

@end

58

Page 59: 하이브리드앱 아키텍쳐 및 개발 사례

Lessons����������� ������������������  Learned59

Page 60: 하이브리드앱 아키텍쳐 및 개발 사례

to.����������� ������������������  ����������� ������������������  개발자

[경고]����������� ������������������  이����������� ������������������  웹은����������� ������������������  당신이����������� ������������������  알았던����������� ������������������  그����������� ������������������  웹이����������� ������������������  아닙니다.����������� ������������������  

The����������� ������������������  Web����������� ������������������  is����������� ������������������  Dead.

크로스����������� ������������������  플랫폼?����������� ������������������  새로운����������� ������������������  플랫폼!!

이����������� ������������������  자바스크립트는����������� ������������������  당신이����������� ������������������  알았던����������� ������������������  

그����������� ������������������  자바스크립트가����������� ������������������  아닙니다.

웹����������� ������������������  요소����������� ������������������  기술����������� ������������������  +����������� ������������������  (GUI)����������� ������������������  애플리케이션����������� ������������������  아키텍쳐

...

60

Page 61: 하이브리드앱 아키텍쳐 및 개발 사례

cc.����������� ������������������  기획자,����������� ������������������  디자이너,����������� ������������������  ...

[경고]����������� ������������������  이����������� ������������������  웹은����������� ������������������  당신이����������� ������������������  알았던����������� ������������������  그����������� ������������������  웹이����������� ������������������  아닙니다.

The����������� ������������������  Web����������� ������������������  is����������� ������������������  Dead.

저비용����������� ������������������  고품질?!

웹의����������� ������������������  한계,����������� ������������������  장점,����������� ������������������  단점을����������� ������������������  고려한����������� ������������������  기획����������� ������������������  &����������� ������������������  디자인과

적절한����������� ������������������  품질����������� ������������������  목표����������� ������������������  설정

무작정����������� ������������������  네이티브����������� ������������������  앱의����������� ������������������  UI/UX����������� ������������������  따라하기����������� ������������������  금지!

...

61

Page 62: 하이브리드앱 아키텍쳐 및 개발 사례

References

· 하이브리드����������� ������������������  모바일����������� ������������������  앱����������� ������������������  프레임웍����������� ������������������  http://slideshare.net/iolo/hybrid-mobile-application-framework

· 단일����������� ������������������  페이지����������� ������������������  인터페이스����������� ������������������  웹/앱����������� ������������������  개발����������� ������������������  http://slideshare.net/iolo/ss-7719322

· Android����������� ������������������  SDK����������� ������������������  WebView����������� ������������������  레퍼런스����������� ������������������  http://goo.gl/iqr9H

· iOS����������� ������������������  SDK����������� ������������������  UIWebView����������� ������������������  레퍼런스����������� ������������������  http://goo.gl/U8XGy

· Android용����������� ������������������  하이브리드����������� ������������������  앱����������� ������������������  템플릿����������� ������������������  https://github.com/iolo/hellowebapp-android

· How����������� ������������������  to����������� ������������������  build����������� ������������������  Android����������� ������������������  App����������� ������������������  with����������� ������������������  HTML/CSS/JavaScript����������� ������������������  http://youtube.com/watch?v=uVqp1zcMfbE

· iOS용����������� ������������������  하이브리드����������� ������������������  앱����������� ������������������  템플릿����������� ������������������  https://github.com/iolo/hellowebapp-ios

· How����������� ������������������  to����������� ������������������  build����������� ������������������  iOS����������� ������������������  App����������� ������������������  with����������� ������������������  HTML/CSS/JavaScript����������� ������������������  http://youtube.com/watch?v=L28lGkoSQ2c

· 푸딩����������� ������������������  얼굴����������� ������������������  인식����������� ������������������  앱(Android)����������� ������������������  https://market.android.com/details?id=com.kth.puddingface

· 푸딩����������� ������������������  얼굴����������� ������������������  인식����������� ������������������  다국어����������� ������������������  앱(iOS)����������� ������������������  http://itunes.apple.com/us/app/id378461555?mt=8

· 앱스프레소����������� ������������������  홈페이지����������� ������������������  http://appspresso.com/

· 폰갭����������� ������������������  홈페이지����������� ������������������  http://phonegap.com/

· 티타늄����������� ������������������  홈페이지����������� ������������������  http://appcelerator.com/

· jQuery����������� ������������������  홈페이지����������� ������������������  http://jquery.com/

· iScroll����������� ������������������  홈페이지����������� ������������������  http://cubiq.org/iscroll/

· JSLint����������� ������������������  홈페이지����������� ������������������  http://jslint.com/

· YUICompressor����������� ������������������  홈페이지����������� ������������������  http://developer.yahoo.com/yui/compressor/

62

Page 63: 하이브리드앱 아키텍쳐 및 개발 사례

That’s����������� ������������������  all����������� ������������������  folks...63

Page 64: 하이브리드앱 아키텍쳐 및 개발 사례

감사합니다모바일개발실 / 앱스프레소팀 / 장동수

iolothebard at kthcorp dot com@iolothebard

64