- Disclaimer
- Technical Information
- Description
- DID-SDK Integration
- Set-up the library
- Implementing the DID package
- Implementation
MIT License
Copyright (c) 2023 Appgate Cybersecurity, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This repository is meant to help you understand the implementation of the native libraries of DID-SDK using Flutter. This repository reviews the initialization of the SDK, account registration processes and authentication services.
The native libraries of DetectID-SDK have the following specifications:
-
iOS: 9.0.0
- didm_sdk.xcframework
- didm_core.xcframework
- appgate_sdk.xcframework
- appgate_core.xcframework
-
Android: 9.0.1
- didm_sdk-9.0.1.aar
- appgate_sdk-2.0.0.aar
- Base SDK compiled: iOS 16.4.
- Xcode: 14.3 (14E222b).
- OS versions compatibility: From 11 to 16.
- Programing Language: Swift 5.8.
- API level SDK compiled: 31.
- API level version compatibility: From 23 (Android 6 - Marshmallow) to 33 (Android 13).
- Programing Language: Kotlin.
- Dependency: Gson, Dagger 2, Firebase and androidx.security.
- Android Studio: Flamingo | 2022.2.1.
- Flutter >= 3.10.5
- Dart >= 3.0.5
On this section, you can review step by step the integration of the SDK and its features.
- Install Android Studio
- Download the Flutter SDK.
- Add Flutter to the PATH environment to enable the use of Flutter doctor:
export PATH="$PATH:`pwd`/your/path/to/flutter-sdk/bin"
Run flutter doctor
and check that you have installed evertything.
At this point, the instructions to add the DID library to an existing project running Flutter on Android and iOS are described. If you have already created one, please proceed with the tutorial. If not, please follow the following Codelab.
Once you have downloaded the folder didsdk
, copy the required .xcframework
files at the following location:
Follow the instructions to install cocoaPods.
sudo gem install cocoapods
If you want to use the QR registration method, remember to add permission for the camera openning App project .xcodeproj
with Xcode:
Privacy - Camera Usage Description
If your find any unknown problem compiling the App after adding the wrapper dependency. Run this command from the Terminal:
flutter pub cache clean
Run the pub get
command from Android Studio.
And then go to your app ios folder (cd [YOUR_APP]/ios
) and run pod install
from Terminal.
Remember that any time you modify the pubspec.yaml
you will need to run the pod install
from the ios folder to synchronize the libraries.
If you get this message in Xcode:
File not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a
Try to solve it with a clean of the enviornment in your app folder from the terminal (cd [YOUR_APP]
)
flutter clean
flutter pub get
cd ios
pod install
If the problem persist you may have to upgrade the Flutter version: flutter upgrade
.
Copy the required the .aar at the following locations:
didsdk/android/libs
In your app go to android/app/build.gradle and initial block add this line:
apply plugin: 'kotlin-kapt'
In your app go to android/app/build.gradle and dependencies block add this line:
implementation fileTree(include: ['*.aar'], dir: 'libs')
implementation 'com.google.dagger:dagger:2.45'
implementation 'com.google.dagger:dagger-android-support:2.45'
kapt 'com.google.dagger:dagger-compiler:2.45'
kapt 'com.google.dagger:dagger-android-processor:2.45'
implementation "androidx.security:security-crypto:1.0.0"
In order to use the DID libraries it is required to change the minimum version of the DID libraries, Change minSdkVersion to 23 in you android/app/build.gradle:
defaultConfig {
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 23
...
}
Sometimes when generating in your app `android/app/build.gradle with the flutter templates you can default the variable
ext.kotlin_version = '1.7.10'
change to:
ext.kotlin_version = '1.8.0'
Open a Flutter project using Android Studio, and add the reference of the library to dependencies
in pubspec.yaml
.
dependencies:
...
didsdk:
path: ../didsdk
Run pub get
:
And then go to /ios
folder in your terminal and run pod install
.
The first step is to register a DetectID Account with one of the methods: by url or by QR code.
This method is used to handle registration procedures via URL and the enrollment process, regardless of whether it is successful or not. This method simplifies the initialization and registration flow of the SDK. Additionally, any errors encountered during the process will be delivered through a future, providing information on what went wrong.
- String: URL for the registration process.
Future<void>
Code | Description |
---|---|
80 | Bad URL - Error with URL, it is empty, it does not contain a valid code or it is not valide scheme. |
81 | Error parsing response - Error in the message body, please validate the service response. |
82 | Error in key generation |
83 | Unreachable - The server is unreachable, check your connection settings or DetectID Server infraestructure. |
98 | Parameter Missing |
400 | Missing parameter / Encryption error. |
403 | Activation code has already been used. |
404 | Activation code not found. |
409 | The device is already registered. |
410 | Activation code has expired. |
417 | The client has reached the maximum number of allowed devices. |
422 | Invalid parameter. (e.g Wrong SDK Version format) |
430 | Unknown internal error. |
500 | System error. |
import 'package:didsdk/didsdk.dart';
Didsdk.didRegistrationWithUrl(url)
.then((_) {
// Registered successfully
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
This is the second method to register a Device with the DID console using a QR code. This method is used to handle registration procedures via QR code. This method receives the information obtained from the QR code. For implementing this you need to have a camera implementation that decodes the QR to a JSON String format.
- String: Represents the QR read by the user containing the registration code with a Json format.
- String (optional): URL for the registration process.
Future<void>
Code | Description |
---|---|
80 | Bad URL - Error with URL, it is empty, it does not contain a valid code or it is not valide scheme. |
81 | Error parsing response - Error in the message body, please validate the service response. |
82 | Error in key generation |
83 | Unreachable - The server is unreachable, check your connection settings or DetectID Server infraestructure. |
98 | Parameter Missing |
400 | Missing parameter / Encryption error. |
403 | Activation code has already been used. |
404 | Activation code not found. |
409 | The device is already registered. |
410 | Activation code has expired. |
417 | The client has reached the maximum number of allowed devices. |
422 | Invalid parameter. (e.g Wrong SDK Version format) |
430 | Unknown internal error. |
500 | System error. |
import 'package:didsdk/didsdk.dart';
Didsdk.didRegistrationByQRCode(qrCode)
.then((value) {
// Registered successfully
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
Didsdk.didRegistrationByQRCode(qrCode, "https://my-custom-url.com")
.then((value) {
// Registered successfully
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
The following methods available in the DID SDK are designed to manage the registered accounts in the Device.
This methods gives the full list of registered accounts in the current device.
Future<List<Account>>
Account {
username: String
organizationName: String
registrationDate: String
activationURL: String
registrationMethod: Int
activeOTPAuth: Bool
activePushAuth: Bool
activeQRAuth: Bool
activePushAlert: Bool
activeVoiceAuth: Bool
activeFaceAuth: Bool
}
import 'package:didsdk/didsdk.dart';
Didsdk.getAccountsAPI().getAccounts()
.then((accounts) {
for (var account in accounts) {
if(account is Account) {
print("[Organization] ${account.organizationName}");
print("[Username] ${account.username}");
}
}
});
This method assigns a customized name to the user account sent as parameter. This value is empty by default; that the company is responsible for defining whether it assigns or not this value to the end user.
- Account: Account that will be updated with the given name.
- String: The name to be assigned to the account.
import 'package:didsdk/didsdk.dart';
Didsdk.getAccountsAPI().setAccountUsername("CustomName", account);
This method deletes the account data associated to a registered device. This will remove the account from the Device, not from the Server.
- Account: Account to be deleted.
import 'package:didsdk/didsdk.dart';
Didsdk.getAccountsAPI().removeAccount(account);
This method allows the SDK to get the latest configuration from the Server associated with the given account.
- Account: Account that will be updated with the Server configuration.
import 'package:didsdk/didsdk.dart';
Didsdk.getAccountsAPI().getAccounts()
.then((accounts) {
for (var account in accounts) {
Didsdk.updateGlobalConfig(account);
}
});
This method allows set application name to DetectID Server.
- String: Represents application name that integrated DetectID SDK.
import 'package:didsdk/didsdk.dart';
Didsdk.setApplicationName("Flutter Demo Example");
The DID SDK offers the following methods to get identifiers that provide information from the current device and communication with the DID Server.
ID used for identifying the app and a device even after uninstalling the app so customers can create a blacklist of devices that they want to block.
Future<String>
import 'package:didsdk/didsdk.dart';
Didsdk.getMobileID().then((value) {
print("Mobile ID: $value");
});
ID used by customers for all request or transactions with DetectID Server API.
Future<String>
import 'package:didsdk/didsdk.dart';
Didsdk.getMaskedAppInstanceID().then((value) {
print("Masked App Instance ID: $value");
});
The DID SDK offers a feature to perform transactions using a QR-based authentication. With the information of the registered account, the SDK can securely decrypt the information from the QR generated by the Server, and also open a secure channel with the Server to confirm or decline the transaction.
To implement this feature, you should have at least one account registered on the Device. Here are the instructions to execute the process.
The first step is to obtain the TransactionInfo
using the Json string read from the QR.
If you have multiple accounts registered on the same Device, make sure to use the same account used in the Server to
generate the QR code, otherwise, it won't be able to decrypt the transaction.
- Account account.
- String: Represents the QR read by the user containing the transaction in a Json format.
Future<TransactionInfo>
Code | Description |
---|---|
81 | Error parsing response. |
90 | Wrong account. |
91 | Wrong data received. |
import 'package:didsdk/didsdk.dart';
late Account account;
Didsdk.getQRAPI().qrAuthenticationProcess(account, qrCode)
.then((transaction) {
if(transaction is TransactionInfo) {
// Use the transaction
}
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
After having a valid TransactionInfo
you can confirm or decline the operation using the following methods.
- TransactionInfo: Represents the pending transaction.
Future<void>
Code | Description |
---|---|
96 | Invalid parameter. |
98 | Error parameter missing. |
99 | Service error - Wrong data received. |
1001 | Authentication factor not enabled. |
1002 | Not available - Transaction with different state from pending. |
1012 | Expired Transaction. |
1021 | Client blocked by Admin - User Manually Blocked by Administrator. |
1022 | Client blocked by System - User Blocked by System for Exceeding Retires. |
import 'package:didsdk/didsdk.dart';
var TransactionInfo? transaction;
// Confirmation
Didsdk.getQRAPI().confirmQRCodeTransactionAction(transaction!)
.then((_) {
// Confirmed transaction successfully
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
// Cancellation
Didsdk.getQRAPI().declineQRCodeTransactionAction(transaction!)
.then((_) {
// Declined transaction successfully
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
DetectID Mobile SDK offers the possibility of authenticating a user through an OTP or one time password. This is a password that is generated by the SDK in the user’s device and validated by the server. This password is valid for a short period of time only and it’s exclusive to the user’s device, making it an adequate method for validating a user’s identity during a transaction. DetectID Mobile SDK has two types of OTP authentication: Time-based OTP and Challenge OTP. Both have important differences in the way the codes are generated; this manual will explain in detail the differences between these two types of OTP authentication.
Warning One-Time Password feature is dependant on the device’s time and date. If this information were to be altered by an undesired party in the end user’s device, they could generate an OTP that could be used for fraudulent purposes in the future. Protecting this confidential information is responsibility of the end user along with the physical integrity of the mobile device to prevent this kind of scenario.
The SDK inside the app is generating OTPs permanently, but the OTP is validated only when the user enters it to be approved by the server, making it impossible to conduct any transactions without both the users static PIN or password and the OTP in the user’s mobile device.
For using this feature, you will need to implement 3 method calls to obtain the information of the Token. One to know the current token, one for getting the time step (in percent from 1 to 100) and one for the Interval (duration of the token in seconds).
- Account: Account that will be used to generate the OTP.
// tokenValue
Future<String>
// timeStepValue: From 1 to 100
Future<Int>
// intervalValue: Duration of the OTP in seconds
Future<Int>
import 'package:didsdk/didsdk.dart';
late Account account;
Future fetchOTPData() async {
final token = Didsdk.getOTPAPI().getTokenValue(account);
final timeStep = Didsdk.getOTPAPI().getTokenTimeStepValue(account);
await Future.wait([token, timeStep]);
String tokenValue = await token;
int timeStepValue = await timeStep;
}
The SDK inside the secured entity’s application requires the user to enter the answer to a challenge presented by the application when a transaction is attempted. The answer to this challenge corresponds to one or more values configured by the secure entity, for example, the cost of the transaction or the name of the store or business involved in the transaction. If the user enters these values correctly, the SDK will generate the OTP that must be entered in the secured entity’s platform to approve the transaction. If the user provides an incorrect answer to the challenge, the generated code will not match with the code expected by DetectID and the transaction will be rejected.
- Account: Account that will be used to generate the OTP.
- String: The answer to generate the OPT.
Future<String>
Code | Description |
---|---|
88 | Invalid challenge length. |
98 | Parameter Missing. |
import 'package:didsdk/didsdk.dart';
var token = "";
late Account account;
Didsdk.getOTPAPI().getChallengeQuestionOtp(account, "My custom response")
.then((value) {
setState(() => token = value);
}).catchError((error) {
var errorDescription = "";
if (error is AppgateSDKError) {
errorDescription = "${error.code} ${error.message}";
}
print(errorDescription);
});
Push notifications are designed to establish a secure channel of communication between the server and the mobile client, facilitating prompt authentication, rejection, or authorization of critical transactions.
These steps must be completed with platform-specific implementation to enable the features that use push notifications such as Push Authentication and Push Alerts.
- Add the Push Notifications Capability.
Note On Android, the plugin is compatible with Firebase and HUAWEI Mobile Services, for the correct operation it is necessary to configure the service provider which is mentioned in the file PUSHSERVICE.md
Go to yourapp/android/app/kotlin or java/yourpackage/MainActivity
and change the extends from FlutterActivity to DIDMainActivity, you can modify the following line of code:
From:
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {}
To:
import com.appgate.didsdk.DIDMainActivity
class MainActivity : DIDMainActivity() {}
In your app go to android/build.gradle
dependencies {
classpath 'com.google.gms:google-services:4.3.15'
}
In your app go to android/app/build.gradle and initial block add this line:
apply plugin: 'com.google.gms.google-services'
Then, in your dependencies block to build.gradle add this line:
implementation 'com.google.firebase:firebase-messaging:23.1.2'
Add your google-service.json to android/app/
Create a service class that extends FirebaseMessagingService and override the following methods:
import com.appgate.appgate_sdk.data.device.provider.PushNotificationProvider
import com.appgate.didsdk.DIDFCMService
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val data: Map<String, String> = remoteMessage.data
DIDFCMService(applicationContext).onMessageReceived(data)
}
override fun onNewToken(newToken: String) {
super.onNewToken(newToken)
DIDFCMService(applicationContext).onNewToken(newToken, PushNotificationProvider.FIREBASE)
}
}
In this class, you can implement the necessary code to handle incoming messages in the onMessageReceived method, and handle token refresh in the onNewToken method.
in your app go to AndroidManifest.xml declare you service firebase, here is an example
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Add to your MainActivity to override the getTokenFirebase method to update the token on application startup.
import android.text.TextUtils
import com.appgate.appgate_sdk.data.device.provider.PushNotificationProvider
import com.appgate.didm_auth.DetectID
import com.appgate.didsdk.DIDMainActivity
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
class MainActivity : DIDMainActivity() {
override fun getTokenFirebase() {
FirebaseMessaging.getInstance().isAutoInitEnabled = true
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
return@OnCompleteListener
}
// Get new FCM registration token
val token = task.result
if (!TextUtils.isEmpty(token)) {
DetectID.sdk(activity).receivePushServiceId(token, PushNotificationProvider.FIREBASE)
}
return@OnCompleteListener
})
}
}
Configure the Maven address of and build dependencies for the AppGallery Connect SDK:
In your app go to android/build.gradle
allprojects {
repositories {
// Add the Maven address.
maven {url 'https://developer.huawei.com/repo/'}
}
}
...
buildscript{
repositories {
// Add the Maven address.
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
// Add dependencies.
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
}
}
Then go to android/app/build.gradle and initial block add this line:
apply plugin: 'com.huawei.agconnect'
In your dependencies block to build.gradle add this line:
implementation 'com.huawei.agconnect:agconnect-core:1.5.2.300'
Add your agconnect-services.json to android/app/
You can create a service class that extends HmsMessageService and override the following methods:
import com.appgate.appgate_sdk.data.device.provider.PushNotificationProvider
import com.appgate.didsdk.DIDFCMService
import com.huawei.hms.push.HmsMessageService
import com.huawei.hms.push.RemoteMessage
class MyHMSService: HmsMessageService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val data: Map<String, String> = remoteMessage.dataOfMap
DIDFCMService(applicationContext).onMessageReceived(data)
}
override fun onNewToken(newToken: String) {
super.onNewToken(newToken)
DIDFCMService(applicationContext).onNewToken(newToken, PushNotificationProvider.HUAWEI)
}
}
In this class, you can implement the necessary code to handle incoming messages in the onMessageReceived method, and handle token refresh in the onNewToken method.
Then in your app go to AndroidManifest.xml declare you service firebase, here is an example:
<service
android:name=".MyHMSService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
Add to your MainActivity to override the getTokenHMS method to update the token on application startup.
import android.text.TextUtils
import android.util.Log
import com.appgate.appgate_sdk.data.device.provider.PushNotificationProvider
import com.appgate.didm_auth.DetectID
import com.appgate.didsdk.DIDMainActivity
import com.huawei.hms.aaid.HmsInstanceId
import com.huawei.hms.common.ApiException
import com.huawei.hms.push.HmsMessaging
class MainActivity : DIDMainActivity() {
override fun getTokenHMS() {
HmsMessaging.getInstance(this).isAutoInitEnabled = true
object : Thread() {
override fun run() {
try {
// Obtain the app ID from the agconnect-service.json file.
val appId = "your-ID"
// Set tokenScope to HCM.
val tokenScope = "HCM"
val token = HmsInstanceId.getInstance(activity).getToken(appId, tokenScope)
// Check whether the token is empty.
if (!TextUtils.isEmpty(token)) {
DetectID.sdk(activity).receivePushServiceId(token, PushNotificationProvider.HUAWEI)
}
} catch (e: ApiException) {
Log.e(TAG, "get token failed, $e")
}
}
}.start()
}
}
In your initial view, request permission to push Android:
Future<void> requestPermission() async {
if (Platform.isAndroid) {
var status = await Permission.notification.status;
if (status.isDenied) {
Map<Permission, PermissionStatus> statuses = await [
Permission.notification,
].request();
print(statuses[Permission.notification]);
}
}
}
Note For more information: https://pub.dev/packages/permission_handler
DetectID SDK offers a push authentication service that sends a push message to the user. This push message allows the user to either accept or cancel transactions through the user’s mobile device. This push message is sent by the server through a push messaging channel and received by the SDK inside the app. This means that to accept a transaction, it would be necessary to have both the user’s static PIN or password and the user’s unlocked device with the app.
In the main.dart
file or where the initial logic of your application has been placed, implement the following subscription:
Stream<TransactionInfo>
Code | Description |
---|---|
85 | Ungranted push notifications permission. |
86 | Invalid APNS Environment. |
These errors are specifically handled for iOS devices.
import 'package:didsdk/didsdk.dart';
Didsdk.getPushAPI().setPushTransactionOpenListener()
.then((stream) {
if(stream is Stream<TransactionInfo>) {
stream.listen((transaction) {
// Present the view to show the TransactionInfo
});
}
}).catchError((error) {
if(error is AppgateSDKError) {
var err = "${error.code} - ${error.message}";
print(err);
}
});
DetectID offers the possibility of sending interactive push transaction messages to the user. These push transaction messages allow the user to accept or reject transactions through their mobile device. The following lines of code can be used to implement this feature after processing a received transaction in the previous listener.
- TransactionInfo: Represents the pending transaction.
Future<void>
Code | Description |
---|---|
96 | Invalid parameter. |
98 | Error parameter missing. |
99 | Service error - Wrong data received. |
1001 | Authentication factor not enabled. |
1002 | Not available - Transaction with different state from pending. |
1012 | Expired Transaction. |
1021 | Client blocked by Admin - User Manually Blocked by Administrator. |
1022 | Client blocked by System - User Blocked by System for Exceeding Retires. |
import 'package:didsdk/didsdk.dart';
var TransactionInfo? transaction;
Didsdk.getPushAPI()
.confirmPushTransactionAction(transaction)
.then((_) {
// Confirmed transaction
})
.catchError((error) {
if(error is AppgateSDKError) {
var err = "${error.code} - ${error.message}";
print(err);
}
});
Didsdk.getPushAPI()
.declinePushTransactionAction(transaction)
.then((_) {
// Declined transaction
})
.catchError((error) {
if(error is AppgateSDKError) {
var err = "${error.code} - ${error.message}";
print(err);
}
});
DetectID offers the possibility of sending informative push messages to the user. Push Alerts accomplish a different function to Push Transaction messages, since push alerts only inform the user about something and only allow them to accept and close the alert once the message is received.
In the main.dart
file or where the initial logic of your application has been placed, implement the following subscription:
Stream<TransactionInfo>
Code | Description |
---|---|
85 | Ungranted push notifications permission. |
86 | Invalid APNS Environment. |
Warning These errors are specifically handled for iOS devices.
import 'package:didsdk/didsdk.dart';
Didsdk.getPushAPI().setPushAlertOpenListener()
.then((stream) {
if(stream is Stream<TransactionInfo>) {
stream.listen((transaction) {
// Present the view to show the TransactionInfo
});
}
}).catchError((error) {
if(error is AppgateSDKError) {
var err = "${error.code} - ${error.message}";
print(err);
}
});
This method is useful to implement a response sent to the Server that the Push Alert transaction has been approved.
- TransactionInfo: Represents the received alert.
void
import 'package:didsdk/didsdk.dart';
var TransactionInfo? transaction;
Didsdk.getPushAPI().approvePushAlertAction(transaction);
The current wrapper was built to handle all push notifications through the DID library. However, it is possible to customize certain settings to enable the integration of multiple Push Notification providers. To set up a different provider for each platform, please follow the steps outlined below:
- Disable automatic subscription. Open the SwiftPushPlugin.swift file within the wrapper and remove the following line located in the
application(:didFinishLaunchingWithOptions:)
method.
// Remove the following line:
// registerForRemoteNotifications()
This action will eliminate the request for Push permission during the initial execution of your app.
- As a result, you will need to create the subscription within the app itself. Implement the following code:
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
//...
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { granted, error in
if granted {
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
} else {
// TODO: Handle the rejection of push notifications permission
}
}
//...
}
//...
}
- Next, you need to override the following methods in the
AppDelegate
:
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
super.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler)
(DetectID.sdk() as? DetectID)?.subscribePayload(notification, withCompletionHandler: completionHandler)
// Add your custom implementation code here
}
override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
super.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
(DetectID.sdk() as? DetectID)?.handleAction(withIdentifier: response)
// Add your custom implementation code here
}
Implementing these 2 calls (subscribePayload()
and handleAction()
) will make sure that DID notifications can be handled correctly.
- And finally if you want to access the device token, override the following method:
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
// Add your custom implementation code here
}
Do never miss the super
call, to ensure that the Plugin has access to the token and the push notifications payloads too.