Xamarin Forms, Prism and Platform Services

One question that I have had a few times now is how do I integrate platform specific implementations of services into the Prism Framework? It’s not hard, in fact, you don’t have to do anything at all! Let’s take a look at how it works. I am going to focus on the Unity container: it’s my favorite for no other reason than it was the first container I started using and it has always worked well for me across all different .NET projects. The other containers have similar capability.

Recap Abstracting Platform Services

All the platforms have very similar capabilities, especially in the case of Bluetooth, Bluetooth LE, GPS, text-to-speech etc., but each of these capabilities requires a platform specific process of consuming them. I am sure most know that an interface needs to beĀ  created the portable/shared project and then platform specific implementations in each of the platform projects. But here is a quick recap of what it looks like.

Portable/Shared Project

Create your Xamarin Forms project and use nuget to add Prism.Unity.Forms. The latest stable release at the time of writing was 6.3.0. Once you have your project created, you would need to create your interface definition. Everyone loves to use text-to-speech for these kinds of samples, so let’s do that.


public interface ITextToSpeech
{
    void SayIt(string text);
}

For each of the platforms the parts that we are interested in for the sake of the article is pretty much the same. I won’t reproduce the actual speech code here, but if you are interested in how it is done, there is a good sample on the Xamarin developer site.

Platform Projects

Here is what the class looks like for each of the platforms.


///usings up here
[assembly: Dependency(typeof(AndroidTextToSpeech))]
namespace Sample.Droid
{
    public class AndroidTextToSpeech : ITextToSpeech
    {
        public void SayIt(string text)
        {
            /// do implementation here
        }
    }
}

/// usings up here
[assembly: Dependency(typeof(IosTextToSpeech))]
namespace Sample.iOS
{
    public class IosTextToSpeech : ITextToSpeech
    {
        public void SayIt(string text)
        {
            // do implementation here
        }
    }
}
/// usings up here
[assembly: Dependency(typeof(UwpTextToSpeech))]
namespace Sample.Uwp
{
    public class UwpTextToSpeech : ITextToSpeech
    {
        public void SayIt(string text)
        {
            // do implementation here
        }
    }
}

As promised, each of the platform implementations look the same and this is the pattern you would follow even if you weren’t using a framework like Prism. The key is the attribute just above the namespace statement that registers your implementation with the Xamarin Forms dependency service.

Consuming in ViewModel

Normally we would consume the service in the view model using the following pattern:

public class MyViewModel : BindableBase
{
    private ITextToSpeech _speechService = null;

    public MyViewModel()
    {
        _speechService = DependencyService.Get<ITextToSpeech>();
    }
}

The above looks ok, but it does tie your view model to the Xamarin Forms DependencyService. This makes things a little more painful for testing.

What Prism Does For You

What Prism does for you is remove that dependency on the Xamarin Forms dependency service and allow you to pass in the service as a constructor parameter like follows:

public class MyViewModel : BindableBase
{
    private ITextToSpeech _speechService = null;

    public MyViewModel(ITextToSpeech speechService)
    {
        _speechService = speechService;
    }
}

How does Prism do that? It creates a special extension to the Unity container (similar capabilities exist within the other containers) that basically say to the container if the requested interface isn’t registered in the container, look for it in the Xamarin Forms DependencyService. That’s pretty cool! No additional work is required and you right away have a more testable and maintainable solution. If you are interested in seeing what this looks like, you can look at the
DependencyServiceStrategy class and the ConfigureContainer method in the PrismApplication class.

 

Xamarin Dev-Days Vancouver Announced

Whoot! Xamarin Dev Days is coming to Vancouver! If you are new to Xamarin and mobile development, this is a great way to jump in and get started and see what all the fuss is about.

Clear your calendar for Saturday September 23 and sign up at the registration page. You can also join the Vancouver Windows Platform Dev Group to learn even more (disclaimer: I am a member and have presented on Xamarin a couple of times).

If you aren’t in Vancouver, there are a number of locations being hosted around the world. You can check them out here.

Xamarin Forms, Autodesk Forge and Android DeepLinking

Finally, after covering UWP and iOS we are going to take a quick look at Android. Android seemed to be the easiest to get setup for me. All I had to do was to make the declaration of the deep linking to an IntentFilter attribute on the MainActivity class. When you add the IntentFilter, Xamarin will automatically update the manifest file for you.

In the code below, the most important items are the DataScheme and DataHost attributes. They are the ones that tell Android that the declared protocol is handled by the application.


[Activity(Label = "DeepLink",
    Icon = "@drawable/icon",
    Theme = "@style/MainTheme",
    MainLauncher = true,
    ConfigurationChanges = ConfigChanges.ScreenSize |
                            ConfigChanges.Orientation)]
[IntentFilter(new[]
    {
        Android.Content.Intent.ActionView },
        AutoVerify = true,
        Categories = new[]
        {
            Android.Content.Intent.CategoryDefault,
            Android.Content.Intent.CategoryBrowsable,
        },
    DataScheme = "bbsw-fm",
    DataHost = "brainbucketsoftware.com")]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(bundle);

        /// ... rest of the OnCreate
    }
}

Unlike iOS and UWP, Xamarin Forms routes the event back to the portable Application class and the OnAppLinkRequestReceived function. From there you can process the access token:

protected override async void OnAppLinkRequestReceived(Uri uri)
{
    base.OnAppLinkRequestReceived(uri);
    bool retrievedToken = await AuthWorkflowService.GetAccessTokenAsync(uri.ToString());
    if (retrievedToken)
        await NavigationService.NavigateAsync(Pages.Test);
}

In the next post, we will look at processing the response to get the access token.

Xamarin Forms UWP Deep-Linking

Introduction

In our last post, we looked at what we needed to do to setup our shared/portable project to authenticate with Autodesk Forge. Almost all of the code the important code is in the shared area, but we do have to do somethings within each of the platform projects. Lets check out UWP.

Protocol Declaration

The first thing that I do is go into the Package.appxmanifest in the UWP project. Once you are in it, click on the “Declarations” tab. On this tab, you can declare lots of different things for your app: able to pick files, camera settings, background tasks among others. The one we are interested in is protocol.

Select protocol and add it to the list of the supported declarations. Give the protocol a name check “ExecutableOrStartPageIsRequired”. For the name, make sure that you give it something unique. Perhaps an abbreviation of your company followed by some kind of app designation.

packageappxmanifest

Override UWP Application.OnActivated

In the UWP platform project, you need to override the Application.OnActivated function to handle the deep-link. Normally Xamarin Forms will just route the URI request to OnAppLinkRequestReceived, but it doesn’t seem to be working for UWP (or iOS). So what we will do, is just call in to a new entry point which then delegates to the protected function.


/// UWP application object
sealed partial class App : Application
{
    // ... other stuff here

    protected override async void OnActivated(IActivatedEventArgs args)
    {
        base.OnActivated(args);

        if (args.Kind == ActivationKind.Protocol)
        {
            var protocolArgs = args as ProtocolActivatedEventArgs;
            DeepLink.App thisApp =
                (DeepLink.App) Prism.Unity.PrismApplication.Current;
            thisApp.UwpIOSOnAppLinkRequestReceived(protocolArgs.Uri);
        }
    }
}

Then we can go back to the application object in our portable library and fix up the OnAppLinkRequestReceived function and the manual entry point we show above that is used for UWP and iOS.


public partial class App : PrismApplication
{
    /// the rest of the class is up here ...

    protected override async void OnAppLinkRequestReceived(Uri uri)
    {
        base.OnAppLinkRequestReceived(uri);
        bool retrievedToken = await GetAccessTokenAsync(uri.ToString());
        if (retrievedToken)
            await NavigationService.NavigateAsync(Pages.Test);
    }

    public void UwpIOSOnAppLinkRequestReceived(Uri uri)
    {
        OnAppLinkRequestReceived(uri);
    }

}

All that is happening above is that when the app is activated because of the protocol that it has registered, it will look at the URL and extract the response code that was returned by Forge. It will then use that response code in a REST API call to get the authorization token and refresh token. If that is successful, we perform a navigation to the next page in our app. Obviously the code isn’t complete as it doesn’t handle any kinds of errors. For the details on how to get the authorization and refresh tokens see the previous post.

And that is it for UWP, just a little bit of code and we are back in our shared code base. Up next will be iOS.

Google Play Services on Marshmallow

When it comes to working on Android apps, I really feel like I am starting completely from scratch … or maybe even a bit less than that. And I end up running across weird problems that end up causing me all kinds of issues. This post will talk about one of those problems and how I combined the posts of two others (who I am sure know much more than I about Android) to address my issue.

I am working on an app that uses maps. I am planning on targeting Marshmallow at a minimum. I am also using the Visual Studio Android Emulator. If you don’t already know, the Visual Studio emulator doesn’t come with the Google Play Services, which are required if you want to use maps in your app.

In a previous app, I was able to spin up an emulator, go to http://teamandroid.com/gapps, download the appropriate zip file and drag and drop to the emulator to install. This worked great for me on both KitKat and Lollipop emulators. On Marshmallow … not so much.

I started surfing … I mean researching. And in my research I came across an article from Cheesebaron which you can see here. In a nutshell, he recommends (with references) two different gapps packages to download. The only problem was that when I tried his method of downloading and drag and drop installing, my emulator just started an endless loop of optimizing packages and rebooting.

I then found another article from Rob Prouse about how to do a low level install of gapps packages from the SD card. When I tried his method, which used the gapps package from teamandroid.com, that failed as well. But at least it seemed to install without any obvious errors.

I finally deleted my emulator, started up a new one and combined the two articles. I downloaded the two packages recommended by Cheesebaron. I installed the first one in the manner recommended by Rob Prouse and after installation, was able to setup my Google account on the emulator. I then installed the second package from Cheesebaron using the same SD card installation method. After rebooting the emulator, I was able to deploy my app and run it. I am not sure if this is normal behavior, but I had to go into the app settings on the emulator and enable location for it. In the past, I seem to remember it asking me on first install, but I could be mistaken.

My new Marshmallow emulator setup is as follows:

  • Download gapps packages from Cheesebaron’s article:
  • Install the first package via the emulator SD card as per Rob Prouse
  • Create your google account in the settings/accounts
  • Install the second package via the emulator SD card as per Rob Prouse.

Hopefully this helps someone else and if not, writing it down will help me.