Tuesday, August 17, 2010

[WP7Dev] PhoneGap and Windows Phone 7

For all my talk and activities around Windows Phone 7 I'm aware I've shown very little about what I've been working on. Here's where I start to address this.
As you may have guessed by the title of this post, I've been looking at adding Windows Phone 7 support to PhoneGap.
For those of you who aren't familiar with PhoneGap it is "an open source development framework for building cross-platform mobile apps". It works by enabling apllicaitons written using the universal languages of HTML, JavaScript & CSS and compiling them into native apps for each supported platform.
I first used PhoneGap early last year when I needed to produce some proof-of-concept apps for the iPhone and I didn't fancy spending the time moving code to objective-C which I already had in JavaScript. (For the project in question it just wasn't worth the effort.) In the intervening time I've kept an eye on the PhoneGap project but not done much with it. I looked at its Windows Mobile support but didn't feel particularly motivated to do much with it. With the release of WP7 I found new interest in the project and am keen that apps developed for other devices/platforms can (where possible) be migrated to WP7 also. I have therefore written some code to try and implement this.

For those that are interested, the code can be found at http://github.com/mrlacey/phonegap-wp7. I know that others have started some work on this also. (Most notably at http://github.com/filmaj/phonegap-winphone.) I thought I would share what I've been doing to help the project. I'd already got further than the version by filmaj when I became aware of and have solved some issues they haven't dealt with yet.

So what is implemented?
In theory the easiest way to show what is implmented is show some test results. So here we are:

It passes 76 of 98 tests. Not bad. (Even if I say so myself).
As it's a shorter list, the tests that fail are the ones which relate to: HTML5 Storage, Contacts, File IO, Maps and methods which require objects being passed in their callback functions.
Some of these could possibly be implemented (File IO and possibly maps) but others just can't, due to limitations of the web browser control and the available APIs. Due to the way that interop with the browser control is implemented it's only possible to pass strings between the JavaScript and the C# code, it's not possible to pass objects to callback functions directly. In my code I have other functions which act as a wrapper to the callback functions so that they are passed appropriate objects but the automated tests don't pick this up.

It's probably a good time to point out that all I've done has only been tested in the Beta emulator. (I'd love to have a real device to test this on. Hint, hint!) Because some functionality requires can't be tested in the emulator, some of it is untested (e.g. navigator.notification.vibrate()) while other code always returns the same default values in the emulator.


How much functionality is implemented?

The following functionality is documented as supported across all platforms which PhoneGap supports:
Accelerometer: GetCurrentAccelleration is implemented but the watcher functions are not as these cannot be tested in the emulator.
Camera: getPicture is implemented but currently doesn't work properly as tombstoning of the app currently means that we lose all javascript references and so we don't have access to the callback.
Supporting tombstoning is the biggest issue with the current code. This could probably be worked around by storing all relevant callback details natively so they could be kept in state across deactivation/activation but I'd like to get some feedback on what I've done so far before spending more time on this.
Device: All features are implemented in JS, but limitations of the WP7 API currently mean that not all details are populated. It should be possible to get theses details with the release version of the API.
Events: deviceReady is not implemented as I have been unable to find a way to create events in the browser. It seems this can't be done, so I have implemented the PhoneGap.available property as a test for confirming loading.
Geolocation: getCurrentPosition is implemented (but returning a hardcoded vallue in the emulator). The watcher functions are not implemented as these cannot be tested in the emulator.
Network: this is implemented
Notification: this is fully implemented.

Additionally, the following other features are also implemented:
DebugConsole: log, warn and error methods
Orientation: getCurrentLocation and the watcher functions (as these can be tested in the emulator)
SMS: Send - triggers the compose functionality
Telephony: Call - triggers the request to make a call


To enable demonstration and testing of the implemented functionality I've created a simple app which demonstrates all the implemented features.




What else?
Other points of note in the code:
  • While it's possible to load a file included in the project (in the webbrowsercontrol) any files loaded this way can't reference other files (JS, CSS, image or ohter HTML files) A partial work around is to try and merge all content into a single file but this can't deal with images. The browser doesn't currenlty support the data protocol but will in the next version (according to an email I've had from the team) so we would have to live without images if we went that route. The alternative is to load all content into Isolated Storage and view it from there. This is what I've done. Also rather than specify all the files to load manually (I couldn't find a way to query these from the XAP) I'm using a T4 template to generate the list of files to load.
  • I'm using a command pattern to handle the different feature implementations. I'm using an abstract base class (PhoneGapCommand) for the commands and two optional interfaces to manage the variations in types of command (IAsyncCommand & IWatcherCommand). This works pretty well but feels like it could be better. I'm keen to discuss/explore alternatives to this.
  • I've implemented a custom back stack to support navigation between pages. This recreates the behaviour you'd see elsewhere if navigating between XAML pages or html pages in IE.
  • Because of the time it can take to load all the files to Isolated Storage and to prevent the webbrowser control being shown before the content has all loaded correctly I've had to implement my own version of the splash screen image. To use this the image must be set to a resource. In my code I have renamed the sample image to make this more obvious.


What next?
Ideally I'd like to contribute this code to the core project but I guess that will depend on what else others have done in terms of WP7 support.
There is also the key issue of how to work with (not around) the application model and how it affects javascript which really needs addressing before this could be considered publicly usable.

Please feel free to leave any feedback in the comments below, or in the discussion I'm about to start in the Google Group.

18 comments:

  1. So sweet! Contributions are like early Christmas presents :)

    Thanks so much for this, awesome job!

    ReplyDelete
  2. Hello,

    I have compilation error in VS2010 - Manifest validation fails: Error code: ValidationSchemaValidation. Any ideas how to fix it?

    Best,
    Valeriy

    ReplyDelete
  3. @Valeriy/Lyuchin

    The current version on GitHub was built against the CTP and has this issue with the RTM version of the SDK.

    I am aware of this and pushing a fix is slowly creeping up my priority list.

    In the mean time you can create a new project and add all the files into it. (This is really all my fix is.)

    Please also note that as this was targetting the CTP it doesn't have support for tombstoning. Fixing that will require a near complete rewrite. :(

    ReplyDelete
  4. I've just pushed a version of this PoC code which works with the RTM version of the WP7 SDK. You can find it at https://github.com/mrlacey/phonegap-wp7/tree/master/rtm/

    ReplyDelete
  5. Thanks! Now it works fine!

    ReplyDelete
  6. You can pass object to Javascript from C# even though it supports strings only,

    JSON

    "{uuid:'hgkjdf67yuth8w54e'}"

    If you pass that to javascript then get javascript to EVAL and return the Evaled Object

    E.G

    function passObj(str){
    var obj = eval(str);
    return obj;
    }

    You just have to construct the Javascript which there are JSON Serializes out there use one of them

    ReplyDelete
  7. Just a follow up you might be able to do it Via .Net

    http://pietschsoft.com/post/2008/02/NET-35-JSON-Serialization-using-the-DataContractJsonSerializer.aspx

    ReplyDelete
  8. @Martin yes you can pass anything to (and from) the webbrowser control but only as a string. Json.net has a better (faster) deserializer than DataContractJsonSerializer. The bigger issue is that the browser control doesn't have native JSON support.

    Hopefully when the pause/resume functionality of PhoneGap 0.9.4 is defined I'll have a guideline for adding the necessary support for tombstoning so this is usable.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Hi,
    solved small bug for you in the DebugConsole. Need to send "DebugConsole.debug" to the phonegap.exe and not just "DebugConsole"

    see fix code:

    DebugConsole.prototype.log = function(message) {
    if (PhoneGap.available) {
    PhoneGap.exec('DebugConsole.debug;INFO;' + this.processMessage(message));
    }
    };

    /**
    * Print a warning message to the console
    * @param {Object|String} message Message or object to print to the console
    */
    DebugConsole.prototype.warn = function(message) {
    if (PhoneGap.available) {
    PhoneGap.exec('DebugConsole.debug;WARN;' + this.processMessage(message));
    }
    };

    /**
    * Print an error message to the console
    * @param {Object|String} message Message or object to print to the console
    */
    DebugConsole.prototype.error = function(message) {
    if (PhoneGap.available) {
    PhoneGap.exec('DebugConsole.debug;ERROR;' + this.processMessage(message));
    }
    };

    Ishai Borovoy

    ReplyDelete
  11. Yaron2:05 pm

    Realizing that it is a partial PhoneGap implementation, we still wish to use it with our software until Nitobi comes up with something. Can we use it freely?

    ReplyDelete
  12. @Yaron Feel free to use as you wish. Please be very aware that the app will not have any support for tombstoning (unless you add it) and there is no guarantee of future compatibility.

    ReplyDelete
  13. hi Matt,

    did you get a chance to work on the tombstoning for phonegap implementation for WP7.

    i am trying to implement tombstoning with the help of your "WP7 Tombstone Helper" on Codeplex. but not much luck so far.

    Any inputs here is much appreciated.

    Thanks
    Lakshman

    ReplyDelete
  14. Lakshman

    I'm still working on the mango version of PhoneGap support. Mango makes things a lot better, but there are still some big issues around maintaining the state of any object in JavaScript. Without that it's going to be a far from perfect solution. The TombstoneHelper library is intended for simple cases which preserve the state of UI elements, not the complex scenarios required for maintaining the state of content in a WebBrowser control.

    We'll get there though.

    Matt.

    ReplyDelete
  15. Hi Matt,

    i got the Camera Function working on the Windows Phone 7.1 (aka Mango) with Phonegap.

    Lakshman

    ReplyDelete
  16. Hi Matt:

    First at all, congratulations for this work.

    I'm new on WP7 and phonegap. I'm trying to migrate some qt + HTML5 app to WP7. The problem is that images defined on html and css are not shown. Path is correct, but don't know if a have to include it in some config file, or where can I save it to the Isolate Storage.

    regards,
    Alejandr

    ReplyDelete
  17. @Alejandr image, css files, etc. need to all be in isolated storage (along with the HTML) otherwise the relative paths won't work correctly.

    ReplyDelete
  18. This is great news!! Can you use an HTML5 canvas?

    ReplyDelete

I get a lot of comment spam :( - moderation may take a while.