Category Archives: Xamarin

Deploying a Xamarin Forms application to TestFlight

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

Pre-requisites

You’ll need an Apple developer account if you intend to eventually deploy your application to the Apple store, using this site https://developer.apple.com/account, however you can use the free provisioning using Free provisioning for Xamarin.iOS apps.

As I already have an Apple Developer account this post will concentrate on provisioning with a Developer account id.

TestFlight

TestFlight is the Apple beta testing tool which allows users to access your application in test (i.e. not live on the app store). Your users will need to install TestFlight, see Beta Testing Made Simple with TestFlight and you’ll need to set up an application for testing via https://appstoreconnect.apple.com/

Deploying your application to TestFlight

Once you’ve built and signed your application so it’s ready for distribution then, one of the simplest ways to deploy your application to TestFlight is install Transporter on your Mac and simply Add the application to Transport which in turn will upload to your TestFlight account.

Your application will go through a build process and when completed you’ll receive an email letting you know. You’ll be waiting for the status of your build (within appstoreconnect) to change state to Approved (this may take a couple of days although I’ve also seen posts from people stating this can take longer). Once approved we select our External Groups (testers) and you should see a Enable Public Link – click on this (enable it). Now you’ll have a link to send to your users, although appstoreconnect should automatically send this to any testers you add.

Note: Your TestFlight build is available for a total of 90 days, ofcourse this excludes the build and review process. If you do not update the application within that time the app will expire.

Once your build has passed review, it’ll go into a Testing status, any testers you’ve added already will get a code to redeem in TestFlight from their device, you can also enable a link that you can send to people to load the application for testing. This obviously allows you to have a core group of testers as well as a public access to testing.

When your application is deployed to your testers via TestFlight, the icon that you launch the application from will have a small orange dot (it looks red on a dark background) to indicate this is a beta application.

When you’re ready to update your testers with a new application, if you only change the Build version, i.e. if your app version is 0.1.0 and build was 1.0, just changing this to 2.0 will mean your application need not go through review again. Instead it’ll go into a Submit Ready state, waiting for you to assign testers and then it’ll switch to Testing.

References

Automatic Provisioning for Xamarin.iOS
TestFlight – How to Upload and Distribute Your App | App Store 2021

Device specific code in Xamarin

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

Occasionally we might need to handle text or UI controls slightly differently on different devices.

In a shared code project we’d probably look to write code using conditional compilation, but this wouldn’t work for PCL code. Also conditional compilation doesn’t work in XAML. So whilst conditional compilation is still a valid technique for shared code projects an alternative is runtime branching based upon the device the code is running on (in other words if or switch code). Xamarin already supplies us with a simple mechanism to achieve this using the OnPlatform method on the Device class.

PCL/Runtime device specific code

So, in code we can use the Device class like this

public class MyPage : ContentPage
{
   public MyPage()
   {
      Padding = Device.OnPlatform(
          new Thickness(0,20,0,0), 
          new Thickness(0),
          new Thickness(0));
   }
}

Or from XAML we can use the OnPlatform element, for example

<ContentPage>
   <ContentPage.Padding>
      <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" />
   </ContentPage.Padding>
</ContentPage>

Conditional Compilation directives

Just to complete the picture, let’s look at what compiler directives exist – these are not exclusive to shared code projects but obviously are available for any use

  • __IOS__ for iOS code
  • __ANDROID__ for Android code
  • __ANDROID_nn__ for Android code, where nn is the Andoird API level supported
  • WINDOWS_UWP for Universal Windows Platform code
  • WINDOWS_APP for Windows 8.1 code
  • WINDOWS_PHONE_APP for Windows Phone 8.1 code

Text to Speech on mobile with Xamarin

Previously I looked at Speech synthesis in Windows with C# but what about speech synthesis on mobile.

Xamarin.Essentials has this covered with the TextToSpeechTextToSpeech class and is included by default when creating a Xamarin Forms mobile application.

It’s really simple to add text to speech capabilities, we simply write code such as

await TextToSpeech.SpeakAsync("Hello World");

As you can see by the use of the await keyword (and the standard Async suffix), the SpeakAsync method returns a task. It also accepts a cancellation token if you need to cancel mid utterance. There’s also an overload which accepts SpeechOptions which allows us to set the volume, pitch and locale.

The second TextToSpeech method is GetLocalesAsync which allows is to get a list of supported locales from the device that can then be used within the SpeakAsync method’s SpeechOptions.

await TextToSpeech.GetLocalesAsync();

Note: It’s fun listening to the attempts at different accents depending upon the locale.

Xamarin UITest (on Android)

Having used the likes of TestStack.White in the past I was interested in trying out the Xamarin UITest library for executing tests against my mobile application’s UI.

For now I’m primarily discussing testing against an Android device or emulator, but I will amend the post as and when I run tests against iOS.

Some problems and solutions

It didn’t go smoothly, initially, getting a project running. Hence, this part of the post is going to cover some of the issues I had and some of the possible solutions.

  • If you have platform-tools.old followed by a number of digits within C:\Program Files (x86)\Android\android-sdk (for example platform-tools.old1970091580), either delete these folders or for safety’s sake, move them outside of the C:\Program Files (x86)\Android\android-sdk folder, otherwise running the UITests seems to get confused which adk it should use.
  • Add an environment variable (if not already existing) named ANDROID_HOME and set it’s value to your install of the android-sdk, i.e. C:\Program Files (x86)\Android\android-sdk
  • The version of the UITest NuGet package seems to be related to the version of the Android SDK, so after you’ve created a UITest project and added the Xamarin.UITest package, depending on the Android SDK you might need to get a previous version of this package – in my case I’m using Xamarin.UITest version 2.2.7.0 and Android SDK Tools 26.1.1
  • For an Android application, we need to set the project properties Android Manifest, Required permissions to include the INTERNET permission
  • For Android projects we need to run against a Release build
  • Again for Android projects, if we added a UITest project which include the ApplInitializer.cs file, we need to supply the application name or the path to the .apk file being used, for example
    if(platform == Platform.Android)
    {
       return ConfigureApp
          .Android
          .InstalledApp("com.putridparrot.MyApp")
          .PreferIdeSettings()
          .EnableLocalScreenshots()
          .StartApp();
    }
    

    Note: In place of InstalledApp we could use ApkFile with the path of our apk file, i.e.

       .ApkFile(@"C:\Development\MyApp\com.putridparrot.MyApp.apk")
    
  • If you’ve previously installed your application on the emulator or device, I found it best to manually uninstall it first
  • Before running your tests, make sure the emulator is running or the device is connected (I know, probably obvious)

Creating our UI test project

  • Add a Xamarin.UITest Cross-Platform Test Project to your solution
  • Build the project so it restores any missing NuGet packages, I needed to update the following packages to Xamarin.UITest version 2.2.7.0 and NUnit 3.11.0.0
  • Deploy your application to your device before running the tests
  • When running your tests, they may take a little time before you see anything happening on the emulator or device – so don’t be too impatient.

Before we can actually run our tests (which we’ll discuss next) we need to build our application and generate an APK for Android (if running against Android).

Writing our UI tests

To allow our UITests to locate controls in our user interface we supply each control (that we need to interact with) with an AutomationId, this should be unique (so it’s easy for our tests to locate).

For Android application I found this configuration works (obviously replace the ApkFile location/name with your apk).

if(platform == Platform.Android)
{
   return ConfigureApp
      .Android
      .ApkFile(@"C:\Development\MyApp\com.putridparrot.MyApp.apk")
      .PreferIdeSettings()
      .EnableLocalScreenshots()
      .StartApp();
}

Note: we should be able to replace the ApkFile line with .InstalledApp(“com.putridparrot.MyApp”) if you prefer.

The UITest project will require an AppInitializer.cs file which, if you created via the project template, will be included. Here’s an example of one

public class AppInitializer
{
   public static IApp StartApp(Platform platform)
   {
      if(platform == Platform.Android)
      {
         return ConfigureApp
            .Android
            .InstalledApp("com.putridparrot.MyApp")
            .PreferIdeSettings()
            .EnableLocalScreenshots()
            .StartApp();
     }
     return ConfigureApp
        .iOS
        .StartApp();
}

Test files (again the project template will include a Tests.cs file) might look like this

[TestFixture(Platform.Android)]
[TestFixture(Platform.iOS)]
public class Tests
{
   private IApp _app;
   private readonly Platform _platform;

   private static readonly 
      Func<AppQuery, AppQuery> LoginButton = 
         c => c.Marked("Login");

   public Tests(Platform platform)
   {
      _platform = platform;
   }

   [SetUp]
   public void BeforeEachTest()
   {
      _app = AppInitializer.StartApp(_platform);
   }

   [Test]
   public void DoesNothing()
   {
      // Arrange
      // Act
      // Assert
   }
}

Writing UI tests is much the same as writing standard unit tests, we mark our test methods with the NUnit TestAttribute, then Arrange, Act and Assert our UI. For example let’s assume we have a button with an AutomationId Login then we can create a static field within our Test class like this

private static readonly 
   Func<AppQuery, AppQuery> LoginButton = 
      c => c.Marked("Login");

This function can be used within various _app methods, such as _app.Tap(LoginButton).

As you’ve guessed I’m testing a login UI, so assuming we have a login screen with username, password and a login button we might setup our tests like this…

First Arrange our UI, for example check that we’re on the correct screen and we’ve entered a username and password. Then we’d Act by tapping the Login button then finally Assert by checking we’ve moved on from the Login screen.

REPL

When we run our tests we might want to run the _app.Repl() method which will display a REPL command line, this allows us to view the tree representing our UI.

References

Cannot run XAMARIN UI TEST on xamarin.forms, error System.Exception

Adding SQLite to my Xamarin forms application

To be totally honest, this post Xamarin.Forms Local Databases covers everything you need to know.

Simply add Frank Krueger’s NuGet package to your shared code project. This library is both a database access library and ORM.

We’ll need to create the database file, hence we can create our file location using the following

private static readonly string DatabaseLocation =
   Path.Combine(
      Environment.GetFolderPath
        (Environment.SpecialFolder.LocalApplicationData), 
        "Capture.db3");

Create the database

var database = new SQLiteAsyncConnection(DatabaseLocation);
await database.CreateTableAsync<DataItem>();

Depending on the use case it may be best to create the database connection when the application starts and keep available whilst the application is running. In this instance my calls to the DB are going to be dictated by the user, i.e. pressing a button, so we can create the connection, then create a table for our data objects.

Note: The data object stored into the database must have a default constructor and not be abstract etc. for it to work with the ORM part of this library.

Closing the database

The database connection does not support the IDisposable interface, so we need to explicitly call

await database.CloseAsync();

Note: I’ve not checked the source for the library and had no issues with not closing the connection.

Inserting items into the database

We can insert new items into the database using

await database.InsertAsync(dataItem);

// or a batch insert using 

await database.InsertAllAsync(dataItems)

// or an insert OR replace using

await database.InsertOrReplaceAsync(dataItem)

Updating rows

We saw that we can InsertOrReplace rows but this is based upon whether the object is unique. In other words the data object is first inserted and then a key returned, if another object matches this newly inserted one, then it’s deleted.

We can call UpdateAsync if we know a data object has already been saved to the database and we just want to update it, i.e.

await database.UpdateAsync(dataItem);

and thus if we’re tracking, within our data object whether it’s been saved and decide whether to update or insert using

if(dataItem.Id != 0)
{
   await database.UpdateAsync(dataItem);
}
else
{
   dataItem.Id = await database.InsertAsync(dataItem);
}

Querying the database

It wouldn’t be much of a database if we couldn’t run queries on it. We can use

var list = 
   await database.QueryAsync<DataItem>(
      "SELECT * FROM [DataItem] WHERE [Success] = 0"
   );

We can also use Linq like this

var dataItem = 
   database.Table<DataItem>()
      .Where(i => i.Name == "Samsung").ToListAsync();

Hence here we’ll get a list of all DataItems with the name “Samsung”.

Deleting data

We can use

await database.DeleteAsync(dataItem);

Deleting the database

As the database is stored as a file we can simply delete the file from the file system using

if (File.Exists(DatabaseLocation))
{
   File.Delete(DatabaseLocation);
}

More on our data objects

The only thing we’ve specified in any of the above code, for our data objects, is that they must have a default constructor on a concrete class, but as this SQLite NuGet package is acting like an ORM (as opposed to us creating our tables etc. in SQL), we’ll probably need some of the following properties added to our data object…

In the above we’ve showed that we can get a key back from an insert etc. but we can also add a key to the data objects themselves and have SQLite supply the keys. So for example we can add the following to our data item class

[PrimaryKey, AutoIncrement]
public int Id { get; set; }

Now the id is our primary key and is automatically supplied during an insert using an AutoIncrement algorithm.

We can also add indexed properties, for example

[Indexed]
public string Name { get; set; }

We can ignore properties by marking them with the IgnoreAttribute, i.e.

[Ignore]
public int AverageDb { get; set; }

Other attributes, include the following UniqueAttribute, MaxLengthAttribute , NotNullAttribute, StoreAsTextAttribute (for enums) and CollationAttribute (BINARY, NOCASE, RTRIM are supported with BINARY being the default) for comparisons.

Preparing a Xamarin Forms app. for deployment to Android

So I’ve created a cross platform application using Xamarin Forms and Visual Studio 2017 and now I want to get it deployed on some devices – in this post I’m concentrating on Android devices. So let’s look at what we need to do to get this application deployed…

I’m going to assume that the application version, icon, permission requirements and all those “standard” things have been implemented/setup and concentrate on getting the application ready for deployment to our device(s).

Release build

Obviously, like any other application, we’ll want to minimize the size of our application and remove any debug centric code that might be wrapped in #if DEBUG etc.

Select the Android project (ensure the build is set to Release), right mouse click and select properties and in Android Options ensure Use Shared Runtime and Use Fast Deployment (debug model only) are unchecked.

Archive and prepare for distribution

The process of bundling up an Android application is known as generating an archive. Right mouse click on the Android project in your solution and select Archive. Visual Studio will now go about archiving your application bundle.

Now click the Distribute button where you’ll be able to target the application’s distribution channel. I have two options Ad Hoc and Google Play. I’m going to stick to Ad Hoc which allows me to use email, a web site etc. to distribute my application via side loading.

We need to sign our application, so if you’ve not yet got a keystore/identity set-up you can just click the + button.

Note: Even if you’re just creating a new keystore for each application you’ll need to make sure you remember your password as this will be required to complete the signing process.

Fill in the options and then press Save As and you’ll be prompted for the keystore password.

We have now created an APK which can be installed onto you Android device. In my case I’m using Microsoft’s AppCenter to allow specific users to access the application for testing.

References

Preparing an Application for Release
Signing the Android Application Package

Upgrading Xcode and Visual Studio for Mac

This post is a note to myself – after upgrading Xcode to 9.4 I found that Visual Studio for the Mac seemed to fail to run on the iOS simulator, instead what happens when you run the VS is that it simply stops, no errors are shown, nothing.

What to do after upgrading Xcode

After upgrading/updating Xcode, always run Xcode to allow it to install any updates. Part of the upgrade might be that the Visual Studio for Mac has updated the simulator, in my case this is what had happened. Xcode 9.4 had the 11.4 version simulator whereas Visual Studio for Mac listed version 11.3.

Running Xcode installed pending updates but I also needed to go to the Xcode Preferences and in the accounts tab, ensure I was signed in (if the login has expired).

Now Visual Studio for Mac displayed the correct versions of the simulator and all worked again.

Xamarin and Visual Studio 2015

I’ve used Xamarin Studio in the past, which is a nice enough environment, but I’ve far more experience with Visual Studio as well as having all my dev tools integrated with it (such as Resharper). Now with Microsoft’s purchase of Xamarin I’ve finally got access to Xamarin’s Visual Studio integrations which also means I can target more platforms in a single solution.

Unfortunately things didn’t “just work” out of the box.

I’m going to go through a few of the issues I found getting started with the Visual Studio integration and hopefully provide solutions and where I can I shall detail how I got everything up and running (assuming I actually do get everything up and running).

What versions am I using?

So I’m going to begin by stating what versions I’m using

  • Visual Studio Professional 2015 (version 14.0.25123.00 Update 2) on Windows 10. This version of Visual Studio includes the Xamarin integration.
  • On the Mac I’m running El Capitan and Xamarin Studio Community edition version 5.10.3 (build 51).

Creating a project

I wanted to jump straight into trying out a Cross-Platform Xamarin.Forms project, so from New Project select Cross-Platform, then Blank App (Xamarin.Forms Portable). I named the project XamarinTest1, obviously name yours whatever you like, but I may refer to this project name within this post.

Visual Studio asks me to choose the target and minimum platform versions for my Universal Windows application – I leave the defaults and press OK.

The project template supplies the following

  • Portable class library – uses for the shared/portable code
  • An Android targeted project
  • An iOS targeted project
  • A UWP/Universal Windows targeted project
  • A Windows 8.1 targeted project
  • A Windows phone 8.1 targeted project

Now my normal inclination is to press the Run button and see what happens…

Getting the Android project up and running

The Android project is selected as the Start-up project, but the first problem occurs.

A message box stating, “There were deployment errors. Continue?” appears. It’s only when I check the Output window that I see a more useful message “Please select a valid device before running the application”. It appears that Visual Studio does not know about the Android virtual devices.

Clicking on the Open Android Emulator Manager button showed I did have emulators set-up (if you hit this problem and no emulators exist, add some).

I found that if I restarted Visual Studio and reloaded the project, it then found the emulators and was able to run correctly.

Getting the iOS project up and running

Select the iOS project and right mouse click on it, then select Set as StartUp project.

To run the iOS application we need to have a Mac running with Xamarin Studio installed. Also we need to set the Sharing System Preferences on the Mac.

Invoke using Cmd-Space and search for Remote Login and then Sharing System Preferences. From here we tick the Remote Login option and set access to specific users.

Now run the iOS application in Visual Studio. If all goes well the iOS emulator will run on the Mac via the Xamarin agent and you can now see what it looks like on your chosen iOS device emulator.

Getting UWP project up and running

Select the UWP project and right mouse click on it, then select Set as StartUp project.

If you now run the UWP application you might get a message box with the following error message: “The project ‘XamarinTest1’ needs to be deployed before it can be started.” etc.

As the message box goes onto say, select the configuration manager and locate the UWP project, check the Build and Deploy options.

If all goes well the application should now run correctly.

Getting Windows 8.1 project up and running

Select the Windows 8.1 project and right mouse click on it, then select Set as StartUp project.

This project should simply work, without any changes required.

Getting Windows Phone 8.1 project up and running

Select the Windows Phone 8.1 project and right mouse click on it, then select Set as StartUp project.

You will need the Windows 8.1 Phone emulator running on your machine (if using Windows 10) and this in turn requires the Hyper V virtualization option on the computer’s BIOS turned on.

Running the application will result in you being asked to download/install the emulator if it’s not on your machine. It’s likely you’ll need to reboot upon completion and/or may be asked if your login user should be part of the Hyper V group – which it should. Once everything is installed correctly then you’ll see a Windows phone emulator appear when you run the application.

Conclusions

It’s unfortunate this stuff doesn’t “just work” immediately out of the box, but with a little tweaking/configuring you can get five different projects running against five different device types and now the world of cross platform C# awaits.

Addendum

Part way through writing this document I foolishly decided to update the Android SDK only to find it failed and left my installation in a non-working state. So here’s what I had to do to get the system working again.

  • Android SDK didn’t appear to be available as a separate download, so I had to install Android Studio and download the NDK seperately
  • Once installed I found the folders of the installations very different from my original install so I needed to option Visual Studio’s Tools | Options
  • Select Xamarin | Android Settings
  • Change the JDK, SDK and NDK paths

So it’s not without its pain points, but eventually I had each of the platform targeted projects running.