The second part of the article I posted earlier is out now: Cloud-Connected Mobile Apps – Build a Xamarin App with Authentication and Offline Support. I think it's been out for a week already, but I've been catching up from the last hurrah of summer vacations.

This Part 2, which covers the Xamarin client side of the project, is the piece that I mostly wrote, with contributions by Mike Wasson on the authentication parts. The code for both the backend and the client are available now via https://aka.ms/altostratusproject (which goes to GitHub). Feel free to make contributions!

And a reminder that there are three extra pieces of content for this article that are posted on my blog here already:

Enjoy


Note: this is a placeholder article so I can create a bit.ly link for an upcoming MSDN Magazine article that will point to the real documentation for this feature. Those docs are currently in progress and will likely be available by the time the article is published. But we have to finish the galley proof for the print magazine now, hence the placeholder!

Until just recently, here in the summer of 2015, the Visual Studio Online build system didn't have support for cross-platform apps like those created with Xamarin. That support has now been added.

When you're on VSO's Build tab for a project, you'll see "Build definitions" and "XAML definitions." The latter, XAML definitions, are those that worked with the previous build system that does not have cross-platform support.

VSO-Build1

If you create a new definition with the big green +, you'll be presented with the new list of templates:

VSO-Build2

Clearly you can see the options for building Xamarin.Android and Xamarin.iOS projects, along with the Xcode option for building a straight iOS native app.

What about Xamarin for Windows? I'm told you can use the Visual Studio template for that, but I haven't tried this myself. In any case, when you use one of the Xamarin templates you'll be required to enter your Xamarin credentials to activate the necessary platform licenses:

VSO-Build3

Anyway, that's all I'll say for now because I haven't tried out all of this myself. Again, proper documentation will be appearing soon on MSDN for all the details.

 


This blog post is an addendum to the article, Build a Xamarin App with Authentication and Offline Support, to be published in MSDN Magazine, September 2015. I'll update this post with a link once the article is available. Part 1, Cloud-Connected Mobile Apps – Create a Web Service with Azure Web Apps and WebJobs, which discusses the backend of the project, is available now.

As promised, there are a few points of interest in the app that have not been discussed previously.

First, we implemented some niceties for displaying items both in the home page list and on the item page:

  • When processing data from the backend in DataModel.ProcessItems, the app generates a description from the first 100 characters of the body. Because that body is typically HTML and the description is plain text, we use a one-line regular expression replacement to do a quick strip of the tags (this is the private function StripHTML in sync.cs):
Regex.Replace(source, "<[^>]*>", string.Empty).Replace("n", " ");
  • Similarly, we noticed during testing that item titles can have smart quotes in them, but the text field in the ListView control will display their escape sequence instead. So another little one-liner (CleanEscapes in sync.cs) takes care of this:
source.Replace("&#39;", """).Replace("&quot;", """);
  • The item page displays the name of the item’s source (such as StackOverflow or Twitter), and to make it easy to go to that source directly the ItemPage constructor makes it a hyperlink with the following code:
this.ProviderLabel.GestureRecognizers.Add(new TapGestureRecognizer
{
    Command = new Command (() =>
    {
        Device.OpenUri(new System.Uri(viewModel.Url));
    })
});
  • It’s also very likely that the item’s HTML displayed in the ItemPage’s WebView will contain hyperlinks. Left to themselves, these hyperlinks will cause navigation within the WebView, but because there are no navigation controls the user wouldn’t be able to return to the item itself. To prevent this, the following code redirects navigations within the WebView to the default browser. The trick (mentioned in Altostratus Extra #1) is that the exact behavior of the WebView varies by platform: on iOS and Windows Phone, a Navigating event will be raised when the webview is first loaded with content from the app, whereas on Android you get the event only for navigations within the WebView once it’s loaded. We thus use Device.OnPlatform to initialize a flag that says whether to ignore the first event:
private Boolean navigateToBrowser = Device.OnPlatform<Boolean>(false, true, false); 

// ...

wv.Navigating += (Object sender, WebNavigatingEventArgs e) =>
{
    if (navigateToBrowser)
    {
       Device.OpenUri(new System.Uri(e.Url));
       e.Cancel = true;
    }

    navigateToBrowser = true;
};

And second, although we wanted a change of configuration to trigger a sync with the backend, we obviously don’t want to do this with every UI activity in the configuration page. Instead, a sync should only be triggered if the user actually changes something in the configuration when they return to the home page.

To implement this, the UserPreferences class in the data model, which matches the data exchanged with the backend, supports cloning an instance (its Clone method) and comparing to another instance (its IsEqual method). The Configuration page uses these within its OnAppearing and OnDisappearing events to have the data model refresh itself if the user made changes when they return to the home page. This way, the user could toggle categories, change the conversation limit, and even log in and log off again, but if ultimately the user returns to the home page with exactly the same configuration, nothing needs to happen in the data model or the home page UI.


This blog post is an addendum to the article, Build a Xamarin App with Authentication and Offline Support, to be published in MSDN Magazine, September 2015. I’ll update this post with a link once the article is available. Part 1, Cloud-Connected Mobile Apps – Create a Web Service with Azure Web Apps and WebJobs, which discusses the backend of the project, is available now.

The OAuth credential flow in Altostratus is as follows, using Facebook as an example. Once the user is

  1. The mobile client app displays a web browser control and navigates to a known URL on the backend.
  2. The backend redirects to the Facebook sign-in page where the user signs in with his or her Facebook credentials.
  3. The backend does sends requests to Facebook to retrieve an access token.
  4. The client app redirects the browser back to the backend’s endpoint. The redirect URL includes the access token in the fragment hash.
  5. The client app has been waiting for the redirect. At this point, it parses the access token from the URL fragment.
  6. If the user is not yet registered with the backend, the client app sends a registration request to the backend. The backend creates a database entry for the user and issues a second access token. This step only happens on the first login.
  7. Once the user is registered, the client app includes the access token to make authenticated requests.

Put graphically:

AltoStratus_OAuth_Flow


This blog post is an addendum to the article, Build a Xamarin App with Authentication and Offline Support, to be published in MSDN Magazine, September 2015. I'll update this post with a link once the article is available. Part 1, Cloud-Connected Mobile Apps – Create a Web Service with Azure Web Apps and WebJobs, which discusses the backend of the project, is available now.

To summarize from the article: Xamarin.Forms is a framework that lets you use a single code base to implement apps with UI on multiple target platforms. However, as written in Part 2, "shared code doesn’t much reduce the effort needed to thoroughly test the app on each target platform: that part of your process will take about as long as it would if you wrote each app natively. Also, because Xamarin.Forms is quite new [it first came out in May 2014], you may find platform-specific bugs or other behaviors that you'll need to handle in your code."

That particular statement comes from direct experience! Here are the behaviors we encountered with Altostratus and had to manage in the client app code (http://aka.ms/altostratusproject, in the MobileClient project):

  • The Xamarin.Forms ListView control supports grouping, but not invocation of group headers as is supported on some individual platforms. We would have liked to enable this feature in the app, but chose not to until Xamarin.Forms makes it work.
  • ListView headers appear on iOS 7 but don’t appear on iOS 8. This is a known bug in Xamarin.Forms.
  • On iOS and Windows Phone, the OnAppearing and OnDisappearing events for page navigations happen in the expected order: the originating page receives an OnDisappearing before the target page receives an OnAppearing. There’s a significant Xamarin.Forms bug on Android (and here's a duplicate bug) that causes the target’s OnAppearing to fire first. For this reason it’s necessary in the app's Configuration page to update the page’s overall changed status with every UI activity, rather than just check it once within OnDisappearing. This clearly causes a lot of extra churn.
  • On all platforms, setting the Minimum property of a Slider control (as used on the Configuration page) will throw an exception unless Maximum is already set to a higher value. This makes it difficult to set the values through data binding, because the order in which XAML binding statements are processed is indeterminate. For this reason, these properties are set in code rather than through data binding. See https://bugzilla.xamarin.com/show_bug.cgi?id=21181 and https://bugzilla.xamarin.com/show_bug.cgi?id=23665.
  • Data binding the items in a drop-down listbox is not supported at the time of writing.
  • The Xamarin.Forms WebView control is written to fire a Navigating event when the user attempts to navigate a link within the WebView. In the mobile client, we capture this event to specifically disallow navigation directly within the control and redirect the navigation to the default browser, see the code in Altostratus Extra #3. (The code for this is in the ItemPage constructor in ItemPage.xaml.cs.) However, on iOS and Windows Phone 8.1, but not Android, the Navigating event is also raised when the WebView is initialized from local content. This means that on those platforms we want to ignore the first Navigating event, whereas on Android we want to pay attention to all of them. So we just set a flag (navigateToBrowser) within the ItemPage constructor to control whether we delegate a navigation to the browser.

 

The lesson to be learned here is that when platform technologies always have their bugs, especially new ones but often mature ones as well. If something you think should be happening isn't, or you encounter some other behavior that seems odd and especially those that are inconsistent between operating systems, check into the applicable bug database like bugzilla.xamarin.com, or check on the applicable forums. It'll save you plenty of frustration. 🙂


We just published Part 1 of a two-part series in MSDN Magazine that covers the cloud-connected mobile app project I worked on earlier this year, which we called “Altostratus” (the name of an interesting cloud).

Part 1 is entitled “Cloud-Connected Mobile Apps – Create a Web Service with Azure Web Apps and WebJobs”, and is on https://msdn.microsoft.com/en-us/magazine/mt185572. I didn’t write much of this first article, personally, as it covers the backend part of the project and I worked primarily on the client.

The Xamarin client is the focus of Part 2 that will be published in early September. In advance of that, you’ll see a couple posts here with some extra material that didn’t fit into the ~5000 words of the article. I’ll be making those posts shortly because we want to make sure the URLs are accurate before going to print. 🙂

The code for both the backend and the client are available now via https://aka.ms/altostratusproject (which goes to GitHub). It is an open project, so if you see anything to improve, we’re happy to accept contributions.

Enjoy



A reader of my recent MSDN Magazine article asked what I thought about performance in Cordova apps, and here's what I wrote in response.

Performance really depends on the underlying hardware, the individual platform, and the version of the platform, because it’s highly dependent upon the quality of the app host and hardware that’s running the code.

On Windows 8.1 and Windows Phone 8.1, you’re running a native app (no webviews), and because Microsoft has put tons of perf work into the IE engine on which the app host is built, JavaScript/Cordova apps run quite well. In the perf tests I did on Windows 8.1 with JavaScript apps (see chapter 18 of my free ebook), I found that the delta from JS to C# was 6-21%, JS to C++ was 25-46%, and C# to C++ was 13-22%. This was for CPU-intensive code (and a Release build outside the debugger, of course) and thus represents the most demanding situations. If you’re primarily working with UI code in the app where the system APIs are doing the bulk of the work, I’d expect the deltas to be smaller because the time spent in UI code is mostly time spent in optimized C++.

On Android, iOS, and Windows Phone 8, Cordova apps run JS inside a Webview, and thus are very much subject to Webview performance. From what I've heard–and I haven't done tests to this effect myself–performance can vary widely between platforms and platform versions. More recent versions of the platforms, e.g. iOS 7/8 and Android 4.2 or so, have apparently improved Webview performance quite a bit over previous versions. 

In short, if you’re targeting the latest platforms, performance is decent and getting better. If you're targeting these systems, then, Cordova performance should be suitable for many types of apps, though probably not for intensive apps.

It's important to note that "performance" is not really a matter of throughput: it's a matter of user experience. I like to say that performance is, ultimately, a UI issue, because even if you don't have the fastest execution engine in the world by some benchmark measure, you can still deliver a great experience. I think of all the video games I played as a kid on hardware that was far inferior to what's probably inside my washing machine today. And yet the developers delivered fabulous experiences.

That said, running JavaScript in a Webview on platforms like iOS isn't going to match a native iOS implementation, especially with signature animations that are really hard to match with CSS transitions and such. But if you're not needing that kind of experience, Cordova can deliver a great experience for users without you having to go native.

I made a diagram that’s on http://www.visualstudio.com/explore/modern-mobile-apps-vs that tries to illustrate where Cordova falls relative to Xamarin, native, and mobile web. The vertical axis is “mobile app user experience” which includes perf as well as the ability to provide a full-on native experience like I just mentioned. 

The diagram is one way to look at the relative strengths of different cross-platform approaches. In the end, you of course have to decide what perf measures are important for your customers, do some tests, and see if Cordova will work for your project. And of course, pester the platform providers to improve Webview perf too! 🙂


Many of you have probably seen this already–an article that I wrote (with contributions from my teammate, Mike Jones), for MSDN Magazine.

http://msdn.microsoft.com/en-us/magazine/dn879349.aspx

I expect to be writing for MSDN more because my larger team at Microsoft owns the content calendar now!

 


I had another interesting struggle today playing around with a TFS build server and unit tests. Ostensibly this was to work through TFS and ALM matters with a Xamarin app, but this particular issue isn't specific to Xamarin.

I'd set up a team project on the TFS server, created and checked in the app, and then added a unit test project to the solution. On the local machine the tests ran fine.

In the build definition for the TFS server, I had the default setting to run tests in any assembly with "test" in the name, and the Unit Test project I added to the solution fit that criteria. I also set the build definition for Continuous Integration to build (and therefore test) on any checkin. I then checked in the unit test project along with a bug in the app code to fail the test, and a build was queued automatically as expected.

However, no tests were run. Hmmm. I checked the log of the build and didn't see my test assembly anywhere. I played around with settings in the build definitions and searched for answers for a while, to no avail.

So what was the problem? Turned out to be another really simple thing: I had neglected to check in the .sln file along with everything else. I'm not sure why that was, but that's what happened. As a result, the TFS build server had the test assembly source code, but because that project wasn't in the solution in its copy of the code, it didn't build it. Therefore it didn't find any test code to run, and thus the build succeeded because it wasn't blocked by a failed unit test.

Once I checked in the solution file, the TFS build included the test assembly and ran those tests as expected upon a checkin, failing the build with my intentional bug in the app code. Correcting that code and checking in again queued another build, which worked.

—-

As an addendum, here are my raw notes on reproducing the problem I'd encountered, setting up the Xamarin project to work with a TFS build server, continuous integration with unit tests. I didn't bother to edit these; I'm only including them as a quick-and-dirty tutorial on a minimal setup to evaluate TFS and CI functionality, because it's not easy to find something short and simple along these lines.

I have a TFS server installed. Made sure that the build agent account can get to necessary resources (important for Xamarin and Android SDK install, but this isn't about that–see previous post).

 

  1. Running Visual Studio, Connect to team server and do Create Team Project…
  2. Map the team project to a local workspace (the folder that will sync)
  3. In Team Explorer – Home > Solutions > Workspace <my machine>, select New… and in the new project dialog, create a blank Xamarin app, MathTestB.
  4. Checked the code in and ran a local build to verify it works. Make sure the solution file is also checked in.
  5. Created a build definition using defaults. Team Explorer > Builds > New Build Definition, trigger build on CI, only change is sending builds to another file share.
  6. Queued a new build to test. Did build definition (right click) > View Controller Queue… to see results.
  7. Got the Android SDK Directory could not be found, set /p:AndroidSdkDirectory=c:android-sdk in the build definition under Process > Build > Advances > MSBuildArguments. Also set MSBuild platform to x86. Saved definition and build again.
  8. Removed Windows Phone 8 project as Silverlight 4 SDK is not on the server. Checked in .sln file which queued a rebuild on the server. This built successfully.
  9. In MathTestB (PCL) > App.cs, add a method called AddOne to return a+1. This is what we'll unit test.
  10. Added a Unit Test project to the solution. Right click solution > Other Languages > Visual C# > Test > Unit Test Project call it AdditionTests. Add reference to MathTestB (required).
  11. In UnitTest1.cs, add

     

    1. using MathTestB.
    2. Change TestMethod1 to TestAddOne.
    3. Add code to test 124+1 = 125
  12. Rebuilt solution. Then did run tests and had success.
  13. Changed MathTestB.App.AddOne to be +2. Ran tests again, they failed.
  14. OK, so we're cool now. Let me now check in AdditionTest as and the change to app.cs. We're cool, right? This queues some builds and should run the test, which should fail on the server.

     

    1. However, it works on the server. Examining the log, we find that no tests were run. Why is that? It's not because the build definition is wrong, it's because I neglected to check in the .sln file that includes AdditionTests. Thus the server isn't building the test assembly, and therefore the build definition isn't finding it.
  15. Checked in the solution file now. New build queued. And it fails as expected.
  16. Restore proper code to app.cs. Check in. Build succeeds as expected.
  1.