Getting Started with iOS

Requirements

  • Xcode 10.0 or above
  • Xcode Deployment Target iOS 10.3 or above

Quick Start

An example project Example.xcodeproj is included with Proxy Mobile SDK for iOS. This example demonstrates how to authenticate a user to the Proxy service and enable the Proxy signal within your app.

Setup

1Step 1: Embed framework into your project

To start developing your own integration, first embed the Proxy SDK Framework into your project. This is commonly done by dragging the framework into you Xcode project with your target selected.

  • Copy ProxySDK.framework into your project file tree at a location of your choosing. In the figure below we have created a folder named "Frameworks" in our project and copied ProxySDK.framework into it.
  • Select your main project in the project navigator.
  • Select your build target in the main editor.
  • Select the "Build Phases" tab of the main editor.
  • Expand the "Link Binary With Libraries" group and drag ProxySDK.framework from the project file tree on the left into this group.
  • Expand the "Embed Frameworks" group and drag ProxySDK.framework from the project file tree into this group.

Figure 1: Embed framework into your project

Figure 1: Embed framework into your project

2Step 2: Configure iOS privacy permissions

The Proxy Mobile SDK uses Bluetooth Low Energy (BLE) to communicate with Proxy devices, which requires certain privacy permissions. Additionally, the SDK uses the camera and photo library to ask the user for their profile photo. Here we describe the required permissions you need to add to your Info.plist, and how we use each one.

NSBluetoothPeripheralUsageDescription (String)
Proxy requires this permission to be able to connect to devices around you.

NSCameraUsageDescription (String)
Proxy uses your camera to let you set your profile picture.

NSPhotoLibraryUsageDescription (String)
Proxy uses your photo library to let you pick a profile picture.

NSLocationUsageDescription (String)
NSLocationWhenInUseUsageDescription (String)
Proxy uses your location to set up geo-fences around places where you use Proxy, to automatically wake up the app at just the right time to interact with Proxy devices. We never track, store, or send your location anywhere. While the Proxy SDK will still work without this location permission, the user will have to re-launch the app after it is terminated (either by the user or by iOS).

NSLocationAlwaysUsageDescription (String)
NSLocationAlwaysAndWhenInUseUsageDescription (String)
Proxy needs "Always" location permission to set up geo-fences around places where you use Proxy, to automatically wake up the app at just the right time to interact with Proxy devices. We never track, store, or send your location anywhere. While the Proxy SDK will still work without this location permission, the user will have to re-launch the app after it is terminated (either by the user or by iOS).

After adding these keys, your Info.plist will look similar to the figure below.

Figure 2: Privacy permissions

notice-error For Proxy to work correctly, the user must grant "Location Permission: Always" to your app, as well as enable Bluetooth and Location on their phone.

3Step 3: Configure iOS background modes

The Proxy Mobile SDK communicates with Proxy devices and with the Proxy cloud service while your app is in the background, and requires the following background modes to operate correctly:

  • Location updates
  • Uses Bluetooth LE accessories
  • Acts as a Bluetooth LE accessory
  • Background fetch
  • Remote notifications

To enable these background modes via Xcode:

  • Select your project in the project navigator.
  • Select your build target in the main editor.
  • Select the "Capabilities" tab of the main editor.
  • Expand the "Background Modes" group and select the check box for each of the required background modes above.

Figure 3: Enable background modes in your project

Figure 3: Enable background modes

After enabling these background modes, your Info.plist should contain an array of keys similar to the figure below.

Figure 4: Background modes

Using the SDK

Initializing

Functionality of the Proxy SDK is accessible via the singleton instance ProxySDK.shared. The singleton pattern ensures that only one instance of the Proxy SDK exists in your app.

The lifetime of the ProxySDK.shared instance should match the lifetime of your app; we recommend initializing it at app launch inside didFinishLaunchingWithOptions in AppDelegate.swift.

First, import the Proxy SDK at the top of the file:
1
import ProxySDK

Add the following in didFinishLaunchingWithOptions app delegate:

1
2
3
// Optionally, enable diagnostic logging to file
ProxySDK.enableLogging = true
ProxySDK.shared.initialize(clientId: "12345")
notice-information Client ID is a unique identifier for your application, you can get yours [here](/your-apps).

Authenticating the user

notice-information You can check if the user is already authenticated with `ProxySDK.shared.isAuthenticated`. This allows you to skip the authentication UI flow and display different UI in your app.

Proxy SDK includes standard user interface elements to make it simple to authenticate a Proxy user and request necessary privacy permissions and data consent within your app. Once the user successfully completes authentication, the Proxy signal is started automatically; it can take as few as four lines of code to get a user authenticated and emitting their Proxy signal from your app. You can see what these interface elements look like below.

Figure 5: Authentication user interface

Figure 5: Authentication user interface

Configuring authentication UI

At a minimum, you must provide the email address of the user you wish to authenticate with the Proxy service. This email address is used to verify their ownership of their Proxy account. You can customize additional aspects of the authentication UI using an instance of ProxyAuthConfig with the following fields:

email: String (required)
User's email address for verifying their account.

appName: String (required)
The name of your application, to be presented in the UI. This may be provided by the Proxy service in the future.

appIcon: UIImage (required)
The icon for your application, to be presented in the UI. This may be provided by the Proxy service in the future.

givenName: String?
User's given name. If you do not supply this, the user will have a chance to complete it later.

familyName: String?
User's family name. If you do not supply this, the user will have a chance to complete it later.

photo: UIImage?
User's photo. If you do not supply this, the user will have a chance to complete it later.

requestPrivacyPermission: Bool (default: true)
If set, show UI for the user to provide consent to share their personal information.

requestLocationPermission: Bool (default: true)
If set, show UI for the user to provide permission to access the phone's location, if necessary.

requestBluetoothPermission: Bool (default: true)
If set, show UI for the user to provide permission to access the phone's Bluetooth functionality, if necessary.
Presenting authentication UI

The function ProxySDK.UI.authNavController() creates the navigation controller that contains the authentication UI. This function accepts instances of ProxyAuthConfig and ProxyAuthDelegate as parameters, and returns a UINavigationController that you can present to the user. The returned controller has modalPresentationStyle property set to .overFullScreen by default.

Results of user authentication, as well as any errors, are reported via the delegate provided to the ProxySDK.UI.authNavController() call.

The following code shows a complete example of configuring and presenting the authentication UI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class YourViewController {
  func showProxyAuth() {
    let email   = "mike@hooli.test"
    let appName = "Hooli"
    let appIcon = UIImage(named: "Hooli") ?? UIImage.init()

    // Populate the auth config
    let authConfig = ProxyAuthConfig(email: email, appName: appName, appIcon: appIcon)

    // Present the auth UI to the user
    let authNav = ProxySDK.UI.authNavController(config: authConfig, delegate: self)
    present(authNav, animated: false, completion: nil)
  }
}

extension YourViewController: ProxyAuthDelegate {
  func proxyAuth(result: Result<String, ProxyError>) {
    switch result {
    case .success(let email):
      print("Proxy Auth Successful! - \(email)")
    case .failure(let error):
      print("Proxy Auth Failed! - \(error)")
    }
  }

  func proxyAuthDidDisplay() {
    print("Proxy Auth Displayed!")
  }

  func proxyAuthDidClose() {
    print("Proxy Auth Closed!")
  }
}

Authenticating the user with custom UI

notice-information You can check if the user is already authenticated with `ProxySDK.shared.isAuthenticated`. This allows you to skip the authentication UI flow and display different UI in your app.

To verify the user, Proxy sends an email with a verification code to the user's email address. The user then enters the received verification code, which is passed back to the SDK to complete verification. This code is generally short-lived and must be used within soon after it is sent.

First, request a verification email to be sent to the user's email address:

1
2
3
4
5
6
7
ProxySDK.shared.sendVerifyCode(email: email) { error in
  if let error = error {
    // Error: email was not accepted, check the email address and try again.
    return
  }
  // Success: email has been sent to the supplied email address.
}

Once the user has supplied you with the code they received in their inbox, your app can complete user authentication with the Proxy SDK:

1
2
3
4
5
6
7
8
ProxySDK.shared.authenticate(email: email, code: code) { error in
  if let error = error {
    // Error: code was not accepted, prompt user to check code or re-send.
    return
  }
  // Success: code has been verified and the SDK is now authenticated
  // to represent this user's signal to Proxy devices.
}

Requesting access for Bluetooth and Location

Now that you have authenticated the user, you will need to do a couple of preparation steps to ensure the user gives your app permission to use the phone's Bluetooth and Location.

Use the convenience property isBluetoothAndLocationAuthorized provided by the SDK to detect if Bluetooth and Location permission prompts are needed:

1
2
3
4
if ProxySDK.shared.isBluetoothAndLocationAuthorized {
  // Skip Bluetooth and Location permission prompts; user has already
  // authorized the app to access the phone's Bluetooth and location.
}

Request permission to access the phone’s Bluetooth with the following helper function:

1
2
// Show an alert for the user to Allow or Disallow access to Bluetooth.
ProxySDK.shared.showEnableBluetoothAlert()

Request permission to access the phone’s Location with the following helper function:

1
2
// Show an alert for the user to Allow or Disallow access to Location.
ProxySDK.shared.showEnableLocationAlert()

To detect whether the user has allowed or disallowed access to Bluetooth and Location, you will need to listen to events that will fire whenever the user allows or disallows access and respond accordingly. The following code demonstrates how to listen to Proxy events regarding changing access to Bluetooth and Location:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Listen to the relevant events.
let nc = NotificationCenter.default
nc.addObserver(self, selector: #selector(self.bluetoothChanged(notification:)), name: ProxyEvent.bluetoothAccessChanged, object: nil)
nc.addObserver(self, selector: #selector(self.locationChanged(notification:)), name: ProxyEvent.locationAccessChanged, object: nil)

@objc func bluetoothChanged(notification: Notification) {
  // User has changed access to Bluetooth.
  print("Bluetooth Access Changed: \(notification.object.debugDescription)")
}

@objc func locationChanged(notification: Notification) {
  // User has changed access to Location.
  print("Location Access Changed: \(notification.object.debugDescription)")
}

Starting the Proxy signal

Once the user is authenticated and has granted all required permissions, your app can start emitting their Proxy Signal. This enables the user to use their Proxy signal to interact with any Proxy supported device.

1
ProxySDK.shared.start()

You can check to see if the Proxy signal is already running using the isProxyOn flag:

1
2
3
if ProxySDK.shared.isProxyOn {
  // Proxy signal is already running, no need to call start()
}

Stopping the Proxy signal

You can stop the Proxy service and stop emitting the user's Proxy signal at any time. You may do this when the user has opted to disable Proxy functionality within your app:

1
ProxySDK.shared.stop()

Signing out the authenticated user

You can instruct the Proxy SDK to forget its currently authenticated user and delete any cached data associated with their account. You should do this whenever the user signs out of your app to prevent leaking the user's data to the next user who signs in.

1
ProxySDK.shared.logout()