0 Comments

Title image showing the xamarin test cloud and ios logo

In this post we will look at how we can test a Xamarin.iOS app which is based on a storyboard. The app which we are testing is a basic app based on the MVVM pattern. You can find a detailed blog post on the in and outs of the app under test here.

Assuming you already have a Xamarin Test Cloud (XTC) project added to your solution as described in this former post. Lets get started by preparing the app to be tested.

Preparing the iOS for the XTC tests

When writing a test with Xamarin Test Cloud the test ideally does not recognize a control by the content it is displaying but rather via an ID which is not visible to the end user but rather a invisible ID. Setting this ID is best done via the accessibility label attribute which can be set in the storyboard under properties:

Shows where under properties the label can be enabled.

This ID will not have to change if the locale changes or the UI element is moved to a different location and therefore will allow you to write more resilient test code.

Writing Test(s)

When the UI is prepared accordingly we can start writing the test. One way is to use the XTC recorder. While this tool brings a great benefit when starting of with or smaller apps (as it would be the case in this post), I usually prefer to use the REPL which is easy to use and can be inserted to be started at any point in your code.

The REPL is especially useful once you have a substantial testing framework written because it allows you to execute it after executing some prearranged steps to get to a certain point which you would like to test.

Shows repl output of the app

Starting the REPL is as easy as adding the following line to your test method:

You can see the entire apps visual tree nicely outlined.

Now we can define the steps we want to perform in our test:

Note how the test takes screenshots at every stage. This allows to easily identify the steps on the Xamarin test cloud and give them a label. While this might be a bit overkill for such a small sample on larger tests when named right the steps and screen shots will greatly help you narrowing down where an error is happening.
One good thing about the tests is that they also run well on your local machine. So using Xamarin Studio on a Mac we can simply execute the tests over the NUnit Runner:

image showing the nunit test runner of xamarin studio.

Or submit it to the test cloud i.e. integrate it in our build process.

Conclusion

This post described how to get started writing automated UI tests with Xamarin Test Cloud for a Xamarin.iOS application. After some minor adjustments to the UI a test can be written using the familiar NUnit testing framework. Keeping in mind that UI tests should not be the only testing you apply to your app since they are rather slow, they do bring a lot of value when used properly since one can easily run the tests on different devices and iOS versions with the Xamarin Test Cloud.

You can find the entire sample on GitHub.

0 Comments

Blog Title Image showing ios logo and Beta Testing with a ruber stamp effect.

When developing your latest and greatest (Xamarin) iOS app there will come a time when you are ready to ship the app to users for some beta testing. This allows you to get some feedback before shipping it to the official store. First thing needed is the application package also known by it’s file ending the IPA. If you are using Xamarin.iOS you can find a more details on building the IPA and setting up the certificates here. Assuming that you have an IPA ready for distribution the most common instruction found on the internet is to use iTunes to side load the app. Now this has a bit of an indirection to it, since the user must be sitting in front of a Laptop which allows him to install the app. In case of a company Laptop with IT policies this may end up being rather complicated. But there is an easier way, you can send a link which the user can select on an iOS Device which will install the app directly onto the device.

For the user to be able to use the app the certificates have to be correctly configured. If not, the user will be able to install the app but unable to launch it, which shows itself with by either closing right after the splash screen or a greyed out app icon.

Sharing your app via link

Now since it would be way to easy to just simply send a link to a file share which allows you to install the app, we jump through an additional hoop to comply with Apples “process”. We need to send the user(s) a link to a plist file that includes a link to the actual app i.e. IPA file:

Now lets go through this step by step:

  1. Upload IPA to the file share of your choosing and get a public URL for the IPA
  2. Edit the plist template above to match the requirements of your app (note the comments)
  3. Upload the plist file to Fileshare and get a public URL to the plist-File
  4. Send link to plist-File to whomever you would like to have the app installed

Since I was met with a confused look the first time I explained this to a co-worker see the graphic bellow and just think of the link to the plist file as a pointer of a pointer Winking smile:

Shows image where beta users taps on a link that is pointed towards the plist file (lying on a file share). The plist itself contains a link to the ipa file which will get installed on the users device.

This is a super easy way to share your app with testers. Then again these steps have to be performed for each update of the software and there is no user monitoring included with this approach. So you can not see if the app crashed nor can you know if a user already installed the latest version of the app. Or simply inform the user while he is using the app that there is an update. Now all this can be included in an app but it requires quite some effort to do so and then again we are talking about code that is only used during beta testing. So if you are developing a larger app with a longer lifetime or multiple beta releases you might want to consider a third party service e.g. Hockey App.

Conclusion

Setting yourself or your company up for running beta tests for iOS is as easy as sharing a link to a file (with some overhead for the publisher). No additional accounts needed or third party services. You could even share this thing from a NAS. That being said I would recommend you check out Hockey App as they do provide a free tier for up to two apps for free (at time of writing) and the process of adding it to your app is a couple of lines of code and a NuGet package.

HTH

0 Comments

nuget

See how you can easily create NuGet packages to publish cross platform C# libraries that allow to integrate platform specific code in your Portable Class Library (PCL) based Projects. In a former post you can read about how to create a cross platform library and see how the library has to be consumed by the e.g. app consuming the library. This post builds up on where that last post left off and shows how we can use the library providing the OS version number in a NuGet package. So the package we want to create has the following structure:

 

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

 

Our goal is to generate a single NuGet package which can be added to any of the above named platforms.

Note: Though this post focuses on the platforms Universal Windows Platform (UWP), Android and iOS the approach can be easily extended to support additional platforms such as .Net, Silverlight et al.

Creating the package definition

First of all we will need to install the NuGet command line tool. Make sure that you add it to your PATH. After it is added to your path you can execute the NuGet commands with PowerShell. To create a NuGet package you need a nuspec file which you can generate by executing the command):

nuget spec

The location of the nuspec file does not really matter – I tend to have it in my root directory i.e. where the Solution file is. If you open the file in your lightweight editor of choice, you can edit the package specification to your gusto or for our sample somewhat like this:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>OSVersion</id>
    <version>1.0.0.3</version>
    <title>OS Version</title>
    <authors>Mark Allibone</authors>
    <owners>Mark Allibone</owners>
    <!--<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>-->
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Get the OS version for your UWP, Android or iOS app.</description>
    <releaseNotes>This is the initial release.</releaseNotes>
    <copyright>Copyright 2015</copyright>
    <tags>OSVersion</tags>
  </metadata>
  
  <files>
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.dll" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.pdb" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI\bin\Release\OsVersionAPI.Core.xml" target="lib\portable-net45+wp8+wpa81+netcore45+monoandroid1+xamarin.ios10+UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.dll" target="lib\UAP10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.pdb" target="lib\UAP10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.UWP\bin\Release\OsVersionAPI.Core.xml" target="lib\UAP10\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.dll" target="lib\monoandroid1\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.pdb" target="lib\monoandroid1\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.Droid\bin\Release\OsVersionAPI.Core.xml" target="lib\monoandroid1\OsVersionAPI.Core.xml" />
    
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.dll" target="lib\xamarin.ios10\OsVersionAPI.Core.dll" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.pdb" target="lib\xamarin.ios10\OsVersionAPI.Core.pdb" />
    <file src="OSVersionAPI.iOS\bin\iPhone\Release\OsVersionAPI.Core.xml" target="lib\xamarin.ios10\OsVersionAPI.Core.xml" />
  </files>
</package>

Beware of the target folder structure, these names may seem a bit strange (I’m looking at you Xamarin.Android…) but these actually have to align with a pattern or else you will run into problems when installing the NuGet package. You can find the target folder names on the NuGet website.

Integrating some Metadata in the NuGet package

You are not required to add the pdb (used for Debugging) or the XML file (Code Documentation for Intellisense) but it is considered best practice and makes the life of the developer using the library easier so I would suggest you follow along with this.

To enable the XML metadata file, right click on a project under Properties, Build you can set the checkmark for XML documentation file. Now you should have an XML file in your build output.

Per default the pdb file should be generated during the build, except for iOS (it’s always you iOS isn’t it…) - anyhow, right click on your project then under Properties, Build, Advanced… set Debug Info to pdb-only.

Beware that these settings are per build Configuration so make sure you set it for Release builds as you usually ship the Release build of a library.

Packing it up

Now all that is left to do is creating the package which we can do with the following command:

nuget pack

After the package is created the next thing to do is make it available for consumption. This means either pushing the package to NuGet or creating your own NuGet repository. Due to the fact, that this here is only a demo I will go with the second option.

Integrating the package in an app

Now we can simply add the OS Version library over the package manager. Notice that we get the same result as in the former blog post but this time the developer using the library will not be required to add the library multiple times to the project i.e. this potential error source no longer exists.

So when we now run the app under UWP we get the following output.

Win10VersionNumber

Note if we would only add the NuGet package to the NativePcl.Core project the output would simply show the stub implementation.

StubVersionNumber

So all the principals that were described in the last post still apply. But adding the library has been greatly simplified.

Conclusion

In this blog post you saw how a cross platform NuGet package can be created which lends itself very well to create cross platform libraries that implement native features which have to implemented differently for each targeted platform. There are many great libraries already out in the wild that use this approach e.g. MVVM Light, SQLite, PCL Storage and many many more.

You can find the sample project on GitHub.

0 Comments

See how you can offer cross platform APIs based on C# that you can consume in Universal Windows Platform Apps (UWP), Xamarin.iOS, Xamarin.Android, Xamarin.Forms, ASP.Net and even your classic .Net WPF app. In my last post I showed how one can use platform specific libraries and code in a Portable Class Library with dependency injection. This approach is great when you are developing your own app but it gets somewhat quirky, when you want to offer a library to fellow co-workers/developers, as you force them to setup your own library through dependency injection. But there is of course another way that allows you to encapsulate your implementation details neatly while still providing platform specific features to your PCL code.

The library in this blog post will provide the OS version for a UWP, Xamarin.iOS and Xamarin.Android app.

Setting up the library

The library consists of four projects:

  • OSVersion.Core
  • OSVersion.UWP
  • OSVersion.Droid
  • OSVersion.iOS

One thing which is a bit special about all the projects is that all of their Default Namespace and the Assembly name all have the same name.

NamespaceBinaryName

In each project we implement the SystemInformationHandler.cs class, on the PCL we simply implement a stub:

public class SystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    public static string OSVersion => "Gnabber";

    #endregion
}

For the other platforms such as UWP we implement the calls to the UWP specific APIs:

public class SystemInformationHandler
{
    public static string OSVersion
    {
        get { return OsVersionString(); }
    }

    private static string OsVersionString()
    {
        string sv = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
        ulong v = ulong.Parse(sv);
        ulong v1 = (v & 0xFFFF000000000000L) >> 48;
        ulong v2 = (v & 0x0000FFFF00000000L) >> 32;
        ulong v3 = (v & 0x00000000FFFF0000L) >> 16;
        ulong v4 = (v & 0x000000000000FFFFL);

        return $"Windows {v1}.{v2}.{v3}.{v4}";
    }
}

So in the end we have implemented the generic class in the PCL and specific classes for each platform we target to support. Now lets see how we can consume this library in an app.

Consuming the library

The app will exist of the usual cross platform mobile app setup which means we will have usual suspects covering Windows, Android and iOS with a Portable Class Library aka Core to share the reusable code.

NativePclProjectOverview

In the core we have our business logic code and view models (I’m a huge fan of the MVVM Light library, to find out more just view my mvvm light posts). In the NativePcl.Core project we have a service OsVersionService.cs for returning the version number:

public class OsVersionService : IOsVersionService
{
    public string GetVersion()
    {
        return SystemInformationHandler.OSVersion;
    }
}

Reference the OSVersion.Core library as binary – DO NOT reference it as project or you will be facing compile errors in one of the next steps. Don’t ask me how I know Winking smile

Because all our assemblies of the OSVersion library will be compiled to assemblies with the same name we can’t just simply reference the project file but have to add the binary i.e. the compiled version of the library. If you are looking at the sample from GitHub, make sure to compile the solution under release build as the OSVersion is referenced via binary in the release output folder of the projects.

The method invokes the OSVersion property in the OSVersion library - leaving out the specific project e.g. UWP intent fully here. On the clients for example the Android app we have a single screen showing the version number defined in the MainView.xaml:

<Page
    x:Class="NativePcl.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NativePcl.UWP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

And the corresponding code behind or as we are using view models MainViewModel.cs:

public class MainViewModel : ViewModelBase
{
    private readonly IOsVersionService _osVersionService;

    public MainViewModel(IOsVersionService osVersionService)
    {
        if (osVersionService == null) throw new ArgumentNullException(nameof(osVersionService));
        _osVersionService = osVersionService;
    }

    public string OSVersion => _osVersionService.GetVersion();
}

If we now run the app we will get the follow output:

coreVersion

Now this is the output we defined in the OSVersion.Core, if we now reference the binary of the OSVersion.UWP in the NativePcl.UWP project things get really interesting. Instead of receiving an error because we are adding two assemblies with the same name the compiler will prefer the platform specific library over the PCL implementation. And even though we never invoke the library directly from our NativePcl.UWP app the OS version returned now is returned from the platform specific i.e. OSVersion.UWP implementation of the GetVersion() method resulting in the following output:

uwpVersion

Now while this approach allows for writing platform independent logic in the PCL and calling platform specific implementations during runtime it is somewhat tedious as it requires that the developer will reference the correct version of the library. And all of them have the same name which is just calling for some frustrated minutes to happen due to referencing the wrong version of the library. Luckily there is a technique that allows to use the approach described above without burdening the developer consuming the library of referencing the binaries correctly. By wrapping the library in a NuGet package consuming the library is as simple as adding the package to all of your projects and the NuGet package manager will just like the build engine prefer to link the platform specific binary over the PCL library to the project. So instead of having to choose which binary to add the developer can now simply add the identical NuGet package to all of the projects and it will just work.

Conclusion

In this post you saw how to create APIs that can be consumed in the PCL and still provide platform specific functionality. For all of this to work we had to set the namespace and assembly of the projects to identical names. On the consumer one can either simply add a NuGet package containing all of the implementations i.e. PCL, UWP, Android and iOS or add the binaries of the corresponding API compilation to the app implementation e.g. OSVersion.Coreto NativePcl.Core.

This approach allows you to create APIs which can be reused across multiple platforms providing the same method definitions across the platforms.

You can find the sample on GitHub. (make sure to compile it first as a release build)

2 Comments

3856456237_f05ebd2602_o

The Portable Class Library (PCL) allows developers to share C#, F# and VB code across multiple devices, platforms and runtime environments such as .Net, Xamarin or Windows Store Apps. In this previous post you can see how you can write portable business logic and integrate it with all the various platforms. But what if you actually want to use something the other way round say the GPS position, file system etc.. What then? This is exactly his post we will look at the following topics:

  • Using Interface Segregation and Dependency Inversion to our favor
    • Interface in the PCL
    • Implementation on the Platform
  • Injecting the implementation at runtime into the PCL
  • Making the resolution of dependencies a breeze with MVVM Light

So lets get to it!

Using Dependency Injection to our favor

Remember SOLID? Well it turns out the last letter stand exactly for the pattern we will be using to solve our “How will I be able to use a platform specific feature cross platform “. The PCL code is platform independent and therefore can be used across multiple platforms, so we want to put near to all of our business logic into a PCL. Further by accessing concrete class implementations via interfaces we can define an Interface in the PCL and create it’s concrete implementation in a platform specific project.

PCLDIOverview

Dependency Injection in action

For example lets say we want to display the current OS version for each platform, this is a very platform specific feature. To access such a information in the PLC we first define an Interface in the PCL that describes the contract the implementation has to implement:

public interface ISystemInformationHandler
{
    string OSVersion { get; }
}

In the concrete platforms we can then inherit the interface and implement the handler which calls the platform specific API (bellow you see the Android implementation):

internal class SystemInformationHandler:ISystemInformationHandler
{
    #region Implementation of ISystemInformationHandler

    //public string OSVersion => System.Environment.OSVersion.ToString();
    public string OSVersion => $"Android {Android.OS.Build.VERSION.SdkInt} {Android.OS.Build.VERSION.Release}";

    #endregion
}

Now in the PCL we can have a class for example a view model that requires the handler to display the information.

public class MainViewModel : ViewModelBase
{
    private readonly ISystemInformationHandler _systemInformationHandler;

    public MainViewModel(ISystemInformationHandler systemInformationHandler)
    {
        if (systemInformationHandler == null) throw new ArgumentNullException(nameof(systemInformationHandler));
        _systemInformationHandler = systemInformationHandler;
    }

    public string OSVersion => _systemInformationHandler.OSVersion;
}

The view model requires as a parameter argument an instance of the IOSVersionHandler interface. So when we create an instance of the MainViewModel in the platform project, we can simply create an instance of interface and pass it into the view model when we create it.

var mainViewModel = new MainViewModel(new SystemInformationHandler());

And receive the following output for e.g. Android:

 

Cross platform Dependency resolution with MVVM Lights

Now resolving all of these dependencies by hand can get very tedious over time. You might have noticed that I’m using MVVM Light which comes with a lightweight Dependency Injection Container called Simple IoC. Lets see how we can use this component to further streamline our cross platform development efforts.

Note:for an introduction to MVVM Light please refer to this blog post for AndroidoriOSto get you started with the basics.

In the PCL we have the ViewModelLocator.cs which defines all of the instances used, but without the platform specific resolution.

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            // Create design time view services and models
            SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandlerStub>();
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }
}

On each platform we now extend the Locator and register the platform specific classes i.e. resolution for interfaces.

internal class Locator : ViewModelLocator
{
    private static readonly Lazy<Locator> _locator = new Lazy<Locator>(() => new Locator(), LazyThreadSafetyMode.PublicationOnly);
    public static Locator Instance => _locator.Value;

    private Locator()
    {
        SimpleIoc.Default.Register<ISystemInformationHandler, SystemInformationHandler>();
    }
}

Now we can simply request an instance of the view model (MVVM Light per default only creates one instance for each registered class) and use it. In Android this would look something like this in the MainActivity.cs:

[Activity(Label = "PclDISample.Droid", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    #region UI Controls

    private TextView OSVersion => FindViewById<TextView>(Resource.Id.OSVersion);

    #endregion

    private MainViewModel VM => Locator.Instance.Main;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        OSVersion.Text = VM.OSVersion;

        var mainViewModel = new MainViewModel(new SystemInformationHandler());
    }
}

In Windows 10 we can simply set the Datacontext accordingly in XAML:

<Page
    x:Class="PclDISample.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclDISample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding OSVersion}" VerticalAlignment="Center" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}"></TextBlock>
    </Grid>
</Page>

As you can see once all is registered with the simple Inversion of Control Container (IoC) of MVVM Light all of the dependency resolution will be performed automatically. If a dependency is missing, an exception will be thrown at runtime (not during compilation), so make sure to test all your views, user controls et al that they load correctly.

Conclusion

In this post you saw how you can use Dependency Injection to provide platform specific features to cross platform code located in the PCL without creating any circular dependency errors. By using interfaces in the PCL and injecting the concrete implementations during runtime we can create thin wrappers that provide platform specific features through a generic defined interface. Finally we saw how we can use MVVM Light to create a more manageable and more manageable dependency resolution with the Simple IoC Locator.

You can find the complete sample on GitHub.

Big thanks to Laurent Bugnion the creator the MVVM Light.