OkHi Documentation
v6.0.0
Ask or search…
K
Comment on page

Android Guide

Learn about OkHi's integration for verifying addresses.

1. Set up OkHi (Client-side)

Check out our full OkVerify integration example

Androidx

Make sure AndroidX is enabled in your project by modifying android/gradle.properties and adding 2 lines:
android.useAndroidX=true
android.enableJetifier=true

Add the OkHi Maven repository to your settings.gradle file

In your settings.gradle file, located at the root folder of your project. Add the new OkHi Maven Repository under the dependencyResolutionManagement section.
gradle
maven
sbt
leiningen
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url "https://repo.okhi.io/artifactory/maven" }
...
}
}
<repositories>
<repository>
<id>repo.okhi.io</id>
<url>https://repo.okhi.io/artifactory/maven</url>
</repository>
</repositories>
resolvers += "repo.okhi.io" at "https://repo.okhi.io/artifactory/maven"
:repositories [["repo.okhi.io" "https://repo.okhi.io/artifactory/maven"]]
The OkHi libraries target Android devices >= SDK 21. Make sure you're targeting at least the same and set compileSdkVersion & targetSdkVersion to 33 by modifying your app/build.gradle file
android {
compileSdkVersion 33
targetSdkVersion 33
minSdkVersion 21
...

Add the OkHi Core library dependencies

gradle
maven
sbt
leiningen
dependencies {
implementation 'io.okhi.android:core:1.7.15'
implementation 'io.okhi.android:okcollect:3.3.20'
implementation 'io.okhi.android:okverify:1.9.31'
}
<dependency>
<groupId>repo.okhi.io</groupId>
<artifactId>android-core</artifactId>
<version>v1.7.15</version>
<artifactId>android-okcollect</artifactId>
<version>v3.3.20</version>
<artifactId>android-okverify</artifactId>
<version>v1.9.31</version>
</dependency>
libraryDependencies += "repo.okhi.io" % "android-core" % "v1.7.15"
libraryDependencies += "repo.okhi.io" % "android-okcollect" % "v3.3.20"
libraryDependencies += "repo.okhi.io" % "android-okverify" % "v1.9.31"
:dependencies [[repo.okhi.io/android-core "v1.7.15"]]
:dependencies [[repo.okhi.io/android-okcollect "v3.3.20"]]
:dependencies [[repo.okhi.io/android-okverify "v1.9.31"]]
Check for the latest release on GitHub:
Next, configure your Android apps as follows:
Open your AndroidManifest.xml located under android/app/src/main/AndroidManifest.xml and add:
  1. 1.
    your credentials (obtain these by filling out this form) as shown below​.
  2. 2.
    required permissions: ACCESS_FINE_LOCATION and ACCESS_BACKGROUND_LOCATION
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
...
<application>
<meta-data android:name="io.okhi.core.branch_id" android:value="<my_branch_id>" />
<meta-data android:name="io.okhi.core.client_key" android:value="<my_client_key>" />
<meta-data android:name="io.okhi.core.environment" android:value="prod" />
<meta-data android:name="io.okhi.core.platform" android:value="android" />
...
</application>
</manifest>
If you're targeting Android versions >= 8 and you're using the OkVerify library you need to make sure your users select "Allow always" when granting permissions otherwise the verification process won't work.

Building with pro-guard enabled

If you have minifyEnabled set to true in your build.gradle file located android/app/build.gradle, you'll need to modify your proguard-rules.pro file, located android/app/proguard-rules.proas shown below to include classes required by the library to run.
-dontwarn sun.reflect.**
-dontwarn java.beans.**
-dontwarn sun.nio.ch.**
-dontwarn sun.misc.**
-keep class com.esotericsoftware.** {*;}
-keep class java.beans.** { *; }
-keep class sun.reflect.** { *; }
-keep class sun.nio.ch.** { *; }
-keep class com.snappydb.** { *; }
-dontwarn com.snappydb.**
# If you don't use OkHttp as a dep and the following
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-dontwarn org.conscrypt.ConscryptHostnameVerifier

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

Add a button to your UI that would enable the launching of OkHi address collection tool.
We recommend that you persist the verification state of the user in your app's local storage. This state can be used to ensure that a user may only verify a predefined number of addresses. Usually, one address is for most use cases.
Create an instance of the OkVerify class to be used later in your class.
Important: Make sure to invoke the static init method once on app start.
Java
Kotlin
1
public class Sample extends AppCompatActivity {
2
3
private OkHi okhi;
4
private OkCollect okCollect;
5
private OkVerify okVerify;
6
7
@Override
8
protected void onCreate(Bundle savedInstanceState) {
9
super.onCreate(savedInstanceState);
10
setContentView(R.layout.activity_main);
11
setUpOkHi();
12
Button btn = findViewById(R.id.btnSubmit);
13
btn.setOnClickListener(view -> handleButtonClick());
14
}
15
16
private void handleButtonClick() {
17
OkHiUser user = new OkHiUser.Builder("+234xxxxx") // It is important to provide your actual phone number, as a message will be sent to this number
18
.withFirstName("Gift")
19
.withLastName("Moore")
20
.withEmail("[email protected]") // it is important to use your actual email address, an email may be sent to the provided address
21
.build();
22
startAddressCreation(user);
23
}
24
25
private void startAddressCreation(OkHiUser user) {
26
okhi.requestEnableVerificationServices(new OkHiRequestHandler<Boolean>() {
27
@Override
28
public void onResult(Boolean result) {
29
if (result) {
30
okCollect.launch(user, OkCollectLaunchMode.CREATE, new OkCollectCallback<OkHiUser, OkHiLocation>() {
31
@Override
32
public void onSuccess(OkHiUser okHiUser, OkHiLocation location) {
33
startAddressVerification(okHiUser, location);
34
}
35
@Override
36
public void onClose() {
37
Toast.makeText(Sample.this, "User closed", Toast.LENGTH_LONG).show();
38
}
39
@Override
40
public void onError(OkHiException e) {
41
Toast.makeText(Sample.this, e.getCode() + ":" + e.getMessage(), Toast.LENGTH_LONG).show();
42
}
43
});
44
}
45
}
46
@Override
47
public void onError(OkHiException e) {
48
Toast.makeText(Sample.this, e.getCode() + ":" + e.getMessage(), Toast.LENGTH_LONG).show();
49
}
50
});
51
}
52
53
private void startAddressVerification(OkHiUser user, OkHiLocation location) {
54
okVerify.start(user, location, new OkVerifyCallback<String>() {
55
@Override
56
public void onSuccess(String result) {
57
Toast.makeText(Sample.this, "Started verification for: " + result, Toast.LENGTH_LONG).show();
58
}
59
60
@Override
61
public void onError(OkHiException e) {
62
Toast.makeText(Sample.this, e.getCode() + ":" + e.getMessage(), Toast.LENGTH_LONG).show();
63
}
64
});
65
}
66
67
private void setUpOkHi() {
68
69
final OkHiTheme theme = new OkHiTheme.Builder("#333333").setAppBarLogo("https://cdn.okhi.co/icon.png").setAppBarColor("#333333").build();
70
final OkHiConfig config = new OkHiConfig.Builder().withStreetView().build();
71
72
int importance = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? NotificationManager.IMPORTANCE_DEFAULT : 3;
73
OkVerify.init(getApplicationContext(), new OkHiNotification(
74
"Verifying your address",
75
"We're currently verifying your address. This won't take long",
76
"OkHi_Test",
77
"OkHi Address Verification",
78
"Alerts related to any address verification updates",
79
importance,
80
1, // notificationId
81
2 // notification request code
82
));
83
84
try {
85
okhi = new OkHi(this);
86
okCollect = new OkCollect.Builder(this).withTheme(theme).withConfig(config).build();
87
okVerify = new OkVerify.Builder(this).build();
88
} catch (Exception e) {
89
e.printStackTrace();
90
}
91
}
92
93
@Override
94
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
95
super.onActivityResult(requestCode, resultCode, data);
96
okhi.onActivityResult(requestCode, resultCode, data);
97
}
98
99
@Override
100
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
101
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
102
okhi.onRequestPermissionsResult(requestCode, permissions, grantResults);
103
}
104
105
}
1
class MainActivity : AppCompatActivity() {
2
private lateinit var okhi: OkHi
3
private lateinit var okCollect: OkCollect
4
private lateinit var okVerify: OkVerify
5
6
override fun onCreate(savedInstanceState: Bundle?) {
7
super.onCreate(savedInstanceState)
8
setContentView(R.layout.activity_main)
9
setUpOkHi()
10
}
11
12
public fun handleButtonPress(v: View) {
13
requestPermissions()
14
}
15
16
private fun requestPermissions() {
17
okhi.requestEnableVerificationServices(object : OkHiRequestHandler<Boolean> {
18
override fun onResult(result: Boolean) {
19
if (result) {
20
startAddressCreation();
21
}
22
}
23
override fun onError(e: OkHiException) {
24
e.printStackTrace()
25
}
26
})
27
}
28
29
private void startAddressCreation(OkHiUser user) {
30
val user = OkHiUser.Builder("+234xxxx") // It is important to provide your actual phone number, as a message will be sent to this number.
31
.withFirstName("Gift")
32
.withLastName("Moore")
33
.withEmail("[email protected]") // It is important to use your actual email address, an email may be sent to the provided address
34
.build()
35
okCollect.launch(user, new OkCollectCallback<OkHiUser, OkHiLocation>() {
36
@Override
37
public void onSuccess(OkHiUser okHiUser, OkHiLocation location) {
38
startAddressVerification(location);
39
}
40
41
@Override
42
public void onClose() {
43
showMessage("User closed.");
44
}
45
46
@Override
47
public void onError(OkHiException e) {
48
showMessage(e.getCode() + ":" + e.getMessage());
49
}
50
});
51
}
52
53
private fun startAddressVerification(user: OkHiUser, location: OkHiLocation) {
54
okVerify.start(user, location, object : OkVerifyCallback<String> {
55
56
override fun onSuccess(result: String) {
57
Log.v("OkVerify", "Verification started for: $result")
58
}
59
60
override fun onError(e: OkHiException) {
61
e.printStackTrace()
62
}
63
})
64
}
65
66
private fun setUpOkHi() {
67
val theme = OkHiTheme.Builder("#333333").setAppBarLogo("https://cdn.okhi.co/icon.png").setAppBarColor("#333333").build()
68
val config = OkHiConfig.Builder().withStreetView().build()
69
val importance = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) NotificationManager.IMPORTANCE_DEFAULT else 3
70
OkVerify.init(applicationContext, OkHiNotification(
71
"Verifying your address",
72
"We're currently verifying your address. This won't take long",
73
"OkHi_Test",
74
"OkHi Address Verification",
75
"Alerts related to any address verification updates",
76
importance,
77
1,
78
2
79
)
80
)
81
try {
82
okhi = OkHi(this)
83
okCollect = OkCollect.Builder(this).withTheme(theme).withConfig(config).build()
84
okVerify = OkVerify.Builder(this).build()
85
} catch (e: Exception) {
86
e.printStackTrace()
87
}
88
}
89
90
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
91
super.onActivityResult(requestCode, resultCode, data)
92
okhi.onActivityResult(requestCode, resultCode, data)
93
}
94
95
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
96
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
97
okhi.onRequestPermissionsResult(requestCode, permissions, grantResults)
98
}
99
}
Test
If verification has started successfully:
  • A persistent notification should show, indicating that verification is ongoing
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.
Node.js
1
//Secure new address endpoint
2
app.post("/users/addresses", async (req) => {
3
const { user, location } = req.body;
4
const { id, firstName, lastName, phone } = user;
5
const {
6
id: locationId, displayTitle, title, subtitle, country, state, city, countryCode, lat, lon, plusCode, propertyName, streetName, url, streetViewPanoId, streetViewPanoUrl
7
} = location;
8
console.log(user, location);
9
// Store the location.id. Used to match webhook updates
10
return;
11
});

4. Handle verification events (Server-side)

OkHi sends verification status updates over a few days while verification is ongoing. Follow the webhook guide to set up a webhook to 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
Node
// 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

Title
Scenario
How to test
Create an address
Address creation succeeds and verification is initiated
Launch OkHi's address manager via the button you created and create an address. A sticky notification appears on android.
Dashboard
When verification is initiated, the address shows up on OkDash
Check OkDash, you should see a list of all the addresses created. It takes ~3min for addresses to show up on OkDash
Proof of address
When an address is verified, the webhook receives the status update and the app shows the correct verification status.
A proof of address certificate is made available on OkDash.
Install your app on your personal device that you move around with and create your home address. Check okDash in 3 days for your proof of address certificate once your address has been verified.
Business logic
When an address is verified or not, the correct business logic is applied successfully.
Conduct a comprehensive test with multiple users, wherein they create various addresses to observe diverse outcomes. These outcomes may include successful creation of home addresses, entering incorrect addresses, refusing to grant necessary location permissions, or uninstalling the app immediately after initiating the address verification process, among other scenarios.

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.Builder
private void setUpOkHi() {
final OkHiTheme theme = new OkHiTheme.Builder("#333333")
.setAppBarLogo("https://cdn.okhi.co/icon.png")
.setAppBarColor("#333333")
.build();
// ...Other setup details
try {
okhi = new OkHi(this);
okCollect = new OkCollect.Builder(this)
.withTheme(theme)
.withConfig(config).build();
okVerify = new OkVerify.Builder(this).build();
} catch (Exception e) {
e.printStackTrace();
}
}}

Customizing 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.
OkHiConfig config = new OkHiConfig.Builder()
.withStreetView()
.withWorkAddressType(false)
.withHomeAddressType(true)
.build();

Customise notification icon & color

You can specify a custom default icon and a custom default color by adding these lines inside the application tag to set the custom default icon and custom color. You'll need to have already created the icon resource in your Android application. Icon assets can be created by following these steps
<application>
<meta-data android:name="io.okhi.core.branch_id" android:value="<my_branch_id>" />
<meta-data android:name="io.okhi.core.client_key" android:value="<my_client_key>" />
<meta-data android:name="io.okhi.core.environment" android:value="prod" />
<meta-data android:name="io.okhi.core.platform" android:value="android" />
<!-- Set custom default icon for OkVerify's foreground service -->
<meta-data android:name="io.okhi.android_background_geofencing.foreground_notification_icon" android:resource="@drawable/ic_person_pin" />
<!-- Set custom default icon color for OkVerify's foreground service -->
<meta-data android:name="io.okhi.android_background_geofencing.foreground_notification_color" android:resource="@color/colorAccent" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

Important: Prepare for submission to the Google Play store

Submitting an app to the Google Play 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:

Next steps