Overview
Poilabs Visually Navigation SDK Implementation and Installation Guide. SDK support iOS and Android Native Applications. Besides, React or Flutter apps can use this SDK as a native library. For more information, see below.
To integrate and run the applications, the following variables are needed.
| Variable Name | Description |
| APPLICATION_ID | Application ID for Customer`s application, Provided by Poilabs. |
| APPLICATION_SECRET_KEY | Access Token for Customer`s application, Provided by Poilabs. |
| UNIQUE_ID | User ID to identify your app user. It must be unique for every app user. |
| JITPACK_TOKEN | Jitpack token for adding jitpack dependencies. If you have your own token, you can remove it. |
| redirectUrl | Define URL to redirect requests on your servers |
[tabby title=”iOS Native”]
iOS Native
To integrate PoilabsVdNavigation into your Xcode project using Swift Package Manager:
- In Xcode, select "File" > "Swift Packages" > "Add Package Dependency..."
- Enter the repository URL:
https://github.com/poiteam/ios-vd-navigation-pod.git - Specify the version or branch you want to use
- Click "Next" and then "Finish"
All required dependencies (PoilabsPositioning, PoilabsSdkAnalytics, PoilabsCore) are defined in the package and will be automatically installed.
To integrate PoilabsNavigation into your Xcode project using CocoaPods, specify it in your Podfile:
pod 'PoilabsVdNavigation'
To Integrate this framework you should add some features to your project info.plist file.
+Privacy - Location Usage Description
+Privacy - Location When In Use Usage Description
You should import PoilabsVdNavigationUI
import PoilabsVdNavigationUIPoilabsVdNanigationUI initializer has UIViewController handler. When process is completed, it returns a viewcontroller. You should show it to start framework.
let lang = Locale.current.languageCode ?? "tr"
let appId = APPLICATION_ID
let secret = APPLICATION_SECRET_KEY
let uniqueIdentifier = UNIQUE_ID
PoilabsVdNavigationUI(withApplicationID: appId,
withApplicationSecret: secret,
withUniqueIdentifier: uniqueIdentifier) { (controller) in
//show controller
}didUserLocationChange callback is triggered when location change.
func poilabsVdNavigation(didUpdate userLocation: CLLocationCoordinate2D) {
}[tabby title=”Android Native”]
Android Native
PoiLabs Visually Disabled Navigation SDK is an indoor navigation android library. It provides navigation for blind people inside applications.
You can download our SDK via Gradle with following below steps
- Add jitpack dependency to your project level build.gradle file with their tokens. JITPACK_TOKEN is a token that PoiLabs will provide for you it will allow you to download our sdk.
allprojects {
repositories {
maven {
url "https://jitpack.io"
credentials { username = 'JITPACK_TOKEN' }
}
}
}- Add PoiLabs VD Navigation SDK dependency to your app level build.gradle file
dependencies {
implementation 'com.github.poiteam:Android-VD-Navigation-SDK:7.0.8'
} In order to our SDK can work properly we need location permission and bluetooth usage for scanning for beacons by using our sdk the below permissions will add to your manifest file.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Minimum requirements
| Supported Minimum Android |
|---|
| Android 5.0 (API level 21) |
After getting permissions you can now use PoiLabs navigation SDK. In this section we will introduce our SDK methods for you
With this class you can start SDK functionallity. You should init this class with required parameters that has been described below and you should provide an impelementation of VDResponseListener interface.
Parameters:
- context : an instance of your application context
- APPLICATION_ID
- APPLICATION_SECRET_KEY
- redirectUrl
- localeLanguage : the language tag of your app language ("en", "tr")
- title: a title that will show on the first page of SDK
- implementation of VDResponseListener
VDResponseListener it has two methods:
- fun onSuccess() this callback means that SDK is ready and you can start the PoiVdNavigationActivity
- fun onFail(Throwable throwable) this callback means something wrong has happened and you can not use SDK right now. You can check the error with throwable parameter and if needed you can contact with PoiLabs.
LocationCallback it has two methods:
- fun onLocation(latitude:Double, longitude:Double, floorLevel:Int?) this callback returns user current location
- fun onStatusChanged(status:PLPStatus) this is an optional callback that returns sdk current status
Common Errors:
| Error | Probable Cause | Fix |
|---|---|---|
| HTTP 403 | The APPLICATION_ID and APPLICATION_SECRET_KEY is wrong | Check your credentials |
Using SDK if you have redirectURL
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
PoiManager.init(
activity,
appId = APPLICATION_ID,
secret = APPLICATION_SECRET_KEY,
optionalUrl = "https://redirect.url",
language = localeLanguage,
title = "A title for your app",
vdResponseListener = object : VDResponseListener {
override fun onSuccess() {
PoiManager.setUniqueId("IGA test unique id")
Intent(requireContext(), PoiVdNavigationActivity::class.java).also {
startActivity(it)
}
}
override fun onFail(throwable: Throwable?) {
Toast.makeText(requireContext(), throwable?.message, Toast.LENGTH_SHORT).show()
}
},
locationCallback = object : LocationCallback {
override fun onLocation(latitude: Double, longitude: Double, floorLevel: Int?) {
Log.i("TAG", "onLocation: $latitude, $longitude, $floorLevel")
}
override fun onStatusChanged(status: PLPStatus) {
Log.i("TAG", "onStatusChanged: $status")
}
})
}Using SDK without redirectURL
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
PoiManager.init(
activity,
appId = APPLICATION_ID,
secret = APPLICATION_SECRET_KEY,
language = localeLanguage,
title = "A title for your app",
vdResponseListener = object : VDResponseListener {
override fun onSuccess() {
PoiManager.setUniqueId("IGA test unique id")
Intent(requireContext(), PoiVdNavigationActivity::class.java).also {
startActivity(it)
}
}
override fun onFail(throwable: Throwable?) {
Toast.makeText(requireContext(), throwable?.message, Toast.LENGTH_SHORT).show()
}
},
locationCallback = object : LocationCallback {
override fun onLocation(latitude: Double, longitude: Double, floorLevel: Int?) {
Log.i("TAG", "onLocation: $latitude, $longitude, $floorLevel")
}
override fun onStatusChanged(status: PLPStatus) {
Log.i("TAG", "onStatusChanged: $status")
}
})
}-printmapping out.map
-keepparameternames
-renamesourcefileattribute SourceFile
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,EnclosingMethod
# Preserve all annotations.
-keepattributes *Annotation*
# Preserve all public classes, and their public and protected fields and
# methods.
-keep public class * {
public protected *;
}
# Preserve all .class method names.
-keepclassmembernames class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String, boolean);
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers class * extends java.lang.Enum {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your library doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keep public interface com.poilabs.vd.nav.non.ui.jsonclient.ApiInterface
-keep public interface com.poilabs.vd.nav.non.ui.jsonclient.VDResponseListener
-keep class com.poilabs.vd.nav.non.ui.models.** { *; }
-keep class com.poilabs.vd.nav.non.ui.manager.VDCallbacks
-keep class com.poilabs.android.poilabsanalytics.model.** { *; }
-dontwarn com.poilabs.vd.nav.non.ui.Utils.**
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
<init>(...);
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
*** rewind();
}
[tabby title=”React Native”]
React Native Implementation
To integrate PoilabsVdNavigation into your Xcode project using CocoaPods, specify it in your Podfile.
Also you should enable use_frameworks!
use_frameworks option should be before use_react_native!() function call. It will avoid getting multiple command produce error
use_frameworks!
.....
use_react_native!(
.....
)
.....
pod 'PoilabsVdNavigation'
To Integrate this framework you should add some features to your project info.plist file.
+Privacy - Location Usage Description
+Privacy - Location When In Use Usage Description
+Privacy - Bluetooth Peripheral Usage Description
+Privacy - Bluetooth Always Usage Description
Create a Swift file named PoilabsVdNavigationManager with content below. This will be your Map View.
Do not forget change application id and application secret key with those which are given by Poilabs.
import UIKit
import PoilabsVdNavigationUI
@objc class PoilabsVdNavigationManager: NSObject {
@objc func showPoilabsVdNavigation() {
let appId = "applicationId"
let secret = "applicationSecret"
let uniqueIdentifier = "UNIQUE_ID"
let _ = PoilabsVdNavigationUI(withApplicationID: appId, withApplicationSecret: secret, withUniqueIdentifier: uniqueIdentifier) { controller in
DispatchQueue.main.async {
let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) ?? UIApplication.shared.windows.first
let topController = keyWindow?.rootViewController
topController?.show(controller, sender: self)
}
}
}
}You should create a header file called PoilabsNavigationBridge.h and a Objective-C file called PoilabsNavigationBridge.m with content below.
Do not forget to change YOUR_PROJECT_NAME with your project name.
#ifndef PoilabsNavigationBridge_h
#define PoilabsNavigationBridge_h
#import <React/RCTBridgeModule.h>
@interface PoilabsNavigationBridge : NSObject <RCTBridgeModule>
-(void) showPoilabsVdNavigation;
@end
#endif /* PoilabsNavigationBridge_h */#import <Foundation/Foundation.h>
#import "PoilabsNavigationBridge.h"
#import "YOUR_PROJECT_NAME-Swift.h"
@implementation PoilabsNavigationBridge: NSObject
RCT_EXPORT_MODULE(PoilabsNavigationBridge);
RCT_EXPORT_METHOD(showPoilabsVdNavigation) {
dispatch_async(dispatch_get_main_queue(), ^{
PoilabsVdNavigationManager* vdManager = [[PoilabsVdNavigationManager alloc] init];
[vdManager showPoilabsVdNavigation];
});
}
@endYou can download our SDK via Gradle with following below steps
- Add jitpack and mapbox dependency to your project level build.gradle file with their tokens. JITPACK_TOKEN is a token that PoiLabs will provide for you it will allow you to download our sdk.
allprojects {
repositories {
maven {
url "https://jitpack.io"
credentials { username = 'JITPACK_TOKEN' }
}
}
}- Add PoiLabs Vd Navigation SDK dependency to your app level build.gradle file
dependencies {
implementation 'com.github.poiteam:Android-VD-Navigation-SDK:7.0.6'
} In order to our SDK can work properly we need location permission and bluetooth usage for scanning for beacons by using our sdk the below permissions will add to your manifest file.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Create a java file named PoilabsPackage with content below.
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Collections;
import java.util.List;
public class PoilabsPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.singletonList(new PoilabsNavigationBridge(reactContext));
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}Create a Kotlin file call PoilabsNavigationBridge
import android.content.Intent
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.getpoi.android_vd_nav_ui.view.PoiVdNavigationActivity
import com.poilabs.vd.nav.non.ui.jsonclient.VDResponseListener
import com.poilabs.vd.nav.non.ui.models.PoiManager
class PoilabsNavigationBridge internal constructor(context: ReactApplicationContext?) :
ReactContextBaseJavaModule(context) {
override fun getName(): String {
return "PoilabsNavigationBridge"
}
@ReactMethod
fun showPoilabsVdNavigation() {
currentActivity?.let { activity ->
PoiManager.init(
context = activity.baseContext,
appId = "APPLICATION_ID",
secret = "APPLICATION_SECRET_KEY",
language = "en",
title = "PLACE_TITLE",
vdResponseListener = object : VDResponseListener {
override fun onSuccess() {
Intent(activity.applicationContext, PoiVdNavigationActivity::class.java).also {
activity.startActivity(it)
}
}
override fun onFail(throwable: Throwable?) {
}
})
}
}
}Open up your MainApplication.java file, which can be found in the following path: android/app/src/main/java/com/your-app-name/MainApplication.kt
Locate ReactNativeHost’s getPackages() method and add your package to the packages list getPackages() returns:
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(PoilabsPackage())
}You should import NativeModules
import {
NativeModules,
} from 'react-native';You can start PoilabsVdNavigation with calling bridge method
NativeModules.PoilabsNavigationBridge.showPoilabsVdNavigation();[tabby title=”Flutter”]
Flutter Implementation
PoilabsVdNavigation
Flutter apps integrate the VD Navigation SDK through MethodChannel, bridging to native iOS and Android SDKs. Each platform handles SDK initialization and UI natively, while Flutter triggers navigation via a shared channel.
Architecture
| Layer | Technology |
|---|---|
| Dart / Flutter | MethodChannel bridge |
| iOS Native | PoilabsVdNavigationUI (CocoaPods) — returns UIViewController |
| Android Native | PoiManager + PoiVdNavigationActivity (JitPack) |
iOS Side
Installation
To integrate PoilabsVdNavigation into your iOS project using CocoaPods, add to your Podfile. The use_frameworks! directive must appear before any Flutter-related calls:
use_frameworks!
# Flutter pods
flutter_application_path = '../my_flutter_app'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
pod 'PoilabsVdNavigation'
Then run:
$ pod install
$ open Runner.xcworkspace
Pre-Requirements
Add the following keys to your Info.plist:
+Privacy – Location Usage Description
+Privacy – Location When In Use Usage Description
+Privacy – Location Always Usage Description
+Privacy – Location Always and When In Use Usage Description
+Privacy – Bluetooth Peripheral Usage Description
+Privacy – Bluetooth Always Usage Description
Usage — AppDelegate.swift
Register a FlutterMethodChannel in your AppDelegate. When Flutter calls start, initialize PoilabsVdNavigationUI which returns a UIViewController:
import UIKit
import Flutter
import PoilabsVdNavigationUI
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(
name: "com.poilabs/vdNavigationChannel",
binaryMessenger: controller.binaryMessenger
)
channel.setMethodCallHandler { [weak self] (call, result) in
if call.method == "start" {
self?.startVdNavigation(from: controller, result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func startVdNavigation(from controller: UIViewController, result: @escaping FlutterResult) {
let lang = Locale.current.languageCode ?? "tr"
let appId = "APPLICATION_ID"
let secret = "APPLICATION_SECRET_KEY"
let uniqueId = "UNIQUE_ID"
PoilabsVdNavigationUI(
withApplicationID: appId,
withApplicationSecret: secret,
withUniqueIdentifier: uniqueId,
lang: lang
) { navController in
DispatchQueue.main.async {
controller.present(navController, animated: true)
result("NavigationStarted")
}
}
}
}
If you need to specify a custom redirect URL:
PoilabsVdNavigationUI(
configUrl: "https://your-redirect-url.com",
withApplicationID: appId,
withApplicationSecret: secret,
withUniqueIdentifier: uniqueId,
lang: lang
) { navController in
DispatchQueue.main.async {
controller.present(navController, animated: true)
result("NavigationStarted")
}
}
Android Side
Installation
Add JitPack repository to your project-level build.gradle:
allprojects {
repositories {
maven {
url "https://jitpack.io"
credentials {
username = 'JITPACK_TOKEN'
}
}
}
}
Add the VD Navigation SDK dependency to your app-level build.gradle:
dependencies {
implementation 'com.github.poiteam:Android-VD-Navigation-SDK:7.0.6'
}
Pre-Requirements
The following permissions are required in your AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Minimum requirement: Android 5.0 (API level 21)
Usage — MainActivity.kt
Register a MethodChannel in your MainActivity. When Flutter calls start, initialize PoiManager (two-phase init):
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.content.Intent
import com.getpoi.android_vd_nav_ui.view.PoiVdNavigationActivity
import com.poilabs.vd.nav.non.ui.jsonclient.VDResponseListener
import com.poilabs.vd.nav.non.ui.models.PoiManager
import com.poilabs.vd.nav.non.ui.models.LocationCallback
import com.poilabs.positioning.model.PLPStatus
class MainActivity : FlutterActivity() {
private val CHANNEL = "com.poilabs/vdNavigationChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method == "start") {
startVdNavigation(result)
} else {
result.notImplemented()
}
}
}
private fun startVdNavigation(result: MethodChannel.Result) {
PoiManager.init(
context = this,
appId = "APPLICATION_ID",
secret = "APPLICATION_SECRET_KEY",
language = "en",
title = "Navigation",
vdResponseListener = object : VDResponseListener {
override fun onSuccess() {
PoiManager.setUniqueId("UNIQUE_ID")
Intent(this@MainActivity, PoiVdNavigationActivity::class.java).also {
startActivity(it)
result.success("NavigationStarted")
}
}
override fun onFail(throwable: Throwable?) {
result.error("VD_INIT_FAILED", throwable?.message, null)
}
},
locationCallback = object : LocationCallback {
override fun onLocation(latitude: Double, longitude: Double, floorLevel: Int?) {
// Handle location updates
}
override fun onStatusChanged(status: PLPStatus) {
// Handle status changes
}
}
)
}
}
Using SDK with a redirect URL — add the optionalUrl parameter:
PoiManager.init(
context = this,
appId = "APPLICATION_ID",
secret = "APPLICATION_SECRET_KEY",
optionalUrl = "https://your-redirect-url.com",
language = "en",
title = "Navigation",
vdResponseListener = object : VDResponseListener { ... },
locationCallback = object : LocationCallback { ... }
)
Dart / Flutter Side
Create a simple Flutter widget that triggers native VD Navigation via MethodChannel:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class VdNavigationScreen extends StatelessWidget {
static const _channel = MethodChannel('com.poilabs/vdNavigationChannel');
const VdNavigationScreen({super.key});
Future<void> _startNavigation() async {
try {
await _channel.invokeMethod('start');
} on PlatformException catch (e) {
debugPrint('VD Navigation error: ${e.message}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('VD Navigation')),
body: Center(
child: ElevatedButton(
onPressed: _startNavigation,
child: const Text('Start VD Navigation'),
),
),
);
}
}
Configuration
| Variable Name | Description |
|---|---|
| APPLICATION_ID | Application ID for Customer’s application, provided by Poilabs. |
| APPLICATION_SECRET_KEY | Access Token for Customer’s application, provided by Poilabs. |
| UNIQUE_ID | User ID to identify your app user. Must be unique for every user. |
| JITPACK_TOKEN | Jitpack token for downloading Android SDK. Provided by Poilabs. |
| redirectUrl | (Optional) Define URL to redirect requests on your servers. |
Callback Reference
iOS
| Callback | Description |
|---|---|
| PoilabsVdNavigationUI completion handler | Returns a UIViewController when SDK is ready. Present it to start navigation. |
| poilabsVdNavigation(didUpdate:) | Triggered when user location changes. Returns CLLocationCoordinate2D. |
Android
| Callback | Interface | Description |
|---|---|---|
| onSuccess() | VDResponseListener | SDK is ready. Launch PoiVdNavigationActivity. |
| onFail(Throwable) | VDResponseListener | Initialization failed. Check throwable for details. |
| onLocation(lat, lng, floor) | LocationCallback | Returns user’s current indoor position. |
| onStatusChanged(PLPStatus) | LocationCallback | SDK status changed (scanning, navigating, etc.). |
Common Errors
| Error | Probable Cause | Fix |
|---|---|---|
| HTTP 403 | APPLICATION_ID or APPLICATION_SECRET_KEY is wrong | Verify your credentials with Poilabs. |
| MissingPluginException | MethodChannel name mismatch between Dart and native | Ensure both sides use com.poilabs/vdNavigationChannel. |
| iOS build fails with “framework not found” | use_frameworks! missing or misplaced in Podfile |
Add use_frameworks! before Flutter pod imports. |
| Android: minSdkVersion error | App targets below API 21 | Set minSdkVersion 21 in app-level build.gradle. |
| Android: VDResponseListener.onFail called | Network or credential issue during init | Check internet connection and credentials. Contact Poilabs if persistent. |
[tabbyending]