現今幾乎所有網站都宣稱「使用 [瀏覽器 X] 提供最佳視圖」。現代的 Ajax 函式庫如 Prototype、Dojo 和 YUI,有效縮小了 Firefox、Internet Explorer 和 Safari 之間的差距。然而,使用 Nokia、Motorola 或 Apple 手機的用戶,可能無法享受瀏覽器的獨立性。即使是最新呼籲「支援完整 HTML」的行動瀏覽器,也能從簡單修改網頁內容中獲益。本文將展示如何優化 Grails 應用程式,使其適用於行動瀏覽器。
若您仍猶豫為何要讓網站方便行動瀏覽,請看看行動 Web 使用率成長的統計數字。這份全球統計確實令人印象深刻,但我對行動 Web 的熱情源於個人經驗。2007 年春天我購入剛上市的 iPhone,從此尋找適合用它瀏覽的網站。雖然它能訪問任何非 Flash 或 Java applet 的網站,但適合 800x600 解析度顯示器的內容,在 3.5 吋螢幕上效果大打折扣。
我常訪問那些針對手機限制調整 UI 的網站。許多網站用「m」取代傳統的「www」網址,如 https://m.cnn.com、https://m.yahoo.com 和 https://m.google.com。有些網站如 https://www.twitter.com 則會依裝置自動調整輸出內容:電腦版提供完整功能,手機版則精簡內容以適應螢幕。本文將示範如何在不改變網址的前提下,提供最佳 UI。
身為 Java 開發者,我習慣「一次編寫,到處執行」的承諾,從未考慮為特定作業系統或硬體優化應用程式。但開發行動 Web 時,必須熟悉支援不同行動裝置的三種主要技術:
您可以將 WML 和 XHTML-MP 標記與 Grails 的 Groovy Server Pages (GSP) 結合,生成行動友善頁面。此外,我也將展示如何修改 Grails 產生的 HTML,讓頁面在 iPhone 上顯示更佳。
WML 是類似 HTML 的標記語言,但非真正的 HTML(WML 1.0 於 1998 年標準化,最新版為 1.3)。WML 無法在網頁瀏覽器直接檢視(需模擬器),同樣 HTML 也無法在 WML 瀏覽器檢視。手機廠商通常提供在後台實現 HTML 與 WML 相互轉換的閘道。
WML 透過無線應用協定(WAP)傳輸,類似 HTML 透過 HTTP 傳輸。WAP 和 WML 在場合上常互換使用:手機說明書總誇耀內建 WAP 瀏覽器或支援 WML 1.x。
若針對 BlackBerry 用戶(佔智慧型手機市場約 40%),則必須了解 WML。雖然技術達人可下載 Opera Mini 等真正的網頁瀏覽器,但 BlackBerry 仍標配 WAP 瀏覽器。
若您關注「精通 Grails」系列,可修改熟悉的旅行規劃應用程式,使其方便手機瀏覽。在 web-app 目錄建立 testwml.gsp,輸入靜態 WML:
<% response.setContentType("text/vnd.wap.wml") %>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
"https://www.phone.com/dtd/wml11.dtd" >
<wml>
<card id="f1" title="Flight 1">
<p mode="wrap">From: DEN</p>
<p mode="wrap">To: ORD</p>
<p mode="wrap">UAL 1234</p>
<p mode="wrap">Jun 30, 10:30am</p>
<p>
<anchor>Next<go href="#f2"/></anchor>
</p>
</card>
<card id="f2" title="Flight 2">
<p mode="wrap">From: ORD</p>
<p mode="wrap">To: DEN</p>
<p mode="wrap">UAL 9876</p>
<p mode="wrap">Jul 02, 1:15pm</p>
<p>
<anchor>Previous<go href="#f1"/></anchor>
</p>
</card>
</wml>

關鍵點:
text/html 改為 text/vnd.wap.wml。.wml 副檔名,大多數網頁伺服器會自動回傳正確 MIME 類型。<wml> 標籤開頭結尾,無 <html>、<head>、<body>。<card>,擁有獨立 id 和 title 屬性。<anchor> 標籤類似 HTML <a>,語法不同。利用 wtai:// 協定建立撥號超連結:
<do type="accept">
<go href="wtai://wp/mc;3035551212"/>
</do>
在個人電腦檢視需 WAP 模擬器。造訪 dotMobi 模擬器(Java applet),輸入網址即可預覽。
結合 GSP 標記(<g:each>、<g:if>)與 WML:
<% response.setContentType("text/vnd.wap.wml") %>
<%
def flightList = []
flightList << [iata1:"DEN", iata2:"ORD"]
flightList << [iata1:"ORD", iata2:"DEN"]
%>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
"https://www.phone.com/dtd/wml11.dtd" >
<wml>
<g:each in="${flightList}" var="${flight}" status="i">
<card id="f${i}" title="Flight ${i}">
<p mode="wrap">From: ${flight.iata1}</p>
<p mode="wrap">To: ${flight.iata2}</p>
<g:if test="${flightList.size() > i+1}">
<p>
<anchor>Next<go href="#f${i}"/></anchor>
</p>
</g:if>
</card>
</g:each>
</wml>
雖然常有人斷言 WML 生命將盡,但僅支援 WML 的手機仍在流通。現代手機趨向避開「分離但平等」的 WML 平台,轉用真正的網頁瀏覽器。下節將示範為 WML 2.x 或 iPhone 建立行動友善網站,只需調整現有 HTML,而非轉換完全不同的標記語言。
WML 2.x 實質上是 XHTML 的一種方言:XHTML-MP。它嚴格要求格式良好的 XML:正確關閉容器標籤、屬性用引號括住、元素名稱小寫。XHTML-MP 是 XHTML-Basic 的超集,稍作調整即可符合 XHTML-Basic 規範。限制包括:不可使用巢狀表格或框架、僅支援 GIF 和 PNG 圖片、需指定圖片大小與替代文字。
優化小螢幕網站必須減少每請求回傳資料,網頁(含 HTML、CSS、圖片)最好小於 20KB,善用 Expires 或 Cache-Control 標頭主動快取。將長內容分割為 2-3 頁,如 m.cnn.com 將文章分 3-4 頁並提供「全文」連結。
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"https://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="https://www.w3.org/1999/xhtml" xml:lang="en">
...
</html>
雖然許多行動裝置接受 application/xhtml+xml,仍建議使用 application/vnd.wap.xhtml+xml。前者有助於桌面瀏覽器除錯。
線上驗證工具:W3C mobileOK Basic Checker、ready.mobi 測試工具。後者提供更豐富資訊,包含多種裝置視覺化預覽與詳細測試結果(通過/失敗/警告)。

預設 Grails 產生的頁面不符合 XHTML-MP。需修改 AirportController 加入 mlist 閉包,建立 mlist.gsp 並調整:
<html> 標籤加入必要 DTD 與 xmlns 屬性。text/html 的 meta 標籤。main.gsp 中的 CSS 連結(SiteMesh 預設只修飾 text/html)。<thead>、<tbody>,採直向排版適應手機螢幕。<% response.setContentType ("application/xhtml+xml")%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"https://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="https://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
<link rel="stylesheet" href="${createLinkTo(dir:'css',file:'main.css')}" />
<meta name="layout" content="main" />
<title>Airport List</title>
</head>
...
</html>

必要修改很少,可透過 grails install-templates 調整預設範本。
iPhone 的 Safari 瀏覽器與桌面版共用程式碼庫,開發方式相同。但可移除影響外觀的顯示提示。iPhone 螢幕 320x480,瀏覽器預設網頁寬度 980 像素,導致文字過小。使用 viewport meta 標籤修正:
<meta name="viewport" content="initial-scale=1.0" />
也可指定寬高:
<meta name="viewport" content="width=600;height=400" />
<a href="tel:303-555-1212">303-555-1212</a><a href="mailto:scott@aboutgroovy.com">Scott Davis</a><a href="https://maps.google.com/maps?q=denver+international+airport">DEN</a> 會啟動原生 Maps App。<a href="https://maps.google.com/maps?daddr=denver+airport&saddr=coors+field+denver,+co">Directions</a>三種基本策略可混合使用:
m. 子網域(如 m.google.com)或 .mobi 網域。accept 值,伺服器回傳最適合的 MIME 類型。這三種策略不互斥,可全採用,確保服務全球 33 億手機用戶。
讓 Grails 應用程式支援手機的方法多樣:iPhone 幾乎免修改、XHTML-MP 裝置需小幅調整、WML 1.x 則需重寫。善用文中介紹的模擬器與驗證器,定能順利支援行動 Web。下一篇將探討如何處理 Grails 中的既有資料庫,敬請期待。