Validic Mobile Library (Xamarin iOS)

Requirements

Installation

Add Validic dynamic-link libraries to your project’s References. In Xamarin Studio, double click References in the left panel. In the .Net Assembly tab click Browse and select ValidicCore.iOS.dll, ValidicBluetooth.iOS.dll, ValidicHealthKit.iOS.dll, ValidicOCR.iOS.dll.

Adding Framework

You should now see ValidicMobile.iOS under “References” in the panel on the left.

Supporting iOS 10

iOS 10 requires usage descriptions to be declared in project’s Info.plist.

Camera Usage Description

Health Kit Usage Description

Bluetooth Usage Description

If these values are not provided, the app will crash at runtime with an error reported to the console log.

Provisioning a User

The Validic Mobile library requires a Validic user. A Validic user can be provisioned using the Validic API. The library requires a Validic user ID, user access token and organization ID. It is recommended to provision the user on your server, the mobile app could then authenticate to the server and retreive the Validic credentials.

Records

The Validic Mobile library supports the following record types:

Managing a Session

Overview

VLDSession stores a user, their current HealthKit subscriptions and all pending record uploads. This data is persisted between app launches but is deleted if endSession is called.

VLDSession is a singleton object and must be accessed by its SharedInstance method. The different components of the Validic Mobile library rely on a valid user existing in the current VLDSession singleton object.

To start a VLDSession you will need a VLDUser object. Generally you retrieve the credentials to instantiate a user object from your server. The credentials needed are a Validic user ID, an organization ID and a user access token.

VLDUser user = new VLDUser ("user_id", "organization_id", "access_token");

The user object is then passed to the StartSessionWithUser() method. Note: starting a session will delete the current session if it exists.

VLDSession.SharedInstance().StartSessionWithUser (user);

Notifications

When VLDSession uploads a record it will send an NSNotification. To listen for this notification add an observer to the NSNotificationCenter with the string Constants.kVLDRecordSubmittedNotification. The object property of the notification will contain the VLDRecord object uploaded.

When VLDSession uploads an image, it will send a different notification, Constants.kVLDRecordImageSubmittedNotification. The object property of the notification will contain the VLDRecord object with the media property populated.

If a 400 error is returned from the server, the record will be discarded and an NSNotification will be posted. To listen for this notification add an observer to the NSNotificationCenter with the constant Constants.kVLDRecordSubmissionFailedNotification. The object property of the notification will contain the invalid VLDRecord object. The userInfo dictionary for this notification will contain one key, error with the NSError object for the failed upload.

If VLDSession attempts to upload the image associated with a record and the upload fails, an NSNotification, Constants.kVLDRecordImageSubmissionFailedNotification will be posted.

Bluetooth

Peripherals

VLDBluetoothPeripheral represents Bluetooth peripheral models that can be discovered or read from by VLDBluetoothPeripheralController.

A peripheral object contains various information to be displayed to the user:

Supported Peripherals

To retrieve a List of supported peripherals simply call:

foreach (VLDBluetoothPeripheral peripheral in VLDBluetoothPeripheral.SupportedPeripherals)
{
    Console.WriteLine(peripheral.Name);
}

Other methods are available on VLDBluetoothPeripheral to allow retrival of a specific peripheral, or to retrieve a list of peripherals of a specific peripheral type. See the VLDBluetoothPeripheral documentation for additional information.

Pairing

Certain peripherals require pairing with the mobile device before a reading can be taken. You can check the requiresPairing property on the VLDBluetoothPeripheral object to know if it must be paired.

To pair a peripheral with the mobile device, call the PairPeripheral() method on VLDBluetoothPeripheralController.

VLDBluetoothPeripheral peripheral = // A peripheral from the supportedPeripherals list
VLDBluetoothPeripheralController controller = new VLDBluetoothPeripheralController();
controller.WeakDelegate = this;

controller.PairPeripheral(peripheral);

To know if a peripheral was successfully paired you will need to implement the pairing methods of the VLDBluetoothPeripheralControllerDelegate protocol.

[Export("bluetoothPeripheralController:didPairPeripheral:")]
public void BluetoothPeripheralControllerDidPairPeripheral (VLDBluetoothPeripheralController controller, VLDBluetoothPeripheral peripheral)
{
    // Peripheral paired successfully
}

[Export("bluetoothPeripheralController:didNotPairPeripheral:error:")]
public void BluetoothPeripheralControllerDidNotPairPeripheral(VLDBluetoothPeripheralController controller, VLDBluetoothPeripheral peripheral, NSError error)
{
    // Peripheral did not pair
}

Reading

Once you are ready to read from a peripheral, the process is fairly similar to the pairing process. You’ll want to first show peripheral.Instructions and eventually show peripheral.ReadingInstructions once BluetoothPeripheralControllerIsReadyToReadFromPeripheral() is called.

VLDBluetoothPeripheralController controller = new VLDBluetoothPeripheralController ();
controller.WeakDelegate = this;

controller.ReadFromPeripheral (peripheral);

You must also implement the reading methods of the VLDBluetoothPeripheralControllerDelegate protocol.

[Export("bluetoothPeripheralController:isReadyToReadFromPeripheral:")]
public void BluetoothPeripheralControllerIsReadyToReadFromPeripheral (VLDBluetoothPeripheralController controller, VLDBluetoothPeripheral peripheral)
{
    // Time to present the readingInstructions to the user
}

[Export("bluetoothPeripheralController:shouldSubmitReadings:fromPeripheral:")]
public bool BluetoothPeripheralControllerShouldSubmitReadings (VLDBluetoothPeripheralController controller, VLDRecord[] records, VLDBluetoothPeripheral peripheral)
{
    // To have the reading automatically added to the session and uploaded
    // return true from this method. To first have the reading validated by the user
    // you can return false from this method. Once the user has validated the reading
    // you must manually submit the record by calling VLDSession.SharedInstance().submitRecords(record);
    return true;
}

[Export("bluetoothPeripheralController:readingFailedForPeripheral:error:")]
public void BluetoothPeripheralControllerReadingFailed (VLDBluetoothPeripheralController controller, VLDBluetoothPeripheral peripheral, NSError error)
{
    // Reading failed
}

Passive Bluetooth Reading

The ValidicMobile library supports passively reading from a given set of Bluetooth peripherals. Passive Bluetooth reading is a long lived capability. Once enabled, the library will listen for and read from the specified peripherals. Reading will automatically occur once the peripheral is discovered regardless of app state. This includes if the application is currently in the foreground, in the background, or has been terminated due to memory pressure. Apps using this feature must have been started by the user at least once since the iOS device has booted otherwise the feature will not be active even if enabled.

VLDBluetoothPassiveManager is a singleton which coordinates the passive reading process. Passive reading is enabled by passing it an array of peripheral IDs:

VLDBluetoothPassiveManager.SharedInstance().PeripheralIDs = new NSNumber[] { 1, 2 };

To disable passive reading, set the peripheralIDs property to an empty array or nil.

VLDBluetoothPassiveManager.SharedInstance().PeripheralIDs = null;

Xcode Project changes

Passive Bluetooth reading relies upon iOS Bluetooth state restoration and background processing support. Apps using passive reading need to set Bluetooth as a required background mode in the Info.plist. In Xcode, in the Info.plist add a new key, Required background modes, add an item with value App communicates using CoreBluetooth.

Background Bluetooth

If editing the XML source file, add Bluetooth-central background mode as follows:

    <key>UIBackgroundModes</key>
    <array>
        <string>Bluetooth-central</string>
    </array>

To support state restoration, a method on the passive manager must be called on app launch. This should be done in the application:didFinishLaunchingWithOptions: method of the AppDelegate as follows:

        public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
        {
            // Bluetooth passive support if launched to handle discovered peripheral
            VLDBluetoothPassiveManager.SharedInstance().RestoreState();
            return true;
        }

State restoration will automatically start the app in the background when a requested peripheral is discovered. Within application:didFinishLaunchingWithOptions:, apps can determine if they were launched in background and avoid expensive operations.

Notifications

Passive readings are automatically sent to the Validic server. Session notifications are sent on upload success or failure. Passive Bluetooth specific notifications are sent when a device is discovered and becomes ready to read. Notifications are also sent for reading success and failure. These notifications specify the associated peripheral ID in the userInfo dictionary with a key, peripheralID.

Considerations

There are situations where passive Bluetooth reading is stopped and requires the app to be relaunched. These situations include:

Passive Bluetooth reading has some additional considerations due to the behavior of the iOS Bluetooth stack and background support.

HealthKit

The Validic Mobile library provides a simple way to read and upload data from HealthKit to Validic. VLDHealthKitManager can subscribe to specific HealthKit sample types and automatically upload them to Validic in the background as new data is recorded.

Subscribing to HealthKit updates only needs to be done once for a user. The subscriptions will be persisted across app launches in the VLDSession object. A typical use of the HealthKit component would be to create a UISwitch that adds the required subscriptions when turned on and removes them when turned off.

To properly process the delivery of data in the background, the subscription observers need to be recreated immediately when the app is launched. To do this, you need to call VLDHealthKitManager.SharedInstance().ObserveCurrentSubscriptions(); inside your application delegate’s FinishedLaunching() function. Example:

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
    VLDHealthKitManager.SharedInstance().ObserveCurrentSubscriptions();
    return true;
}

Note: Calling VLDSession.SharedInstance().EndSession(); will remove all HealthKit subscriptions and stop listening for new data.

Historical Fetch

The Validic Mobile library provides the ability to query 6 months of data for a subset of data types provided by HealthKit by specifying one of more values of the VLDHealthKitHistoricalSet enum.

To fetch 6 months of historical HealthKit data, call the FetchHistoricalSets() method on VLDHealthKitManager and pass in the datasets you want to fetch.

OCR

OCR provides the capability to obtain readings from devices without requiring Bluetooth or HealthKit integration. The simplest way to use this feature is to present an instance of the VLDOCRViewController after initializing it with the ID of a VLDOCRPeripheral.