通常能想到的就是偵測每個request的User-Agent,依據瀏覽器版本調整畫面大小或元素等,通常User-Agent大概像是這樣"Nokia6600/1.0 (4.03.24) SymbianOS/6.1 Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0"。
User-Agent會記載手機裝置型號、作業系統、瀏覽器版本等等資訊,可說非常方便,但現在手機出新已是家常便飯,我們怎麼去判斷呢?又要怎麼掌握全世界所有的行動裝置型號呢?
WURFL就是在做這個事的,WURFL的全名是"Wireless Universal Resource File",這是一個Open Source Project,主旨在於透過社群的力量將全世界所有的行動裝置都收集在一起,可以先試試http://wurflpro.com/(如下圖),在User-Agent輸入Apple按下Search即可看到Apple相關的設定檔!
接下來就要試寫一個最簡單的範例:
首先要有WURFL.xml,這個XML即記錄所有手機的資訊,大概說明一下內容的格式:
<?xml version="1.0" encoding="UTF-8"?>
<wurfl>
<version>...</version><!--說明WURFL的版本資訊-->
<devices><!--包含所有的設備資訊,devices包含了上千個device,而且持續成長中-->
<device user_agent="Nokia3100" fall_back="nokia_generic_series40" id="nokia_3100_ver1">
<!--指出一個裝置的資訊,user_agent為裝置型號,id指出該裝置在WURFL的ID號碼,fall_back為此裝置的上一層裝置的ID號碼-->
<!--在WURFL中的屬性是有繼承概念的,如果在當前設找不到某個屬性,就往所繼承的裝置尋找,直到找到或到最上一層的根-->
<group id="product_info"><!--每個屬性都會按照類別分組,一個device下可以有很多的group-->
<capability name="model_name" value="3100"/>
<!--capability代表一個真正的屬性,每個Group可以擁有很多的capability-->
...
</group>
...
</device>
...
</devices>
</wurfl>
開始前要先準備幾樣東西:
- 下載WURFL.zip,下載後不用解壓縮,因為在執行時期WURFL的lib會自行處理。
- 下載wurfl-1.2.jar,等下會用到的Lib。
- 準備backport-util-concurrent.jar、commons-collections-3.2.1.jar、commons-lang-2.5.jar、commons-logging-1.1.1.jar。
範例實作是參考NEW WURFL Java API
建立一個個Web Project後,加入一個Servlet,此Servlet程式碼如下:
package net.sourceforge.wurfl.core.example;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sourceforge.wurfl.core.CapabilityNotDefinedException;
import net.sourceforge.wurfl.core.Device;
import net.sourceforge.wurfl.core.MarkUp;
import net.sourceforge.wurfl.core.WURFLHolder;
import net.sourceforge.wurfl.core.WURFLManager;
/**
* Servlet implementation class HelloWorld
*/
public class HelloWorld extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 此範例不會以下的檔案...
*/
private static final String XHTML_ADV = "xhtmladv.jsp";
private static final String XHTML_SIMPLE = "xhtmlmp.jsp";
private static final String CHTML = "chtml.jsp";
private static final String WML = "wml.jsp";
// private final Log log = LogFactory.getLog(getClass());
protected void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//取得WURFLHolder..
WURFLHolder wurflHolder = (WURFLHolder) getServletContext()
.getAttribute("net.sourceforge.wurfl.core.WURFLHolder");
//從WURFUL取得Manager...
WURFLManager wurfl = wurflHolder.getWURFLManager();
//從Manager取得Device資訊....
Device device = wurfl.getDeviceForRequest(request);
System.out.println("Device: " + device.getId());
//把Device所有屬性都印出來...
HashMap map = (HashMap)device.getCapabilities();
Set set = map.keySet();
Iterator iter = set.iterator();
System.out.println("device.getCapabilities.size = " + map.size());
while(iter.hasNext())
{
String key = (String)iter.next();
System.out.println("Capability key = " + key + ",value = " + map.get(key));
}
//把Device所有屬性都印出來...
//根據MarkUp決定欲顯的網頁格式及頁面...
MarkUp markUp = device.getMarkUp();
String jspView = null;
if (MarkUp.XHTML_ADVANCED.equals(markUp)) {
jspView = XHTML_ADV;
} else if (MarkUp.XHTML_SIMPLE.equals(markUp)) {
jspView = XHTML_SIMPLE;
} else if (MarkUp.CHTML.equals(markUp)) {
jspView = CHTML;
} else if (MarkUp.WML.equals(markUp)) {
jspView = WML;
}
System.out.println("View: " + jspView);
// MIME type is decided by JSP. Only in case of XHTML
// will we need to multi-serve i.e text/html vs application/xml+xhtml vs
// application/vnd.wap.xml+xhtml
if (markUp == MarkUp.XHTML_ADVANCED || markUp == MarkUp.XHTML_SIMPLE) {
String contentType = "text/html";
try {
contentType = device
.getCapability("xhtmlmp_preferred_mime_type");
} catch (CapabilityNotDefinedException e) {
throw new RuntimeException(
"Somethingh is seriously wrong with your WURFL:"
+ e.getLocalizedMessage(), e);
}
request.setAttribute("contentType", contentType);
System.out.println("ContentType: " + contentType);
}
//根據MarkUp決定欲顯的網頁格式及頁面...
request.setAttribute("markUp", markUp);
request.setAttribute("device", device);
request.getRequestDispatcher("WEB-INF/jsp/" + jspView).forward(request,
response);
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
}
最後要設定web.xml檔:
<listener>
<listener-class>
net.sourceforge.wurfl.core.web.WURFLServletContextListener
</listener-class>
</listener>
要加入listener才能取得WURFLHolder物件。
WURFL在執行時期要取得手機資訊得依賴之前下載的WURFL.zip,所以將WURFL.zip放到WEB-INF/,然後在web.xml中加入context-param:
<context-param>
<param-name>wurfl</param-name>
<param-value>/WEB-INF/wurfl.zip</param-value>
</context-param>
如此;執行剛才建立的Servlet即可得知Device為何了,可利用Firefox的User Agent Switcher模擬iPhone 3.0可在Console中看到"Device: apple_iphone_ver3_sub7a341_enus"。
以上即為WURFL的簡單範例,WURFL還有PHP版本,台灣有一本翻譯的繁體書有寫WURFL的PHP版本:Smartphone 智慧型手機網路應用程式開發實戰。
WURFL還有Patch_xx.xml的應用及整合Spring的範例,都可在WURFL官網查詢到。
WURFL Java細節可參考WURFL API Docs。
1 則留言:
Touche. Great arguments. Keep up the amazing effort.
Feel free to surf to my web site: schools for sonogram technician
張貼留言