iOS

Integrate the Colocator iOS library into your native iOS app

Versions prior to 2.7.1 will not work after the 27th of August 2020

Adding the dependency

Cocoapods

Add the CCLocation pod to your Podfile

platform :ios, '9.0'
use_frameworks!
target 'YourAppTarget' do
  pod 'CCLocation'
end

Integration Sample

Carthage

Add CCLocation modules to your Cartfile

github "crowdconnected/colocator-ios" "2.7.5"
github "ReSwift/ReSwift" "5.0.0"
github "antitypical/Result" "5.0.0"
github "apple/swift-protobuf" "1.12.0"
github "facebook/SocketRocket" "0.4.2"
github "instacart/TrueTime.swift" "5.0.3"

Integration Sample

Add items to your info.plist

Add the Background Modes

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
    <string>fetch</string>
    <string>remote-notification</string>
</array>

Add Permission Descriptors

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>
<key>NSMotionUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>

NSLocationAlwaysUsageDescription

  • Displayed by the OS after the application already have always permission, but as a reminder for the user, asking if one wishes to continue with Always or downgrade to While In Use
  • Example “Only by now selecting “Always Allow” below can you continue to stay up to date with last-minute schedule changes, security alerts and more relevant contextual messages based on your location during the festival.”

NSLocationAlwaysAndWhenInUseUsageDescription

  • Displayed by the OS after the application tried to access location in background, asking the user to continue with While In Use location permission or switch to Always
  • Example “Only by now selecting “Always Allow” below can you continue to stay up to date with last-minute schedule changes, security alerts and more relevant contextual messages based on your location during the festival.”

NSLocationWhenInUseUsageDescription

  • Displayed when location permission is requested in code for the first time (even if asking for always permission)
  • Example “Only by now selecting “While In Use below can you continue to stay up to date with last-minute schedule changes, security alerts and more relevant contextual messages based on your location during the festival.”

NSBluetoothPeripheralUsageDescription

  • Required, but not shown to the user

NSMotionUsageDescription

  • This is only used in specific applications
  • For outdoor only applications it is required, but not shown to the user

Getting Permission

Location Permission

Colocator requires “Always” Location Permission to operate.

Request “Always” Location Permission from the user. From iOS 13 onwards this will display a pop-up with 3 options: “Only Once”, “Only While Using” and “Never”. Here we want the user to select “Only While Using”.

Once the library has attempted to get a location in the background and the user unlocks their phone they will be present with another pop-up with 2 options: “Always”, “Only While Using”. Here we need the user to select “Always”

let locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()

Enabling Location Gathering

The library must be started within the func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) method of the AppDelegate. It may additionally be started elsewhere to fit in with your onboarding flow but the start(apiKey:) method has to be called on the DispatchQueue.main thread.

import CCLocation
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    CCLocation.sharedInstance.start(apiKey: YOUR_APP_KEY)        
    return true
}

Background Refresh

We use background refresh to periodically check whether we should enable location tracking. Please enable this by registering for Background Refresh events:

UIApplication.shared.setMinimumBackgroundFetchInterval(UIMinimumKeepAliveTimeout)

and calling the library when one occurs:

func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    // At background refresh, the CCLocation library should be notified to update its state
    CCLocation.sharedInstance.updateLibraryBasedOnClientStatus(clientKey: YOUR_APP_KEY) { success in
        if success {
            completionHandler(.newData)
        } else {
            completionHandler(.noData)
        }
    }
}

Silent Push Notifications

We use Silent Push Notifications to enable location tracking at a given time. Please enable this by:

  1. Ensuring the app has notification permission
  2. Registering for remote notifications
UIApplication.shared.registerForRemoteNotifications()
  1. Sending the APNS Token as an alias:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // For CCLocation messaging feature, send device token to the library as an alias
    let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    CCLocation.sharedInstance.addAlias(key: "apns_user_id", value: tokenString)
}
  1. Calling the library when one is received:
if userInfo["source"] as? String == "colocator" {
    CCLocation.sharedInstance.receivedSilentNotification(userInfo: userInfo, clientKey: YOUR_APP_KEY) { isNewData in
        if isNewData {
            completionHandler(.newData)
        } else {
            completionHandler(.noData)
        }
    }
}

Disabling Location Gathering

If required you can stop the library

CCLocation.sharedInstance.stop()

Sending an Alias

Aliases are key-value pairs. They are primarily used to send alternative IDs for a device, for example a unique Push Notification identifier. Go to the Push Notification Integrations page for more details

CCLocation.sharedInstance.addAlias(key: "YOUR_KEY", value: "YOUR_VALUE")

Indoor Location Service

For indoor location and positioning, a few more steps need to be implemented

Add Permission Descriptors to your info.plist

<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-peripheral</string>
    <string>bluetooth-central</string>
</array>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>
<key>NSMotionUsageDescription</key>
<string>YOUR_TEXT_GOES_HERE</string>

NSBluetoothAlwaysUsageDescription

  • This is only used in specific applications
  • Displayed when the application starts using Bluetooth for the first time or when triggered through CCLocation library
  • Example “We need to access Bluetooth for improving location accuracy”

NSMotionUsageDescription

  • Displayed when motion & fitness activity is used for the first time or when triggered through CCLocation library
  • Example “This app uses motion updates to determine your location indoors”

Getting Indoor Location Permissions

Bluetooth Permission

The permission pop-up will be displayed automatically when the app starts using Bluetooth, but it can also be triggered in code to fit in with your application's flow.

CCLocation.sharedInstance.triggerBluetoothPermissionPopUp()

Motion & Fitness Permission

The permission pop-up will be displayed automatically when the app starts using Motion, but it can also be triggered in code to fit in with your application's flow.

CCLocation.sharedInstance.triggerMotionPermissionPopUp()

Setting the CCLocationDelegate

  • Set up the delegate
CCLocation.sharedInstance.delegate = self
  • Handle the method from CCLocationDelegate
didReceiveCCLocation(_ location: LocationResponse) { 
  // Your code here
}
  • LocationResponse object contains “floor” field starting with SDK v2.7.0

Location Callbacks - Only for Indoor Navigation Purposes

The latest location can be sent back to the device either as a one-off or a stream of updates. This is primarily used for displaying the location of the device on a map.

Request one location:

CCLocation.sharedInstance.requestLocation()

Request a stream of location updates:

CCLocation.sharedInstance.registerLocationListener()

Stopping Location Updates

Please make sure you unregister from location callbacks when the user is not using the indoor map screen or navigation.

This is important for battery and performance optimization.

Stop the stream of updates:

CCLocation.sharedInstance.unregisterLocationListener()

Test Library Integration

After doing all the required steps to integrate Colocator into your iOS app, check the main aspects and the status of the library

let integrationStatus = CCLocation.sharedInstance.testLibraryIntegration()
print(integrationStatus)