Xamarin iOS App Settings

When we talk about app settings we could mean a few different things. The actual settings values which are stored by your app, an in-app method to view/edit those settings or the iOS Settings UI which exposes both system and application settings to the user in the centralised place.

In this article we’ll look at the last of these. If you are creating a cross platform app you’ll probably never look into this as the main place to store your settings because you’ll want a consistent UI within your app to expose settings. The iOS Settings app will always have an entry for your app anyway as this exposes permissions which your app has requested and allows the user to change their preferences. You may have also noticed that when debugging your Xamarin app you’ll see entries added here for the Xamarin debugger.

In my previous blog post I wrote about visualising screen taps in your app in order to capture video walkthroughs. I decided I didn’t want the option for this exposed via the apps own Settings page, and I wanted to be able to set it before even launching the app, so I looked into adding it to this menu. As it turns out it is actually quite easy. I’m going to assume you use the NSUserDefaults mechanism for storing the underlying setting value. You might use this directly or via a cross-platform API such as Pontoon to abstract this away behind a common API.

First you need to create a folder within your Xamarin iOS project called “Settings.bundle”. Within this, you add an XML file called “Root.plist” and set the Build Action to “BundleResource”. This XML file is in Apple’s horrible “Property List” XML format and contains a dictionary with a single entry with the key “PreferenceSpecifiers”. The value if this is an array of dictionaries, each of which represents an individual preference item. Here is my example adding a single Boolean toggle:-

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
   <dict>
      <key>PreferenceSpecifiers</key>
      <array>
         <dict>
            <key>Type</key>
            <string>PSToggleSwitchSpecifier</string>
            <key>Title</key>
            <string>Show touches</string>
            <key>Key</key>
            <string>ShowTouches</string>
            <key>DefaultValue</key>
            <false/>
         </dict>
      </array>
   </dict>
</plist>

This give you the simple output shown below. The section header with your app name is added for you. Here you can see each entry defines the setting type (which affects other options available), the display text, the key (which is the name of the setting in code), and the default value (of the correct type for your setting).

Visible Touch App Settings

There are other type specifiers for other settings types such as text or selections from multiple fixed values. You can read more details here.

While this might seem a bit disconnected from your app you can open this settings page programmatically. Useful not just for showing the user these custom settings but also if you want to assist the user in turning an app permission back on. There is a hard-coded Uri to launch your app specific settings page which you can call using:-

UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));

Some 3rd-party apps make extensive use of this to display app settings and properties. Take a look at Microsoft Word which uses this mechanism to display product version and licensing information as well as app settings. How much you intend to integrate with it is entirely up to you, but it can help your app feel more integrated when it offers these kinds of hooks into the OS.

Touchscreen Visualisation on Xamarin iOS

Seems to Have an Invisible Touch

To produce a demonstration video on Android you can turn on screen visualisations from the Developer settings menu and this will shows screen interactions on a screen capture. No such option exists on iOS so you need to write some custom code in your app instead. A couple of solutions exist for native iOS app but to use these from Xamarin would require additional code to wrap. The alternative is to write the code from C# to achieve the same result.

Wrap or Write

My requirements were quite simple, for a first version I only needed to show single touch events and I wanted something which looked visually similar to the Android equivalent. It turns out that the solution is to inherit from UIWindow and add some extra code to capture touch events and draw to the screen. This means a single solution works anywhere in your app as a single Window is used regardless of what views you have. This should work in Xamarin Forms on iOS too by adding similar code to the FinishedLaunching method in your AppDelegate.

When you create a blank Xamarin iOS app it will generate a Main.storyboard for the UI and this is hooked up in the Info.plist manifest so there will be no code in FinishedLaunching to setup the Window and root ViewController. The first step therefore is to un-set this:-

visible-touch-info

Then you can add code in the FinishedLaunching method to create the Window and load the storyboard.

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
	// Set a custom Window which handles touch events
	Window = new InTheHand.TouchWindow(UIScreen.MainScreen.Bounds);

	// Load root view controller from Storyboard into Window.
	// You can't set this from Info.plist as it'll use a regular UIWindow.
	Window.RootViewController = UIStoryboard.FromName("Main", null).InstantiateInitialViewController();
	Window.MakeKeyAndVisible();

	return true;
}

Some solutions to this use graphics to display the touch circle but I’ve gone for straightforward UIKit drawing code with a circular UIBezierPath. The full code for a working demo app is on GitHub here:-

https://github.com/inthehand/VisibleTouch

You can see the effect of this code in this video:-

There are some limitations with this code. It supports single touch gestures only, if you use multiple fingers you’ll get a circle jumping around to the latest event. The circle can disappear quite abruptly, it will probably look better with a simple animation to fade out. I haven’t included code here to turn the visualisations on or off. Chances are you won’t want them on all the time so it would make sense to add a setting somewhere to toggle this. I did this myself using a settings bundle so you could toggle the setting before even running the app. That was interesting in itself and easier to integrate with Xamarin iOS than I expected but that is a topic for another blog post.

If there is significant interest in this I can release this as a NuGet package for easy integration into your Xamarin iOS project. For now you can take the TouchWindow.cs code and drop it into a project and modify the AppDelegate as described above.

Calendar Import is Back

I was almost at the point of retiring the app since Mail & Calendar has supported iCalendar (.ics) files for a while now. Then I came across a scenario where the app is still required. vCalendar files (.vcs) are very similar but use version 1.0 of the vCalendar spec whereas iCalendar is version 2.0. Mail & Calendar still can’t open this format at the time of writing.

I’ve updated the UWP app for Creators Update and later and it now just registers for .vcs files (all .ics files will be handled by the Calendar app and this avoid the OS popping up a choose app dialog unnecessarily). Doing the update also made me check that it could work on Surface Hub and HoloLens (although it just uses the standard 2D Calendar UI). If you get .vcs files via email attachments or online this is a really simple (and free) app to import them into the Windows Calendar.

Download from the store for all Windows 10 devices:-

https://www.microsoft.com/store/productId/9WZDNCRDZZZF

 

Using specific versions of UWP from Win32

From a Win32 .NET library (One that targets desktop apps whether Console, WinForms or WPF) you can add two references and take advantage of (most) UWP APIs.

The first is a .NET library which handles interop with the UWP / WinRT APIs:-

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll

The second is the metadata for the UWP APIs themselves:-

C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd

This describes the v1.0 versions of the API Contracts. These are expanded with each Windows 10 version and so you may find you want to target newer APIs and they are not available here. In a UWP project you can easily toggle the minimum target version of Windows 10 and this defines the API surface available to you. No such option exists for this kind of interop so instead you can switch the Windows.winmd reference for an alternative version. These are installed into subfolders of the above folder with the build number of each installed SDK. The latest released version for the April 2018 update is in 10.0.17134.0. As with UWP development you need to choose your API level carefully as it will affect which machines you can deploy to. For a library developer you need to ensure you document the minimum version you support to avoid any surprises.

Xamarin Forms MediaElement

Some time ago I created a MediaElement control for Xamarin Forms for displaying video (and audio) content across the main mobile platforms and it’s been steadily improving and has been used in a number of projects.

After some discussions on GitHub I started the process of integrating the control into Xamarin Forms itself with a Pull request opened last week. There will be some API changes in the transition and I’ll be sure to keep the current control available until its fully integrated into a stable Xamarin Forms release.

Things are progressing well with some reviews and code changes, partly to fit the Xamarin coding style and partly having fresh eyes looking at the code pointing out some improvements. I’ve already created a new renderer for WPF which supports the basics (The WPF MediaElement doesn’t have built-in transport controls so this isn’t supported yet). It highlighted something as I was testing on iOS where the video just wouldn’t work. I later remembered that unless you explicitly request it in your info.plist the app will block any http resources. But you’ll not get an error, the video will simply be stuck in the ReadyToPlay state. Switching to an https target fixed the issue immediately. This lead me to create the following table showing supported URI types and how they map on each platform. These apply to both the InTheHand.Forms version and the Xamarin.Forms control although only the latter has WPF support:-

 

Uri Scheme Android iOS UWP WPF
HTTP/HTTPS Yes HTTPS only or set NSAppTransportSecurity in info.plist Yes Yes
file Yes Yes Yes Yes
ms-appx Yes. Items must have the build action AndroidResource and be located in the Resources/raw folder of the project Yes. Items must have the build action BundleResource Yes Maps to pack://application:,,,{localpath}
ms-appdata Yes (Local+Temp) Yes (Local+Temp) Yes (Local, Temp and Roaming) Yes (Local+Temp)

Azure IoT DevKit – External Connectivity

Beyond the sensors built into the board the possibilities are endless when you consider attaching external devices. As I mentioned in my previous post, the DevKit has an edge connector with a number of input/output pins as well as power. You’ll need an “edge connector breakout” like this to make use of them.

I found this excellent post by Jeremy Lindsay which included a table of the pin numbers and how they map to Arduino pin names – you need this so that you can refer to a physical pin on the edge connector breakout to a pin in your Arduino sketch.

From this it’s possible to rig up an LED or similar on a breadboard and set it from code. One of the things I wanted to try out was using an ultra-sonic distance sensor and this is where I hit a snag. Unlike many Arduino boards there is no 5v output (even though it is driven from a USB 5v input) and the sensor I am using requires one. I’ve had to order a few more parts before I can make progress on this project. Essentially I’ll need a separate 5v supply to my breadboard and will have to convert the output from the sensor down to the 3.3v expected by the DevKit board.