Search…
Flutter SDK Installation Guide
Pngme's Data SDK is used to fetch user authenticated data from an Android device using the Flutter development framework.

Step 1: Install the Native Android SDK

In Flutter, go to /Android folder, then open build.gradle and add maven into repositories:
1
allprojects {
2
repositories {
3
...
4
maven { url 'https://jitpack.io' } // <-- add this line
5
}
6
}
Copied!
Upgrade Kotlin version on your project, go to /Android folder, then open build.gradle and update ext.kotlin_version to '1.4.32' if you are using an older version, if you are using a newer version please ignore this step
1
buildscript {
2
ext.kotlin_version = '1.4.32' // <-- update version here
3
repositories {
4
google()
5
jcenter()
6
}
Copied!
Now, go to Android/app and open build.gradle and change Y.X.Z for our latest stable version.
The current stable version is:
1
dependencies {
2
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
3
implementation 'androidx.appcompat:appcompat:1.2.0'
4
// Add from here
5
implementation ('com.github.pngme:android-sdk:vY.X.Z') {
6
// Exclude is not needed in all projects so if your app does not compile fue do a
7
// missing dependency, please remove this exclusion
8
exclude group: "org.jetbrains.kotlinx",
9
module: "kotlinx-coroutines-core"
10
}
11
implementation 'androidx.appcompat:appcompat:1.2.0'
12
// to here
13
}
Copied!

Step 2: Build the Flutter Wrapper

The first step is to create a loading screen in Flutter that initiates loading the SDK permission flow.

Create a Loading Screen

To add assets to the wrapper, enter onto the Android Drawable folder android/app/src/mail/res/drawable and add a new ic_pngme_logo.xml and paste the following code into ic_pngme_logo.xml.
1
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2
android:width="41dp"
3
android:height="40dp"
4
android:viewportWidth="41"
5
android:viewportHeight="40">
6
<group>
7
<path
8
android:pathData="M20.2092,40C31.0768,40 39.8867,31.0457 39.8867,20C39.8867,8.9543 31.0768,0 20.2092,0C9.3417,0 0.5318,8.9543 0.5318,20C0.5318,31.0457 9.3417,40 20.2092,40"
9
android:strokeWidth="1"
10
android:fillColor="#060403"
11
android:fillType="nonZero"
12
android:strokeColor="#00000000"/>
13
</group>
14
<path
15
android:pathData="M12.1851,12.459C11.4373,12.459 10.8324,12.6913 10.3705,13.156L10.3705,12.6393L8.9189,12.6393L8.9189,21.5192L10.3705,21.5192L10.3705,18.1186C10.8324,18.5833 11.4373,18.8155 12.1851,18.8155C12.9108,18.8155 13.5414,18.5152 14.0766,17.9144C14.6117,17.3135 14.8793,16.5565 14.8793,15.6433C14.8793,14.7301 14.6099,13.9711 14.0711,13.3662C13.5322,12.7615 12.9035,12.459 12.1851,12.459ZM11.9322,17.4337C11.5216,17.4337 11.1587,17.2675 10.8434,16.9351C10.5281,16.6026 10.3705,16.172 10.3705,15.6433C10.3705,15.1146 10.5281,14.682 10.8434,14.3456C11.1587,14.0091 11.5216,13.8409 11.9322,13.8409C12.3793,13.8409 12.7477,14.0051 13.0373,14.3335C13.3269,14.6619 13.4717,15.0986 13.4717,15.6433C13.4717,16.188 13.3269,16.6226 13.0373,16.9471C12.7477,17.2715 12.3793,17.4337 11.9322,17.4337ZM19.1572,12.459C18.446,12.459 17.8705,12.6994 17.4307,13.18L17.4307,12.6393L15.979,12.6393L15.979,18.6353L17.4307,18.6353L17.4307,15.9797C17.4307,14.6019 17.8852,13.9129 18.7943,13.9129C19.1315,13.9129 19.401,14.0412 19.6026,14.2975C19.8041,14.5538 19.905,14.8943 19.905,15.3188L19.905,18.6353L21.3566,18.6353L21.3566,14.9824C21.3566,14.2374 21.155,13.6306 20.7518,13.162C20.3485,12.6933 19.817,12.459 19.1572,12.459ZM28.2738,12.6393L26.8221,12.6393L26.8221,13.156C26.3602,12.6913 25.7554,12.459 25.0076,12.459C24.2891,12.459 23.6604,12.7615 23.1216,13.3662C22.5827,13.9711 22.3133,14.7301 22.3133,15.6433C22.3133,16.5565 22.5809,17.3135 23.1161,17.9144C23.6513,18.5152 24.2818,18.8155 25.0076,18.8155C25.7554,18.8155 26.3602,18.5833 26.8221,18.1186L26.8221,18.5392C26.8221,19.0439 26.67,19.4284 26.3657,19.6927C26.0614,19.9571 25.6674,20.0892 25.1836,20.0892C24.839,20.0892 24.5604,20.0232 24.3478,19.891C24.1351,19.7588 23.9152,19.5366 23.6879,19.2241L22.5112,20.3175C23.0171,21.1988 23.9079,21.6393 25.1836,21.6393C26.0926,21.6393 26.8349,21.387 27.4105,20.8823C27.9859,20.3776 28.2738,19.6767 28.2738,18.7795L28.2738,12.6393ZM25.2606,17.4337C24.8133,17.4337 24.4449,17.2715 24.1553,16.9471C23.8657,16.6226 23.7209,16.188 23.7209,15.6433C23.7209,15.0986 23.8657,14.6619 24.1553,14.3335C24.4449,14.0051 24.8133,13.8409 25.2606,13.8409C25.6711,13.8409 26.034,14.0091 26.3493,14.3456C26.6645,14.682 26.8221,15.1146 26.8221,15.6433C26.8221,16.172 26.6645,16.6026 26.3493,16.9351C26.034,17.2675 25.6711,17.4337 25.2606,17.4337Z"
16
android:strokeWidth="1"
17
android:fillColor="#FFFFFE"
18
android:fillType="nonZero"
19
android:strokeColor="#00000000"/>
20
<path
21
android:pathData="M22.4923,23.6066C21.614,23.6066 20.9249,23.9115 20.425,24.5214C20.0011,23.9115 19.3801,23.6066 18.5623,23.6066C17.858,23.6066 17.2939,23.8148 16.8698,24.2313L16.8698,23.774L15.3705,23.774L15.3705,29.3408L16.8698,29.3408L16.8698,26.6633C16.8698,26.0907 16.9835,25.663 17.2106,25.3804C17.4378,25.0978 17.7558,24.9565 18.1647,24.9565C18.4828,24.9565 18.7478,25.0661 18.9598,25.2856C19.1719,25.505 19.2779,25.7969 19.2779,26.1613L19.2779,29.3408L20.7772,29.3408L20.7772,26.6633C20.7772,26.0981 20.8946,25.6723 21.1293,25.386C21.3641,25.0996 21.6859,24.9565 22.0948,24.9565C22.4128,24.9565 22.6778,25.0661 22.8899,25.2856C23.1019,25.505 23.2079,25.7969 23.2079,26.1613L23.2079,29.3408L24.6959,29.3408L24.6959,25.8601C24.6959,25.1982 24.4801,24.6571 24.0485,24.2369C23.6168,23.8167 23.0981,23.6066 22.4923,23.6066ZM31.4996,26.4514C31.4692,25.6184 31.1758,24.936 30.6193,24.4042C30.0627,23.8724 29.3982,23.6066 28.6258,23.6066C27.8004,23.6066 27.1057,23.8836 26.5416,24.4377C25.9774,24.9918 25.6953,25.7002 25.6953,26.5629C25.6953,27.4257 25.9755,28.1322 26.5359,28.6826C27.0962,29.233 27.7853,29.5082 28.6031,29.5082C29.2392,29.5082 29.7957,29.3631 30.2729,29.0731C30.7499,28.783 31.1096,28.3554 31.3519,27.7901L30.0116,27.5112C29.7163,28.0021 29.2467,28.2475 28.6031,28.2475C28.2548,28.2475 27.95,28.1304 27.6887,27.8961C27.4275,27.6618 27.259,27.3476 27.1833,26.9534L31.4996,26.9534L31.4996,26.4514ZM28.6258,24.8895C28.9439,24.8895 29.224,24.9751 29.4664,25.1462C29.7087,25.3172 29.8752,25.5738 29.9661,25.9159L27.2287,25.9159C27.312,25.5887 27.4881,25.3358 27.7569,25.1573C28.0257,24.9788 28.3153,24.8895 28.6258,24.8895Z"
22
android:strokeWidth="1"
23
android:fillColor="#FFFFFE"
24
android:fillType="nonZero"
25
android:strokeColor="#00000000"/>
26
<path
27
android:pathData="M10.2092,29.5082C10.9219,29.5082 11.4996,28.921 11.4996,28.1967C11.4996,27.4724 10.9219,26.8852 10.2092,26.8852C9.4966,26.8852 8.9189,27.4724 8.9189,28.1967C8.9189,28.921 9.4966,29.5082 10.2092,29.5082"
28
android:strokeWidth="1"
29
android:fillColor="#D92265"
30
android:fillType="nonZero"
31
android:strokeColor="#00000000"/>
32
</vector>
33
Copied!

Create a Loading Screen Layout

Next, add the loading screen layout. Before the SDK loads, for approximately one full second the SDK loading screen will appear on either a black or white background (depending on whether the phone is in dark or light mode). To do this, add a new file called view_pngme_helper.xml on android/app/src/main/res/layout
Create a layout folder if needed, some Flutter projects may not have this by default.
android/app/src/main/res/layout
view_pngme_helper.xml
1
<?xml version="1.0" encoding="utf-8"?>
2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
android:background="@color/background"
4
android:orientation="horizontal"
5
android:layout_gravity="center_vertical"
6
android:gravity="center|center_vertical"
7
android:layout_width="match_parent"
8
android:layout_height="match_parent">
9
10
<ImageView
11
android:id="@+id/pngme_logo"
12
android:layout_width="70dp"
13
android:layout_height="70dp"
14
android:src="@drawable/ic_pngme_logo"
15
/>
16
17
</LinearLayout>
Copied!

Call the SDK and Pass Params

Now add some logic by opening Android Studio. Create a new Kotlin class with File -> New -> Kottlin File/Class name it as PngmeSDKHelper.kt click OK.
The PngmeSDKHelper class will be in charge of receive parameters and open the PngmeSDK library
Copy and paste the code below into the PngmeSDKHelper.kt you have just created.
1
package com.yourpackage_name
2
3
// copy from here ->
4
// here you should change for your app name
5
import com.example.my_app.MainActivity.Companion.RESULT_SDK_ON_CLOSE_DIALOG
6
import com.example.my_app.MainActivity.Companion.RESULT_SDK_ON_COMPLETE_OK
7
import com.example.my_app.MainActivity.Companion.RESULT_SDK_ON_ERROR
8
9
import com.pngme.sdk.library.PngmeSdk
10
import com.pngme.sdk.library.data.UserInfo
11
12
import androidx.appcompat.app.AppCompatActivity
13
import android.os.Bundle
14
15
class PngmeSDKHelper : AppCompatActivity() {
16
17
override fun onCreate(savedInstanceState: Bundle?) {
18
super.onCreate(savedInstanceState)
19
setContentView(R.layout.view_pngme_helper)
20
initSDK()
21
}
22
23
private fun initSDK() {
24
PngmeSdk.init(this)
25
26
val user = UserInfo()
27
user.companyName = intent.getStringExtra("companyName")
28
user.userFirstName = intent.getStringExtra("userFirstName")
29
user.userLastName = intent.getStringExtra("userLastName")
30
user.userPhone = intent.getStringExtra("userPhone")
31
user.userEmail = intent.getStringExtra("userEmail")
32
33
// optional
34
val externalId = intent.getStringExtra("externalId");
35
if (externalId != null) {
36
user.externalId = externalId;
37
}
38
39
PngmeSdk.registerUser(user)
40
PngmeSdk.start(onComplete = :: onComplete, onError = :: onError, onCloseDialog = :: closeDialog )
41
}
42
43
private fun closeDialog() {
44
setResult(RESULT_SDK_ON_CLOSE_DIALOG)
45
this.finish()
46
}
47
48
private fun onComplete() {
49
setResult(RESULT_SDK_ON_COMPLETE_OK)
50
this.finish()
51
}
52
53
private fun onError(errorMessage: String) {
54
setResult(RESULT_SDK_ON_ERROR)
55
//Optional, Use it to log errors, if needed
56
// DO NOT FINISH FROM HERE, IT WILL CRASH IF YOU DO IT
57
}
58
59
}
Copied!
After creating PngmeSDKHelper.kt you must edit your AndroidManifest.xml to add this activity.
1
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
package="com.yourpackage_name">
3
4
5
<application
6
android:name="io.flutter.app.FlutterApplication"
7
android:label="my_app"
8
...>
9
<activity
10
android:name=".MainActivity"
11
android:launchMode="singleTop"
12
...>
13
........More boilerplate code
14
</activity>
15
16
<!-- Add code from here -->
17
<activity android:name="com.example.my_app.PngmeSDKHelper" android:theme="@style/Theme.AppCompat.NoActionBar" />
18
<!-- To here -->
19
20
...
21
</application>
22
</manifest>
23
Copied!

Main Activity

Navigate to your Android MainActivity.kt and add some magical code to call the already created PngmeSDKHelper.kt
To expose a method to Flutter, utilise the Flutter channels: https://flutter.dev/docs/development/platform-integration/platform-channels
Edit your main activity to look like the code below:
MainActivity.kt
1
package com.yourpackage_name
2
3
import io.flutter.embedding.android.FlutterActivity
4
import io.flutter.embedding.engine.FlutterEngine
5
6
7
// imports that you need to add
8
import androidx.annotation.NonNull
9
import io.flutter.plugin.common.MethodChannel
10
import android.content.Intent
11
import com.pngme.sdk.library.PngmeSdk
12
import com.pngme.sdk.library.common.Environment
13
import com.pngme.sdk.library.data.KYCDataInfo
14
import com.pngme.sdk.library.data.LoanInfo
15
import com.pngme.sdk.library.data.UserInfo
16
// end of imports
17
18
class MainActivity: FlutterActivity() {
19
private val CHANNEL = "com.flutter.pngme/sdk"
20
private var openSDKResult: MethodChannel.Result? = null
21
22
23
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
24
25
// < -------- Copy and Paste code from here -------- >
26
super.onActivityResult(requestCode, resultCode, data)
27
if (requestCode == REQUEST_START_SMS_SDK) {
28
29
when (resultCode) {
30
RESULT_SDK_ON_COMPLETE_OK -> openSDKResult?.success(SUCCESS)
31
RESULT_SDK_ON_CLOSE_DIALOG -> openSDKResult?.success(SDK_WAS_DISMISSED)
32
RESULT_SDK_ON_ERROR -> openSDKResult?.error(E_ON_SDK, E_ON_SDK, E_ON_SDK)
33
}
34
}
35
}
36
37
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
38
super.configureFlutterEngine(flutterEngine)
39
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
40
call, result ->
41
if (call.method == "OpenSDK") {
42
43
// Set environment variable
44
val clientKey : String? = call.argument("clientKey")
45
if (clientKey != null && clientKey.isNotBlank()) {
46
val environmentString : String? = call.argument("environment")
47
val environment: Environment = when (environmentString) {
48
"INTERNAL_TESTING" -> Environment.Dev
49
"SANDBOX" -> Environment.Sandbox
50
else -> Environment.Prod
51
}
52
PngmeSdk.setEnvironment(environment, clientKey, context )
53
}
54
55
if (PngmeSdk.needInitOfSDK(this)) {
56
// Get params from Flutter call
57
val companyName : String? = call.argument("companyName")
58
val userFirstName : String? = call.argument("userFirstName")
59
val userLastName : String? = call.argument("userLastName")
60
val userPhone : String? = call.argument("userPhone")
61
val userEmail : String? = call.argument("userEmail")
62
val externalId : String? = call.argument("externalId")
63
64
// Add params to send to PngmeSDKHelper
65
val intent = Intent(context, PngmeSDKHelper::class.java)
66
intent.putExtra("companyName", companyName)
67
intent.putExtra("userFirstName", userFirstName)
68
intent.putExtra("userLastName", userLastName)
69
intent.putExtra("userPhone", userPhone)
70
intent.putExtra("userEmail", userEmail)
71
intent.putExtra("externalId", externalId)
72
openSDKResult = result
73
// Launch the activity
74
activity.startActivityForResult(intent, REQUEST_START_SMS_SDK)
75
} else {
76
result.success(SUCCESS_ALREADY_SENDING_SMS)
77
}
78
// Optional methods
79
} else if (call.method == "updateUser") {
80
val user = UserInfo()
81
user.companyName = call.argument("companyName")
82
user.userFirstName = call.argument("userFirstName")
83
user.userLastName = call.argument("userLastName")
84
user.userPhone = call.argument("userPhone")
85
user.userEmail = call.argument("userEmail")
86
user.externalId = call.argument("externalId")
87
result.success(PngmeSdk.updateUser(user, context))
88
} else if (call.method == "hasPermission") {
89
result.success(PngmeSdk.hasPermission(context))
90
} else if (call.method == "checkPermissionFlow") {
91
result.success(PngmeSdk.checkPermissionFlow(context))
92
} else if (call.method == "isPermissionEnabledAndWasSessionStarted") {
93
result.success(!PngmeSdk.needInitOfSDK(context))
94
} else if (call.method == "sendKYCData") {
95
val kycDataInfo = KYCDataInfo();
96
if (call.hasArgument("idImage")) kycDataInfo.idImage = call.argument("idImage");
97
if (call.hasArgument("idNumber")) kycDataInfo.idNumber = call.argument("idNumber");
98
if (call.hasArgument("idType")) kycDataInfo.idType = call.argument("idType");
99
if (call.hasArgument("issuer")) kycDataInfo.issuer = call.argument("issuer");
100
if (call.hasArgument("kycVerified")) kycDataInfo.kycVerified = call.argument("kycVerified");
101
PngmeSdk.sendKYCData(kycDataInfo, context)
102
result.success(true)
103
} else if (call.method == "sendLoanInfo") {
104
val loanInfo = LoanInfo();
105
if (call.hasArgument("idLoan")) loanInfo.idLoan = call.argument("idLoan");
106
if (call.hasArgument("timestamp")) loanInfo.timestamp = call.argument("timestamp");
107
PngmeSdk.sendLoanInfo(loanInfo, context)
108
} else if (call.method == "forceSentSMS") {
109
result.success(PngmeSdk.forceSentSMS(context))
110
}
111
// End of optional methods
112
else {
113
result.notImplemented()
114
}
115
}
116
}
117
118
companion object {
119
120
const val REQUEST_START_SMS_SDK = 11
121
private const val E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"
122
private const val E_ON_SDK = "E_ON_SDK"
123
private const val SUCCESS_ALREADY_SENDING_SMS = "SUCCESS_PNGME_IS_ALREADY_SENDING_SMS"
124
private const val SUCCESS = "SUCCESS"
125
private const val SDK_WAS_DISMISSED = "SDK_WAS_DISMISSED"
126
127
const val RESULT_SDK_ON_COMPLETE_OK = 3
128
const val RESULT_SDK_ON_CLOSE_DIALOG = 4
129
const val RESULT_SDK_ON_ERROR = 5
130
131
}
132
// < -------- Copy and Paste code to here -------- >
133
}
Copied!
In the above code, a channel name is defined by where you 'listen' and wait for calls. Then a method is defined and named "OpenSDK".
When "OpenSDK" method is called from Flutter, check if a session was initiated by calling needInitOfSDK.
1
PngmeSdk.needInitOfSDK(this)
Copied!
This function returns a boolean, which is used to check if the SDK should be opened. Remember that the Pngme SDK asks for user permissions once and then (so long as permissions continue to be granted) sends SMS silently in the background. There is no need to open the Pngme SDK again unless a user has disabled SMS permissions.
If PngmeSdk.needInitOfSDK(this) returns true, pass the required params from the Flutter call to PngmeSDKHelper.kt
Finally, the activity is launched with the following method:
1
context.startActivity(intent)
Copied!

Calling a Method from Flutter

We have created a "com.flutter.pngme/sdk" channel and defined "OpenSDK" function in MainActivity.kt, now let's call it from Flutter.
Within the Flutter file, add the following import:
1
import 'package:flutter/services.dart';
Copied!
Now you are able to define the channel:
1
static const platform = const MethodChannel('com.flutter.pngme/sdk');
2
3
void openSDK() async {
4
String value;
5
try {
6
value = await platform.invokeMethod("OpenSDK", <String, dynamic>{
7
'companyName': 'Your company name',
8
'clientKey': 'Your Client key',
9
// Data from clients
10
'userFirstName': 'Name',
11
'userLastName': 'LastName',
12
'userPhone': '878792132',
13
'userEmail': '[email protected]',
14
});
15
print(value);
16
} catch (e) {
17
print(e);
18
}
19
}
Copied!
Note: Parameter, channel and method names are defined as Magic strings for documentation purposes. Another option is to move it to a file with constant variables.
Run your app to see the Pngme permission screen when the OpenSDK method is called.

Param Descriptions

Param
Required
Default Value
Type
Description
environment
No
'PRODUCTION'
Enum ( 'PRODUCTION')
Set environment, in order to be able to test the SDK
companyName
Yes
-
String
Used to show your company name on components
clientKey
Yes
-
String
On this param you should pass your client key provided by the Pngme team. For security reasons, avoid hardcoding this key on your code, we highly recommend to use it from your .env file
userPhone
Yes
-
String
country code + phone number string. Ej: for Ghana (country code +233) phone number 03X XXX XXXX you should pass '23303X XXX XXXX'
Warning: Pngme assumes that this data is verified by your app. If email or phoneNumber are not verified, please let our support team know.
userFirstName
Yes
-
String
User first name
userLastName
Yes
-
String
User last name
userEmail
No
-
String
User email
externalId
No
-
uuid string
You can pass your uuid in this field, this can be useful to identify your users last when obtaining processed data from our servers.

Updating user information

Once you open the permission flow and the user accepted the permission our servers will create a user with all the params that you sent to OpenSDK method. But it's possible that for any reason some of the user's data was changed on your app and you want to notify the change to Pngme in order to keep the records updated and consistent.
In order to be able to update user information we expose a method where you can pass updated data.
It's important to know that the method needs to receive all user information again.
1
void _updateUser() async {
2
bool success;
3
try {
4
success = await platform.invokeMethod("updateUser", <String, dynamic>{
5
'companyName': _companyName,
6
'userFirstName': _userFirstName,
7
'userLastName': _userLastName,
8
'userPhone': _userPhone,
9
'userEmail': _userEmail,
10
'externalId': _externalId,
11
});
12
_showMyDialog('Update user result', success.toString());
13
} catch (e) {
14
_showMyDialog('Error on SDK', e.toString());
15
}
16
print(success);
17
}
Copied!
updateUser method should be called after the user granted permissions and accepted terms and conditions
If you update phone number SDK will create and register a new user so information from previous user will keep unchanged and new SMS will be send to the new user session,

Auxiliar methods

In most cases, there is no need to make use of any auxiliar method. With the previous code example, you can show the flow to ask permissions; however, if you call it and permissions are already enabled, the popup will not be shown.
Add auxiliar methods to know the current state of permissions.
Check that auxiliar methods are already declared on MainActivity.kt so you can call them from the.dart file

Checking permissions

Check the permission status by invoking hasPermission async function, which will return a boolean.
1
bool value = await platform.invokeMethod("hasPermission");
Copied!

Knowing user interactions

Gain visibility of a user's behavior leading to their current state of permission (accepted or denied) with the checkPermissionFlow function. It returns 3 possible values:
  • "CLOSE FLOW"
  • "NEVER ASK AGAIN"
  • "NO ACTION PERFORMED"
Then, using checkPermissionFlow and arePermissionsEnabled, you can see the permission's current status and the user's most recent interaction with the SDK.
1
String value = await platform.invokeMethod("checkPermissionFlow");
Copied!

Checking if a session started

There are a couple scenarios where permissions can be enabled but a session has not started on the SMS SDK. These scenarios are:
  • The user granted permission via Android app settings
  • The sms SDK was opened, the user accepted the permissions, but for whatever reason (network issue, no connection, timeout) Pngme's API did not started a new session.
In these described scenarios, open permissions flow by calling SmsPngmeAndroid again. This should start a new session. Once a session starts, the SDK sends sms in the background. To know if a session started, expose boolean operation isPermissionEnabledAndWasSessionStarted and use:
1
bool value = await platform.invokeMethod("isPermissionEnabledAndWasSessionStarted");
Copied!

Sending KYC and Loan application data to Pngme

Once the SDK permissions are approved and SMS data is being sent you can send additional data that can be accessed via our API or Customer Management Platform (CMP).

Send KYC Data

If you verify identities via KYC within your app, you can send this data to our API in order to be able to see it when using our Customer Management Platform to see KYC data.
Note: Currently our API is not processing: id Number, idType, idImage and issuer Data. We will continue providing this solution in the near term. We recommend sending the data so in near future when the API includes these fields you do not have to release a new version.
If your KYC consists of one or more documents, you can send additional documents by calling sendKYCData various times.
Remember that this method should be called after OpenSDK()
1
static const platform = const MethodChannel('com.flutter.pngme/sdk');
2
3
void _sendKycData() async {
4
bool success;
5
try {
6
success = await platform.invokeMethod("sendKYCData", <String, dynamic>{
7
idNumber: 'G4564654',
8
idType: 'passport',
9
issuer: 'anIssuer',
10
kycVerified: true,
11
idImage: 'Image URL or BASE64 encoding',
12
});
13
} catch (e) {
14
_showMyDialog('Error on SDK', e.toString());
15
}
16
print(success);
17
}
Copied!

KYC Params

Param
Required
Type
Description
kycVerified
Yes
Boolean
Required boolean param, here you should pass true if the user successfully passed your KYC process
idNumber
No
String
On this property you should pass the idNumber e.g. : 'G0000000'
idType
No
String
On this param you should pass the document type e.g: 'passport', 'nationalId
issuer
No
String
Issuer or organization that checks user identity
idImage
No
String (Url Or Base45 encoding)
Used to send user document picture

Send Loan info

The library allows you to send Loan information to Pngme's API, to be consumed later within the Customer Management Platform or directly via our API.
Remember that this method should be called after user OpenSDK()
1
static const platform = const MethodChannel('com.flutter.pngme/sdk');
2
3
void _sendLoanData() async {
4
bool success;
5
try {
6
success = await platform.invokeMethod("sendLoanInfo", <String, dynamic>{
7
'idLoan': "#loanID",
8
'timestamp': 1625236994,
9
});
10
} catch (e) {
11
_showMyDialog('Error on SDK', e.toString());
12
}
13
print(success);
14
}
Copied!

Loan Params

Param
Required
Type
Description
idLoan
Yes
String
On this property you should pass the LoanId
timestamp
No
Integer
Optional loan applied Unix timestamp on milliseconds

ForceSendSMS

Once the openSDK method is called, and the user accepts the SMS permission the SDK will continue sending SMS data every 12 hours on the background (even if the app is closed) by using the native android worker managers. For certain devices, configurations or Android customization layers this worker managers could be stopped. To avoid this situation we expose the forceSentSMS method.
forceSentSMS runs on background and it's invisible for users. If you call forceSentSMS before asking for permission there is no problem it will ignore the action and will start sending sms after user accepts permissions.
1
bool value = await platform.invokeMethod("forceSentSMS");
Copied!

What's new

1.0.30 release on October 11 of 2021

This release includes:
  • UpdateUser method
  • Better handing of client keys (now there are 1 key for prod and other for testing)
  • Recovery mechanism driven by servers in order to get all sms in case of data lost

1.0.29 release on July 29 of 2021

This release includes better analytical bug tracking. Implementation changes: this version requires Kotlin 1.4.32 or newer to run (instruction at the top of this doc).
Implementation changes: This version requires to update android files
Last modified 30d ago