2013/08/19

PhoneGap + Sencha Touch Quickstart (Part III)


透過前兩篇(Part I, Part II)我們分別建立的 PhoneGap 專案與 Sencha Touch 專案,再來就是將他們合併,也就是讓 Sencha Touch 透過 PhoneGap run 在模擬器上



Part III:Sencha Touch 與 PhoneGap 的結合


1. 把 Sencha Touch web page 複製到 PhoneGap

我們可以把 PhoneGap 想像成一個載體 (webview),上面運行著 Sencha Touch web page,而透過 javascript 可以和底層的 device 溝通。

所以最快的方式就是把 build 出來的 Sencha Touch package 複製到 PhoneGap 底下的 www 資料夾,然後重新 build PhoneGap,再重新 build 各平台的專案。
(在此為了簡化示範流程,才會用手動的方式複製,真正在開發時應該使用 ST project 內的 build.xml 去描述此步驟)

編譯出來的 ST 程式碼
 
Copy 到 PhoneGap 的www
注意來源跟目的,一個是 ST 一個是 PhoneGap。
另外原本在 www 裡面的 config.xml 要留著,編譯時會用到!
$ cp -a SenchaTouch/hello/build/HelloWorld/package/* PhoneGap/hello/www/
$ phonegap build ios
$ phonegap build android

按照 Part I 的方式分別編譯 ios/android 並運行
Good! It works.


2. 加入 PhoneGap deviceready event

由於 Sencha Touch demo 程式中並未使用到 PhoneGap 提供的 API,為了證明它可以work,所以我們要修改 Sencha Touch project 中的 index.html,加入很簡單的程式碼:當 deviceready event 觸發時就在 debug window 印出 deviceready (註:device ready 就表示 API 可以呼叫了)
加在 <head></head>之間,include "touch/microloader/development.js" 之後
<script type="text/javascript" src="phonegap.js"></script>
<script type="text/javascript">
document.addEventListener('deviceready', function() {
  console.log('deviceready');
}, false);
</script>

重新編譯 Sencha Touch project 後產生 package,將其 copy 到 PhoneGap ... (重複步驟1)
還記得編譯 ST 的指令嗎
$ sencha app build package

若看到 demo 網頁出現,同時 console 也跑出 deviceready 字眼,表示我們成功結合 Sencha Touch 與 PhonaGap 了!

iOS 訊息
2013-08-19 23:51:55.016 HelloWorld[71208:c07] deviceready
Android 訊息
I/Web Console( 1291): deviceready at file:///android_asset/www/index.html:61

註:
ios 的 debug window 在 Xcode 裡面
android 可以透過下面指令觀看整個系統的 log
$ adb -s emulator-5554 logcat

PhoneGap + Sencha Touch Quickstart (Part II)


上一篇講完了如何建立 PhoneGap 專案並且 run 在模擬器上,再來要講 Sencha Touch 這個 mobile web framework



Part II: 建立 Sencha Touch 專案


1. 下載 Sencha Touch SDK 與 Sencha Cmd

SDK 有分兩種版本 GPL 與 Commercial,目前最新版本為 2.2.1 在此下載
解壓縮開之後可以得到 touch-2.2.1 資料夾

Sencha Cmd 有 Mac 專屬版本,最新版本為 3.1.2 在此下載
下載後是個安裝檔,請指定安裝路徑。安裝後請把 sencha 執行檔的路徑加到環境變數 $PATH

試一下是否 work
$ sencha help | head -n 1
Sencha Cmd v3.1.2.342


2. 建立專案

利用 Sencha CMD 來建立專案,請指定 sdk 路徑到剛剛下載的 touch-2.2.1,HelloWorld 為專案名,"./hello"是專案建立的位置
$ sencha -sdk ~/Development/touch-2.2.1 generate app HelloWorld ./hello
產生專案資料夾 hello,裡面的 index.html 就是 app 的首頁
app.js 是程式進入點,app 資料夾依據 MVC 的分類放置自己的程式碼
resources 擺放 css, image, icon 這些檔案
touch 放置 Sencha Touch 原始碼,編譯時會引用


3. 編譯專案

夠過編譯可以將引用到的 javascript 從 source 中抽出並壓縮,SCSS 的部分也是會經過 compass 編譯壓縮
$ sencha app build package
在 hello/build/HelloWorld/package 資料夾下可以看到編譯結果


4. 測試

啓動 MacOS 內建 apache
$ sudo apachectl start

將 hello/build/HelloWorld/package copy 到 apache 預設的 document root: /Library/WebServer/Documents/hello
瀏覽網頁 http://localhost/hello/ 即可看到 demo 網站

PhoneGap + Sencha Touch Quickstart (Part I)


PhoneGap + Sencha Touch 這是跨平台 mobile app 開發的一種組合,在開發速度與效能都能接受的情況下,我近期都投入在這個 framework。在此要與大家分享如何快速建立一個 mobile app,系列文章包含三部分:

基本需求

開發環境 MacOS
PhoneGap 3.0.0
SenchaTouch 2.2.1


Part I:建立 PhoneGap 專案


1. 安裝 Mobile SDK

PhoneGap 支援的 mobile 平台有很多種,在這邊只針對 iOS 與 Android 做說明。
iOS 需要安裝 Xcode,可以從 app store 下載,目前我使用的版本是 4.6.3。
而 Android 的部分請參照 Android Platform Guide 下載 ADT,裡面包含了 Eclipse 編輯器與 SDK,SDK 的路徑必須加到環境變數 $PATH,日後 command line 會使用到。


2. 安裝 PhoneGap

PhoneGap 3.0.0 開始的 command line tool 改由 npm 套件管理程式來維護,所以我們要先安裝 node。Node.js官方網站有提供 Mac 專屬的.pkg可以下載,不過我習慣抓 source code 下來編譯,node 安裝好之後自然也會有 npm 指令可以用

利用 npm 來安裝 phonegap
$ sudo npm install -g phonegap
$ phonegap -v
3.0.0-0.14.3


3. 建立 PhoneGap 專案

$ phonegap create hello com.example.hello HelloWorld
產生 hello 資料夾,裡面包含 merges, platforms, plugins, www
platform 擺放各 mobile 平台的專案,plugins 存放提供你存取 device-level API 的 plugin,而 www 就是 app 主程式,平時就是編譯這一份檔案,預設會有基本的 demo 程式在裡面

剛建立好的 phonegap project 是不包含任何 mobile 平台支援,我們要加入 ios, android
$ phonegap build ios
$ phonegap build android
可以看到 hello/platform/ 之下有這兩個平台的專案資料夾

再來我們安裝 device-level API 支援,在此僅安裝最基本的 console plugin,至少可以拿來 debug,其它像是 camera, geolocation... 日後都可以依需求再安裝
$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git


4. 編譯 PhoneGap 專案

PhoneGap 提供 command line 的方式可以編譯與運行,在此我則採用自己的方式
$ phonegap build
下達此指令後,PhoneGap 會從 hello/www 去建立各平台的必要資源,包含 app 原始碼與 plugin,可以在下面資料夾看到編譯結果
hello/platform/ios/www
hello/platform/android/assets/www


5. 編譯各平台的專案並運行

iOS 的部分,用 Xcode 開啓 hello/platform/ios/HelloWorld.xcodeproj,按下左上角的編譯就可以在模擬器上面運行了。同時間在 console window 也可以看到 deviceready 的字眼


Android 的部分程序比較多,請先參照 Android Platform Guide 設定模擬器並開啓

編譯 android 專案
$ cd platform/android
$ ant debug

列出可用的模擬器
$ adb devices
List of devices attached
emulator-5554   device

安裝到模擬器
$ adb -s emulator-5554 install -r bin/HelloWorld-debug.apk
337 KB/s (1579758 bytes in 4.565s)
        pkg: /data/local/tmp/HelloWorld-debug.apk
Success

2013/06/20

jQuery Mobile: Page 動態載入與切換

jQuery Mobile Page 是在 implement mobile app 很常用到的元件,它可以模擬 iOS navigation controller + view controller 的操作界面,不用寫太多程式碼就可以達到這樣的 UI 呈現,但真正在使用時,常常會遇到動態載入 page 或是同一個 page 要呈現不同 content 的時候,對於我這個初學者而言,也還在摸索怎麼管理這些page。

以下列出幾種動態載入 page 的方式:

Static page

提供兩種切換頁面的方式
In html file
<div data-role="page" id="page1">      
    <div data-role="header">         
        <h1>Page 1</h1>     
    </div>
    <div data-role="content">
        <a href="#page2">Change Page</a>
        <a href="#" onclick="$.mobile.changePage('#page2');">Change Page</a>
    </div>
    <div data-role="footer"> 
        <h4>Page Footer</h4>             
    </div> 
</div>    

<div data-role="page" id="page2">         
    <div data-role="header">    
       <h1>Page 2</h1>     
    </div>
    <div data-role="content">  
        <p>In page 2</p>
    </div>
    <div data-role="footer">   
        <h4>Page Footer</h4>      
    </div>
</div>


Load from html file

先放一個空的 page,再用 ChangePage() 的方式 load 下一個 page,把 page 分開在不同的檔案,code 比較清楚
In html file
<div data-role="page" id="page1">
</div>

In js file
$(function(){ 
    $.mobile.changePage("tpl/page2.html", {
        transition: "pop",
        reverse: false,
        changeHash: false
    });
});


Load html file as template

用 ajax 的方式去 load html 並當成 template,套用 data 後變成 page
index.html
<div data-role="page" id="page2">
 <div data-role="header">
  <h1><%= title %></h1>
 </div>

 <div data-role="content">
  <p><%= content %></a>
 </div>

 <div data-role="footer">
  <h4>Page Footer</h4>
 </div>
</div>

In js file
需要搭配 underscore.js 的 template
$(function(){
    $.get('tpl/page2.html', function(data) {
        var tpl = _.template(data);
        var m = {title: "This is title", content: "In the page 2"};
        var newPage = $(tpl(m));
        newPage.appendTo($.mobile.pageContainer);
        $.mobile.changePage(newPage);
    });
});

但上述的方法有個問題,就是 page 一直用 append 的方式加到 html 裡,對記憶體是個消耗,尚在思考要怎麼管理這些 page...

2013/06/16

jQuery Mobile + PhoneGap 快速打造 App

再次回到 mobile app 的世界。

最近接了一個 case,要做一個跨平台的 news feed,想到的組合就是 jQuery Mobile + PhoneGap,為了讓 code 更乾淨,也加入了 backbone.js 這個 MV* framework,說真的,這樣的組合我還沒開發過任何一支產品,本身是 back-end 起家,frontend 算是玩興趣的,兜一些小玩意還可以,開發大 project 就辛苦些...


用 jQuery mobile 兜 UI 比 native code 快了 n 倍,常用的 page view、table view、navigation bar...都可以在簡單的幾行 html 搞定。呈現 static 資料很容易,如果是 dynamic 資料對我這新手就...
分析需求之後,大概就幾個版型:category list、title list、content display,然後塞進不同的資料(來源可以是 api server 吐回來的 json)


Main menu 打算用 slide panel 來呈現,panel 這物件是要擺在 page 裡面的,那如果每個 page 都需要 panel 該怎做?
javascript - jquery mobile: do I have to create a new panel for every page - Stack Overflow
一份 menu 共用摟,我想到的是把 panel 獨立成一個 template,在 pageshow event 去加載
看到一些蠻炫的 panel


jQM 的 page sample 中,同個 html 嵌了多個 page,這在現實環境也是不合需求的。第一、全部的 page 放在同一頁肯定 code 會過長,第二、page 的內容會是 dynamic 的,page 本身應該只是個樣版
官網有提到動態載入 page 的方式:jQuery Mobile and Dynamic Page Generation
很明顯的沒有 router 與 template 的支援,code 相當冗長,於是就引入了 backbone.js 的 route 與 underscore.js 的 template

由於 jQM 與 backbone.js 都會監聽 hash change event,若要使用後者的 router,請參考


如果閒自己寫 html 太慢,可以使用 jQM UI builder

2013/05/21

解開 fd_set size limitation

寫 socket programming 時會用 select 搭配 fd_set 來偵測 file descriptor 是否可讀寫
但 Linux 系統預設的 fd_set size 只有 1024,若同時間處理的 fd 超過 1024 就會出問題


修改下面這兩個檔案,重新 build application 時就會引用到新的 define 值

/usr/include/bits/typesizes.h:
#define    __FD_SETSIZE        1024

/usr/include/linux/posix_types.h:
#define    __FD_SETSIZE        1024

2013/04/25

初次玩 Backbone.js: 多種 Template 的實作方式

假設我想設計一個公司資料,model 為單一員工資料,包含 id 與 name。collection 為部門資料,由多個員工所組成。而 view 用來顯示部門資料之用。
// Models
company.models.Employee = Backbone.Model.extend({
    defaults: {
        id: undefined,
        name: undefined
    }
});

// Collections
company.collections.Department = Backbone.Collection.extend({
    model: company.models.Employee
});

// Views
company.views.EmployeeList = Backbone.View.extend({
    el: "#container",
 
    render: function() {
        ...
    }
});

// Create base data
var c = new company.collections.Department(
        [{id:1, name: "Star Willard"},
         {id:2, name: "Rhona Eggleston"},
         {id:3, name: "Cassi Chowdhury"},
         {id:4, name: "Leigh Nilson"},
         {id:5, name: "Niesha Auger"}
        ]);

// Create view
var v = new company.views.EmployeeList({collection: c});
v.render();


以下就來探討 render function 該怎麼把 collection 套用到 template 並呈現在 UI 上