iOS Guide

Learn about OkHi's integration for verifying addresses.

1. Set up OkHi (Client-side)

The OkHi libraries are fully documented and compatible with apps supporting iOS 12 and above. You would require the latest versions of Xcode & Swift

To install the library:

1 In Xcode, select File > Add Packages... and enter the following URL as the repository URL

https://github.com/OkHi/ios-okhi

2. Select the default main branch

3. Add the OkHi library package product to the target of your app

Address verification requires AlwaysAndWhenInUseUsage location to verify the user's address

To satisfy these requirements add the following to your info.plist file and provide a useful description as to why your application needs access to the user's location.

<key>NSLocationWhenInUseUsageDescription</key>
<string>String that explains why you need this permission</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>String that explains why you need this permission</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>String that explains why you need this permission</string>

Background Modes Capabilities

OkVerify obtains and transmits verification signals in the background, to enable this make sure to add "Location updates" and "Background fetch" at Background Modes under Signing & Capabilities of your target

Authentication

In your AppDelegate.swift file configure the OkHi Auth object with your client key and branch ID. Sign up here. Make sure to also setup your app's context with meta data about your application

import OkHi

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let okHiAppContext = OkHiAppContext().withAppMeta(name: "My Awesome App", version: "1.0.0", build: "1")
    let okHiAuth = OkHiAuth(
        branchId: "", // your branch ID
        clientKey: "", // your client key
        environment: OkHi.Environment.prod,
        appContext: okHiAppContext
    )
    OkCollect.initialize(with: okHiAuth)
    OkVerify.initialize(with: okHiAuth, launchOptions: launchOptions)
    return true
}

2. Create and verify an address (Client-side)

Add a button to your UI that would enable launching of OkHi address collection tool.

We recommend that you persist the verification state of the user in your app local storage. This state can be used to ensure that a user may only verify a predefined number of addresses. Usually one address for most use cases.

For OkVerify to work correctly "Always" Location permission needs to be granted by your users. The library provides the requestBackgroundLocationPermission method that enables you to manage these permission requirements as shown below.

import UIKit
import OkHi
import CoreLocation

class ViewController: UIViewController {
    private let okCollect = OkCollect()
    private let okVerify = OkVerify()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Called in the initial screen
        OkVerify.onStart()
        // Do any additional setup after loading the view.
        okCollect.delegate = self
        okVerify.delegate = self
    }
    
    @IBAction func onButtonPress(_ sender: UIButton) {
        if okVerify.isLocationServicesEnabled() {
            if okVerify.isBackgroundLocationPermissionGranted() {
                startAddressCreation()
            } else {
            // TODO: Show location permissions primer here
                okVerify.requestBackgroundLocationPermission()
            }
        }
    }
    
    func startAddressCreation() {
        let okHiTheme = OkHiTheme()
            .with(logoUrl: "https://cdn.okhi.co/icon.png")
            .with(appBarColor: "#ba0c2f")
            .with(appName: "OkHi")
        let okHiConfig = OkHiConfig().enableStreetView().enableAppBar()
        guard let vc = okCollect.viewController(
            with: OkHiUser(phoneNumber: "+234xxxxx") // It is important to provide your actual phone number, as a message will be sent to this number
                .with(firstName: "Gift")
                .with(lastName: "Moore")
                .with(email: "giftmoore@okhi.com"),
            okHiTheme: okHiTheme,
            okHiConfig: okHiConfig
        ) else {
            return
        }
        self.present(vc, animated: true, completion: nil)
    }
    
    func startAddressVerification(user: OkHiUser, location: OkHiLocation) {
        okVerify.startAddressVerification(user: user, location: location)
        // TODO persist address verification state in app local database store
    }
    
}

extension ViewController: OkCollectDelegate {
    func collect(didEncounterError error: OkHiError) {
        // handle error
        debugPrint(error)
    }
    
    func collect(didSelectAddress user: OkHiUser, location: OkHiLocation) {
        startAddressVerification(user: user, location: location)
    }
    
    
}

extension ViewController: OkVerifyDelegate {
    func verify(_ okverify: OkVerify, didChangeLocationPermissionStatus requestType: OkVerifyLocationPermissionRequestType, status: Bool) {
        if requestType == .always && status {
            startAddressCreation()
        }
    }
    
    func verify(_ okverify: OkVerify, didInitialize result: Bool) {
        print("initialized successfully")
    }
    
    func verify(_ okverify: OkVerify, didEncounterError error: OkVerifyError) {
        debugPrint(error)
    }
    
    func verify(_ okverify: OkVerify, didStartAddressVerificationFor locationId: String) {
        print("started verification for: \(locationId)")
    }
    
    func verify(_ okverify: OkVerify, didStopVerificationFor locationId: String) {
        print("stopped verification for: \(locationId)")
    }
    
    func verify(_ okverify: OkVerify, didUpdateLocationPermissionStatus status: CLAuthorizationStatus) {
        // called on each status change
        print("location permission status updated")
    }
    
    func verify(_ okverify: OkVerify, didUpdateNotificationPermissionStatus status: Bool) {
        print("push notification permission status updated")
    }
}

Test

Verification has started successfully:

When you simulate a change in the location of the device, you should see the GPS icon lighting up at the top of the screen

Common issues:

  • if background location permission is not granted, verification will not start

3. Add address endpoint (Server-side)

Here's a sample address payload that the client would get on successful address collection:

{
    "user": {
        "id": "B5QgvjE8WC",
        "phone": "+234xxxx",
        "firstName": "Gift",
        "lastName": "Moore"
    },
    "location": {
        "id": "8F0yPK1Zdj",
        "lat": 6.442849499999999,
        "lon": 3.424421,
        "plusCode": "6FR5CCVF+4Q",
        "propertyName": "10",
        "streetName": "Raymond Njoku Street",
        "title": "Raymond Njoku Street",
        "subtitle": "10",
        "url": "https://okhi.me/8F0yPK1Zdj",
        "streetViewPanoId": "ufxEWf-zpKLcTxIe04o6Bg",
        "streetViewPanoUrl": "https://maps.googleapis.com/maps/api/streetview?size=640x640&fov=45&location=6.44275037195316%2C3.424513218681455&heading=321.4785708568841&pitch=-9.5945875978788",
        "userId": "B5QgvjE8WC",
        "displayTitle": "10, Raymond Njoku Street",
        "country": "Nigeria",
        "state": "Lagos",
        "city": "Eti-Osa",
        "countryCode": "ng"
    }
}

Create a secure endpoint on your server that your app can use to pass address details to your server. Remember to handle corner cases such as, address updates, multiple addresses if your app supports it.

//Secure new address endpoint
app.post("/users/addresses", async (req) => {
  const { user, location } = req.body;
  const { id, firstName, lastName, phone } = user;
  const {
    id: locationId, displayTitle, title, subtitle, country, state, city, countryCode, lat, lon, plusCode, propertyName, streetName, url, streetViewPanoId, streetViewPanoUrl
  } = location;
  console.log(user, location);
  // Store the location.id. Used to match webhook updates
  return;
});

4. Handle verification events (Server-side)

OkHi sends verification status updates over a few days while verification is on going. Follow the webhook guide to setup a webhook and receive these verification status updates and run actions such as upgrading a user's KYC level.

5. Show verification status in app(Server- & Client-side)

Create a secure endpoint to enable your app to retrieve address details, including the verification status received from the webhook

// Secure address retrieval endpoint
app.get("/users/addresses", (req) => {
  // Get data from db. Example result:
  const dbResult = {
    "id": "8F0yPK1Zdj",
    "status": "verified",
    "displayTitle": "10, Raymond Njoku Street",
    "title": "Raymond Njoku Street",
    "subtitle": "10",
    "country": "Nigeria",
    "state": "Lagos",
    "city": "Eti-Osa",
    "countryCode": "ng",
  }
  return dbResult;
});

Show the resulting address details and status on the address page in your app.

6. Test the integration

7. Customise the integration

Create a location permissions primer (Required)

Create your custom location permissions primer to educate your user on the requirement for location permissions. Make sure to follow our design best practices to ensure you meet the Google Play store and AppStore requirements.

Customise OkCollect (optional)

Its possible to completely transform the default appearance of OkHiLocationManager to better match your brand by providing values to the theme prop

Its possible to completely transform the default apperance of OkHiLocationManager to better match your brand by providing values to the okHiTheme prop

let okHiTheme = OkHiTheme()
    .with(logoUrl: "https://cdn.okhi.co/icon.png")
    .with(appBarColor: "#ba0c2f")
    .with(appName: "OkHi")
let okHiConfig = OkHiConfig().enableStreetView().enableAppBar()
guard let vc = okCollect.viewController(with: OkHiUser(
        phoneNumber: "+234xxxxx"
    ), 
    okHiTheme: okHiTheme, 
    okHiConfig: okHiConfig
) else {
    return
}
self.present(vc, animated: true, completion: nil)

Customising address type

You may turn off either of the OkHi address types. This is to allow your users to create either home or work addresses to better suit your use-case. By default both address types are on.

let okHiConfig = OkHiConfig().enableStreetView().enableAppBar().withAddressTypes(work: true, home: false)

8. Getting ready to go live

Production credentials

Notify us that you'd like to cut a production build so we can supply production credentials.

Prepare for submission to App Store

Submitting an app to App Store that has background location permissions has a few extra requirements. Follow these guide to know what to expect and how to handle the extra requirements:

Publishing to App Store

Next steps

Review Full integration sample project

Review iOS libraries documentation

Review OkHi integration best practices

Last updated