編輯:中級開發
簡介: 學習如何使用混合應用程序編程模型為 WebSphere® Commerce 構建移動應用程序。本文描述混合模型,它與其他移動應用程序編程模型的區別,並通過兩個用例研究介紹如何使用它為 WebSphere Commerce 構建 iPhone® 和 android® 應用程序。
概述
隨著擁有 Internet 訪問能力的移動設備的快速增長,移動應用程序已經成為許多跨渠道零售解決方案的必要組成部分。特別是,iPhone OS 和 android 設備的日益流行已經推動了對原生應用程序的需求,這些應用程序擁有在移動浏覽器中運行的 web 應用程序所不能提供的能力。但是,從頭開始構建一個完全原生的應用程序需要投入極大的技能和資源,而且為一個平台編寫的大部分代碼將不能在另一個平台上重用。這正是混合應用程序編程模型的用武之地 — 通過混合模型,您可以重用您的許多現有 web 應用程序資產來構建移動應用程序。
注意,本文面向有興趣為 WebSphere Commerce 構建移動應用程序的架構師和開發人員。本文假定您對 WebSphere Commerce 和移動應用程序開發有基本的了解。本文的配套白皮書 Leveraging mobile commerce in your multi-channel strategy 討論了移動商務的市場機遇,簡要描述了一些在 WebSphere Commerce 中利用那些機遇的解決方案。.
移動應用程序編程模型
我們可以將提供移動應用程序的方法歸為三類:web 應用程序、原生(設備上)應用程序,或二者的結合。下面幾個小節簡要描述每個模型的部分特征。
移動 web 應用程序
通過結合使用 Html、層疊樣式表(CSS)和 JavaScript 將移動 web 應用程序交付給移動設備。您可以或多或少地對移動設備進行一些定制。還可以定制特定設備。
這個模型的好處是,它基於我們熟悉的 web 編程技巧。它不需要最終用戶安裝任何特殊應用程序,因為它依賴內置浏覽器。迭代開發很容易實現。更新不需要用戶操作,只需更新服務器提供的內容。它還擁有一個好處:相同的、或近乎相同的內容能夠服務不斷增長的移動設備系列產品。
WebSphere Commerce 第 7 版包含了一個 Madisons Mobile store,它為智能手機提供定制的 web 體驗。但是,這種方法也有一些缺點,包括應用程序可能缺乏原生應用程序的觀感,可能有性能影響,以及不能訪問一些設備功能,比如本地地址簿或相機。
這種方法也依賴移動浏覽器的功能,這可能是一個嚴重的不兼容性來源,特別是對於比較老的手持設備。Html5 和 Webkit 浏覽器引擎的流行將有助於緩解這些問題,但前提是功能更強大的新設備獲得市場份額。
原生應用程序
相比之下,原生應用程序專門針對一個單一的移動平台編碼,使用制造商提供的特定於設備的函數和庫。這樣的應用程序能夠輕松集成平台的獨特觀感,通常比 web 應用程序表現更出色。它們可以任意訪問 API 支持的原生設備功能。
問題是必須為每個受支持的平台從頭編寫應用程序。這樣的設備數量眾多,並且更新換代速度很快,因為大量公司通過功能越來越強大的設備爭奪市場份額。編寫原生應用程序也需要專業技術,平台之間的技術要求差異很大,不容易從一個平台遷移到另一個平台。
混合應用程序
混合應用程序試圖結合 web 應用程序和原生應用程序的優勢,是本文關注的焦點。基本的思路是編寫一個原生應用程序 shell,但通過使用 web 視圖(集成通常使用的 Html、CSS 和 Javascript)來提供主內容。原生框架可能包含一些可以從 JavaScript 訪問的庫,以便訪問一些設備功能,比如本地地址列表、GPS、相機和其他設備特性。這允許 web 應用程序包含訪問設備功能的代碼。
混合應用程序模型的一個關鍵特性是在 JavaScript 例程和原生設備功能之間架起一座橋梁。如果每個用戶都必須針對每個受支持的設備重新開發這個框架,那麼這個開發任務非常艱巨。但是,實際上,有幾個現成的這種性質的框架可用,既有專有的,也有開源的。如果這樣一個框架支持多個設備,則意味著可以對所有受支持的設備使用相同的服務器端代碼,只需要最小的細微定制,這意味著可能能夠極大地節約需要的資源。
注意,原生和混合應用程序之間的差別主要位於實現層面。從最終用戶的角度看,混合應用程序和原生應用程序通常沒有區別。混合應用程序可以通過平台的應用程序市場(例如 iPhone App Store)交付給最終用戶並提供原生用戶體驗,就像原生應用程序那樣。
混合應用程序的基本原理
本質上,混合應用程序是包含嵌入式 web 內容的原生應用程序。混合應用程序的 UI 通常結合使用原生視圖和 web 視圖 — 可以顯示本地或遠程 web 內容的視圖。一個典型的混合應用程序示例是應用程序中的主內容區域由一個單一的 web 視圖構成。可以使用特定於平台的 CSS 來向 web 內容提供原生觀感,同時可以使用原生視圖來呈現使用 web 內容和 CSS 難以構造的平台特有控件,比如菜單和選項卡欄。
注意,沒有關於使用原生視圖和 web 內容的固定規則。有些場景允許主要使用 web 內容,而另一些場景可能需要大量使用原生視圖。
在圖 1 中的左邊,可以看到在 Mobile Safari 中顯示的 Madisons Mobile starter store(藍色的 web 內容)。右邊顯示了混合應用程序中的相同內容(web 內容為藍色,原生內容為紅色)。
圖 1. 混合 vs. 移動 web 應用程序的用戶界面
圖 2 比較了不同移動平台上的 UI 元素。
圖 2. 比較不同平台上的 UI 元素
原生代碼和嵌入的 web 內容的交互
在許多移動平台上,應用程序的原生代碼可以執行嵌入的 web 內容中的 JavaScript 函數。這允許原生代碼從 web 內容獲取信息(比如一個 HTML 表單輸入的值)並觸發 web 內容中的動作(比如,隱藏/顯示一個 Html 元素)。相反,原生代碼可以截獲由嵌入的 web 內容發起的請求並代表 web 內容執行原生函數。這實際上是原生代碼和嵌入的 web 內容之間的一個雙向橋梁,通常用於向嵌入的 web 內容提供 web 內容通常無法訪問的 web 功能的訪問權。
一個例子是向嵌入的 web 內容提供對本地地址簿的訪問權。通常,移動設備的本地地址簿不允許 web 內容訪問。但是,通過原生代碼和 web 內容之間的這個雙向橋梁,混合應用程序的嵌入 web 內容就能以 web 內容的名義請求原生代碼顯示本地地址簿。用戶在本地地址簿中執行完需要的操作(例如,選擇一個電子郵件地址)後, 原生代碼可以執行一個 JavaScript 回調函數來將控件和數據傳回嵌入的 web 內容(見圖 3)。
圖 3. 原生代碼和嵌入的 web 內容之間的交互
如果針對多個移動平台,那麼使 Javascript 和原生代碼之間的這個橋梁在所有平台之間盡可能相似肯定有好處。這允許跨多個移動平台使用相同的 web 內容(因此也是相同的 JavaScript)。開源 PhoneGap 就是這樣一個開發框架,盡管它沒有在本文討論的原型中使用。
在下面的用例研究中,我們將介紹如何應用這些模式來為 WebSphere Commerce 構建 iPhone 和 android 應用程序。
用例研究 1. 使用混合模型為 WebSphere Commerce 構建一個 iPhone 應用程序
我們的第一個用例研究是一個 Madisons iPhone 應用程序,它已作為一個概念證明構建。這個應用程序本質上是作為一個具有原生觀感的 iPhone 應用程序打包的 Madisons Mobile starter store,它包含移動 web 應用程序中沒有的一些附加特性,其中包括:
圖 4 顯示應用程序的主屏幕。可以看到,交互式電子營銷點占據了主屏幕的主要內容區域,還可以看到應用程序的原生導航控件。
圖 4. Madisons iPhone 應用程序 - 主屏幕
圖 5 展示了應用程序的目錄浏覽流。您看到一位購物者如何導航到一個產品並將其添加到關注列表或購物車。
圖 5. Madisons iPhone 應用程序 - 目錄浏覽
圖 6 展示了應用程序的商店定位器流。您看到一位購物者如何使用應用程序的商店定位器和地理位置支持來定位附近的商店。
圖 6. Madisons iPhone 應用程序 - 商店定位器
圖 7 展示了應用程序的結賬流。您看到一位購物者如何使用應用程序進行店內采購。
圖 7. Madisons iPhone 應用程序 - 購物車和結賬
高級設計
我們將這個 Madisons iPhone 應用程序設計為一個廣泛使用導航和選項卡條界面的生產力應用程序。它的屏幕流與 Madisons Mobile starter store 的頁面流基本相同。應用程序被組織為一些選項卡,每個選項卡對應 starter store 的一個部分。每個選項卡下方的屏幕通過一個導航界面管理, 替代了 starter store 中的標題欄和浏覽路徑記錄。應用程序的主內容區域由一些 UIWebVIEw 實例組成,這些實例使用一個特定於 iPhone 的 CSS 顯示一些遠程 Madisons Mobile 頁面,而導航和選項卡欄通過原生視圖和控件呈現。
與所有 iPhone 應用程序一樣,Madisons iPhone 應用程序使用 iPhone SDK 予以開發。iPhone SDK 包含一組開發工具來編寫和測試 iPhone 應用程序,主要包括:
注意,下面的小節假設您對 iPhone 應用程序開發有基本的了解。要了解 iPhone 應用程序開發的細節,請參閱 iPhone Dev Center 和iPhone Human Interface Guidelines。
服務器端更改
設備檢測
我們使用 WebSphere Commerce 的設備檢測功能來識別來自 Madisons iPhone 的請求。我們在WC_eardir/xml/config/com.ibm.commerce.foundation-ext 目錄中創建一個 wc-devices.XML 文件來將 UIWebVIEw 用戶代理映射到一個設備格式 ID。然後,我們使用這個設備格式 ID 來:
清單 1 展示將來自應用程序的請求映射到適當的設備格式的自定義 wc-devices.XML 文件。參閱 表 1 了解更改後的文件的位置。
清單 1. 將 UIWebVIEw 用戶代理映射到設備格式 ID -12 的 wc-devices.XML
<_config:Devices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ibm.com/xmlns/prod/commerce/foundation/config \ ../xsd/wc-devices.xsd" xmlns:_config="http://www.ibm.com/XMLns/prod/commerce/foundation/config"> <_config:DeviceGroup internalID="-11" channelID="-6"> <_config:Device name="BlackBerry Bold 9000" userAgentPattern="BlackBerry9000.*"/> <_config:Device name="BlackBerry Storm 9530" userAgentPattern="BlackBerry9500.*"/> <_config:Device name="BlackBerry Curve 8320" userAgentPattern="BlackBerry8320.*"/> <_config:Device name="HTC S740" userAgentPattern=".*MSIEMobile.*"/> <_config:Device name="Nokia S60" userAgentPattern=".*SymbianOS.*Series60/3.1.*Nokia3250.*" /> <_config:Device name="Nokia N97" userAgentPattern=".*SymBianOS.*SerIEs60/5.0.*Nokia3250.*" /> <!-- Maps the Mobile Safari user agent to device format ID -11. --> <_config:Device name="Apple iPhone" userAgentPattern=".*iPhone.*Safari.*"/> </_config:DeviceGroup> <!-- Maps the UIWebView user agent to device format ID -12. The UIWebView user agent is different from the Mobile Safari user agent in that the UIWebVIEw user agent does NOT contain the substring "Safari". --> <_config:DeviceGroup internalID="-12" channelID="-6" > <_config:Device name="Apple iPhone Native App" userAgentPattern=".*iPhone.*"/> </_config:DeviceGroup> </_config:Devices>
清單 2 展示添加到 struts-config-ext.XML 的自定義 Struts 配置條目。這個文件將來自我們的應用程序的請求映射到 Madisons Mobile starter store。
清單 2. 將來自設備格式 ID -12 的視圖請求映射到 Madisons Mobile starter store JSP 文件的 Struts 配置條目節選
<forward className="com.ibm.commerce.struts.ECActionForward" name="ChangePassword/10000001/-12" path="/mobile/UserArea/AccountSection/PasswordSubsection/PassWordUpdateForm.jsp"/> <forward className="com.ibm.commerce.struts.ECActionForward" name="ReLogonFormView/10000001/-12" path="/mobile/UserArea/AccountSection/LogonSubsection/UserTimeoutView.jsp"/> <forward className="com.ibm.commerce.struts.ECActionForward" name="RememberMeLogonFormVIEw/10000001/-12" path="/mobile/UserArea/AccountSection/LogonSubsection/logon.JSp"/> <forward className="com.ibm.commerce.struts.ECActionForward" name="AccessControlErrorVIEw/10000001/-12" path="/mobile/GenericError.JSP"/>
清單 3 展示對 JSTLEnvironmentSetup.JSPf 文件進行的更改,以支持特定於我們的應用程序的 web 內容增強,特別是特定於 iPhone 的 CSS。
清單 3. 基於設備格式 ID 更改 CSS 路徑的 JSTLEnvironmentSetup.JSPf 代碼
<%-- Set variables for device specific rendering --%> <c:if test="${EC_deviceAdapter.deviceFormatId == -12}"> <c:set var="_iPhoneNativeApp" value="true"/> <c:set var="mobileBasePath" value="mobile/iPhone"/> <c:set var="pageMax1" value="500"/> <c:set var="pageMax2" value="500"/> </c:if> <c:set var="CSSPath" value="${JSPStoreImgDir}${mobileBasePath}/${vfileStylesheet}"/>
注意,我們已經將這些更改集成到 WebSphere Commerce V7 Feature Pack 1 中。如果您已安裝 Feature Pack 1 並發布了 Madisons Mobile 增強商店歸檔,那麼 Madisons Mobile starter store 將使用這些更改更新。
特定於 iPhone 的 CSS
我們使用了一個特定於 iPhone 的 CSS(清單 4)來向嵌入的 web 內容提供原生觀感。我們還使用 CSS 來:
注意 CSS 使用許多帶有 -webkit-
前綴的屬性,這是 CSS3 屬性的 WebKit 實現。大多數這些屬性可以在 iPhone 和 android 上工作,因為這兩個平台都使用 WebKit 作為 web 內容的渲染引擎。
清單 4. 特定於 iPhone 的 CSS 節選
/* Defines the look of section headers */ div.heading_container { /* Gives the background a slight gradient */ background-image: -webkit-gradIEnt(linear, left top, left bottom, from(white), to(#e0e0e0)); border-color: #e0e0e0; border-style: solid; border-width: 1px 0px 0px 0px; margin: 0px; padding: 5px 10px; } /* Defines the look of section titles */ div.heading_container > h2 { margin: 0px; padding: 0px; color: gray; font-weight: bold; font-size: 14px; overflow: hidden; /* Truncates the title and adds a trailing ellipsis (...) if it overflows */ text-overflow: ellipsis; white-space : nowrap; /* Gives the title an embossed look */ text-shadow: white 0px 1px 0px; } div.content_box > ul { margin: 0px; padding: 0px; list-style: none; } /* Hides the bullets (>>) */ span.bullet { display: none } /* Gives lists the look of edge-to-edge tables */ div.content_box > ul > li { background-color: white; border-color: #e0e0e0; border-style: solid; border-width: 0px 0px 1px 0px; margin: 0px; padding: 10px; } /* Gives clickable list items the look of table items */ div.content_box > ul > li > a { /* Adds trailing chevrons (>) to the table items */ background-image: url('../images/chevron.png'), url('../images/link.png'); background-position: center right, top left; background-repeat: no-repeat, repeat-x; display: block; margin: -10px; padding: 10px 20px 10px 10px; color: black; font-size: 17px; font-weight: bold; overflow: hidden; /* Truncates the text and adds a trailing ellipsis (...) if it overflows */ text-decoration: none; text-overflow: ellipsis; white-space : nowrap; -webkit-background-size: auto auto, auto 100%; } /* Defines the look of table items when tapped */ a.arrow:active { background-color: #ff5000; /* Reverses the color of the chevron and text */ background-image: url('../images/chevron_white.png'), url('../images/link.png'); color: white; } * { /* Disables the default tap highlight color */ -webkit-tap-highlight-color: rgba(0,0,0,0); /* Disable text selection and the copy-and-paste callout */ -webkit-touch-callout: none; -webkit-user-select: none; }
圖 8 展示 Html 列示前後。
圖 8. Html 列示,之前和之後
同樣,特定於 iPhone 的 CSS 包含在 Feature Pack 1 Madisons Mobile enhancements store 歸檔中。它位於 store 目錄下的 mobile/iPhone/CSS 目錄中,在 store 歸檔發布之後。
表 1 列示了服務器端更改的摘要。
表 1. 服務器端更改摘要
應用程序代理和視圖層級
我們使用 Interface Builder 在應用程序的主 NIB 文件(MainWindow.xib)中定義 Madisons iPhone 應用程序的視圖層級。它由一組通過原生導航和選項卡欄界面管理的視圖組成 — 通過UINavigationController
和 UITabBarController
控制的合成視圖。視圖層級頂部是一個選項卡欄界面,位於應用程序的 UIWindow
實例正下方。選項卡欄界面由一個 UITabBarController
實例控制,該實例構造和管理選項卡欄界面下方的視圖,包括選項卡欄及其選項卡,每個選項卡都有一個由導航界面管理的視圖堆棧。每個導航界面都由一個 UINavigationController
實例控制,該實例構造和管理導航界面下方的視圖,包括導航欄及其視圖堆棧(參見表 2)。
表 2. MainWindow.xib 的結構
如圖 9 所示,每個導航界面的頂級視圖是一個由視圖控制器(WebVIEwController
類)控制的視圖。這個視圖在其自己的 NIB 文件(WebVIEwController.xib)中定義,由一個 UIWebVIEw
實例和一個 UIActivityIndicatorVIEw
實例組成。當應用程序啟動時,應用程序代理指導每個 WebVIEwController
實例加載每個選項卡的初始 web 內容,比如 Home 選項卡的 http://host/webapp/wcs/stores/servlet/mIndex_storeId_catalogId_langId。
圖 9. 應用程序的視圖層級
清單 5 展示 TestUIShellAppDelegate 類中用於指定每個選項卡的根視圖的初始 URL 的代碼。
清單 5. TestUIShellAppDelegate - applicationDidFinishLaunching
- (void)applicationDidFinishLaunching:(UIApplication *)application { NSString *langId = NSLocalizedString(@"langId", @""); WebViewController *webViewController = (WebViewController *)homeTabNavigationController.topViewController; NSString *urlString = [NSString stringWithFormat:@"http://%@/webapp/wcs/stores/servlet/mIndex_%@_%@_%@", host, storeId, catalogId, langId]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; webViewController.request = request; webViewController = (WebViewController *)storeLocatorTabNavigationController .topViewController; urlString = [NSString stringWithFormat:@"http://%@/webapp/wcs/stores/servlet/mStoreLocatorView? catalogId=%@ \ &fromPage=&storeId=%@&langId=%@", host, catalogId, storeId, langId]; request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; webViewController.request = request; // Similar code for the other tabs... [window addSubview:tabBarController.vIEw]; [window makeKeyAndVisible]; }
清單 6 展示 WebVIEwController 類中用於加載 URL 請求的代碼。
清單 6. WebViewController - vIEwDidLoad
// Implement viewDidLoad to do additional setup after loading the view, typically from a // nib. // The view is loaded from the NIB file when the view first appears, // or when it needs to reappear after being unloaded due to memory warning - (void)viewDidLoad { [super viewDidLoad]; // Load the request [webVIEw loadRequest:request]; }
導航界面
UIWebVIEw instances
之間的導航(例如,用戶通過點擊一個類別從主屏幕導航到類別屏幕)由 UINavigationController
和WebVIEwController
實例管理。總之,應用程序視圖層級中的每個UIWebVIEw
實例都由一個 WebVIEwController
實例控制。WebVIEwController
實例還被配置為 UIWebVIEw
實例的代理(WebVIEwController
類實現 UIWebVIEwDelegate
協議),允許WebVIEwController
實例截獲由 UIWebVIEw 實例的 web 內容發出的 URL 請求。
例如,當用戶點擊主屏幕上的一個類別(見圖 10)時,UIWebVIEw
實例的 web 內容(Madisons Mobile 主頁)發出一個 URL 請求來加載那個類別頁面。WebVIEwController
實例充當 UIWebVIEw
實例的代理,截獲 URL 請求,將一個新 WebVIEwController
實例推到UINavigationController
實例的導航堆棧上,並提示新的WebVIEwController
實例加載其 UIWebVIEw
實例中的 URL 請求。
圖 10. 導航界面
加載開始時,將顯示 UIActivityIndicatorVIEw
實例,表明屏幕正在加載。加載結束時,UIActivityIndicatorVIEw
實例隱藏,通過stringByEvaluatingJavaScriptFromString:
方法從 web 內容提取文檔標題並將其設置為屏幕標題。導航欄上的後退按鈕被自動編程為受到點擊時從導航堆棧自動彈出頂部視圖控制器。
清單 7 展示 WebVIEwController 類中用於截獲並處理普通 URL 請求的代碼。
清單 7. WebVIEwController.m 節選 - 處理普通 URL 請求
- (BOOL)webView:(UIWebView *)aWebView shouldStartLoadWithRequest:(NSURLRequest *)aRequest navigationType:(UIWebViewNavigationType)navigationType { if (webView.request == nil || [activityIndicatorView isAnimating]) { // Continue loading if it is the initial request of the web view or if it is // a redirect (in which case loading is not "finished") return YES; } else if (...) { // Code to intercept other URL requests } else { // Push a new WebViewController instance onto the navigation stack and use it // to load the request WebViewController *newWebViewController = [[WebViewController alloc] initWithNibName:@"WebViewController" bundle:nil]; [webViewController.navigationController pushViewController:newWebViewController animated:YES]; [newWebViewController release]; return NO; } return NO; } - (void)webViewDidStartLoad:(UIWebView *)aWebView { webView.hidden = YES; [activityIndicatorView startAnimating]; } - (void)webViewDidFinishLoad:(UIWebView *)aWebView { // Extract the document title from the web content and set it as the title // of the view if (self.navigationItem.title == nil) { self.navigationItem.title = [webVIEw stringByEvaluatingJavaScriptFromString:@"document.title"]; } webView.hidden = NO; [activityIndicatorVIEw stopAnimating]; }
對於Android 3.x honeycomb系統來說屏幕的兼容性很重要,這裡目前我們就主流的Android 1.5~2.3.4的軟件如何兼容android 3.0有關
收集用戶數據您已經創建了 Activity 主屏幕布局,現在可以創建用戶界面表單來收集數據了。在本例中,您將創建一個 Robotics Club R
簡介: 學習了解 IBM® Rational® Rhapsody® V7.5.2 版本中的新特性與改進之處,幫助系統管理員和實時、嵌入
簡介: 一直以來,“對多個浏覽器進行測試” 像是一條難以解開的咒語,因為需要對大量浏覽器進行測試。對所有浏覽器進行測試(尤其是目前)幾乎是不可能的。但是這比您