構建經過 Database.com 提供技術支持的 PhoneGap 應用程序

 要求
其餘必要產品
Database.com account
用戶級別
所有

必需產品
PhoneGap Build
範例文件
Database.Com-PhoneGap-Sample
在這篇文章中,咱們將探究使用 PhoneGap 構建的移動應用程序的建立過程,全部數據 均經過 Database.com 提供並保存。在深刻探討技術細節以前,咱們先來回顧一下相關術語。

PhoneGap

PhoneGap 是一種免費的開放源碼技術,旨在使開發人員使用基於 Web 的傳統技術,建立可以在多個平臺上進行本機安裝的移動應用程序。咱們最好將 PhoneGap 視爲佔據設備整個寬度和高度的 Web 視圖。在該 Web 視圖內,您須要使用 HTML、CSS 和 JavaScript 語言構建應用程序接口。


圖 1. 應用程序 Web 視圖
該應用程序的 Web 視圖基於操做系統的本機 Web 視圖,其本質上與標準 Web 瀏覽器相同(窗口鑲邊除外)。您將徹底使用 HTML、CSS 和 JavaScript 語言構建全部導航和內容元素,並使用 JavaScript 編寫應用程序邏輯。

PhoneGap 提供了一個 JavaScript 與本機之間的橋樑。這樣,您的應用程序將無需編寫任何本機代碼便可與本機操做系統進行交互。您徹底用 JavaScript 構建應用程序邏輯,並利用 PhoneGap API 與設備操做系統進行交互。


圖 2. PhoneGap 可助您訪問各類設備功能
「開箱即用」的 PhoneGap 可訪問設備加速計、羅盤及地理位置功能,訪問設備聯繫人、本機文件系統、設備相機、媒體播放及捕獲功能。您能夠在多個平臺上訪問上述全部功能,而無需編寫任何本機代碼行,全部功能徹底能夠經過 JavaScript 進行訪問。若是這還不夠,您還能夠經過在可擴展架構之上構建「本機插件」來輕鬆擴展 PhoneGap,稍後我將在本文中進行進一步的細節說明。

PhoneGap 還提供了一種針對經常使用移動生態系統包裝應用程序的方式。PhoneGap 應用程序的輸出內容是二進制應用程序存檔,其中包含應用程序賴以運行的全部必要的 HTML、CSS 和 JavaScript 資產。


圖 3. PhoneGap 針對常見移動生態系統包裝應用程序
對於 iOS 設備,此輸出爲 IPA 文件,對於 Android 而言是 APK 文件,而對於 Windows Phone 則是 XAP 文件等… 全部這些二進制文件格式均爲正常存檔,您能夠將它們上傳至 iTunes Store、Google Play、BlackBerry App World 及 Windows Phone Marketplace,也能夠直接安裝至某臺設備。單個 PhoneGap 應用程序代碼庫可針對 Apple iOS、Google Android、Windows Phone、BlackBerry、HP WebOS、Symbain 及 Samsung Bada 操做系統,且可針對手機和平板電腦規格。

正如我前面所說,PhoneGap 是一種免費的開放源碼技術。整個 PhoneGap 代碼庫都可做爲 Apache Cordova項目的一部分進行免費訪問。您能夠當即下載源代碼、進行更改及回饋項目!

Database.com

Database.com是 salesforce.com 提供的一個雲數據庫。Database.com 提供了多種託管關係數據庫功能,您能夠藉此輕鬆地進入應用程序內部,而且無需自行對基本結構進行管理。您能夠運用基於 Web 的管理界面來建立對象和關係,並利用 REST 或 SOAP API 訪問本身的數據。您能夠經過 開發人員中心瞭解有關 Database.com 功能的更多信息。

應用程序

在本文中,咱們將會瀏覽使用 Database.com 上的數據的基本 PhoneGap 應用程序的建立過程。

下面是相關基本概念:它是一種可供「現場」工做人員使用的應用程序,用之前往不一樣的位置,收集聯繫人或「潛在客戶」。它能夠用來蒐集聯繫人信息及註釋,也能夠記錄用戶的 GPS 座標,以識別信息捕獲位置。它還可以讓您返回並編輯此前捕獲的數據。固然,還須要確保該應用程序可以在各類平臺上進行訪問。下面讓咱們來看一下基本流程,而後咱們將詳細介紹如何建立該應用程序。


圖 4. 示例應用程序的三個主界面
您能夠看到,該應用程序包含三個主界面,「Home」 界面(讓您自行選擇添加新記錄仍是查看現有記錄)、「Leads」 列表(用於顯示現有記錄)及添加/編輯記錄的表單。還有一個是登陸/身份驗證界面,咱們將在稍後進行介紹,但如今您能夠看到這是一個簡單的應用程序用例。

您能夠在如下網址下載此應用程序的完整源代碼:https://github.com/triceam/Database.Com-PhoneGap-Sample.

數據庫
此應用程序將對數據存儲使用 Database.com 上的一個自定義表。雖然這是一個基本的單表示例,但 Database.com 還能夠支持大型的多重關係數據結構。

註冊免費賬戶後,登陸並單擊 System Overview 界面上的 「Create A New Object」。


圖 5. 在 System Overview 界面上建立新對象
這將會顯示 「New Custom Object」 對話框。您須要在此處輸入對象標籤/名稱。我在這裏建立了一個 「Lead」 對象。歸入即將經過 PhoneGap 應用程序捕獲的潛在客戶。


圖 6. 輸入對象標籤/名稱。
接下來,向 "Lead" 對象添加自定義字段。在 「Custom Fields & Relationships」 部分,單擊 「New」 按鈕添加數據字段。

我添加了 「First Name」、「Last Name」、「Latitude」、「Longitude」、「Notes」、「Email」 及 「Telephone」 字段。只需按照在線嚮導中所列的步驟 - 它將會指導您完成此流程。


圖 7. 在 「Custom Fields & Relationships」 下添加數據字段
此時,咱們已經建立了這些數據對象,它們將用於保存在應用程序內捕獲的數據。然而,您還須要再執行一個步驟,才能在 PhoneGap 應用程序內使用這些對象。爲遠程訪問數據,您必須建立一個遠程訪問「應用程序」。此應用程序的配置將包括一個獨特的密鑰,用來以正確的方式對用戶進行身份驗證及識別您的數據對象。

要建立遠程訪問「應用程序」,只需展開 「Develop」 類別,而後選擇 「New」。


圖 8. 在 「Develop」 類別中建立新的遠程訪問「應用程序」
這將會顯示 「Remote Access Edit」 表單,您須要在這裏指定應用程序名稱、聯繫人電子郵件及應用程序的回調 URL 配置。應用程序名稱將用做登陸應用程序時的說明性文字,回調 URL 將用來在用戶成功完成身份驗證後重定向用戶的瀏覽器。


圖 9. 在 「Remote Access Edit」 表單中指定應用程序詳細信息
在保存此信息後,系統將會向您提供一個「用戶密鑰」,供您在此後登陸及訪問 Database.com 中的數據服務時使用。記錄您的用戶密鑰。稍後您須要在 JavaScript 配置中使用此密鑰。


圖 10. 從 Database.com 登陸及訪問數據服務須要使用的「用戶密鑰」
在獲取用戶密鑰後,您即可以開始經過 Database.com 來回推拉數據。

Forcetk.js
該應用程序將使用 forcetk.js JavaScript 包裝器與 Database.com 的 REST API 開展通訊。Forcetk.js (Force.com JavaScript REST Tookit) 是 REST API的一個開放源碼包裝器,用以簡化基於 JavaScript 的應用程序內部的 Force.com/Database.com 數據使用過程。Forcetk.js 可提供 OAuth2身份驗證掛鉤及各類輔助方法,從而使數據檢索和更新變得異常方便。

在 PhoneGap 中構建應用程序時,無需代理便可直接訪問 force.com REST API(與您在構建基於標準瀏覽器的應用程序時的操做相同)。

PhoneGap 應用程序

在利用 PhoneGap 時,您應當徹底用 HTML、CSS 和 JavaScript 語言建立應用程序。您能夠在任何文本編輯器中開發這些應用程序。自行決定使用哪一種方法。您可使用簡單文本編輯器(如 TextMate)、HTML 編輯器(如 Dreamweaver),也可使用複雜 IDE(如 Xcode、Eclipse 或 Visual Studio)。Xcode、Eclipse 或 Visual Studio 等 IDE 可以讓您使用 USB 鏈接直接在設備上部署 PhoneGap 應用程序。不過,您也可使用PhoneGap Build(一種基於雲的 PhoneGap 編譯器),您只需加載 HTML、CSS 和 JavaScript 代碼,它便可爲您生成平臺特定二進制文件。

因爲要使用 HTML、CSS 和 JavaScript 構建應用程序界面,您能夠利用現有的工具和框架提升開發人員的工做效率。此示例將利用如下工具加快開發流程:

Zepto.js – 一種開發加速器庫,用以提供建立交互式動態 JavaScript 體驗所需的實用工具和快捷功能。Zepto.js 包含一種 jQuery 兼容語法,並通過移動核心優化。
Twitter Bootstrap – 一種用戶界面樣式庫,用以提供各類 CSS 樣式及 HTML/JavaScript 組件,從而使您的應用程序更像「應用程序」,而非「只是網頁」。
Mustache.js – 一種易於使用的模板庫,可以讓您建立 HTML「模板」,以便在動態 JavaScript 應用程序內部使用。模板技術有助於您輕鬆分離 HTML 用戶界面層與 JavaScript 語言編寫的應用程序邏輯。
首先,在應用程序內建立根 HTML 文件,它將成爲該應用程序的切入點。全部 PhoneGap 應用程序均經過 "index.html" 文件啓動,它也是應用程序的「根」。我在 index.html 文件內歸入了全部適當的庫,並加入了空白 HTML <body>。 HTML <body> 空白是由於咱們將經過 JavaScript 動態建立整個用戶界面。

<html>
    <head>
    <link rel="stylesheet" href="assets/css/bootstrap.css" type="text/css" />
    <link rel="stylesheet" href="assets/css/styles.css" type="text/css" />
        <script type="text/javascript" src="js/libs/zepto.js"></script>
        <script type="text/javascript" src="js/libs/forcetk.js"></script>
        <script type="text/javascript" src="cordova-1.7.0.js"></script>
        <script type="text/javascript" src="js/libs/ChildBrowser.js"></script>   
        <script type="text/javascript" src="js/libs/mustache.js"></script>       
        <script type="text/javascript" src="js/salesforceWrapper.js"></script>         
        <script type="text/javascript" src="js/application.js"></script>            
    </head>
    
    <body></body>
    
</html>
在完成 PhoneGap 應用程序初始化後,將會發送 "deviceready" 事件。此事件代表,應用程序內容均已充分加載,全部 PhoneGap API 均已完成初始化。

document.addEventListener( "deviceready", onDeviceReady );

var sfw;

function onDeviceReady( event ) {
    console.log("deviceready");
    
    //initialize salesforce wrapper
    sfw = new SalesforceWrapper();
}
首先,應用程序會初始化我建立的名爲 "SalesforceWrapper" 的 JavaScript 類。SalesforceWrapper 類包裝 forcetk.js 庫,以便簡化身份驗證並歸入訪問 force.com REST API 所需的所有配置信息。在這個類中,您將須要使用用戶密鑰(經過「遠程訪問」配置獲取,咱們已在前文進行過討論)設置 clientID 值。

function SalesforceWrapper() {
    /* AUTHENTICATION PARAMETERS */
    this.loginUrl = 'https://login.salesforce.com/';
    this.clientId = 'YOUR_KEY_GOES_HERE;
    this.redirectUri = 'https://login.salesforce.com/services/oauth2/success';
    
    /* CLASS VARIABLES */
    this.cb = undefined;     //ChildBrowser in PhoneGap
    this.client = undefined; //forceTk client instance
    
    this.init();
}

SalesforceWrapper.prototype.init = function() {
    this.client = new forcetk.Client(this.clientId, this.loginUrl);
    this.cb = window.plugins.childBrowser;
}

SalesforceWrapper.prototype.login = function (successCallback) {
    this.loginSuccess = successCallback;
    var self = this;
    self.cb.onLocationChange = function (loc) {
        if (loc.search(self.redirectUri) >= 0) {
            self.cb.close();
            self.sessionCallback(unescape(loc));
        }
    };
    self.cb.showWebPage(self.getAuthorizeUrl(self.loginUrl, self.clientId, self.redirectUri));
}

SalesforceWrapper.prototype.getAuthorizeUrl = function (loginUrl, clientId, redirectUri) {
    return loginUrl + 'services/oauth2/authorize?display=touch' + '&response_type=token&client_id=' + escape(clientId) + '&redirect_uri=' + escape(redirectUri);
}

SalesforceWrapper.prototype.sessionCallback = function(loc) {    var oauthResponse = {};
    
    var fragment = loc.split("#")[1];
    
    if (fragment) {
        var nvps = fragment.split('&');
        for (var nvp in nvps) {
            var parts = nvps[nvp].split('=');
            oauthResponse[parts[0]] = unescape(parts[1]);
        }
    }
    
    if (typeof oauthResponse === 'undefined' || typeof oauthResponse['access_token'] === 'undefined') {
        console.log("error");
    } else {
        this.client.setSessionToken(oauthResponse.access_token, null, oauthResponse.instance_url);
        if ( this.loginSuccess ) {
            this.loginSuccess();
        }
    }
    this.loginSuccess = undefined;
}
SalesforceWrapper 類簡化了 forcetk.js的示例,於是您只需使用應用程序中的一行代碼便可完成身份驗證:

sfw.login( setupHomeView );
SalesforceWrapper的登陸函數只須要一個參數 – 一個將在用戶成功登陸後進行調用的函數引用。

您可能還注意到,SalesforceWrapper 是指 ChildBrowser JavaScript 類。ChildBrowser 類是 ChildBrowser PhoneGap 原生擴展的一部分,同時適用於 iOS、Android、BlackBerry 和 Windows Phone。所以,您的 PhoneGap 應用程序將具備「子」Web 視圖,在這種狀況下,該「子」Web 視圖將用於對 Force.com API 進行身份驗證。

一旦 SalesforceWrapper 類完成初始化,Moustache.js 模板也將進行初始化。每一個模板都是一個獨立的 HTML 文件,將用於呈現界面,於是必須加載至內存才能使用。

var templates = {
    structure:"views/structure.html",
    home:"views/home.html",
    form:"views/formView.html",
    list:"views/dataView.html",
    listItem:"views/listItem.html",
    loaded: 0,
    requested: 0,
}; 

function onDeviceReady( event ) {
    console.log("deviceready");
    
    //initialize salesforce wrapper
    sfw = new SalesforceWrapper();
    
    //load Mousetache HTML templates
    for (var key in templates) {
        (function() {
            var _key = key.toString();
            if ( _key != "loaded" && _key != "requested" ){
                templates.requested ++;
         
                 var templateLoaded = function( template ){
                    onTemplateLoaded( template, _key );
                 }
                
                $.get( templates[ _key ], templateLoaded );
             }
         })();
    }
}

function onTemplateLoaded(template, key) {
    
    console.log( key + ": " + template);
    templates[ key ] = template;
    templates.loaded ++;
    
    if ( templates.loaded == templates.requested ) {
        setupDefaultView();
    }
}
一旦模板加載完成,setupDefaultView() 函數也將隨之調用。這將會根據 templates.structure 模板建立初始用戶界面。

var header, container;

function setupDefaultView() {
    console.log("setupDefaultView");
    $("body").html( templates.structure );
    header = $("body").find("#header");
    container = $("body").find("#content");
    
    $('#login').tap(function (e) {
        e.preventDefault();
        sfw.login( setupHomeView );
    });
}
隨後,它會爲該模板的「標頭」和「容器」元素設置引用以供往後使用,而後將事件處理程序添加至 「login」 按鈕,這樣當用戶點按該按鈕時,將會調用 SalesforceWrapper 類的登陸功能。

您能夠從下面的 templates.structure 模板中查看 HTML:

<div id="header">Welcome</div>
<div id="content">
    <h3 style="padding-top:1.5em; padding-bottom:1.5em;" class="alert alert-info">Press the "Login" button to authenticate via Database.com.</h3>
    <br/><br/>
    <a id="login" class="btn btn-success">Login</a>
</div>
經過 CSS 樣式應用格式,呈現的輸出內容以下所示。一旦用戶點按 「Login」 按鈕,將會顯示 Database.com 的 OAuth 登陸界面。


圖 11. 用戶點按 Login,然後顯示 Database.com 的 OAuth 登陸界面
全部身份驗證操做均在 ChildBrowser 內處理,且徹底由 Database.com 進行維護。做爲一名開發人員,您沒必要再擔憂用戶賬戶管理或登陸功能,由於 force.com 將會代您進行處理。用戶只需具有 Database.com 數據對象(數據庫)的訪問權限。一旦用戶成功經過身份驗證, setupHomeView()函數當即獲得調用,並會顯示該應用程序的「Home」界面。

setupHomeView()函數重置/清除容器元素的內容,而後填入 templates.home 模板內容,並添加適當的事件處理程序。

function resetContainer() {
    //this removes child elements and cleans up event handlers
    container.children().remove();
    container.removeClass("nopadding");
}

function setupHomeView() {
    resetContainer();
    container.html( templates.home );
    header.html( "Welcome" );
    
    $('#addNew').tap(function (e) {
        setupFormView();
        e.preventDefault();
        e.stopPropagation();
        return false;
    });
    
    
    $('#queryMyRecords').tap(function (e) {
        setupListView();
        e.preventDefault();
        e.stopPropagation();
        return false;
    });
}
您能夠查看下面的 templates.home 模板:

<h3>Please select an option:</h3>

<a id="addNew" class="btn btn-info">Add New Record</a>
<br/>
<a id="queryMyRecords" class="btn btn-info">Query My Records</a>
用戶將會在手機上看到呈現的輸出內容,以下所示。您能夠看到,其中包含兩個按鈕,一個用於添加新記錄,另外一個用於查詢 Database.com 中的現有記錄。


圖 12. 呈現的輸出
接下來,咱們來看一下當用戶單擊 「Add New Record」 按鈕時會發生什麼情況。當用戶單擊此按鈕時,將會調用setupFormView() 按鈕,從而建立新表單以便蒐集用戶數據。

function setupFormView(data) {
    resetContainer();    
    var html =  Mustache.to_html( templates.form, data ); 
    container.html( html );
    currentLead = data;
    
    //request current location
    if ( !(data && data.Id) ) {
        header.html( "New Lead" );
        navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError );
    }
    else {
        header.html( "Edit Lead" );
    }
        
    $('#save').tap( saveFormData );
    $('#cancel').tap( navigateBackFromFormView );
}
setupFormView()函數將清除容器元素,而後填入templtes.form模板中的 HTML。此時,您將會發現模板技術變得十分有用。接下來,讓咱們來看一下表單模板:

<div id="form">
    <label for="first">First Name</label>
    <input id="first" type="text" value="{{First__c}}" />

    <br/>
    <label for="last">Last Name</label>
    <input id="last" type="text" value="{{Last__c}}" />

    <br/>
    <label for="phone">Telephone</label>
    <input id="phone" type="text" value="{{Telephone__c}}" />

    <br/>
    <label for="email">Email</label>
    <input id="email" type="text" value="{{Email__c}}" />

    <br/>
    <label for="notes">Notes</label>
    <textarea id="notes" type="text">{{Notes__c}}</textarea>

    <br/>
    <span id="location" class="alert alert-info">Location: {{Latitude__c}},{{Longitude__c}}</span>

    <br/>
    <br/>
    <a id="save" class="btn btn-success">Save</a>
    <a id="cancel" class="btn btn-danger">Cancel</a>
</div>
該表單包含用於生成用戶界面的 HTML。雙括號 "{{" 和 "}}" 中括住的值將填充爲傳遞至 Mustache 模板引擎的數據。括號內包含的各值與傳遞至 Mustache.js 的數據對象屬性相對應。

用戶界面的 HTML 字符串經過 Mustache.to_html() 函數生成。您能夠在上方的 setupFormView 函數中看到,to_html()函數使用 data 參數生成模板 HTML。當建立新的潛在客戶時,會向此函數傳遞一個空對象,所以該表單的 HTML 將包含空值。當編輯現有的潛在客戶時,將會調用此函數,但會傳入填充的數據對象。這將會重用同一 HTML 模板,但會填充傳入的數據。

當呈如今 PhoneGap 應用程序內時,您將會看到表單外觀以下所示。當捕獲新潛在客戶時,經過 PhoneGap API 獲取 GPS 位置。


圖 13. 新潛在客戶表單顯示 PhoneGap API 中的 GPS 位置
用戶能夠輸入適當的數據,而後單擊 「Save」 或 「Cancel」。若是用戶取消操做,則應用程序會將用戶返回。然而,若是用戶保存數據,則表示應用程序將數據推送至 Database.com。

在saveFormData()JavaScript 函數內,從輸入表單中檢索數據,而後將數據分配至某個「數據」對象,數據也將發送至 Database.com。saveFormData() 函數既可用於建立新潛在客戶,也可用於更新現有的潛在客戶。若是存在 currentLead 變量,則用戶編輯現有的潛在客戶,不然用戶建立新的潛在客戶。若是用戶正在建立新潛在客戶,則調用 forcetkclient.create 函數,不然調用client.update 函數。

function saveFormData( event ) {
    
    var data = {};
    data.First__c = $("#first").val();
    data.Last__c = $("#last").val();
    data.Telephone__c = $("#phone").val();
    data.Email__c = $("#email").val();
    data.Notes__c = $("#notes").val();
    
    if ( currentLead ) {
        //copy it back to the object in memory
        currentLead.First__c = data.First__c;
        currentLead.Last__c = data.Last__c;
        currentLead.Telephone__c = data.Telephone__c;
        currentLead.Email__c = data.Email__c;
        currentLead.Notes__c = data.Notes__c;
        
        //use the original lat/lon location
        data.Latitude__c = currentLead.Latitude__c;
        data.Longitude__c = currentLead.Longitude__c;
    }
    else if ( lastCoords ) {
        data.Latitude__c = lastCoords.latitude;
        data.Longitude__c = lastCoords.longitude;
    }
    try {
        if ( currentLead == undefined ) {
            sfw.client.create("Lead__C", data, saveDataSuccess, saveDataError );
        } else {
            sfw.client.update("Lead__C", currentLead.Id, data, saveDataSuccess, saveDataError );
        }
    } 
    catch(e){
        console.log(e);
    }
}

function saveDataSuccess( result ) {
    alert("Data Saved");
    navigateBackFromFormView();
}

function saveDataError( request, status, error){ 
    console.log( request.responseText ); 
    alert( request.responseText );
}
當調用 client.create(),時,您只需傳遞該類型的對象(數據對象)及成功和錯誤回調函數。當引用該類型的對象時,您可能已經注意到它是 "Lead__c",而不是 "Lead",您或許早已預料到。這是由於 Database.com 中的自定義對象和自定義數據字段必須使用 "__c" 後綴。

當調用 client.update()時,您須要傳遞該類型的對象,並更新對象 ID,同時該數據對象包含新值及成功和錯誤回調函數。

若是保存數據時發生錯誤,系統將會向用戶顯示消息。若是沒有錯誤,系統會將用戶返回至上一個視圖。

接下來,咱們來看一下從 Database.com 檢索數據的工做流程。從應用程序主屏幕中單擊 "Query My Records" 按鈕。這將會調用setupListView() JavaScript 函數。

function setupListView() {
    resetContainer();
    
    var html = templates.list; 
    container.html( html );
    header.html( "Leads" );
    
    if(lastData) {
        renderListData();
    }
    else {
        queryRecords();
    }
    
    $('#cancel').tap( setupHomeView );
}
setupListView() 函數將清除容器,並填入 templates.list 模板中的 HTML。此模板並不實際顯示數據,而是建立 dataContainer元素並在那裏顯示列表數據。

<div id="dataContainer">loading...</div>
<br/><br/>
<a id="cancel" class="btn btn-danger" style="width:70%">Cancel</a>
若是用戶從編輯表單返回,將會呈現已有的內存數據。然而,對於新請求,將會調用 queryRecords()函數。

從 Database.com 查詢數據很是方便。當使用 forcetk.js 工具包時,您只需調用 client.query()方法,傳入帶有成功和錯誤回調函數的 SOQL 查詢。SOQL是一種 Salesforce 對象查詢語言,與其餘數據庫產品使用的 SQL(結構化查詢語言)極其類似。SOQL 可以讓您從相關對象建立不可勝數的自定義數據查詢,正如您使用 SQL 可能出現的狀況同樣。Database.com 還包含一種在線 Workbench工具,可以讓您對 SOQL 查詢進行測試,而後再將它們輸入實際的應用程序。

queryRecords()函數以下所示,在這裏您能夠看到,它會傳入 SOQL 查詢來檢索數據:

function queryRecords() {
    
    var query = "SELECT Email__c,First__c,Id,Last__c,Latitude__c,Longitude__c,Notes__c,Telephone__c "+
    "FROM Lead__c " + 
    "ORDER BY Last__c, First__c"
    
    sfw.client.query( query, onQuerySuccess, onQueryError );
}

function onQuerySuccess( response ) {
    
    lastData = { "records": response.records };
    renderListData();
}

function onQueryError( request, status, error ) {
    $("#dataContainer").html( "Error loading data: <br/>" + request.responseText );
}
從 Database.com 返回數據後,將會調用 onQuerySuccess 函數,然後隨之調用renderListData() 函數。

function renderListData() {
    if ( lastData ) {
        container.addClass("nopadding");
        var html = Mustache.to_html( templates.listItem, lastData ); 
        $("#dataContainer").html( html );
        $("#dataContainer").find("li").tap( onListItemTap );
        $("#cancel").tap( navigateBackFromListView );
    }
}
renderListData()函數基於從服務器返回的數據使用templates.listItem模板生成 HTML 列表,而後向全部 <li> 元素添加 "tap" 事件處理程序。

接下來,讓咱們來看一下 templates.listItem模板的內容:

<ul>
{{#records}}
    <li id="{{Id}}">
        <strong>{{Last__c}}, {{First__c}}</strong>
        <div class="subtext">{{Email__c}} </div>
    </li>
{{/records}}
</ul>
此模板指示 Mustache.js 遍歷全部「記錄」,並輸出包含該潛在客戶姓名和電子郵件地址的 <li> 元素。

呈現數據後,您可能會看到相似於下方屏幕截圖的界面。全部列表格式設置均以 CSS 語言處理,所以視覺效果更像是移動應用程序列表,而非項目符號 HTML 列表。


圖 14. CSS 格式設置將列表顯示爲移動應用程序列表
當用戶點按列表項時,將會調用 onListItemTap 函數。此函數將會獲取與點按的列表項對應的 JavaScript 對象引用,然後調用前文所討論的 setupFormView() 函數,傳入適當的對象。

function onListItemTap( event ) {
    
    var target = $( event.target )
    while (target.get(0).nodeName.toUpperCase() != "LI") {
        target=target.parent();
    }
    var id = target.attr("id");
    
    var data = getRecordById(id);    
    setupFormView( data );
    
    event.preventDefault();
    event.stopPropagation();
    

function getRecordById( id ) {
    
    if ( !lastData  ) return;
    var records = lastData.records;
    
    for (var x=0; x<records.length; x++ ) {
        if (records[x].Id == id ) {
            return records[x];
        }
    }
}
因爲重用了 setupFormView() 函數,它也會重用 templates.form模板,但填入從 Database.com 檢索到的數據。請參閱下面的屏幕截圖,看看顯示填充數據的示例。


圖15. 重用 templates.form,填入從 Database.com 檢索到的數據
咱們如今已經介紹完檢索及保存 Database.com 數據的端到端解決方案,接下來談談部署問題。

部署

一項部署方案是導出 IDE 的應用程序存檔。對於 iOS 應用程序,必須使用 Xcode on OS X;對於 Android 應用程序,必須使用 Eclipse(可使用 Windows、Linux 或 OS X);對於 BlackBerry 應用程序,必須使用 BlackBerry 工具;而對於 Windows Phone,則必須使用 Visual Studio(僅限 Windows)。部署至多個平臺意味着具備多個開發環境。

PhoneGap Build將在此大顯身手!PhoneGap Build 有助於開發人員上傳代碼,或者將 PhoneGap Build 指向 Git 或 SVN 庫,PhoneGap Build 將執行基於雲的編譯,從而爲用戶提供 URL 以便下載特定於設備的應用程序二進制文件。

在 Web 瀏覽器中,只需導航至 http://build.phonegap.com,而後登陸便可。當您登陸後,單擊右上角的 "new app" 按鈕。將會顯示一個對話框,示意您上傳代碼或者指定 Git 或 SVN 庫。


圖 16. 在 New app 中,上傳代碼或者指定 Git 或 SVN 庫
一旦 PhoneGap Build 可以訪問您的代碼,它將會自動執行基於雲的編譯,從而爲您提供連接和 QR 代碼供您下載應用程序二進制文件。


圖 17. 基於雲的編譯,其中提供了連接和 QR 代碼供您下載應用程序二進制文件
若是您在移動設備上使用 QR 代碼閱讀器,則能夠經過捕捉圖片直接將應用程序二進制文件下載至該設備。QR 代碼閱讀器將啓動應用程序二進制文件下載,以便在您的設備上進行安裝。

如今您會有一個應用程序使用 Database.com 中的數據、在多臺設備上運行,並構建於單一代碼庫之上。下圖爲此應用程序圖像,它可同時在 Motorola Atrix (Android) 和 iPhone 4 (iOS) 上運行。


圖 18. 該應用程序可同時在 Motorola Atrix (Android) 和 iPhone 4 (iOS) 上運行
T您能夠在如下網址下載此應用程序的完整源代碼:https://github.com/triceam/Database.Com-PhoneGap-Sample。請隨意以此做爲 PhoneGap 和 Database.com 支持的應用程序的學習起點。

爲何選擇 PhoneGap?

若是仍然不肯定 PhoneGap 是否適合您,請繼續閱讀本文,瞭解您可能須要在下一個項目中使用 PhoneGap 的幾大緣由。

針對多個平臺
PhoneGap 可以讓您針對多個移動平臺利用一個代碼庫。Web 已經經過 HTML、CSS 和 JavaScript 解決了跨平臺應用程序問題。PhoneGap 充分利用 HTML、CSS 及 JavaScript 的普及性,協助您經過上述這些技術構建移動應用程序。

利用現有技能
因爲 PhoneGap 應用程序均採用 HTML、CSS 和 JavaScript 構建而成,開發人員無需學習新型語言或開發範例。開發人員可重用自身先前熟悉的技能和工具快速高效地開發移動應用程序。這樣既省時又省錢。

重用現有工具
因爲 PhoneGap 應用程序利用 Web 技術,所以有數不清的現有二進制文件或框架可供您利用以加速應用程序開發。不管是 jQuery 或 Zepto 等解決方案加速器框架,Twitter Bootstrap、jQuery Mobile 或 Sencha 等用戶界面工具包,仍是 Raphael.js、Highcharts 或 RGraph.js 等數據可視化庫,您的應用程序內部都有大量開源和商業資源可供利用。

可擴展
PhoneGap 提供了一些「開箱即用」的原生操做系統集成。可是,若是您要執行更多工做,它也能夠完成。PhoneGap 的原生 API 構建於可擴展的基礎之上,使開發人員可以建立可經過 JavaScript 應用程序調用的自定義原生代碼。若是您願意,可讓 PhoneGap「完成更多操做」。Github 上甚至還提供了大量開放源碼框架: https://github.com/phonegap/phonegap-plugins。

若是您須要一個插件來爲鏈接至 Apple TV/Airplay 的 iOS 應用程序營造多屏幕體驗,且這由 JavaScript 全面控制,那麼 有一個專門的插件:


圖 19. 專爲鏈接至 Apple TV/Airplay 的 iOS 應用程序提供多屏幕體驗的插件
若是您要集成條形碼掃描儀、分析、推送通知、消息和通知或廣告網絡,咱們也提供了相應的插件 (及許多其餘插件)。

若是您要使用 PhoneGap Web 視圖做爲本機應用程序組件,一樣也能夠實現。

PhoneGap 是一種工具,供開發人員建立可以以各類方式使用的應用程序,並使用各類熟悉的可擴展技術實施開發。

開放源碼
PhoneGap 是一種徹底免費的開放源碼技術。PhoneGap 的整個代碼庫都可做爲 Apache Cordova項目的一部分進行免費訪問。若是您要添加或調整功能,能夠採用這項技術。若是您要在 PhoneGap 之上構建工具,也能夠採用這項技術。若是您發現了一個錯誤並但願爲採用 PhoneGap 技術的任何其餘人修復該錯誤,那麼徹底有能力實現(咱們鼓勵這樣作)!

下一步閱讀方向

關於PhoneGap的更多內容,請訪問PhoneGap Build頁面。學習Database.com的更多特性,請訪問其開發者主頁。
相關文章
相關標籤/搜索