PhoneGap2012. 6. 29. 17:40

jQuery Mobile은 어플리케이션이 모바일 환경에 최적화되도록 자동으로 HTML의 상당 부분을 변경하거나 개선합니다. 이러한 jQuery Mobile의 자동 최적화는 대부분의 모바일 어플리케이션에서 유용한 것이지만 어떤 특별한 경우에는 필요치 않거나 오히려 없는 편이 더 나을 수도 있습니다.  jQuery Mobile은 이런 상황을 감안해 기본 설정의 주요 부분을 재정의할 수 있게 지원합니다.

PhoneGap은 HTML파일을 읽어들이면서 HTML문서에서 참조하도록 정의된 phonegap-1.1.0.js 라는 파일을 찾습니다. 그리고 해당 파일이 정상적으로 포함된 경우 deviceready 라는 이벤트를 발생시킵니다.

이 두 라이브러리가 서로 각자 초기화가 완료된 후에야 각 라이브러리에서 제공하는 모든 기능을 충분히 활용할 수 있게 됩니다. 하지만 이 두 라이브러리의 초기화 과정에서 서로 충돌이 발생해서 둘중 한가지는 충분히 초기화 되기 이전에 페이지가 사용자에게 노출되어 에러를 발생하게 하는 원인이 됩니다.



PhoneGap의 초기화 이벤트 처리하기

앞에서 이야기 했듯이 PhoneGap은 deviceready라는 이벤트를 HTML문서가 초기화 되면 발생시킵니다.

HTML파일에서는 다음과 같이 PhoneGap의 초기화 이벤트를 처리할 수 있습니다.
  1. <script src="phonegap-1.1.0.js"></script>  
  2. <script type="text/javascript">  
  3. document.addEventListener("deviceready"function(){  
  4.     // 초기화에 필요한 수행  
  5. }, false);  
  6. </script>  


jQuery Mobile의 초기화 수행

jQuery Mobile에서는 jQuery Mobile이 초기화 되기 이전에 필요한 기본 처리들을 충분히 수행한 후에 초기화 할 수 있도록, 자동 초기화를 중지시키고 수동으로 초기화하는 기능을 제공하기 위해서 jQuery Mobile이 초기화 되기 이전에 mobileinit라는 이벤트를 발생시킵니다.

이 mobileinit라는 이벤트를 구현해서 jQuery Mobile이 초기화를 하지 못하도록 막을 수 있습니다.

$.mobile.autoInitializePage 라는 속성에 false라는 값을 대입하면 됩니다.
  1. <script type="text/javascript">  
  2. $(document).bind("mobileinit"function() {  
  3.     $.mobile.autoInitializePage = false;  
  4. });  
  5. </script>  

이 mobileinit라는 이벤트는 jQuery 라이브러리가 로드되고, jQuery Mobile 라이브러리가 로드되기 전에 발생합니다. 따라서 위의 소스는 위치가 매우 중요해 지는데요, 다음과 같이 작성되어야 합니다.
  1. <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />  
  2. <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>  
  3. <script type="text/javascript">  
  4. $(document).bind("mobileinit"function() {  
  5.     $.mobile.autoInitializePage = false;  
  6. });  
  7. </script>  
  8. <script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>  

이렇게 $.mobile.autoInitializePage = false; 속성을 지정해 주면 jQuery Mobile은 명시적으로 $.mobile.initializePage(); 라는 메소드를 호출하기 전까지 초기화를 수행하지 않습니다.

PhoneGap과 연관 없이 단순히 필요한 사전 처리만을 수행한 후에, jQuery Mobile을 수행하기 위해서는 다음과 같이 처리하도록 jQuery Mobile API에서 소개하고 있습니다.
  1. <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />  
  2. <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>  
  3. <script type="text/javascript">  
  4. $(document).bind("mobileinit"function() {  
  5.     $.mobile.autoInitializePage = false;  
  6.     // 초기화에 필요한 처리 (1)  
  7. });  
  8. </script>  
  9. <script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>  
  10. <script src="phonegap-1.1.0.js"></script>  
  11. <script type="text/javascript">  
  12. $(document).ready(function() {  
  13.     // 초기화에 필요한 처리 (2)  
  14.      $.mobile.initializePage();  
  15. });  
  16. </script>  
만약 초기화 과정에서 jQuery Mobile에서 제공하는 $.mobile 이라는 객체의 기능을 사용해야 한다면, 초기화 처리는 (2)번 부분에 기술되어야 하며, 그렇지 않은 경우는 (1)과 (2) 원하는 곳에 넣으면 됩니다. 처음에는 $.mobile.initializePage(); 를 mobileinit 이벤트 함수 안에서 호출했더니 메소드를 찾지 못한다면에 에러가 났었습니다.



moibleinit 이벤트에서 deviceready 이벤트 처리

jQuery Mobile과 phonegap을 함께 초기화 하기 위해서는 jQuery Mobile의 mobileinit 이벤트에서 $.mobile.autoInitializePage = false; 를 지정하여 초기화를 중지시킨 다음에 이 부분에 phonegap의 deviceready 이벤트를 정의해 줍니다.

아래와 같이 처리해 주면, jQuery Mobile은 스스로의 초기화를 중지시킨 후에, phonegap의 deviceready 이벤트가 발생할 때 까지 기다릴 겁니다.
  1. $(document).bind("mobileinit"function() {  
  2.     $.mobile.autoInitializePage = false;  
  3.     document.addEventListener("deviceready"function(){  
  4.         // phonegap의 초기화가 완료된 후의 처리  
  5.     }, false);  
  6. });  

deviceready 이벤트가 발생하여 phonegap의 초기화가 완료되면, 그 안에서 아직 수행되지 않은 jQuery Mobile의 초기화를 명시적으로 호출합니다.
  1. <script src="phonegap-1.1.0.js"></script>  
  2. <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />  
  3. <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>  
  4. <script type="text/javascript">  
  5. $(document).bind("mobileinit"function() {  
  6.     $.mobile.autoInitializePage = false;  
  7.      document.addEventListener("deviceready"function(){  
  8.         $.mobile.initializePage();  
  9.     }, false);  
  10. });  
  11. </script>  
  12. <script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>  


샘플코드

아래 샘플은 위와 같은 초기화 방식을 적용하여, jQuery Mobile에서 phoneGap의 deviceready 이벤트를 받아, 단말기의 기본 사양을 출력하도록 한 샘플입니다.

출력 값의 속성 이름을 알기 위해서 phonegap의 샘플 코드를 참조했으며, 출력값을 inset-listview에 넣었습니다.
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>Hello PhoneGap</title>  
  5.     <meta charset="utf-8"/>  
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=medium-dpi" />  
  7.     <script src="phonegap-1.1.0.js"></script>  
  8.     <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />  
  9.     <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>  
  10.     <script type="text/javascript">  
  11.         $(document).bind("mobileinit"function() {  
  12.             $.mobile.autoInitializePage = false;  
  13.             document.addEventListener("deviceready"function(){  
  14.                 $.mobile.initializePage();  
  15.                 document.getElementById("platform").innerHTML = device.platform;  
  16.                 document.getElementById("version").innerHTML = device.version;  
  17.                 document.getElementById("uuid").innerHTML = device.uuid;  
  18.                 document.getElementById("name").innerHTML = device.name;  
  19.                 document.getElementById("width").innerHTML = screen.width;  
  20.                 document.getElementById("height").innerHTML = screen.height;  
  21.                 document.getElementById("colorDepth").innerHTML = screen.colorDepth;  
  22.             }, false);  
  23.         });  
  24.     </script>  
  25.     <script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>  
  26. </head>  
  27. <body>  
  28. <div data-role="page">  
  29.     <div data-role="header">  
  30.         <h1>PhoneGap Init</h1>  
  31.     </div>  
  32.     <div data-role="content">  
  33.         <ol data-role="listview" data-inset="true" data-theme="d">  
  34.             <li>Platform: <span id="platform"> &nbsp;</span></li>  
  35.             <li>Version: <span id="version"> &nbsp;</span></li>  
  36.             <li>UUID: <span id="uuid"> &nbsp;</span></li>  
  37.             <li>Name: <span id="name"> &nbsp;</span></li>  
  38.             <li>Width: <span id="width"> &nbsp;</span></li>  
  39.             <li>Height: <span id="height"> &nbsp;</span></li>  
  40.             <li>Color Depth: <span id="colorDepth"> &nbsp;</span></li>  
  41.         </ol>  
  42.     </div>  
  43. </div>  
  44. </body>  
  45. </html>  

실행하면 아래와 같이 결과가 나옵니다. 안드로이드 (삼성 갤럭시S2)에서만 테스트 해 봤습니다.

혹시 iOS나 다른 폰에서 결과가 동일하지 않다면 피드백 주시면 감사하겠습니다.

Posted by 다오나무
PhoneGap2012. 6. 26. 15:30

PhoneGap(폰갭)에서는 anrdoid.app.Activity.onKeyDown() 메소드를 아래와 같이 재정의하여 사용자가 하드웨어 취소키(back키)를 누르면 브라우저의 뒤로가기를 수행합니다.

// com.phonegap.DroidGap.onKeyDown(int, KeyEvent) 메소드 

public boolean onKeyDown(int keyCode, KeyEvent event) {
 ... ...
     // If back key
     if (keyCode == KeyEvent.KEYCODE_BACK) {

     // If back key is bound, then send event to JavaScript
     if (this.bound) {
     this.appView.loadUrl("javascript:PhoneGap.fireEvent('backbutton');");
     }

     // If not bound
     else {

     // Go to previous page in webview if it is possible to go back
     if (this.appView.canGoBack()) {
     this.appView.goBack();
     }

     // If not, then invoke behavior of super class
     else {
     return super.onKeyDown(keyCode, event);
     }
     }
     }
... ...


그러나 때로는 사용자가 취소키를 누르면 이전 웹페이지로 이동하지 않고 앱을 종료시키는 것으로 정책을 바꾸고 싶은 경우도 있습니다. (특히나 아이폰을 고려하여 이전버튼을 포함하도록 웹페이지를 디자인한 경우).

폰갭에서는 취소키 동작을 재정의하는 2가지 방법이 있습니다.
 
1. DroidGap의 onKeyDown 메소드 오버라이딩
DroidGap을 상속받은 Activity에서 onKeyDown 메소드를 오버라이딩해서 백버튼을 적절히 핸들링해줍니다. 아래코드에서는 앱 종료여부를 묻는 확인창을 띄우도록 했습니다.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        confirmAppExit();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

private void confirmAppExit() {
    AlertDialog.Builder db = new AlertDialog.Builder(this);
    db.setTitle(R.string.exit_app_title)
         .setMessage(R.string.exit_app_message) // "프로그램을 종료하시겠습니까?"
         .setCancelable(true)
         .setPositiveButton(android.R.string.ok, new OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 finish(); //확인버튼 누루면 앱 종료
             }
         })
         .setNegativeButton(android.R.string.cancel, null)
         .show();
}



2. 폰갭 javascript의 'backbutton' 이벤트 재정의(phonegap 0.9.5 이상)

function onLoad() {
    document.addEventListener("backbutton", backKeyDown, true);
}
function backKeyDown() {
    if (confirm('프로그램을 종료하시겠습니까?')) {
        navigator.app.exitApp();
    }
}
...
...
<body onload="onLoad()">


단순히 취소키 눌렀을 때 페이지 뒤로가기를 막으려면 아래코드로 충분합니다.

navigator.app.overrideBackbutton(true);

Posted by 다오나무
PhoneGap2012. 6. 26. 13:44

이제는 유지보수에만 전념하던 그래서 약간은 지루했던(잘 알지도 못하면서;) 안드로이드 개발에 또 하나의 도전 과제가 생겼다. 나태에 젖어 흐느적 거리고 있던 내게 팀장님이 재미있는 미끼를 던져주었다. 이름 하여 PhoneGap 하고픈 말은 나중에 보중하고 일단 개발자라면 늘 친숙한 Hello world 부터 찍어보자

개발자는 두 가지 부류가 있다.
설계를 머리에 이고 키보드 부터 두드리는자,
그리고 UML부터 그려가며 말과 글과 그림그리며 오감으로 개발을 시작하는 자.
다들 안다. 후자가 고수의 길이며 정도라고..
하지만 난 늘 전자의 유혹에 무릎을 꿇는다..
후자 스타일이라면 먼저 PhoneGap 이 무언지 부터 살펴보자
http://phonegap.com/

시작하기
http://phonegap.com/start#android

1.요구사항
- 이클립스 3.4 이상 필요하단다 찾아보니 Ganymede 이상이면 될듯하다. 아직도 난 정식명칭이 궁금 가니메데? 개니메드? 가나이메드? ㅋ
- 이클립스를 사용하지 않는 이 듀토리얼의 터미널 버전 - 이건 무슨말인지 모르겠다;

2. SDK 설치 + PhoneGap
- 이클립스 받아 설치
- 안드로이드 SDK 받아 설치
- ADT 까지 받아 설치, 여기까지는 기존에 안드로이드 개발을 했던 분이라면 이미 준비되어 있을거라 생각된다.
- PhoneGap 최신 버전을 받아서 압축을 풉니다. 이 압축 푼 내용을 안드로이드 디렉토리와 함께 작업할 껍니다. 나는 다른 라이브러리 처럼 플러인이나 라이브러리 path를 잡아줘야 되는 줄 알았다.
하지만 내용을 보면 알겠지만 jar, js, htm 이 들어 있어 안드로이드 소스에 직접 복사해서 넣는 방법을 쓰며 배포시 패키지 만들때 포함되어 릴리즈 되는 것 같다.

3. 새 프로젝트 만들기
- New>Android Project 로 실제 Helloworld 안드로이드 프로젝트를 만든다.
- 버전선택을 맘대로 정한다. 테스트로 2.2
- 앱네임과 패키지 명, 메인 액티비티 명을 이름 짓는다.
- 최소 sdk 버전은 써도 안써도 좋다. 2.2로 정했다면 2.2의 api 레벨인 8로 테스트로 세팅한다.
여기까지는 기존에 안드로이드 개발해보신 분이라면 무난히 수월하게 따라 왔으리라고 본다.
이 후에 설정 작업이 재미있다.
- 여러분이 만든 Helloworld 프로젝트 루트 디렉토리에 다음과 같이 /libs  디렉토리를 만들고 기존에 있는 /assets 디렉토리 밑에 /www 디렉토리를 새로 만든다. 그러면 /libs , /assets/www  두 개의 디렉터리가 만들어진다.
- 아까 다운로드 받아 압축 풀어놨던 파일들 중에 android 디렉토리 안에 phonegap.js 파일을 /assets/www 에 복사해 붙여 넣는다.
- phonegap.jar 파일을 /libs 디렉토리 안에 복사하기 해서 붙여 넣는다.
- 마지막으로 이번엔 xml 디렉토리 전체를 복사하여 /res 디렉토리에 붙여넣는다.
- 이제 만들었던 메인 액티비티 소스를 고쳐보자. 
- 고치기에 앞서서 추가했던 jar를 프로젝트 path에 설정해주자. 프로젝트명 오른쪽 마우스 클릭해 Properties를 선택하여 java build path를 살펴보면 Libraries 탭을 설정해서 Add JARs를 선택해 현재 프로젝트에 속해있는 phonegap.jar 파일을 선택해 포함시킨후 확인 저장한다.
- 다음으로 소스를 고친다 이미 기본으로 생성된 소스를 다음과 같이 수정한다.
- Activity 로 extends된 클래스를 DroidGap으로 바꾼다.
- 뷰를 그려주는 역할을 하는 setContentView() 대신 super.loadUrl("file://android_asset/www/index.htm"); 으로 설정한다. 해당 index.htm 은 조금 있다 만들겠다. file:///android_asset 은 루트의 기본 디렉토리인 /assets 를 말합니다.
- ctrl + o 를 눌러서 import com.phonegarp.*; 이 추가되고 import android.app.Activity;는 제거됩니다.
- 그리고 환경설정파일인 AndroidManifest.xml 파일에 버전정보 다음으로 아래 내용을 추가합니다. 아래는 제 소스 샘플입니다.

<?xml version="1.0" encoding="utf-8"?>
 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.binsolb.phonegap.helloworld"
      android:versionCode="1"
 
      android:versionName="1.0">
 
  <supports-screens
android:largeScreens="true"
 
android:normalScreens="true"
 
android:smallScreens="true"
 
android:resizeable="true"
 
android:anyDensity="true"
 
/>
<uses-permission android:name="android.permission.CAMERA" />
 
<uses-permission android:name="android.permission.VIBRATE" />
 
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
 
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
 
<uses-permission android:name="android.permission.INTERNET" />
 
<uses-permission android:name="android.permission.RECEIVE_SMS" />
 
<uses-permission android:name="android.permission.RECORD_AUDIO" />
 
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
 
<uses-permission android:name="android.permission.READ_CONTACTS" />
 
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
<uses-permission android:name="android.permission.GET_ACCOUNTS" 
/>
 
<uses-sdk android:minSdkVersion="8" />
 
    <application android:icon="@drawable/icon" android:label="@string/app_name">
 
        <activity android:name=".HelloActivity"
                  android:label="@string/app_name"
 
                  android:configChanges="orientation|keyboardHidden">
 
            <intent-filter>
 
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
 
            </intent-filter>
 
        </activity>
 
    </application>
 
</manifest>


- 그리고 다음의 회전설정도 추가해줍니다.

4. Hellow World htm 만들기
-앞서 말씀드렸던 htm파일을 만듭니다. 위치는 /assets/www  아래에 index.htm  파일을 아래와 같이 만듭니다.

<!DOCTYPE HTML>
<html>
<head>
<title>PhoneGap</title>
<script type="text/javascript" charset="utf-8" src="phonegap-1.3.0.js"></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>

- 스크립트 파일 명은 복사 해 넣은 버전의 파일명 그대로 쓰시면됩니다. 위는 제 샘플입니다.
5 배포합니다.
- 시뮬레이터로 배포 또는 디바이스로 배포를 합니다.
- Run as > Android Application 선택으로 실행시킵니다.

6. 결과 확인


잘나오는 군요 뿌듯합니다 이제 간단히 tv팟을 만들어봐야겠어요!


*혹시 잘 모르시는 분은 좀더 자세한 설명의 아래 페이지를 참고하세요~
http://wiki.phonegap.com/w/page/30862722/phonegap-android-eclipse-quickstart

Posted by 다오나무
PhoneGap2012. 6. 26. 10:43

최근엔 "하이브리드 앱"이라는 용어가 마케팅으로 사용될 정도로 PhoneGap에 대한 관심이 많습니다. 하지만 아래와 같은 장점을 가지고 있지만 단점도 가지고 있습니다.


장점

- 기존 Javascript 코드를 부분적으로 재사용 가능

- 하나의 웹 코드 (HTML, CSS, Javascript)를 작성하면 부분적으로 여러 플랫폼(iOS, Android, Window Phone, Black berry, webOS, smybian, bada) 재사용 가능 


단점

- 웹베이스로 코드가 동작 되기 떄문에 비교적(Native App과 비교하면) 느리다.

- PhoneGap API들은 가장 기본이 되는 것만 제공해 준다. (PhoneGap API 참고 : http://docs.phonegap.com/en/1.7.0/index.html)

- Native 고유의 기능을 사용해야만 구현 할 수 있는 기능들이 있다 (예) Android의 Background Service


이러한 장.단점들을 가지고 있지만 단점들을 보면 정말 부족해 보입니다. 이 단점을 어느 정도 극복 하기 위한 방법이 각 플랫폼 별로 Plugin을 개발해서 사용하는 것 입니다.


PhoneGap Plugin

Plugin을 만든다는 것은 Native 코드를 이용해서 필요한 기능들 만들어서 사용한다는 것 입니다. iOS의 경우에는 Objective-C로 Android는 Java로 기존 Native에서 동작하는 코드를 PhoneGap Plugin 형식에 맞게 제공하여 PhoneGap을 이용한 앱에서 이를 사용할 수 있도록 합니다.


무엇을 할 수 있는가?

많은 연산을 필요로 하는 작업은 Native에서 처리 (더 빠르다?)

- PhoneGap API에 없는 기능들을 추가해서 사용 (Android의 Background service, 바이너리 이미지를 PhotoLibrary에 저장)

- Native 언어적으로 복잡한 비지니스 로직을 처리 하는 방법이 있을 경우 플러그인으로 만들어서 사용




개발 방법

PhoneGap Plugin은 Javascript코드와 Native코드 쌍으로 이루어져 있습니다. 여러 플랫폼에 대응하는 Plugin기능을 만드려면 플랫폼 마다 구현해 줘야 합니다. Javascript는 기본 인터페이스를 만들어 놓고 세부적인 내용은 플랫폼 별로 다르게 작성 되야 합니다.


PhoneGap 1.5 부터 Apache Cordova로 이름이 바뀌면서 덩달아 Namespace도 모두 바뀌었습니다. 아래 내용은 PhoneGap 1.5 이후 버전에 맞게 작성 되었습니다.


iOS (wiki : http://goo.gl/fNC4c)

예제 코드는 Javascript에서 Plugin으로 Hellow World 문자열을 전달하여 전달된 문자열이 Hellow World가 맞다면 성공, 아니면 실패를 반환하는 코드 입니다. 원본 코드는 위의 wiki에서 확인 가능 합니다.


1.  사용할 Objective-C 코드 작성

(코드 출처 :  http://goo.gl/fNC4c)

#import <Foundation/Foundation.h>
#import <Cordova/CDVPlugin.h>
   
 
// CDVPlugin을 상속
@interface MyClass : CDVPlugin {
      
      // 호출된 Javascript를 참조 하는 ID
      NSString* callbackID; 
 }
 
@property (nonatomic, copy) NSString* callbackID;
 
// Instance Method 
- (void) print:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
  
@end


#import "MyClass.h"
       
 @implementation MyClass
 
 @synthesize callbackID;
 
 -(void)print:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options 
 {
           // arguments에 제일 마지막에 있는 값이 callbackID이다.
           self.callbackID = [arguments pop];
 
           // Javascript로 부터 전달된 값을 저장
           NSString *stringObtainedFromJavascript = [arguments objectAtIndex:0];                
 
           // Javsacript로 확인된 메세지를 보내기 위해 Objective-C에서 값 생성
           NSMutableString *stringToReturn = [NSMutableString stringWithString: @"StringReceived:"];
 
           // 전달된 값과 생성된 값을 합침
           [stringToReturn appendString: stringObtainedFromJavascript];
            
           // Javascript에 전달할 결과 값을 생성 CDVPluginResult 로 생성 해야만 한다. 전달하는 문자열은 UTF-8로 인코딩
           CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                  messageAsString: [stringToReturn stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
 
           // Javascript로 부터 전달된 값이 HellowWorld이면 성공 Callback 실행, 실패면 실패 Callback 실행
           if ([stringObtainedFromJavascript isEqualToString:@"HelloWorld"] == YES)
           {
                  // Call the javascript success function
                  [self writeJavascript: [pluginResult toSuccessCallbackString:self.callbackID]];
           else
           {   
                  // Call the javascript error function
                  [self writeJavascript: [pluginResult toErrorCallbackString:self.callbackID]];
           }
  }
  @end


2. 위에서 작성된 Plugin 코드를 실행할 Javascript 클래스 생성 및 실행 예제


var MyPlugin = {
     nativeFunction: function(types, success, fail) {
          return Cordova.exec(success, fail, "MyPlugin""print", types);
     }
};
 
MyPlugin.nativeFunction(
      ["HelloWorld"],
      function(result) {
           alert("Success: \r\n"+result);     
      },
      function(error) {
           alert("Error: \r\n"+error);     
      }
); 



3. 위의 코드들이 제대로 동작하게 할 설정  


Cordova.plist



<plist version="1.0">

     <dict>
          ...
          <key>Plugins</key>
          <dict>
               ...

               <key>MyPlugin</key>

               <string>MyClass</string>
               ...
          </dict>
          ...
     </dict>
</plist>





다른 플랫폼에 대한 Plugin 개발 방법은 여기서(http://goo.gl/O6XHI) 확인 가능 합니다


결론


PhoneGap은 모바일 개발 인력이 부족한 환경에서 빠른 시간 안에 더 많은 플랫폼을 대응할 수 있다는 장점을 가지고 있습니다. 하지만 이러한 생산성은 모든 플랫폼에 적용되는 것이 아닙니다. 지극히 한정적인 서비스에서 그리고 웹기반으로 서비스를 구축했을때 장점을 가진 환경에서만 위의 장점을 누릴수 있습니다. 많은 서비스들이 하이브리드 앱으로 서비스를 시작했다가 결국에는 Native 로 다시 만드는 사례가 많아 지고 있는 이유는, 하이브리드 앱 개발이나 HTML5 라는 용어가 단순히 유행 처럼 서비스에 적용하는 사례들이 많아 지고 있기 때문이 아닐까 생각해 봅니다.


저도 PhoneGap에 대해 공부 하고 있는 상태지만, 서비스에 해당 기술을 도입함에 앞서서 앞으로 만드려고 하는 서비스가 퍼포먼스를 중시하는 서비스 인지, 아니면 특별한 기능이 있는데 이를 하이브리드 앱으로 개발해도 가능 할지에 대해 반드시 확인하고 적용해 보는게 좋습니다. 

제대로된 선행 조사와 서비스에 대한 이해가 있는 상태에서 PhoneGap을 선택했을때는 더할나위 없이 빠른 퍼포먼스를 낼 수도 있는 플랫폼이지만 그게 아니라면 빠른 생산성은 커녕 유지 보수 하는데 더 많은 시간과 인력이 필요하게 될거라 생각 합니다.


PhoneGap의 모든것이라는 제목으로 3개의 포스팅을 하였는데요. 모든것을 다룬것 같진 않네요. 처음 시작하기에 앞서 한번 훑어 보면 좋은 글이라고 봐주셨으면 합니다.


제가 언급한 내용중 잘못된 내용이 있으면 바로 잡아 주세요.

Posted by 다오나무
PhoneGap2012. 6. 26. 10:39



이번 문서에서는 PhoneGap를 셋팅하고 (iOS) PhoneGap 프로젝트에서 javascript 초기화에 대해 다룬다.


Getting Start PhoneGap



PhoneGap을 시작하는 사람들을 모두 들어가 봤을만한 공식 사이트다. 아주 친절하게도 http://phonegap.com/start 이 주소로 들어 가면 플랫폼 별로 초기 셋팅을 어떻게 하는지에 대해 순서대로 나와 있다. 



주의 해야할 사항은 xcode 를 이용하여 iOS 플랫폼에 셋팅을 하는 경우라면 초기에 PhoneGap을 설치하고 Cordova Project로 생성을 한 뒤에 위와 같은 폴더 구조가 나오는데 바로 컴파일을 하면 제대로된 화면이 안나오고 아래와 같은 메세지를 볼수 있다.



PhoneGap에서 사용되는 javascript 와 html, css파일들은 프로젝트 하위의 www 폴더에 생성되는데 xcode에서 이를 인식하지 못하여 발생하는 문제이다. xcode에 플러그인 형식으로 설치 하는 거라 플러그인에서 생성 시킨 폴더(www)를 자동으로 프로젝트에 추가 해주지 못해서 그런것 같다. 위의 문제는 프로젝트를 한번 컴파일 한뒤에 프로젝트를 저장한 폴더에 이동해 보면 www폴더가 생성되어 있는걸 볼수 있는데 아래와 같이 프로젝트에 추가해 주면 제대로 동작 하게 된다.


www폴더를 드래그 해서 위의 phonegap_sample 프로젝트에 드랍해 주면 프로젝트에서 www를 인식 하게 된다. 





www/index.html 



<script type=
"text/javascript" charset="utf-8" src="cordova-1.5.0.js"></script>
<script type="text/javascript">
 
function onBodyLoad() {
 
    document.addEventListener("deviceready", onDeviceReady, false);
}
 
function onDeviceReady()
{
    // Device Ready!
}
 
  
</script>
<body onload="onBodyLoad()">
</body>


www폴더를 보면 PhoneGap을 동작하는데 필요한 cordova.js와 index.html 이 있다. cordova.js를 PhoneGap을 초기화 하고 디바이스와 통신하는데 필요한 준비 및 API로 구성되어 있다. 한번 훑어 보는것도 좋을듯 하다.


위의 코드는 index.html에서 기본적인 source만 뽑아낸 것이다. 어플리케이션이 실행 되면 처음으로 시작되는 곳이 index.html 이다. 모든 초기화는 여기서 이루어 진다. 일반 웹 페이지와 다른 것은 "deviceready" 이벤트를 통해 PhoneGap이 동작하는 기기(플랫폼)가 준비가 되었는지 확인하는 과정이 필요하다. 위의 코드에서 알수 있듯이 onDeviceReady가 호출 된 후에에 PhoneGap API 등을 사용할 수 있다. 그 전에 호출을 해봤자 실행 되지 않는다.



2개의 문서로 마무리를 지으려고 했는데, 문서를 작성하면서 생각이 덧붙여 지면서 분량이 더 많아 졌다. 다음 문서에서는 iOS와 Android 플랫폼에서 동작하는 Plugin 개발하는 방법을 다루겠다.

Posted by 다오나무
PhoneGap2012. 6. 26. 09:37


PhoneGap

PhoneGap의 기본컨셉은 대부분의 모바일 플랫폼이 WebView를 가지고 있기 때문에 기본적인 기능들은 HTML과 CSS, Javascript로 만들어서 WebView에서 동작하게 하고 Device(Native)의 도움이 필요한 영역은 PhoneGap framework가 도움을 줘서 설치되어 동작하는 어플리케이션을 만들수 있는 방법을 제공 하는 것이다.





Apache Cordova

Adobe가 PhoneGap을 인수한 뒤에 PhoneGap을 Apache재단에 기부하였다. 그래서 Opensource가 되었고, PhoneGap 1.5 (Cordova) 버전부터 클래스 이름이 죄다 바뀌어 버렸다.


PhoneGap에서 제공하는 것들

WebView만으로는 구현이 어렵거나, Native의 도움이 필요한 기본 기능들은 PhoneGap API을 통해 사용 가능하다. 

지원하는 API 는 다음과 같다.

  • 각각의 기능별로 예제 코드와 함께 정리가 잘되어 있어서 쉽게 적응할 수 있다.
  • 각 API별로 지원하는 플랫폼이 명시 되어 있다. (iOS와 Android는 대부분 지원)


Accelerometer : Tap into the device's motion sensor.

Camera : Capture a photo using the device's camera.

Capture : Capture media files using device's media capture applications.

Compass : Obtain the direction that the device is pointing.

Connection : Quickly check the network state, and cellular network information.

Contacts : Work with the devices contact database.

Device : Gather device specific information.

Events : Hook into native events through JavaScript.

File : Hook into native file system through JavaScript.

Geolocation : Make your application location aware.

Media : Record and play back audio files.

Notification : Visual, audible, and tactile device notifications.

Storage : Hook into the devices native storage options.



PhoneGap의 동작 원리

PhoneGap을 이용하여 만든 어플리케이션들도 결국에는 Native 어플리케이션으로 컴파일되어 설치 된다. Adobe AIR과 같이 코드가 바이너리로 설치 파일에 포함되는 형식이 아니라, Native 어플리케이션 위에서 PhoneGap이 동작하고 이 PhoneGap을 통해 Javascript로 만든 어플리케이션과 통신하는 과정을 통해 실행 된다. 하지만 Javascript는 Native와 다른 환경에서(WebView) 동작한다. JavaScript는 네이티브 코드와 데이터를 공유할 수 없다. 그래서 PhoneGap에서는 별도의 통신 방법을 만들어 웹뷰에서 네이티브 코드와 데이터를 교환한다. 각각의 플랫폼(iOS, Android...) 마다 WebView와 Native와 서로 통신하는 방법이 다르다. 이렇게 통신하는 방법이 다르기 때문에 PhoneGap에서 이를 지원한다. 이러한 방법이 PhoneGap이 동작하는 원리이다.

PhoneGap을 Native에서 동작하는 코드들과 (각각 플랫폼 마다 별개) cordova.js 과의 통신을 통해 동작한다. (Plugin이 있다면 Plugin을 제어 하는 코드들도 함께 동작) 

각각의 플랫폼마다 WebView와의 통신 방법이 다르므로 모두 언급할 수 없기에 대표적으로 iOS와 Android를 설명하면 다음과 같다. 더 자세한 내용은여기를 참고하라.


IOS


Custom Scheme 이란? (예제)

tel:01012341234
kakaolink://sendurl?msg=[message]&url=[url]&appid=[appid]&appver=[appver]
gap://ready



iOS에서는 WebView에서 Native로 명령을 전달하고 받기 위한 방법으로 Custom Scheme를 사용한다. 아래와 같은 형식으로 WebView에서 호출하면 Native에서는 클래스(class), 함수(command) 그리고 함수에 전달될 인자(arguments) 를 통해 Native Code를 실행 한다.


yourscheme://<class>.<command>/[<arguments>][?<dictionary>]


반대로 Native Code에서 WebView로 명령은 iOS SDK의 stringByEvaluatingJavaScriptFromString를 이용한다.



NSString* status = @
"Native To WebView!";
[webView stringByEvaluatingJavaScriptFromString:status];


Android

WebView에 있는 addJavascriptInterface를 통해 Javascript가 호출할 수 있는 코드정보를 미리 등록해서 이를 이용해서 WebView에서 Native코드를 실행한다.

등록


webView.addJavascriptInterface(new MyNativeAPI(), "MyNativeAPI");
Class MyNativeAPI {
 
    public String whereAmI() {
        return "I am in Native";
    }
}


호출


MyNativeAPI.whereAmI();


반대로 Native Code에서 WebView로 명령은 WebView클래스의 loadUrl() 을 이용한다.


webView.loadUrl("javascript:alert('I am in WebView')");


PhoneGap을 사용하면 위에서 언급한 제공하는 API 만으로 어플리케이션을 구현하는데 부족함이 많다. 그래서 PhoneGap에서는 이 부족한 기능을 특정 플랫폼에 맞게 PhoneGap Plugin을 개발하여 사용할수 있다. (Adobe AIR의 Native Extention 이라 생각하면 되겠다) PhoneGap의 근본 취지와는 다르게 Plugin은 특정 플랫폼에 맞춰서 따로 따로 개발해 줘야한다. 2번째 문서에서는 간단히 PhoneGap Plugin을 개발하는 방법에 대해 다룰 것이다.

Posted by 다오나무