Windows Phone HTML5 hybrid

Introduction

When apps for mobile devices were first introduced by the launch of the iPhone, they were written natively for the platform. As time went, more platforms entered the arena namely Android and Windows Phone. All three platforms has a fair user base. When a company or organization wants to create an app they are faced with the choice “what platforms do you want to target? What platform is used by your customers?” Often the answer to that question is that the users are spread among the three platforms and the company wants to target as many of their customers as possible.
As always there are (most often) restrictions to the projects and the biggest restriction is budget. It can be very expensive to target all the platforms with native code, especially if you build big apps like mobile web shops. Decisions must be made in how to proceed. One option is to forget about the apps and go web. That can be a good decision sometimes but not always, for instance many companies’ wants to be published and exposed via the different app stores or when the phone characteristics is needed (GPS etc.). Fortunately there is another way – Hybrid apps. The app is native but the content is built with HTML and CSS. The content is the same for the different platforms but it is hosted in a native app shell – one for each platform.
This blog post will show how you can create a hybrid app on the Windows Phone platform. As always the demo project source will be available at the bottom of the post 🙂

How to do it

First of all, launch your Visual Studio and then go File->new project. In the project dialog, choose the Windows Phone HTML5 App.

project selection

The project template that is created is basically an app containing a Web Browser control (IE) with navigational buttons; forward and back.


    




    
        
        
        
            
        
    

 

Take a look at the project structure. You will notice that you got one more folder than when you are creating other types of Windows Phone apps, namely the folder called Html. This is where we will put our content.
project_structure

From the start you will see that the Html folder contains an index file. This is set in code to be the file that the app will navigate to when the app starts. This is set in the code behind;

        private string MainUri = "/Html/index.html";

        private void Browser_Loaded(object sender, RoutedEventArgs e)
        {
            // Add your URL here
            Browser.Navigate(new Uri(MainUri, UriKind.Relative));
            Browser.IsScriptEnabled = true;
        }

If we inspect the index.html file we see that it is just plain html;

 
        

MY APPLICATION

page title

Try to run the app and you will get;
first_run

So far so good. We have a running app that uses an html file. We can now add as many html files as we want to create our content. Our html files work just like they would on the web, with link navigation etc. Well this will not suffice in most cases, we want to use the cool features in the phone! So our next mission is to get connectivity from the phone to the web page and back!

Send data to and from a web page

The potential for an app to send data to and from a web page is great. The cases can be for instance to send GPS-coordinates, accelerometer data and other cool sensor information. The glue between the phone and the web is our old friend, JavaScript. To enable scripting between the page and the app shell we need to do two things. First we need to set IsScriptEnabled to true on the Browser object and then we need to add an event to the Browser control that handles notifications from the web page. The event handler for this event is where all calls from the web pages will end up.

ScriptNotify="Browser_ScriptNotify_1"

The first demo we are going to implement is a GPS-tracking web page. We will use the GPS-chip in the phone and let the web page decide when the tracking is on or off. When the tracking is on, the phone will send GPS-data to the web page that will be displayed.
First step is to create the web page for our demo. We call the page gpspage.html and we place it in our html folder. Then we add some basic html to our page.


    

HTML5 hybrid demo

gps location

You are here:

We add a few rows to our css file just to emphasize on the lat, long part and when we are at it, we add css for links for our index file as well.

a {
    color:#b6ff00;
    font-size:14pt;
}

.coordinates {
    color:#b6ff00;
}

After we added the nice css we will add our JavaScript for the page. Three methods is added to the page. One for starting the GPS-tracking, one for stopping it and one for setting the location. The first two methods are calling the app-native shell and sends a string as parameter. The windows.external.notify is the method used to send data to the native part and it is the “ScriptNotify” event handler described earlier that will handle the call. The third method setLocation is a method that we will use from the native shell to set GPS-updates when they occur.

    

So now we have the interface. There are a few things left to do before we have a runnable demo. First of all, since we wants to use the GPS, we need to add that capability in the manifest file.
locationCapability

Then we will need to write some native code for the GPS to work. This is done in the MainPage.cs file. First we add a field for our GeoCoordinateWatcher and then we initialize it in the constructor of the page.

        private GeoCoordinateWatcher coordinateWatcher;
        
        public MainPage()
        {
            InitializeComponent();
            coordinateWatcher = new GeoCoordinateWatcher();
            coordinateWatcher.PositionChanged += coordinateWatcher_PositionChanged;
        }

Next thing is to add the handler for the position changed event. First we need to check to see if the page we are navigated to in the Browser has the script that we wants to access. Since we only added it to the gpspage we check to see that that is the current page. Otherwise we skip the location update. If we don’t do this, the browser will throw an exception. Note the InvokeScript method returns and object. This is good since our JavaScript methods could be implemented to return a value.

 void coordinateWatcher_PositionChanged(object sender, GeoPositionChangedEventArgs e)
 {
      //Check to see that we only send GPS-data to our page that can handle it
      if (Browser.Source.OriginalString == "/Html/gpspage.html")
      {
         var result = Browser.InvokeScript("setLocation", new string[] { e.Position.Location.Latitude.ToString(), e.Position.Location.Longitude.ToString() });
       }
  }

Next we need to implement the start and stop. First we navigate to our method for handling notifies from the web pages and add a switch for where we are. This is to keep our code nice and tidy. And then we add a handling method for the GPS page.

        private void Browser_ScriptNotify_1(object sender, NotifyEventArgs e)
        {
            switch(((WebBrowser)sender).Source.ToString())
            {
                case "/Html/gpspage.html": ManageGPSPage(sender, e); break; 
            }
        }

        private void ManageGPSPage(object sender, NotifyEventArgs e)
        {
            if (e.Value == "startGpsTracking")
            {
                coordinateWatcher.Start();
            }
            else if (e.Value == "stopGpsTracking")
            {
                coordinateWatcher.Stop();
            }
        }

Final step before we run our app is to add a link to our index file so we can navigate to our GPS tracking page.

GPS-Demo

No we will run our app, navigate and start our tracking and it will look like this;
first run  tracking

For the fun of it and to demonstrate how easy it is to use the phone resources we are going to add another demo. This time we will use the case where you have some contact info and the desire is for the user to make a quick call from the app. First we adds a new web page to the html folder called contact.html and set it up with html and JavaScript as follows;




    
    
    Windows Phone
    


    

HTML5 hybrid demo

contact

Contact information

Name: John Doe

Division: Sales

Now we have html for the layout, a button for the calling and a JavaScript method that will call the native shell and provide a phone number for the contact. Next we will add the code for handling this. First stop is to extend our ScriptNotify event handler and adding a method for handling the call where we will use a PhoneCallTask for the actual phone call. If you are new to the launchers and choosers concept, please read my previous post on that topic. https://www.bjarneryd.se/?p=134

private void Browser_ScriptNotify_1(object sender, NotifyEventArgs e)
{
    switch(((WebBrowser)sender).Source.ToString())
    {
        case "/Html/gpspage.html": ManageGPSPage(sender, e); break;
        case "/Html/contact.html": ManageContactPage(sender, e); break;
    }
}

private void ManageContactPage(object sender, NotifyEventArgs e)
{
    var pct = new PhoneCallTask();
    pct.PhoneNumber = e.Value;
    pct.Show();
}

Since we are going to use the dialer we need to add the capability for that or the app will throw an exception. So navigate to the manifest and add the capability;

dialer

Finally we need to add a new link in our index file.

Contact Demo

Running the app and making a call will now look like;

mainpage contact page

prompt call phone call

Handling back behavior

So now we have created a hybrid app with two nice features that uses the native shell. The only thing is that the navigation is a bit odd. If the user tries to navigate back using the hardware button after selecting a new web page, the app will close. This is because the navigation is done in the browser and not in the app itself. This can create frustration among the users since they expect the app to navigate back. To add a feeling of being more native, you can override the default back behavior for the button. To do this, add the following method in the code behind.

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    if (Browser.CanGoBack)
    {
        Browser.GoBack();
        e.Cancel = true;
    }
    else
    {
        base.OnBackKeyPress(e);
    }
}

What we do in the code above is to see if the browser has back entries. If it does and therefore can go back, we navigate in the browser. If not, meaning we are back at the index file or we never navigated away, we will adapt the default approach and exit the app. By doing it like this we add the same navigational pattern as all native apps.

Download the source code below.

download source code

Set your Windows Phone 8 app as a lock screen provider

A great feature introduced in Windows Phone 8 is the ability for an app to become a lock screen provider. The feature enables more personalization for the users who can have content on their lock screen that is relevant to them, and that updates! Say for instance that you creates an app for a social network that handles images submitted by a user, then you can use this feature to show different images from that image collection on the users lock screen. To update the lock screen image periodically, you can use a background agent. As always you can find the demo project as a zip file in the end.

Only one app can be used as a lock screen provider at the time, and the user can change the provider form the settings panel or an app can request to be the provider at run time.

To change the provider outside any app, the user can do this by going to settings and then lock screen. Here is a drop down list called “Background”. The apps presented here is the ones with the required capability in the manifest. We will take a look at this later on.

lockscreensettings          chooselockscreenprovider

So let’s look at the code. For this demo I have created a demo image in Paint. We will start our demo with a new Windows Phone project. Then we will add my image to a folder that we can name Images.

folders

When this is done we need to take care of the app manifest. In this case we can’t just open it like we do when we add capabilities and other features. Instead we need to open with an XML-editor. Right click the WMAppManifest.xml file and choose Open with. In the dialog that is shown, select XML (Text) Editor and press OK. This will open up the manifest file as XML.

openwith

Next step is to add the extension.


  

This must be added just below the tag!
What happens if we forget the manifest step? If you do you will, as with capabilities, run into an exception while trying to set the background image, as seen below.

exception

Now when everything is set up, we will dive into the code and with just a few lines add great functionality to the app.

We will create an async method where we will add our code that we want to run when the app starts to set the background image, and then call the method from the constructor.

The first thing in the new method is to see if our app is currently the provider, and if not, ask the user if he/she want to use the app as the provider. (If the user has selected the app via settings, the app will be the provider).

 

//Check to see if the app is currently the lock screen provider
if (!LockScreenManager.IsProvidedByCurrentApplication)
{
    //Request to be lock screen provider
    await LockScreenManager.RequestAccessAsync();
}

This will result in the following when starting the app;
setaslockscreen

As we see, the user is in control of his/her phone and the app cannot change anything without his/her knowledge.
Next step is to set the image as lock screen background. This can also be done by a background agent if periodically updates is the goal.

//Check to see if the app is currently the lock screen provider
if (LockScreenManager.IsProvidedByCurrentApplication)
{
    //Set the image to the lock screen image
    Uri imageUri = new Uri("ms-appx:///Images/lockscreen.png", UriKind.RelativeOrAbsolute);
    LockScreen.SetImageUri(imageUri);
}

The whole method will look like this;

private async void SetLockScreen()
{
    //Check to see if the app is currently the lock screen provider
    if (!LockScreenManager.IsProvidedByCurrentApplication)
    {
    //Request to be lock screen provider
    await LockScreenManager.RequestAccessAsync();
    }

    //Check to see if the app is currently the lock screen provider
    if (LockScreenManager.IsProvidedByCurrentApplication)
    {
    //Set the image to the lock screen image
    Uri imageUri = new Uri("ms-appx:///Images/lockscreen.png", UriKind.RelativeOrAbsolute);
    LockScreen.SetImageUri(imageUri);
    }
}

When we run the app we will can use F12 to simulate the power button to lock the phone and then to unlock it. This will show us that we succeeded in setting a new background image to the lock screen!
changedlockscreen

 
download source code

Guide to Launchers and Choosers

Launchers and choosers are great example of how you can use the Windows Phone 8 platform to add built in functionality to your app in a consistent way. The big benefit except constancy is that you can add quite complex tasks to your app without having to re-invent the wheel or code “nice to have functions” but instead focus on your business goal and app purpose and the best of it all, it’s easy to get started. The biggest difference between launchers and choosers are that launchers launches a task without having some return value while choosers launches a task that returns a value or an item.

Remember, the different launchers and choosers might require capabilities enabled in the app manifest!

Launchers are functionality to launch a task to be performed from your app e.g. a phone call. A note is that when the launcher is executed, the user will leave your app, and might not return. In other words, the app will become dormant or tombstoned. If the user returns, the app will be Activated or Launched at that point. You can often configure the input to a launcher but for some it’s not necessary. A good example for the modification of the input to a launcher is the PhoneCallTask. It requires a phone number to be supplied, but the property for displayname is optional. You can use the PhoneCallTask in your app to provide a phone call functionality with only three lines of code, and still get a consistent UI that the users are familiar with. Below is two code examples for how to add a PhoneCallTask to an app. (The Phone CallTask needs the capability ID_CAP_PhoneDialer.)

Just invoking without display name;

 
            var phoneCallTask = new PhoneCallTask();
            phoneCallTask.PhoneNumber = m_Customer.PhoneNumber;
            phoneCallTask.Show();

Setting the displayname;

 
            var phoneCallTask = new PhoneCallTask();
            phoneCallTask.PhoneNumber = m_Customer.PhoneNumber;
            phoneCallTask.DisplayName = m_Customer.Name;
            phoneCallTask.Show();

The result will be;

phoneCallTask

 

There is a great number of Launchers and the complete list are;

launchers

Choosers are as I pointed out earlier, something that returns a result, if the user returns. As with launchers, the user will leave the app when the chooser is executed and there is no guarantee that the user will come back. Choosers can be used to improve your app and give you as a developer a shortcut to functionality that you might need e.g. pic a photo from the photo album. When we code the choosers we need to add a callback for when (if) the chooser returns with a result since we leave the app. You will find an example below, of how to pick a photo from the media store and displays it in the UI. In this example we will also add the feature to take a picture with the camera.

 

 
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            var photoChooserTask = new PhotoChooserTask();
            photoChooserTask.ShowCamera = true;
            photoChooserTask.Completed += photoChooserTask_Completed;
            photoChooserTask.Show();
        }

        void photoChooserTask_Completed(object sender, PhotoResult e)
        {
            if (e.ChosenPhoto != null)
            {
                var bitMap = new BitmapImage();
                bitMap.SetSource(e.ChosenPhoto);
                MyImage.Source = bitMap;
            }
        }

And the result will be;
photochooser
The list of choosers are shorter than the list for launchers but contains a great deal of nice built in features;

choosers

Windows Phone text to speech

In Windows Phone there are great features to communicate with an app using voice. In previous post I have described how to command your app using your voice. In this post I will cover on how the app can respond using text to speech. The feature text to speech can be used in various scenarios to give the user feedback and is definitely a great tool to optimize your apps accessibility. The entire source code can be downloaded at the end of the post.

Windows Phone have support for 15 languages (sadly, not Swedish) and each language comes with two voices, one male and one female. The phone has one voice set as default. This can be viewed and changed in the phone settings. The default voice is the one to be used if not the app say otherwise.

windows phone settings

windows phone settings
speech settings

speech settings

First of all we create a simple UI with three buttons supporting our three scenarios. Add event handlers to the buttons.

main ui

main ui

Now we need to add speech recognition capability to the app. If not, we will get a security error when we try to speak any text. Open the app manifest and add the capability as shown in the picture below.

Speech recognition capability

Speech recognition capability

Now we will dig into the code and start with scenario number 1. The crazy thing here is that only two lines of code are needed to speech text with the default voice. First of all we create a new method and in that we create a SpeechSynthesizer object that will be used to speak the text we will provide for it. Then we will use the method SpeakTextAsync on the synthesizer-object and send in the text. Note that this method is async so we need to decorate our method with the async keyword.

 
        private async void GreetInEnglish()
        {
            //Fist create the synth that will be playing the sound
            SpeechSynthesizer synth = new SpeechSynthesizer();
            //await the synth while it speaks the text of your choice. This will use the default voice.
            await synth.SpeakTextAsync("Hello man! How are you today? Well i'm just fine myself!");
        }

Run the app and hear it greet you! 🙂

Now for scenario no 2 we will start out as in scenario 1 with a new method. Now we will tell the phone to use a female French voice. This is easily done by querying the InstalledVoices.All for a voice that is of culture “fr-FR” and female. Then we will tell the SpeechSynthesizer-object to use that voice. I have used Google-translate to translate the text from the previous sample to French. This will make the speech sound more natural J

 
        private async void GreetInFrench()
        {
            //Create the synth that will be playing the sound
            SpeechSynthesizer synth = new SpeechSynthesizer();

            //Find the voice of your choice. In this case french woman
            var voice = (from x in InstalledVoices.All
                     where x.Language == "fr-FR" &&
                     x.Gender == VoiceGender.Female
                     select x).FirstOrDefault();

            //Tell the synth to use the selected voice
            synth.SetVoice(voice);

            //await the synth while it speaks the text of your choice with the selected voice
            await synth.SpeakTextAsync("Bonjour homme! Comment allez-vous aujourd'hui? Eh bien, je suis juste moi-même très bien!");
        }

For our final scenario we will create a method that will loop through all the installed voices and let them say “Hello World”. Just as in the previous example we will use the installed voices, but this time we will loop over them and let each and one of them speak the text.

 
        private async void LoopAllVoices()
        {
            //Create the synth that will be playing the sound
            SpeechSynthesizer synth = new SpeechSynthesizer();

            //Loop all the installed voices
            foreach (var voice in InstalledVoices.All)
            {
                //Tell the synth to use the selected voice
                synth.SetVoice(voice);
                //await the synth while it speaks the text with the current voice
                await synth.SpeakTextAsync("Hello world!");
            }
        }

Download the source code and have fun! 🙂

download source code