65.9K
CodeProject 正在变化。 阅读更多。
Home

如何使用 PhoneGap 在 Windows Phone 上创建 HTML5 应用

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2012 年 3 月 15 日

CPOL

13分钟阅读

viewsIcon

44782

如何使用 PhoneGap 在 Windows Phone 上创建 HTML5 应用

本文将首先探讨 PhoneGap 为 HTML5 应用带来的附加价值。然后,我们将学习如何创建我们的第一个项目,并在其中通过 JavaScript 代码获取加速度计的值。最后,我们将回顾一个几乎原封不动地移植到 PhoneGap 的完整 HTML5 游戏示例,以利用 Windows Phone 上的加速度计。

  1. 引言
  2. PhoneGap:填补空白的框架
  3. 创建我们的第一个 PhoneGap 项目
  4. 从 JavaScript 获取加速度计的值
  5. 回顾使用 HTML5 平台游戏(Platformer)的完整示例
    1. 强制横屏模式
    2. 处理各种分辨率
    3. 通过文件系统调用加载关卡,而不是使用 XHR
    4. 修改游戏玩法以使用加速度计
    5. 最终结果截图和部分手机的 FPS
    6. 可下载的完整 Visual Studio 解决方案
  6. 结论

引言

Windows Phone 的 Mango 更新通过嵌入的 IE9 浏览器带来了对 HTML5 的支持。与桌面版一样,移动版 IE9 通过 Windows Phone 的 GPU 提供硬件加速。因此,结合 JavaScript,IE9 现在可以成为通常保留给“原生代码”的有趣用户体验的基础。

使用 HTML5 作为开发平台的优点是能够相对轻松地将部分代码重用到其他兼容平台,如 Android 或 iOS。因此,HTML5 在过去几个月里引起了移动开发人员生态系统的广泛关注。

然而,尽管 HTML5/CSS3/SVG 和 JavaScript 规范在过去几个月里取得了长足的进步,但它们仍然缺少一些构建移动应用的主要功能。事实上,手机或平板电脑提供了特定的功能,例如:GPS、加速度计、摄像头、发送短信、访问联系人等。

为了从 JavaScript 代码访问这些功能,W3C 一直在努力开发我们称之为“设备 API”或DAP的标准。不幸的是,我们可以认为目前还没有这些规范的实现,正如这份文档似乎证实的那样:移动 Web 应用标准:2011 年 11 月的当前状态和路线图。Mozilla 已经通过其所谓的Web API,或多或少地分叉了这些规范,以支持他们的Boot To Gecko项目。这是一个好消息,因为一种实现形式似乎已经开始,并且正在与 W3C 进行持续的讨论。然而,即使事情开始缓慢推进,我们可能还需要等待几年才能获得一个在所有平台上广泛实现的稳定官方 W3C 规范。

那么问题来了:在此期间我们应该怎么做?HTML5 真的能解决这些场景吗?

PhoneGap:填补空白的框架

在等待真正的标准化规范的同时,我们别无选择:我们需要为目标平台创建 JavaScript 和原生代码之间的桥梁,以便访问其功能。其想法是:采用每个平台的原生语言(C#、Objective-C 和 Java),并用这些语言创建一个框架,该框架将公开面向 JavaScript 开发人员的接口。

这正是PhoneGap所做的。以本文的主要主题 Windows Phone 为例。Windows Phone 的 PhoneGap 项目只是一个 Silverlight 应用程序,它托管 WebBrowser 控件(因此是 IE9)以及一个用 C# 编写的 Silverlight 程序集,该程序集负责访问加速度计、GPS、联系人、摄像头等。这样,作为 JavaScript 开发人员,您将使用一个名为WP7GapClassLib.dll(PhoneGap 核心运行时)的 DLL,通过使用嵌入在phonegap-1.3.0.js文件中的代码,甚至不知道它的存在。这个 DLL 包含一些 C# 代码,这些代码会调用手机上可用的 Silverlight 运行时。由于运行时可以访问手机的所有功能,JavaScript 也可以。然后,JavaScript 库将充当两个世界之间的网关。此外,使用此库的好处是,您的代码在 Android 或 iOS 的 PhoneGap 版本上通常可以原封不动地运行。PhoneGap 因此提供了一种有趣的可移植性形式。

顺便说一句,请注意,自最近的 1.3.0 版本以来,PhoneGap 对 Windows Phone 的支持已经完全完成。

最后,PhoneGap 还提供了另一项有趣的服务。它将您的 .js、.css、.html、.png 资源嵌入其项目中,将其打包成传统的应用程序。总之,您可以使用 PhoneGap 将您的 HTML5 应用程序打包到各种应用程序商店中。例如,使用这种方法构建的SujiQ Windows Phone 应用程序就是这种情况。

创建我们的第一个 PhoneGap 项目

必备组件

以下是您需要遵循的最早步骤

  1. 下载 Windows Phone SDK:Windows Phone SDK
  2. 在其网站上下载 PhoneGap 的最新版本(今天为 1.3.0):http://phonegap.com/
  3. 解压下载的文件
  4. PhoneGapStarter.zipPhoneGapCustom.zip 文件复制到 \Documents\Visual Studio 2010\Templates\ProjectTemplates

文件 -> 新建项目

完成上述步骤后,您就可以创建第一个 PhoneGap 项目了。启动 Visual Studio 2010,选择“Visual C#”模板,并通过“Gap”关键字进行筛选。然后您应该会看到一种名为 PhoneGapStarter 的新项目类型。

将您的项目命名为“MyFirstPhoneGapProject”。完成后,您将在解决方案资源管理器中找到我之前提到的文件。

您只需将您的 HTML5 应用程序插入“www”目录即可。

以下是一些关于此默认项目模板的技巧,我想与您分享

  • 切勿触碰 phonegap-1.3.0.js 文件,如果您希望在其他 PhoneGap 版本上保持可移植的代码。
  • 您添加到“www”目录中的所有文件都必须在属性窗口中设置为“Content”。
  • 您可以在下载的 PhoneGap 存档的“Windows Phone\framework”目录中找到 WP7GapClassLib.csproj C# 项目,而不是使用 WP7GapClassLib.dll 二进制文件。这有助于您在需要时进行调试或探索 PhoneGap 库的原生代码。

好的,现在让我们开始做一些默认情况下通过 IE9 Mango 正常不可能做到的事情:从 JavaScript 访问加速度计的值。

从 JavaScript 获取加速度计的值

在这里,我们将看到一种非常简单的方法来获取加速度计(模拟器或真实设备)返回的值。

打开 “index.html” 页面,将其默认的 body 替换为以下内容

<body>
    <h1>Accelerometer sample</h1>
    <div id="valueX"></div>
    <div id="valueY"></div>
    <div id="valueZ"></div>
</body>

我们将简单地使用 3 个 <div> 标签来显示加速度计的当前 X、Y 和 Z 值。

下一步是将最后一个默认的 <script> 块替换为以下内容

<script type="text/javascript">
    document.addEventListener("deviceready", onDeviceReady, false);

    // variable to output the current x, y & z values of the accelerometer
    var valueX;
    var valueY;
    var valueZ;

    // when PhoneGap tells us everything is ready, start watching the accelerometer
    function onDeviceReady() {
        valueX = document.getElementById("valueX");
        valueY = document.getElementById("valueY");
        valueZ = document.getElementById("valueZ");
        startWatch();
    }

    // start monitoring the state of the accelerometer
    function startWatch() {
        var options = { frequency: 500 };
        navigator.accelerometer.watchAcceleration(onSuccess, onError, options);
    }

    // if the z-axis has moved outside of our sensitivity threshold, move the aarvark's head in the appropriate direction
    function onSuccess(acceleration) {
        valueX.innerHTML = "X: " + acceleration.x;
        valueY.innerHTML = "Y: " + acceleration.y;
        valueZ.innerHTML = "Z: " + acceleration.z;
    }

    function onError() {
        alert('onError!');
    }
</script>

我认为代码本身相对易于理解。首先要注意的是,您需要等待 PhoneGap 触发的“deviceready”事件,以确保处于稳定状态。然后您需要订阅此事件。在我们的例子中,我们将通过 OnDeviceReady() 函数进行回调。此函数获取对 3 个 <div> 标签的引用,然后每 500 毫秒使用 startWatch() 函数请求通知加速度计中的任何更改。通知将发送到 onSuccess() 函数,该函数将能够访问包含 x、y 和 z 值的 acceleration 对象。您可以在 PhoneGap 网站上找到完整的文档:PhoneGap 文档 - API 参考 - 加速度计

这就是您在 JavaScript 端需要做的全部。但是,为了使其正常工作,您需要在项目属性中指定您希望请求访问设备的传感器。为了正确执行我们的应用程序,所需的权限列在“Properties”目录中可用的 WMAppManifest.xml 文件中。默认情况下,自 1.3.0 起,PhoneGap 会列出严格的最小权限。

<Capabilities>
  <Capability Name="ID_CAP_IDENTITY_DEVICE" />
  <Capability Name="ID_CAP_IDENTITY_USER" />
  <Capability Name="ID_CAP_LOCATION" />
  <Capability Name="ID_CAP_NETWORKING" />
  <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
</Capabilities>

接下来,您需要为您的 PhoneGap 应用程序添加所需的权限。在我们的例子中,我们需要添加此行

<Capability Name="ID_CAP_SENSORS" />

以允许访问加速度计。您可以在此处找到所有可用权限的完整列表:Windows Phone 的应用程序清单文件

好的,我们将在模拟器中进行第一次测试。按“F5”键,让我们看看结果。

通过在右侧的模拟器中移动虚拟手机,您应该会看到加速度计的值更新。恭喜!

您可以在此处下载此第一个解决方案的完整源代码http://david.blob.core.windows.net/html5/MyFirstPhoneGapProject.zip

使用法语本地化的手机时出现的问题

如果您在设置为使用法语本地化的手机上测试相同的代码(例如我的!),您会觉得应用程序根本不起作用……事实确实如此。我花了一些时间调试代码,并发现 phonegap-1.3.0.js 中抛出了以下异常

"Error in success callback: Accelerometer = Syntax error"

在转储值之后,我看到错误是由于尝试反序列化以下格式错误的 JSON 字符串引起的

"{\"x\":0,00472,\"y\":-0,19879,\"z\":-0,98115}" 而正确的 EN-US 格式是:"{\"x\":0.00472,\"y\":-0.19879,\"z\":-0.98115}"

是的,我们在法国使用逗号作为数字分隔符。

解决此问题的 2 种方法

  1. 懒惰的方法:将您的手机切换到 EN-US(我知道,这不算是一个解决方案!)。
  2. 修复 C# 代码中出现的问题。为此,请将 WP7GalClassLib 库的 Accelometer.cs 文件中的以下代码替换为
/// <summary>
/// Formats current coordinates into JSON format
/// </summary>
/// <returns>Coordinates in JSON format</returns>
private string GetCurrentAccelerationFormatted()
{
    string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}",
                    accelerometer.CurrentValue.Acceleration.X.ToString("0.00000"),
                    accelerometer.CurrentValue.Acceleration.Y.ToString("0.00000"),
                    accelerometer.CurrentValue.Acceleration.Z.ToString("0.00000"));
    resultCoordinates = "{" + resultCoordinates + "}";
    return resultCoordinates;
}

为此行:

private string GetCurrentAccelerationFormatted()
{
    string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}",
             accelerometer.CurrentValue.Acceleration.X.ToString("0.00000", CultureInfo.InvariantCulture),
             accelerometer.CurrentValue.Acceleration.Y.ToString("0.00000", CultureInfo.InvariantCulture),
             accelerometer.CurrentValue.Acceleration.Z.ToString("0.00000", CultureInfo.InvariantCulture));
    resultCoordinates = "{" + resultCoordinates + "}";
    return resultCoordinates;
}

这样,示例将与所有本地化一起工作。我在这里填写了一个关于此主题的错误:https://issues.apache.org/jira/browse/CB-141,提出了与下一个版本(2.0.0)通常会包含的解决方案相同的建议。

顺便说一句,您可能想知道我如何调试 PhoneGap 项目的 JavaScript 部分?好吧,您只需使用出色的jsConsole项目即可。如果您想了解更多信息,请阅读我同事的一篇文章:jsConsole 在 Windows Phone Mango 的 IE9 中进行远程调试

回顾使用 HTML5 平台游戏(Platformer)的完整示例

现在让我们回顾一个更复杂的示例。我的想法是从我之前写过的游戏中开始。它在这篇文章中有介绍:HTML5 Platformer:将 XNA 游戏完整移植到 <canvas> 和 EaselJS。我想看看在手机上运行它需要做什么。

第一步是简单地将不同的 .js、.png、.css 文件复制/粘贴到“www”目录中,并将它们标记为“Content”。以下是后续步骤。

强制横屏模式

游戏需要在横屏模式下进行。因此,我强制了这种方向。我还移除了侧面的信息栏(系统托盘)。为此,您需要打开 MainPage.xaml 文件并更改这些属性。

SupportedOrientations="Landscape" Orientation="Landscape"
shell:SystemTray.IsVisible="False"

处理各种分辨率

由于我的主要目标是构建一个可以在最多设备上运行的游戏,因此我需要处理许多不同的分辨率。

为此,我对您可以在另一篇文章中下载的 Platformer 的初始代码进行了轻微修改。现在游戏可以通过对图像和精灵应用缩放比例来在任何分辨率下运行。一切都基于来自 Windows Phone (800x480) 的特定比例进行重绘,该比例为 100%。您可以在此处使用桌面浏览器测试此版本:HTML5 Platformer ReScale,并尝试动态调整浏览器窗口大小。此外,如果您的屏幕分辨率为 16:9 宽高比,请按 F11 键进入全屏模式!在此模式下的体验非常好,如您在此截图中看到的。

在缩放操作期间,我们让浏览器处理抗锯齿。根据您使用的浏览器,您还会注意到性能会因窗口大小而异。在我的机器上,IE9/IE10 对全屏模式或小分辨率似乎相对不受影响,并保持稳定的 60 fps 帧率。

通过文件系统调用加载关卡,而不是使用 XHR

在初始代码中,与每个关卡关联的 .TXT 文件存储在 Web 服务器上,并通过 XmlHttpRequest 调用下载。由于我们现在完全在客户端离线模式下运行,因此 XHR 本地调用不太合适。因此,我将 PlatformerGame.prototype.LoadNextLevel 函数的初始代码替换为以下代码。

PlatformerGame.prototype.LoadNextLevel = function () {
    this.levelIndex = (this.levelIndex + 1) % numberOfLevels;

    // Searching where we are currently hosted
    var nextFileName = "app/www/assets/levels/" + this.levelIndex + ".txt";
    try {
        var instance = this;
        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);

        function gotFS(fileSystem) {
            fileSystem.root.getFile(nextFileName, null, gotFileEntry, fail);
        }

        function gotFileEntry(fileEntry) {
            fileEntry.file(gotFile, fail);
        }

        function gotFile(file) {
            readAsText(file);
        }

        function readAsText(file) {
            var reader = new FileReader();
            reader.onloadend = function (evt) {
                instance.LoadThisTextLevel(evt.target.result.replace(/[\n\r\t]/g, ''));
            };
            reader.readAsText(file);
        }

        function fail(evt) {
            console.log(evt.target.error.code);
        }
    }
    catch (e) {
        console.log("Error loading level: " + e.message);
        // Probably an access denied if you try to run from the file:// context
        // Loading the hard coded error level to have at least something to play with
        this.LoadThisTextLevel(hardcodedErrorTextLevel);
    }
};

我只是重用了 PhoneGap 文档中提供的代码:FileReader。如您所见,您可以通过 PhoneGap 从 JavaScript 完全访问 Windows Phone 文件系统。

炫酷技巧:为了帮助您调试手机的隔离存储中实际存储了什么,您应该查看这个很棒的工具:由 Samuel Blanchard 编写的IsoStoreSpy

修改游戏玩法以使用加速度计

好的,最后一步是将本文的所有部分混合在一起以获得最终结果。为此,我将以下代码添加到 Player.js 文件中的 Player 对象的构造函数中。

var options = { frequency: 500 };
var that = this;

navigator.accelerometer.watchAcceleration(
    function (accelerometer) { that.moveDirectionAccel(accelerometer); },
    function () { console.log("Error with accelerometer"); }, 
    options);

这是在加速度计变化期间将调用的函数。

Player.prototype.moveDirectionAccel = function(acceleration) {
    var accelValue = -acceleration.y;


    // Move the player with accelerometer
    if (Math.abs(accelValue) > 0.15) {
        // set our movement speed
        this.direction = Math.clamp(accelValue * this.AccelerometerScale, -1, 1);
    }
    else {
        this.direction = 0;
    }
};

我还为 canvas 上的“onmousedown”事件添加了一个处理程序,以便在用户点击屏幕时进行跳跃。

最终结果截图和部分手机的 FPS

首先,让我们在 Windows Phone 模拟器中回顾一下结果。

在我的机器上,帧率在 54 到 60 fps 之间波动。在真实设备上,帧率因型号而异。以游戏的第一个关卡为例。在 LG E900 上,帧率约为 22 fps。在 HTC Radar 上,约为 31 fps。在 Nokia Lumia 800 上,约为 42 fps

在这种情况下,游戏玩法可能不太令人信服。确实,我使用全屏 canvas 来绘制整个游戏。对于性能有限的移动设备来说,这不是一个好主意,尽管诺基亚似乎足够强大来处理这种方法。更好的方法是将屏幕划分为各种小的 canvas,然后通过修改它们的 CSS 属性来移动它们。例如,HTML5 版的愤怒的小鸟就是这样做的。一些 JS 游戏框架开始为您处理这种复杂性。想法是使用高级 API编写一次游戏,然后根据性能,框架可以切换全屏 canvas 或通过 CSS 移动的各种小 canvas。

您会明白:目前移动设备上的 HTML5 游戏体验才刚刚起步。但其未来看起来非常有前途!

可下载的完整 Visual Studio 解决方案

您可以在此处找到 HTML5 Platformer for PhoneGap 的完整源代码HTML5GapPlatformer.zip

其他有用资源

结论

PhoneGap 提供了有趣的前景,可以帮助您编写手机应用程序。它允许您利用您现有的 JavaScript、HTML 和 CSS 技能。PhoneGap 不一定会涵盖当前原生开发栈(Silverlight 或 XNA)提供的所有场景。但如果您想利用团队的 HTML 技能,可以研究一下。您需要注意正确识别要处理的项目类型。

您还可以考虑混合这两种环境来创建混合体验:主分支将使用“HTML5”编写,某些特定部分将使用原生代码编写。使用这个想法,已经创建了一些插件来进一步集成到 Metro UI 中:PhoneGap Windows Phone 插件。例如,您会发现其中一个允许 JavaScript 代码更新磁贴。

最后,PhoneGap 和 HTML5 也可以实现与其他平台的相对可移植性……但有一些限制。但这是一个庞大的主题,涉及激烈的辩论,需要专门的文章来详细阐述。

David

© . All rights reserved.