2 Comments

Twitter Bootstrap broken in Windows Phone, Wensus image

Unfortunately the latest Twitter Bootstrap is broken with Windows Phone: The responsive layout doesn't work.

We noticed this when updating the Wensus website. This is how the site worked with a version 2.2.1 (captured from Windows Phone emulator):

And this is what happened after we upgraded to latest Twitter Bootstrap version (2.3.1):

Rolling back to 2.2.1 fixed the issue.

There's a short discussion about this on GitHub dating back to last December. The issue has been closed as the Bootstrap team doesn't officially support Windows Phone. Which is really unfortunate.

Here's a short tutorial on how to make Durandal, PhoneGap and Windows Phone 8 work together:

Download and install PhoneGap’s Visual Studio 2012 template

Start by downloading PhoneGap. At the time of writing this, the latest version is 2.7.0. From inside the zip, copy CordovaWP8_2_7_0.zip(in folder lib/windows-phone-8)to Documents/Visual Studio 2012/Templates/ProjectTemplates:

image

Create a new Windows Phone 8 app using the template

Next step is to create the actual Windows Phone 8 app. For that, use the new Cordova-template:

image

Clone the Durandal and add it to the app

Next step is to get Durandal. After cloning the project, copy App, Content and Scriptsfolders into the app’s www-folder:

image

Now we just need to modify the PhoneGap’s Index.html so that it uses Durandal.

Create the Index.html for Durandal

Open the index.html and replace the content with this:

<!DOCTYPE html>
<html>
<head>
    <title>Durandal</title>

    <link rel="apple-touch-startup-image" href="Content/images/ios-startup-image-landscape.png" media="(orientation:landscape)" />
    <link rel="apple-touch-startup-image" href="Content/images/ios-startup-image-portrait.png" media="(orientation:portrait)" />
    <link rel="apple-touch-icon" href="Content/images/icon.png" />

    <!--Durandal does not require Bootstrap or Font Awesome. 
            They are used to make the samples look nice.-->
    <link rel="stylesheet" href="Content/bootstrap.min.css" type="text/css" />
    <link rel="stylesheet" href="Content/bootstrap-responsive.min.css" type="text/css" />
    <link rel="stylesheet" href="Content/font-awesome.min.css" type="text/css" />

    <!--The css in this file makes the modal dialogs work right.-->
    <link rel="stylesheet" href="Content/durandal.css" type="text/css" />

    <!--Css specific to the samples.-->
    <link rel="stylesheet" href="Content/app.css" type="text/css" />

    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="format-detection" content="telephone=no" />

    <meta name="viewport" content="width=device-width" />
    <script type="text/javascript" src="cordova-2.7.0.js"></script>
</head>
<body>
    <div id="applicationHost"></div>

    <script type="text/javascript" src="Scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="Scripts/knockout-2.2.1.js"></script>
    <script type="text/javascript" src="Scripts/sammy-0.7.4.js"></script>
    <script type="text/javascript" src="app/durandal/amd/require.js" data-main="app/main"></script>
</body>
</html>

In theory, that should be it. But if you run the app, you’ll notice that everything is not working correctly:

image

The source of problem can be found from Visual Studio’s output window:

image

So it cannot find the shell.html, even though it’s where it should be:

image

“Fix” the PhoneGap

The PhoneGap Visual Studio 2012 template includes the PhoneGap’s source code, which is great. If you now open the Plugins/File.cs and set a breakpoint to readResourceAsText-method, you’ll see what’s causing the problem:

image

PhoneGap tries to read the file from a wrong folder!The folder is missing the www-part.

Now make a little tweak to the code:

                pathToResource = "www/" + pathToResource;
                var resource = Application.GetResourceStream(new Uri(pathToResource, UriKind.Relative));

And then run the app again and here it is! Durandal running in a PhoneGap based Windows Phone app:

image

Source Code

I created a repository for this sample on GitHub. It’s available from here.

5 Comments

Background

Even if your Windows Phone 7 app doesn’t require any features from the new OS and even if it runs just fine in Windows Phone 8 phones, there’s a clear benefit from creating a separate WP8 version of the app: The WP8 compiled version of the app will play nicely with phones using 720p resolution (for example HTC 8X).

To illustrate, here’s a WP7 app running on a 720p Windows Phone 8 device:

image

Here’s the same app, this time updated to WP8:

image

As you can see, the WP7 version doesn’t use the full screen. As a result, the app (especially with a colorful background) looks ugly because of the black bar.

Options

There’s many articles on how developers can use a separate project for every platform. The basic idea is:

  1. Open your Windows Phone 7 app solution
  2. Create a new WP8 project into the solution
  3. Use Visual Studio’s “Add As Link” feature to copy all the files from the original WP7 project to the new WP8 project.

This works but it adds some complexity: If you add a new file to the WP7 project, you must remember to add it also to the WP8 project.

Instead of the method described above, we’ve had good success with a solution where we create a new “startup” project for the app. The benefits from this method is that once it has been set-up, you can continue working on the main project(s). If you add a new page, you don’t have to link it anywhere. Your app’s actual code isn’t linked between the projects.

Startup Project

The idea with the startup project is to have a project with a minimum amount of code which must be kept in sync between the WP7 and the WP8 versions.The startup project only has a single page and the user actually never sees it. As soon as the user hits the page, she is automatically navigated to the actual start page of your application, which resides in a completely different project (the main project of the app).

With the startup project, the application has the following structure:

The Main project:The original project which contains the actual application, all the pages etc. Can be multiple projects too, not limited to a single project.

The Startup project: A simple startup project which automatically redirects the user to the Main Project.

Example

Given a simple Windows Phone 7 app:

image

1. Add a new startup project

image

image

image

2. Add reference from Startup project to MainProject.

3. Modify the new project’s MainPage

We don’t want the user to see the MainPage.xaml from the startup project. Instead, the user should see the MainProject’s MainPage.xaml as the first page. In order to accomplish this, modify the startup project’s page to include automatic navigation to the main project:

namespace AppStartup.wp7
{
    public partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            this.NavigationService.Navigate(new Uri("/MainProject;component/MainPage.xaml", UriKind.Relative));
        }
    }
}

4. Remove the startup project’s page from the navigation stack

User is now automatically taken to the main project’s page. But the back button doesn’t work correctly. To fix this, the startup project’s page must be removed from the navigation stack. This can be done on the main project’s page:

namespace MainProject
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            if (e.NavigationMode == NavigationMode.New)
                NavigationService.RemoveBackEntry();
        }
    }
}

5. Add a new startup project for the Windows Phone 8 version

The WP7 version is ready so we just need a project for the WP8 version:

image

image

image

6. Link the files between projects

Remove Assets, Resources, App.xaml, LocalizedString.cs and MainPage.xaml from the WP8 version, leaving it blank. Or leave the Assets folder if you don’t want to play with the app’s icons:

image

Select all the files and folders from Wp7 project, press CTRL+SHIFT and drag the files to the Wp8-project. This will automatically add the files as links:

image

7. Fix the app’s icons from the WMAppManifest.xml

If you deleted the Assets folder, you’re most likely going to see an error stating that app’s icons couldn’t be found:

image

To solve this, open WMAppManifest.xaml and point the icons to correct files.

8. Solve the other issues

Now there’s just two small things to do. First, open the WP8’s startup project and set the “Startup object”:

image

Then, add a reference from the WP8 startup project to the MainProject.

That’s it.You can now start the WP8 version of the app. Even though the MainProject is a WP7 assembly, the page is shown in full size:

image

The benefit from this is that once you’ve done the setup, you can continue editing the MainProject. There’s no MainProject.wp8 or MainProject.wp7, all the new pages will automatically work on both of the versions. And it’s likely that you never have to touch the startup projects once you’ve configured them once.

Just remember to submit the Startup.wp7.xap and the Startup.wp8.xap, not the main project.

Source code

An example solution can be found from GitHub (directory wp7-wp8-Startup-project).

1 Comments

TechDays 2013 is held in Helsinki next week, between the 5th and 6th of March. I’m giving a “Lessons Learned” style presentation there on the Azure track. The presentation contains information about the following subjects:

  • Cloud from the startup’s perspective: Where and how to maximize the usage of slower and cheaper CPU cycles
  • Building for scalability
  • Table Storage: Optimizing for the performance
  • Using Node.js and MongoDB in a modern Azure app
  • etc

Overall the presentation will focus on our lessons learned from building the Wensus.com app analytics service. What has worked, what hasn’t. What would we do differently if we had to start now.

The presentation is in Finnish. Also, during the TechDays, you can find me from the Microsoft’s “BizSpark lounge”  where we have our own stand.

2 Comments

I’ve been working with an app which has both the Windows Phone 7.5 and the Windows Phone 8 versions. Both of these versions have their own project files which target the correct platform but they reference and use a background agent compiled as a 7.5 project. The problem: Background agent was working on the 8.0 version, but the 7.5 threw a System.InvalidOperationException when it tried to start the agent. Here’s the stack trace:

And here’s the agent:

image

The application correctly referenced the project and the WMAppManifest.xml contained the agent:

      <ExtendedTask Name="BackgroundTask">
        <BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="scheduled-agent-wp7" Source="scheduled-agent-wp7" Type="scheduled-agent-wp7.ScheduledAgent" />
      </ExtendedTask>

So what was the problem? The XML.

When you add a reference to the agent, it automatically creates the XML into the WMAppManifest.xml. But in this case, it generated the wrong XML.If you check screenshot of the code, you can see that the agent’s class is scheduled_agent_wp7.ScheduledAgent. But the generated XML tries to reference a class scheduled-agent-wp7.ScheduledAgent.

Manually fixing the WMAppManifest.xml helped to solve the issue.