web 2.0

Windows Mobile技术文章翻译系列(3)--为Windows Mobile 6.5开发Widget

作者:MicroSoft  时间:2010-4-7  译者:Mobile On Line

译者序言:手势(Gesture)微技(Widget)是Windows Mobile 6.5中的两大新特性。对于Gusture API,前面的文章中已经做了介绍,本文则主要介绍另一个新特性Widget。

摘要

Windows Mobile Widget 是一种单纯的用以展示从Internet获取的数据的应用程序。他用JavaScript编写,为Windows Mobile平台带来了丰富的Web开发体验。由于widget是安装并运行在移动设备本地的,因此与常规Web应用程序相比,可以提供更为易用和友好的用户体验。

 

适用平台

Windows Mobiel 6.5

 

索引

 

简介

Windows Phone为移动设备用户提供了丰富的用户体验和强大的功能特性。Windows Mobile Widget是用Web开发技术编写的应用程序;他可以连接到Web服务以获取和显示数据。Widget可以传递业务数据、天气信息、新闻更新、交通地图等,甚至可以幻灯片播放在线相册。JavaScript和Web开发技术中的动态标记及样式表的灵活,结合新的Widget对象,使得Web开发者可以创建出具有本地Windows Mobile程序外观的富Internet应用程序。

从Windows Mobile 6.5.4开始,开发者就可以使用Visual Studio创建Windows Mobile Widget了。

 

Widge和Windows Moible 6.5

Widget在概念上就像Windows  Vista中的Gadget挂件一样。HTML标记语言可CSS层叠样式表提供用户界面,JavaScript用以编写代码。Gadget为Windows Vista平台带来了丰富的Web开发体验,而Widget同样为Windows Mobile平台带来了这些。动态HTML(DHTML)用以动态展示数据以创建用户界面,同时XMLHttpRequest组件用于从Web载入数据。整个应用程序使用JavaScript控制流程。Widget安装在移动设备本地,像Windows Vista Gadget一样,widget也运行于本地但是可以使用从云中动态访问数据。

Windows Phone可以通过Microsoft Iternet Explorer访问Web应用程序;然而,这会导致网络传输的增加,因为服务器端的页面更新结果必须下载到设备。使用AJAX的Web应用程序减小了页面更新,但是在初始化时仍然会有一次文件下载(Script/HTML/CSS)。Widget与Web应用程序相比减小了网络访问,因为脚本和样式表是安装在本地的。随后,Widget执行的网络访问都是纯粹的数据访问。这意味着比Web应用程序更少的网络连接,而这也是对依赖于电话网络并按传输数据量计费的移动设备的一个关键设计特性。另外,JavsScript提供的widget API使开发者可以提供菜单和软键盘集成,以及对Web应用程序不可用的本地数据缓存。

AJAX是一种充满活力的成熟技术,并且拥有很成熟的开发者社区。Widget为Windows Mobile平台带了丰富的体验。

 

开发Widget

Web应用程序开发者可以很平滑的过渡到widget开发,因为大部分的开发都使用相似的技术。Widget对部署和本地化有着特有的需求,相关细节将在本部分给出。

 

创建用户界面

Widget是全屏应用程序,但是因为用户界面是通过HTML提供的,所以widget可以使用HTML布局来容纳电话中窗体元素。另外,开发者可以使用文档body对象来访问屏幕区域并适应设备。Widget API也可以为屏幕方向变化(如设备旋转)提供通知,开发者可以使用此通知来更新用户界面。

类似于AJAX应用程序开发,widget开发者可以响应控件及其他页面元素的事件。Windows Mobile中一个特别有用的功能是本地化。

 

本地化Widget

应用程序资源通常是适用于特定的地点的。特别的。文本应当被本地化为用户设备相应的语言和方言。在设计应用程序时,你应该识别出那些要被本地化的资源,并且为要支持的每一个地点创建一个单独的文件。比如,一个显示货币汇率并存储引用的widget,应该从各自的本地网站获取这些信息,从而使美国的用户能看到Dow Jones 的值,而英国的用户看到FTSE的值。

下面的代码片段摘自两个都叫做directoryUrls.js的文件。第一个文件是widget的默认文件。其资源指出http://mny.mobile.msn.com/en-us/default.aspx?网站用于存储引用。这个文件存储在部署文件中的js脚本文件夹下。第二段代码片段是针对en-UK(British English)的本地资源。在这种情况下,存储引用从http://mobile.uk.msn.com/device/mny/default.aspx?网站获得。这个文件和默认资源同名,但是放在en-UK/js本地化脚本文件下下。很重要的,请注意widget的HTML元素中<script>的src属性没有本地化;src属性只需引用js文件夹下的默认文件,Windows Mobile 6.5就会载入合适的文件。

// 默认地区, js/directoryUrls.js
var MSN_OCID_PARAM = "ocid=widget_mny_1";
var DirectoryUrls = {
   MSNMoney: "http://mny.mobile.msn.com/en-us/default.aspx?" 
      + MSN_OCID_PARAM
}

// UK 地区, en-UK/js/directoryUrls.js
var MSN_OCID_PARAM = "ocid=widget_mny_1";
var DirectoryUrls = {
   MSNMoney: "http://mobile.uk.msn.com/device/mny/default.aspx?" 
      + MSN_OCID_PARAM
}

在运行时,WIndows Mobile 6.5将会检测设备的地区(如en-USen-UK),如果存在一个和以地区名命名的文件夹,他就会使用这个本地化文件夹作为脚本文件的基准文件夹。如果不存在这样的文件夹,Windows mobile会搜索一个以语言名(如en)命名的文件夹。

如果设备找不到任何的本地化文件,将会载入默认文件。Widget代码包含在地区无关的脚本文件中。为了获取用于存储引用的URL,这个代码会访问DirectoryUrls。directoryUrls.js本地化文件中MSNMoney变量MSNMoney将会被Windows Mobile将会被Windows Mobile载入,从中获得适合于地区的URL。

如果你提供了本地化文件,那你也要提供默认文件,这一点很重要。所有的widget文件都可以被本地化。然而,为了减小部署包的大小,最好只对单独的项目局部进行,就像上面演示的一样,而不是简单的提供每一个HTML及JavaScript文件的本地化副本。

 

使用Widget JavsScript对象

一个Widget就是一个用JavaScript编写的单独的本地执行的AJAX应用程序。Widget可以简单到只是一个包含<script>元素的HTML文件,也可以有一个或多个JavaScript文件构成。HTML文件可以包含<object>元素,这就意味着widget也可以显示Flash文件。JavaScript服从于widget安全模型。

Windows Mobile提供了一个叫做widget的JavaScript对象,从而提供对一些设备系统状态信息及widget特有功能的访问。widget对象通过其属性提供一些信息,并且也可以被用于创建一个状态对象以访问其他功能。widget的manifest文件是一个部署在widget中的XML文件。本文将在稍后进行介绍。

属性 描述
authorEmail widget作者的Email地址。manifest文件中<author>元素的emai属性。
authorName widget作者的姓名。manifest文件中的<author>值。
authorURL widget作者的网站地址。<author>元素的href属性。
currentIcon widget的图标。这是一个WidgetIcon类型的对象。
currentIcon widget的描述字符串。<description>元素的值。
Height widget的高度,单位像素。
Identifier widget的属性标识。<widget>元素的uid属性。
Locale widget的地区。这个表现为设备上的区域设置对话框。
Menu widget的菜单对象。这是一个Menu类型的对象。
Name widget的用户友好的名称。<name>元素的值。
version widget的版本。<widget>元素的version属性。
width widget的宽度,单位像素。

下面的代码片段演示了如何使用widget属性。

<div id="divData"></div>
<script type="text/javascript">
divData.innerHTML = "The " + widget.name + " widget is localized to " 
   + widget.locale;
</script>

进一步的系统信息可以通过SystemState对象获得。这个独享拥有如下的属性。

属性 描述
CradlePresent 一个布尔值,指示设备是否插入底座。
DisplayRotation 一个整数值,指示屏幕的横竖。
PhoneHomeService 一个布尔值,指示设备是否已注册到网络。
PhoneOperatorName 一个字符串,指示设备操作者名字。
PhoneRoaming 一个布尔值,指示设备是否处于蛮有状态。
PhoneSignalStrength 一个整数值,指示电话信号强度,用总信号强度百分比表示。
PowerBatteryState 一个整数值,指示电池状态,如电量是否极低或是否充电中。
PowerBatteryStrength 一个整数值,指示当前电池电量,用总电量的百分比表示。

下面的代码演示了如何访问设备相关信息。

<div id="divData"></div>
<script type="text/javascript">
var systemState = widget.createObject("SystemState");
divData.innerHTML = "The phone operator name is " 
   + systemState.PhoneOperatorName + " and the signal strength is " 
   + systemState.PhoneSignalStrength;
</script>

你可以注册一个在属性改变时调用的事件.为了实现这一目的,你可以调用addEventListener方法为要获得通知的SystemState属性的changed事件添加一个事件处理函数。譬如,使用上面代码定义的对象,你可以指定在设备插入底座时,调用一个叫做cradled的函数。

var cradledState = systemState.CradlePresent; 
cradledState.addEventListener("changed", cradled);

大部分的widget和SystemState属性是整数或字符串,但是有些是新的对象类型。比如,widget.currentIcon属性是一个WidgetIcon类型的对象,它具有以下一些属性。

属性 描述
height 一个整数,给出图标的高度。
src 一个字符串,包含图标文件的URL。
width 一个整数,给出图标宽度。

widget.menu是一个Menu对象,下文将会涉及。

 

创建Widget菜单

一个widget可以包含一个菜单,也可以定义设备软键的动作。这些任务通过Menu对象实现。

从Windows Mobile 6.5.3发布开始,触摸砖取代了软键。对开发者而言,从软键到触摸砖的改变是从Windows Mobile 6.5.3自动开始的。以下列出的所有即适用于触摸砖也适用于软键。

方法 描述
append(item) 附加一个MenuItem对象到右软键。
clear() 清除主菜单的内容。
createMenuItem(id) 创建一个指定整数ID的MenuItem对象。
getMenuItemById(id) 返回指定整数ID的MenuItem对象。
remove(item) 从菜单中移除指定的MenuItem对象。
setSoftKey(item, id) 指定特定ID的MenuItem对象到软键。

软键既可以被指派给一个单独的MenuItem对象,也可以指派给由一个或多个MenuItem对象组成的菜单。默认情况下,当widget启动时,左软键包含一个单独的MenuItem对象Exit(用以关闭widget),右软键包含一个菜单,该带单也只包含一个用以退出应用程序的MenuItem对象。下面的示意图展示了当点击右软键时的右菜单。

前面的示意图适用于Windows Mobile 6.5.3以前创建的widget。

menu对象有两个属性,leftSoftKeyIndexrightSoftKeyIndex,用于标识setSoftKey方法指派的菜单项。

以下的代码通过先调用createMenuItem创建了一个新的菜单项。传递给方法的数字标识在代码中必须是唯一的。然后菜单项就可以用显示文本及单击事件处理程序进行初始化。代码最后调用setSoftKey以指派这个菜单项到左软键。

function clickMeHandler() {
   alert("do something");
}   
var menu = widget.menu;
var menu1001 = menu.createMenuItem(1001);
menu1001.text = "Click Me";
menu1001.onSelect = clickMeHandler;
menu.setSoftKey(menu1001, menu.leftSoftKeyIndex);

下面的示意图展示了结果。

如果你使用下面一行代码而不调用setSoftKey,菜单项将被附加到右菜单。

menu.append(menu1001);

下面的示意图展示了结果。

MenuItem对象有一个给出显示文本的text属性,和一个决定菜单项是否可以点击的enabled属性。MenuItem还有一个由Menu.createMenuItem函数指定的只读属性id。菜单项的单击事件会向处理程序传递菜单项的id,所以你可以编写一个通用事件处理程序,用于处理一个以上菜单项的事件。MenuItem也有一个append和一个remove方法用以添加子菜单项。

使用Menu对象的clear、append、remove和setSoftKey方法,以及MenuItem对象的append和remove方法,你可以创建一个复杂的多级菜单。当一个菜单项有子项时,它的单击将打开子菜单,而不是调用你指定的处理程序。

 

调用AJAX代码

widget代码可以使用XMLHttpRequest对象异步访问网络数据,并且可以使用XML DOM 解析返回的数据。下面是一个请求存储标识并在页面上显示标识值的示例表单。

<div id="divQuote">Quote</div>
<form>
   Stock symbol (eg US:MSFT) <input type="text" id="iSymb" />
</form>

下面的onClick是一个菜单项的事件处理函数,用于取回存储引用。

function onClick() {
  var xmlhttp = null;
  if (window.XMLHttpRequest) {
      xmlhttp = new XMLHttpRequest();
  }
  if (xmlhttp) {
     createRequest(xmlhttp, document.getElementById("iSymb").value);
  }
}

这个函数创建一个XMLHttpRequest对象并调用createRequest 以传送对象及一个标识名。

function createRequest(xmlhttp, symb) {
   var url = "http://blu.services.stub.msn.com/"   
      + "StockQuotes.aspx?symbols=" + symb;
   xmlhttp.open("GET", url);
   xmlhttp.onreadystatechange = function() {
       if (xmlhttp.readyState == 4) {
           harvestResults(xmlhttp);
           delete xmlhttp;
       }
   };
   xmlhttp.send();
}

 XMLHttpRequest.open方法的调用创建了一个异步请求,向MSN存储引用服务传递了存储标识。request对象实际上是在send方法被调用时创建。当请求结果返回时,onreadystatechange事件就会触发。存储引用服务返回一个包含一个或多个存储引用的XML文档,这些数据通过harvestResults 函数解析。

function harvestResults(xmlhttp) {
  if (xmlhttp.status == 200) {
     var xmldoc = xmlhttp.responseXML;
     if (xmldoc) {
        var quoteList = xmldoc.getElementsByTagName("ticker");
        if (quoteList != null && quoteList.length > 0) {
           divQuote.innerText = quoteList[0].getAttribute("name") 
              + " $" + quoteList[0].getAttribute("last");
        }
     }
  }
}

responseXML 属性以XML Document Object Model(DOM)形式返回数据。剩下的代码使用DOM获取第一个<ticker> 元素,并从中取得公司全名和最后一个存储值。

widget运行这些代码使用户可以获取单独的存储引用,然后显示在屏幕上。

 

使用Widget持久化

Widget安全拒绝访问常规的Windows Mobile持久化信息(如文件系统和Microsoft SQL Server® Compact Edition数据库)。因为在widget中持久化信息是很有用的,因此widget API提供了一个用于存储简单字符串的持久化机制。持久化数据是各自独立的,因此任何一个widget只能读取他自己存储的数据。然而,需要重点指出的是该存储机制并不加密数据,因此其他的非widget程序(本地或托管代码)都可以访问这些数据。

要存储数据,widget可以调用widget对象中的 setPreferenceForKey 方法。

var symbol = document.getElementById("iSymb").value;
widget.setPreferenceForKey(symbol, "SYMBOL");

上面的代码存储了最后的存储标识请求。代码可以用 preferenceForKey 方法读取其值。

var symbol = widget.preferenceForKey("SYMBOL");

通过持久化机制存储的值会一直存储到widget再次运行时,并在重置之后可用。该机制应当用于存储相对较小的值,因为每个键有一个4000字节的限制。

 

使用widget安全

安全在每一个应用程序中都是极其重要的,而在需要加载网络数据并且程序功能依赖于网络数据的代码中他更加重要。Windows Mobile widget运行与Internet Explorer之下并且服从与Iternet  Explorer沙箱。这就意味着widget不能访问设备中的个人数据,如联系人、Email信息、注册表等,文件系统对widget而言也是无法访问的。此外,默认情况下网络访问也是被禁止的,除非widget的manifest文件通过 <access> 元素请求了该权限。

<access network="true" />

Iternet Explorer安全啊策略被延续了下来。由Iternet Explorer 保持的数据,如cookie、缓存、历史记录等对每个widget都是相互独立的,并且缓存在每次widget启动时都会清空。

一些特殊例外用于放宽沙盒限制,但是仍然要保持widget安全。尽管widget无法访问常规文件,但是可以使用相关HTML元素(如图片文件的<img>标记)的src属性来访问根目录及其子目录中的文件。安全沙箱允许通过一些特殊的协议进行导航,如mailto:/ sms:/callto:/tele: 等,但是在这些特殊的情况下导航被委托给设备进行处理,而用户可以取消任何将被执行的动作。

设备应该受保护以阻止安装流氓代码。首先,用户将只能够通过Microsoft Windows Marketplace for Mobile安装widget,并为之授权。其次,在安装期间及请求确认时,用户会得到通知,所以当用户安装一个widget时,会得到一个显示来自manifest文件的widget描述信息页面,该页面会请求安装代码的权限。此外,在widget运行时也会进行一些安全检查。譬如,如果widget的manifest指示允许widget访问网络,设备会显示一个警告对话框以提示网络访问可能引起额外的话费开销。用户会得到继续运行widget还是退出的选项。

 

提供widget文件

Widget必须包含一个显示用户界面的HTML文件。这个起始文件在widget的manifest的<content> 元素中命名。起始文件中可以包含样式元素和脚本以支持widget功能,但是典型的起始文件一般通过<style><script> 元素引用分离的CSS文件和脚本文件。widget支持资源和代码本地化,如果他们已经存在的话Windows Mobile就会载入他们。所有这些附加文件都应该在widget文件夹中提供。下面的表格总结了widget文件夹中的文件类型。

文件类型 是否必须 描述

<widget>.html

项目的起始文件。<widget>代表manifest文件中指定的widget名称。

config.xml

一个包含了widget元数据的XML文件。

*.ico, *.png, *.jpg

是,至少1个 widget在设备开始菜单中使用的图标。图标文件在manifest文件中指定。运行的Windows Phone只支持.ico文件,而运行文件的Windows Phone支持所有三种格式的文件。

*.js

否,但建议有 JavaScript文件包含了widget的代码。

*.css

否,但建议有 widget的样式表。

Resource files: .jpg, .png, and more

附加资源。

 

创建manifest文件

每个widget必须有一个manifest文件。这个叫做config.xml的XML文件包含一个<widget> 根元素。这个manifest文件包含了这个widget中可能要本地化的数据的相关信息,因此这个manifest文件可以在本地化文件夹中。然而,即使你使用了manifest文件的本地化版本,仍然要注意在在widget根目录中放置一个manifest文件的默认副本,以作为设备的地区无法被识别时的默认值。manifest文件中的 <widget> 元素必须包含起始文件的名字;其他元素是可选但推荐的。下面是一个最小化的manifest文件。

<?xml version="1.0" encoding="utf-8" ?>
<widget xmlns="http://www.w3.org/ns/widgets" version="1.0">
   <content src="StartUp.htm" type="text/html" />
</widget>

这个manifest指明起始文件名为StartUp.htm 。如果设备的区域设备被设置为English(United States),则地区就是en-US,所以当设备运行这个widget时,会首先尝试在en-US文件夹中寻找一个叫做StartUp.htm的文件。如果文件夹不存在,或文件不在该文件夹中,设备会尝试在en文件夹中寻找一个叫做StartUp.htm的文件,如果文件仍不存在,设备会从根目录中载入StartUp.htm文件。

另一个本地化文件是图标文件。运行在设备上的Windows Phone只能使用.ico文件,而其他电话则可以使用.png和.jpg。

下面的表格列出了<widget>元素中的可用元素。

元素 描述

<access>

该元素指示widget的网络需求。如果network 属性为真值,则widget运行前必须从用户处取得网络访问的权限。

<author>

该元素包含了widget的作者信息。可选属性有:href,作者网站的URL;email,作者的Email地址;img,与作者关联的图像。

<content>

该元素是必需的。src属性给出了其实文件的路径。
<description> 该元素是对widget的描述;该描述将在widget安装期间显示。

<icon>

该元素给出了开始菜单上用于widget图标的文件名。src属性给出了文件名。

<name>

该元素给出了widget的用户友好名。该名字将显示在开始菜单上和删除程序页上。

manifest中一些值可以被widget代码通过widget对象的属性来访问。

 

创建部署包

Windows Mobile widget的设计目标之一是提供一个独立的下载部署包。部署包是一个将扩展名由.zip变为.widget的标准zip文件。你可以任意命名该文件,但是最佳实践是使用widget的名字。如果你没有在manifest文件中提供widget的名字,widget安装程序将会用部署文件的名字作为widget在设备上的名字。

zip中包含了Widget运行所需要的所有文件:Web页,图标文件,样式表,JavaScript文件,和其他资源。这些文件以同样的文件夹结构存储于zip文件中,如果你的widget使用了本地化,这个zip文件也会包含盛放本地化文件的本地化文件夹。

 

部署widget

当前版本的Windows Mobile Widget支持两种部署模式:Marketplace部署和Sideload部署。Marketplace是一个计划成为Windows Mobile 应用程序订购平台的在线应用程序商店。

开发者可以通过桌面开发工作站进行Sideload部署。开发者可以拷贝部署文件到设备,然后在设备上运行widget。该部署方法对模拟设备是有效的,但是对于真实设备,开发者必须先添加如下的注册表键值到设备注册表中。

[HKEY_CLASSES_ROOT\riapp]
    "EditFlags"=dword:00010000
[HKEY_CLASSES_ROOT\riapp\Shell\Open\Command]
    @="wmwidgetinstaller.exe %1"

如果没有这些键值,Windows Phone 将无法识别.widget文件。

widget安装程序从widget文件中解压出所有文件放置到\Program Files 下的一个位置。然后安装程序向设备开始菜单添加widget图标,并提供卸载信息以使widget可以通过移除应用程序菜单卸载。widget安装后,widget文件可以通过\Program Files\Widgets\User文件下的一个子文件访问。这就意味着在开发应用程序时,你只需要部署一次.widget文件,然后在更改文件时你可以直接使用Windows资源管理器从开发工作站拷贝文件到设备即可。

 

最佳实践

SystemState对象允许你检测系统状态值并采取恰当的动作;也允许你注册一个在特定值改变时调用的事件处理程序。你可以使用这些值监视电池电池寿命和网络状况,并改变你的代码相应行为。譬如,如果你的应用程序使用网络数据来更新显示,那么你可以选择在没有网络时禁用更新。widget对象有两个叫做onshow和onhide的属性,允许你指派到在widget显示和隐藏时调用的函数,并且你可以选择在widget隐藏时禁用所有网络连接,而在widget显示时恢复。

AJAX中的异步,其基本依据是,因为网络调用需要时间,所以网络调用可以可用户界面代码异步进行。对用户而言,等待界面更新是很沮丧的,尤其是widget第一次启动时。你可以借助持久化API通过缓存重要数据来减轻这种网络延迟;当widget启动时,你可以显示这些缓存数据。同时,你的代码可以执行异步请求,在请求完成时使用新的数据更新用户界面。

通过在缓存中检查关键数据,并且只从网络访问那些缓存中没有的数据这样的手段,缓存数据也可以用于减少网络访问次数。这是特别有用的,尤其对于用户按数据包收发量付费的蜂窝电话网络。类似的,你可以缓存用户输入以用于widget随后的运行,而不是再次请求用户。

你可以使用样式表和DHTML制作一个丰富的用户界面,另外,你可以使用widget API创建一个菜单并指定到软键从而使widget在电话上有一个本地应用的外观。

 

总结

Windows Mobile 6.5为移动设备带来了widget开发。除了提供Web开发丰富的功能和JavaScript的快速开发,widget还提供了一个引人瞩目的开发拥有Windows Mobile本地应用外观和行为的富应用程序的新方法。

其他信息

下面的链接介绍了widget的打包,描述了widget包中的内容及元数据:

Widgets 1.0: Packaging and Configuration, W3C 2008年12月22日工作草案。

下面列出了W3C对于widget标准的要求:Widgets 1.0: Requirements


相关信息

英文原文:Developing Widgets for Windows Mobile 6.5

中文译文:为Windows Mobile 6.5开发Widget

中文翻译:Mobile On Line – MagicBoy's Blog

Tags: