Device Security (Flutter)
Overview
Device Security's SDK is used to perform a number of checks on the target device inclusive of checks for whether or not the device is rooted/jailbroken, using a VPN ....
Minimum Requirements
iOS: 11.0
Android: API level 21
Installation
Installation of Device Security's SDK in flutter requires using the native SDK's for Android and iOS, and the use of Method Channels to utilize the SDK's functions.
iOS
Android
There are a few steps to getting started:
- Import the SDK aars into your project
- Create a folder inside
android/app
called libs - copy sdk files inside the libs folder
- Create a folder inside
- Depend on SDK
- in your app level build.gradle
(android/app/build.gradle)
add implementation statements for the SDKs.
- in your app level build.gradle
android {
// ...
}
flutter {
// ...
}
dependencies {
// ...
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/TMXAuthentication-rl-7.0-60.aar')
implementation files('libs/TMXBehavioSec-rl-7.0-60.aar')
implementation files('libs/TMXDeviceSecurityHealth-rl-7.0-60.aar')
implementation files('libs/TMXProfilingConnections-rl-7.0-60.aar')
implementation files('libs/TMXProfiling-rl-7.0-60.aar')
// ...
}
Code Implementation
After importing the library and frameworks on both android and iOS respectively we then must implement our method channel code.
Dart Implementation
We first need to setup our method channel. For this example we'll be using Getx for state management and placing our business logic code inside a class called Device Security Controller.
First let's create our class and create our method channel and supply it with a string. This string is important as it is used in the native code later to set up communication between the dart, java/kotlin and swift code.
class DeviceSecurityController extends GetxController{
MethodChannel functionChannel = MethodChannel("com.example.function");
}
Next let's write a function to start the device security code in dart that will then communicate with the native code.
startDeviceSecurity() async {
await functionChannel.invokeMethod("startDeviceSecurityCheck");
}
Now the last thing we need is some code that is triggered once the checks are completed
void handleMethodChannelCallback(){
functionChannel.setMethodCallHandler((call) async {
if (call.method == "reportStatusTmx" && call.arguments != null) {
// save the apSession to send to AwareID
} else {
// Throw some error
}
}
}
}
Please note that you must set your method call handler (see in the above code) by calling the handleMethodChannelCallback() before calling startDeviceSecurity().
We do this at the initialization of our class and calling startDeviceSecurity when the state is ready.
Put together our class now looks like:
class DeviceSecurityController extends GetxController{
MethodChannel functionChannel = MethodChannel("com.example.function");
@override
void onInit() {
handleMethodChannelCallback()
super.onInit();
}
@override
void onReady() {
startDeviceSecurity()
super.onReady();
}
void handleMethodChannelCallback(){
functionChannel.setMethodCallHandler((call) async {
if (call.method == "reportStatusTmx" && call.arguments != null) {
// save the apSession to send to AwareID
} else {
// Throw some error
}
}
}
}
startDeviceSecurity() async {
await functionChannel.invokeMethod("startDeviceSecurityCheck");
}
}
Swift Implementation
Let's first create a class to configure our SDK
import Foundation
import RLTMXProfiling
import RLTMXProfilingConnections
public class DeviceSecurityManager {
static let shared = DeviceSecurityManager()
private var profile: AnyObject?
private var sessionID: String?
private init() {}
func getDeviceSecuritySessionId(completion: @escaping (String?) -> Void) {
let profilingConnections = RLTMXProfilingConnections()
profilingConnections.connectionTimeout = // Timeout in seconds
profilingConnections.connectionRetryCount = // Number of retries if connection fails
profile = RLTMXProfiling.sharedInstance()
profile?.configure(configData: [
RLTMXOrgID: // Please contact Aware for your OrgID ,
RLTMXFingerprintServer: "content.maxconnector.com",
RLTMXProfileTimeout: profilingConnections.connectionTimeout,
RLTMXProfilingConnectionsInstance: profilingConnections
])
_ = profile?.profileDevice { result in
guard let results = result else {
completion(nil)
return
}
let status = RLTMXStatusCode(rawValue: (results[RLTMXProfileStatus] as! NSNumber).intValue)!
if status == .ok, let sessionID = results[RLTMXSessionID] as? String {
self.sessionID = sessionID
completion(sessionID)
} else {
completion(nil)
}
}
}
}
Now we can use this class in our app delegate to allow calls into it using our Method Channel.
First we need to make a variable for our method channel
var functionChannel: FlutterMethodChannel?
We also need to use the DispatchQueue in our main function as well as setting the name of our method channel and setting up the call handler
DispatchQueue.main.async {
let controller: FlutterViewController = self.window?.rootViewController as! FlutterViewController
self.functionChannel = FlutterMethodChannel(name: "com.aware.function", binaryMessenger: controller.binaryMessenger)
self.functionChannel?.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult)-> Void in
switch call.method{
case "startDeviceSecurityCheck":
DeviceSecurityManager.shared.getDeviceSecuritySessionId { sessionId in
DispatchQueue.main.async {
if let sessionId = sessionId {
// Reporting back the session ID
self.functionChannel?.invokeMethod("startDeviceSecurityCheck", arguments: sessionId)
result(true) // Indicating the process completion
} else {
//Pass back an error incase the session ID is null
}
}
}
}
Example in Dart using device security
After all this set up then we can use our session id to send to the backend to complete our transaction.
You can find documentation on how to complete this here