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 Access Token

In the previous posts, we went through each platform, looking at how we implement deep linking for each of the platforms. At the end of the deep link flow, we have arrived back within our portable Application object with a URL to process. This URL has a response code at the end that we have to parse out and send back to Forge to get our access and refresh tokens.

This is pretty easy, something like this works:


private string GetResponseCodeFromUrl(string redirectUrl)
{
    string codeParameter = "?code=";
    int pos = redirectUrl.IndexOf(codeParameter);
    string code = redirectUrl.Substring(pos + codeParameter.Length);
    return code;
}

After that we post a REST call to “https://developer.api.autodesk.com/authentication/v1/gettoken&#8221;. Inside of the content of the post call, we need to add a string with all of our app keys and codes, in a similar fashion to how we started off the whole authentication process in the first post of the series. The string content looks like this and should be all on one line.

var content = new StringContent($"client_id={ClientId}&client_secret={ClientSecret}&grant_type=authorization_code&code={ResponseCode}&redirect_uri={CallbackUrl}");

See the above link for an explanation of the ClientId, ClientSecret and redirect_uri. The ReponseCode is simply the code that we retrieved using the above GetResponseCodeFromUrl function above.


private AuthData AuthorizationData { get; set; }

public async Task<bool> GetAccessTokenAsync(string redirectUrl)
{
    ResponseCode = GetResponseCodeFromUrl(redirectUrl);
    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Clear();
        using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://developer.api.autodesk.com/authentication/v1/gettoken"))
        {
            request.Content = new StringContent($"client_id={ClientId}&client_secret={ClientSecret}&grant_type=authorization_code&code={ResponseCode}&redirect_uri={CallbackUrl}");
            request.Content.Headers.ContentType = 
                new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            using (HttpResponseMessage response = await client.SendAsync(request))
            {
                string data = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    AuthorizationData = Deserialize<AuthData>(data);
                    return true;
                }
            }
        }
    }

    return false;
}

If all goes well, we end up getting a response with our authorization data. That structure looks like this:

public class AuthData
{
    [JsonProperty("token_type")]
    public string TokenType { get; set; }

    [JsonProperty("expires_in")]
    public int ExpiresInMinutes { get; set; }

    [JsonProperty("refresh_token")]
    public string RefreshToken { get; set; }

    [JsonProperty("access_token")]
    public string AccessToken { get; set; }

    public DateTime DateGranted { get; set; }

    public AuthData()
    {
        DateGranted = DateTime.Now;
    }
}

I am using Json.NET as my deserializer and am using the attributes to redirect the parsed data into the properties that I want. I think pretty much everyone uses Json.NET, but if it is the first you have heard about it, it is definitely worth your time to look at. Important properties above are:

  • AccessToken: use this for all of your Forge requests so that Forge knows you are authenticated.
  • RefreshToken: the access token will expire. You use the refresh token to request a new one without forcing the user to re-authenticate.
  • ExpiresIn: how many minutes before the access token expires.
  • DateGranted: not returned by Forge, but sets when the token was granted so that we can compute when it expires.
  • And that is about it! In the next post, we will look at refreshing the access token.

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, Autodesk Forge, iOS Deep-Linking

Alright, last time we looked at UWP, and now we will look at iOS. It is a pretty similar effort to UWP. All we need to do is declare the protocol handling and then handle the URL.

Declaring the Protocol

First we have to edit the info.plist file in the iOS project. This file needs to be modified by hand and is just a simple XML file. The plist element is the root element and contains a “dict” object. Each element of the dict object is a setting for the app and it is contained in pairs. For example:

<plist version="1.0">
<dict>
    <key>UIDeviceFamily</key>
    <array>
        <integer>1</integer>
        <integer>2</integer>
    </array>

    ... other settings
</dict>
</plist>

At the end of the file, we can add our protocol declaration. It will look like this:

<plist version="1.0">
<dict>
    ... other settings

    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>same.asyour.bundle.identifier</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>bbsw-fm</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Handling the URL Link

This is almost exactly like how we did it in the UWP platform project. In the AppDelegate class, we need to override the OpenUrl method and delegate back to the portable Application object.


public partial class AppDelegate : global:Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{

    public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
    {
        DeepLink.App thisApp = (DeepLink.App) Prism.Unity.PrismApplication.Current;
        thisApp.UwpIOSOnAppLinkRequestReceived(new Uri(url.ToString()));
        return true;
    }
}

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.

Next up and finally will be the Android implementation.