Ionic mobile integration
The page provides step-by-step integration instructions for embedding Risk Management in an ionic application:
Cross-platform frameworks
This section tells you how to integrate Risk Management SDK using cross-platform frameworks.
Cordova
Cordova is an open-source framework for building mobile applications using HTML5, CSS3, and JavaScript. There's one code base for multiple platforms (Android, iOS, Windows Phone).
It allows you to access native device features using JavaScript - Cordova plugins (Camera, NFC, Bluetooth, GPS and so on) and is typically used in combination with a UI framework.
Ionic
Ionic is built on top of Cordova. It is a front-end, mobile-optimized library and UI framework that can be used to make your Cordova app look native.
Ionic apps are created and developed primarily through the Ionic command line utility (CLI), and use Cordova to build and deploy as a native app. This means you need to install a few utilities to start developing.

Set up your environment
This code lab was tested with following versions:
- Node.js 14.16.0
- Ionic 5.4.16
- Cordova 10.0.0
- Cordova-res 0.15.3
- Risk Management SDK 2.7.0
- macOS 10.15.7
- Xcode 12.4
Go to https://nodejs.org/en/ and download the latest version of Node.js (JavaScript runtime built on Chrome's V8 JavaScript engine).
After installation, you can run the following command line commands:
>> node -v
v14.16.0
>> npm -v
7.6.3
# install Ionic latest 5.x version
>> npm install -g ionic@"<6.0.0"
>> ionic -v
5.4.16
# install Cordova
>> npm install -g cordova@10.0.0
>> cordova -v
10.0.0
>> npm install -g cordova-res
On macOS you can use homebrew to install node and then ionic and cordova.
# install homebrew Homebrew 3.0.0
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew --version
Homebrew 3.2.0-61-gaa14e48
Homebrew/homebrew-core (git revision 8d0a4388c3; last commit 2021-06-28)
Homebrew/homebrew-cask (git revision 96ae460e46; last commit 2021-06-28)
# install Node.js
$ brew install node@14
$ node -v
v14.17.1
# install Cordova
$ npm install -g cordova@10.0.0
$ cordova -v
10.0.0
$ npm install -g cordova-res
# install Ionic
$ npm install -g ionic@"<6.0.0"
$ ionic -v
5.4.16
Create the Cordova plugin
This section provides instructions for creating the native Android or iOS part of the Cordova plugin:
A Cordova plugin is a bit of add-on code that provides a JavaScript interface to native components. It allows your app to use native device capabilities beyond what is available to pure web apps. See the existing Cordova plugins.
To use the Risk Management SDK in an Ionic project, you first need to create a Cordova plugin, which wraps the SDK.
Create the file structure
To create a Cordova plugin, create the following file structure in any location in your file system:
plugin.xmlis the main configuration file for the plugin.package.jsonis a Node.js project description and dependencies.srcis the source code directory for the native Android and iOS platforms.wwwis the javascript API directory.
Create the plugin summary
Edit the package.json file with the plugin summary.
{
"version": "0.0.1",
"name": "gahplugin",
"cordova_name": "GahPlugin",
"description": "GAH plugin",
"license": "Copyright (c) THALES DEVELOPMENT",
"author": {
"name": "Author",
"email": "author@email.com"
},
"keywords": [
"GAH",
"plugin"
]
}
Create the JavaScript API
The JavaScript API available for the developer integrating the plug-in is available in www/GahPlugin.js.
Create this file and add all the APIs that you need in our application to this file.
var exec = require('cordova/exec');
var PLUGIN_NAME = 'GahPlugin';
function GahPlugin() {
}
/**
* Initializes GAH SDK.
*
* @param gahUrl GAH signal collector backend URL.
* @param tmxOrgId Thread matrix organization id.
* @param tmxFpServerUrl Thread matrix server URL.
* @param callback Success callback.
* @param errorCallback Error callback.
*/
GahPlugin.prototype.initialize = function (gahUrl, tmxOrgId, tmxFpServerUrl, callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'initialize', [gahUrl, tmxOrgId, tmxFpServerUrl]);
};
/**
* Retrieves the visit id.
*
* @param callback Success callback.
* @param errorCallback Error callback.
*/
GahPlugin.prototype.getVisiId = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'visitId', []);
};
/**
* Starts prefetch of data, caches signals. Call on applicaiton start, after GAH has been initialized
*/
GahPlugin.prototype.startPrefetch = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'startPrefetch', []);
};
/**
* Stops prefetch of data. Call before application end, or when GAH will not be further used.
*/
GahPlugin.prototype.stopPrefetch = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'stopPrefetch', []);
};
/**
* Clears the transaction resources. Call after each transaction (login, transfer funds etc.).
*/
GahPlugin.prototype.clearTransaction = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'clearTransaction', []);
};
/**
* Checks if signal collection is completed. Needs to be called before {@code getVisiId},
* to check if all signals are collected
*/
GahPlugin.prototype.isSignalCollectionCompleted = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'isSignalCollectionCompleted', []);
};
/**
* Sets the transaction as critical(high value trasfer etc.).
*/
GahPlugin.prototype.setTransactionAsCritical = function (callback, errorCallback) {
exec(callback, errorCallback, PLUGIN_NAME, 'setTransactionAsCritical', []);
};
var gahPlugin = new GahPlugin();
module.exports = gahPlugin;
All the files for the Android native part need to be placed in the src/android folder. The Android native part consists of the following files:
- Java source code
- Risk Management SDK (JAR file and native libraries)
- gradle build file
Java source code
The Java source code needed in the plugin is divided into two classes:
-
src/android/GahPlugin.javais the main entry point in the Android native part.package com.gemalto.plugin.gah; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.json.JSONArray; import org.json.JSONException; /** * GAH plugin wrapping the GAH SDK. */ public class GahPlugin extends CordovaPlugin { private GAHRiskEngineIntegration mEngineIntegration; /** * {@inheritDoc} */ @Override protected void pluginInitialize() { super.pluginInitialize(); mEngineIntegration = new GAHRiskEngineIntegration(cordova.getActivity().getApplicationContext()); } /** * {@inheritDoc} */ @Override public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext) throws JSONException { if (action.equals("initialize")) { final String gahUrl = data.getString(0); final String tmxOrgId = data.getString(1); final String tmxFpServerUrl = data.getString(2); if (gahUrl == null || gahUrl.isEmpty()) { callbackContext.error("Missing mandatory parameter: GAH URL"); return false; } mEngineIntegration.initializeGAH(gahUrl, tmxOrgId, tmxFpServerUrl); callbackContext.success("initialization ok"); } else if (action.equals("visitId")) { mEngineIntegration.requestVisitId(callbackContext); } else if (action.equals("startPrefetch")) { mEngineIntegration.startPrefetchCollection(); } else if (action.equals("stopPrefetch")) { mEngineIntegration.stopPrefetchCollection(); return true; } else if (action.equals("clearTransaction")) { mEngineIntegration.clearTransactionData(); return true; } else if (action.equals("isSignalCollectionCompleted")) { mEngineIntegration.isSignalCollectionCompleted(callbackContext); return true; } else if (action.equals("setTransactionAsCritical")) { mEngineIntegration.setTransactionAsCritical(); } else { callbackContext.error("undefined action"); return false; } return true; } } -
src/android/GAHRiskEngineIntegration.javais a helper classpackage com.gemalto.plugin.gah; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.Log; import com.gemalto.riskengine.GAHBSecConfig; import com.gemalto.riskengine.GAHCore; import com.gemalto.riskengine.GAHCoreConfig; import com.gemalto.riskengine.GAHGemaltoSignalConfig; import com.gemalto.riskengine.GAHPrefetchStatusCallback; import com.gemalto.riskengine.GAHResponseCallback; import com.gemalto.riskengine.GAHSignalGroupConstants; import com.gemalto.riskengine.GAHTMXConfig; import org.apache.cordova.CallbackContext; /** * This class is holding business logic to communicate with GAHRiskEngine * It initiates the App backend server call post getting response from GAHRiskEngine */ public class GAHRiskEngineIntegration { private static final String TAG = GAHRiskEngineIntegration.class.getSimpleName(); private final Context mContext; public GAHRiskEngineIntegration(@NonNull final Context context) { mContext = context; } /** * Initializes the GAH SDK. * * @param url * GAH back end url. * @param tmxOrgId * Thread Matrix SDK organization id. * @param tmxFpServerUrl * Thread Matrix SDK server url. */ public void initializeGAH(@NonNull final String url, @Nullable final String tmxOrgId, @Nullable final String tmxFpServerUrl) { final GAHCoreConfig coreConfig = new GAHCoreConfig.Builder(mContext, url).build(); final GAHGemaltoSignalConfig signalConfig = new GAHGemaltoSignalConfig.Builder().build(); final GAHBSecConfig gahbSecConfig = new GAHBSecConfig.Builder().build(); if ((tmxOrgId != null && !tmxOrgId.isEmpty()) && (tmxFpServerUrl != null && !tmxFpServerUrl.isEmpty())) { final GAHTMXConfig threatMetrixConfig = new GAHTMXConfig.Builder(mContext, tmxOrgId, tmxFpServerUrl) .build(); GAHCore.initialize(coreConfig, signalConfig, threatMetrixConfig); } else { GAHCore.initialize(coreConfig, signalConfig); } } /** * Initiates pre-fetching of signals from all providers before the actual signal collection * This enhances the signal collection time during the actual login */ public void startPrefetchCollection() { GAHCore.startPrefetchSignals(); } /** * Requests the Visit ID value from GAHRiskEngine. * * @param callbackContext * Callback back to javascript. */ public void requestVisitId(@NonNull final CallbackContext callbackContext) { GAHCore.requestVisitID(new GAHResponseCallback() { @Override public void success(final String visitId) { Log.d("******1", "Success Callback from RESDK after getting visitID, visit id:" + visitId); callbackContext.success(visitId); } @Override public void error(final int errorCode, final String errorMessage) { clearTransactionData(); callbackContext.error("Error message: " + errorMessage + " error code: " + errorCode); } }); } /** * Checks if signal collection is completed. * * @param callbackContext * Callback back to javascript. */ public void isSignalCollectionCompleted(@NonNull final CallbackContext callbackContext) { GAHCore.requestPrefetchStatus(new GAHPrefetchStatusCallback() { @Override public void onPrefetchCompleted(final int statusCode, final String message) { if (statusCode == 2100) { callbackContext.success(message); } else { callbackContext.error(message); } } }); } /** * Clears transaction data after every transaction */ public void clearTransactionData() { GAHCore.clearTransactionResources(); } /** * Stops pre-fetching of signals */ public void stopPrefetchCollection() { GAHCore.stopPrefetchSignals(); } /** * Sets the transaction as critical. */ public void setTransactionAsCritical() { GAHCore.setTransactionAsCritical(); } }
Add Risk Management SDK
-
Copy the debug and release libraries into src/android/libs.
-
Copy the 3pty folder in the release package into src/android/libs.
Create the Gradle file
Create the gradle file, which is then merged into the main build.gradle file of the generated Android Studio project.
src/android/gahBuild.gradle
android {
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
}
sourceSets {
main {
debug {
jniLibs.srcDirs += "src/main/libs/debug"
}
release {
jniLibs.srcDirs += "src/main/libs/release"
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "androidx.appcompat:appcompat:1.3.0"
// FPP SDK
debugImplementation files("src/main/libs/debug/GAHRiskEngine.jar")
releaseImplementation files("src/main/libs/release/GAHRiskEngine.jar")
implementation files("src/main/libs/3pty/TMXProfilingConnections-6.2-97.aar")
// 3rd party dependencies
implementation "net.java.dev.jna:jna:5.5.0@aar"
//region Extra dependency for BehavioSec
// Play Services for Activity Recognition
implementation "com.google.android.gms:play-services-location:18.0.0"
// SafetyNet for list of harmful apps
implementation "com.google.android.gms:play-services-safetynet:17.0.0"
// RootBeer lib for root detection
implementation "com.scottyab:rootbeer-lib:0.0.8"
//endregion
}
Update the main plugin.xml file
After you add all the necessary files for the Android platform, update the plugin.xml file.
<?xml version='1.0' encoding='utf-8'?>
<plugin id="com.gemalto.plugin.gah" version="0.2" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>GahPlugin</name>
<js-module name="GahPlugin" src="www/GahPlugin.js">
<clobbers target="GahPlugin" />
</js-module>
<!-- ios -->
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="GahPlugin">
<param name="ios-package" value="GahPlugin"/>
</feature>
</config-file>
<config-file parent="NSLocationWhenInUseUsageDescription" target="*-Info.plist">
<string>required this permission</string>
</config-file>
<!-- Objective-C source code -->
<header-file src="src/ios/GahPlugin.h"/>
<source-file src="src/ios/GahPlugin.m"/>
<header-file src="src/ios/GAHRiskEngineIntegration.h"/>
<source-file src="src/ios/GAHRiskEngineIntegration.m"/>
<!-- FPP SDK libraries -->
<framework src="src/ios/libs/debug/GAHRiskEngine.framework" embed="false" custom="true"/>
<framework src="src/ios/libs/debug/ZDetection.framework" embed="true" custom="true"/>
<framework src="src/ios/libs/debug/TrustDefender.framework" embed="true" custom="true"/>
<!-- <framework src="src/ios/libs/release/GAHRiskEngine.framework" embed="false" custom="true"/> -->
</platform>
<!-- android -->
<platform name="android">
<!-- android permissions -->
<config-file target="AndroidManifest.xml" parent="/manifest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<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_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--Required in Android 9 and above-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
</config-file>
<config-file target="res/xml/config.xml" parent="/*">
<feature name="GahPlugin" >
<param name="android-package" value="com.gemalto.plugin.gah.GahPlugin"/>
</feature>
</config-file>
<!-- java source code -->
<source-file src="src/android/GahPlugin.java" target-dir="src/com/gemalto/plugin/gah" />
<source-file src="src/android/GAHRiskEngineIntegration.java" target-dir="src/com/gemalto/plugin/gah" />
<!-- gradle file -->
<framework src="src/android/gahBuild.gradle" custom="true" type="gradleReference" />
<!-- FPP SDK files -->
<resource-file src="src/android/libs/debug/GAHRiskEngine.jar" target="libs/debug/GAHRiskEngine.jar" />
<resource-file src="src/android/libs/release/GAHRiskEngine.jar" target="libs/release/GAHRiskEngine.jar" />
<resource-file src="src/android/libs/3pty/TMXProfilingConnections-6.2-97.aar" target="libs/3pty/TMXProfilingConnections-6.2-97.aar" />
<!-- FPP SDK native libraries -->
<resource-file src="src/android/libs/debug/arm64-v8a/libmedlc_shared.so" target="libs/debug/arm64-v8a/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/arm64-v8a/libmedlc_shared.so" target="libs/release/arm64-v8a/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/arm64-v8a/libTMXProfiling-6.2-97-jni.so" target="libs/debug/arm64-v8a/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/release/arm64-v8a/libTMXProfiling-6.2-97-jni.so" target="libs/release/arm64-v8a/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/debug/armeabi-v7a/libmedlc_shared.so" target="libs/debug/armeabi-v7a/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/armeabi-v7a/libmedlc_shared.so" target="libs/release/armeabi-v7a/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/armeabi-v7a/libTMXProfiling-6.2-97-jni.so" target="libs/debug/armeabi-v7a/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/release/armeabi-v7a/libTMXProfiling-6.2-97-jni.so" target="libs/release/armeabi-v7a/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/debug/x86/libmedlc_shared.so" target="libs/debug/x86/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/x86/libmedlc_shared.so" target="libs/release/x86/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/x86/libTMXProfiling-6.2-97-jni.so" target="libs/debug/x86/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/release/x86/libTMXProfiling-6.2-97-jni.so" target="libs/release/x86/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/debug/x86_64/libmedlc_shared.so" target="libs/debug/x86_64/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/x86_64/libmedlc_shared.so" target="libs/release/x86_64/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/x86_64/libTMXProfiling-6.2-97-jni.so" target="libs/debug/x86_64/libTMXProfiling-6.2-97-jni.so" />
<resource-file src="src/android/libs/release/x86_64/libTMXProfiling-6.2-97-jni.so" target="libs/release/x86_64/libTMXProfiling-6.2-97-jni.so" />
</platform>
</plugin>
All the files for the iOS native part need to be placed in the src/ios folder. The iOS native part consists of the following files:
-
Objective-C source code
-
Fraud prevention SDK (iOS Framework)
Objective-C source code
The Objective-C source code needed in the plug-in is divided into two classes:
-
src/ios/GahPlugin.hwhich is the main entry point in the iOS native part.#import <Cordova/CDVPlugin.h> /** * GAH cordova plugin wrapping the GAH SDK. */ @interface GahPlugin : CDVPlugin /** * Initializes GAH SDK. */ - (void)initialize:(CDVInvokedUrlCommand*)command; /** * Retrieves the visit id. */ - (void)visitId:(CDVInvokedUrlCommand*)command; /** * Starts prefetch of data, caches signals. Call on applicaiton start, after GAH has been initialized. */ - (void)startPrefetch:(CDVInvokedUrlCommand*)command; /** * Stops prefetch of data. Call before application end, or when GAH will not be further used. */ - (void)stopPrefetch:(CDVInvokedUrlCommand*)command; /** * Clears the transaction resources. Call after each transaction (login, transfer funds etc.). */ - (void)clearTransaction:(CDVInvokedUrlCommand*)command; /** * Checks if signal collection is completed. Needs to be called before {@code getVisiId}, * to check if all signals are collected. */ - (void)isSignalCollectionCompleted:(CDVInvokedUrlCommand*)command; /** * Sets the transaction as critical(high value trasfer etc.). */ - (void)setTransactionAsCritical:(CDVInvokedUrlCommand*)command; @end -
src/ios/GahPlugin.m#import "GahPlugin.h" #import "GAHRiskEngineIntegration.h" @interface GahPlugin() @property(nonatomic, strong) GAHRiskEngineIntegration* integrationEngine; @end @implementation GahPlugin #pragma mark override - (void)pluginInitialize { self.integrationEngine = [[GAHRiskEngineIntegration alloc] init]; } #pragma mark public - (void)initialize:(CDVInvokedUrlCommand*)command { NSString* gahUrl = (NSString*)[command.arguments objectAtIndex:0]; NSString* tmxOrgId = (NSString*)[command.arguments objectAtIndex:1]; NSString* tmxFpServerUrl = (NSString*)[command.arguments objectAtIndex:2]; if (gahUrl == nil || gahUrl.length == 0) { CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Missing mandatory parameter: GAH URL"]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; } [_integrationEngine initializeGAH:gahUrl tmxOrgId:tmxOrgId tmxFpServerUrl:tmxFpServerUrl]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Initialization ok"]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; } - (void)visitId:(CDVInvokedUrlCommand*)command { [_integrationEngine requestVisitID:self.commandDelegate callbackId:command.callbackId]; } - (void)startPrefetch:(CDVInvokedUrlCommand*)command { [_integrationEngine startPrefetchingCollection]; } - (void)stopPrefetch:(CDVInvokedUrlCommand*)command { [_integrationEngine stopPrefetchingCollection]; } - (void)clearTransaction:(CDVInvokedUrlCommand*)command { [_integrationEngine clearResources]; } - (void)isSignalCollectionCompleted:(CDVInvokedUrlCommand*)command { [_integrationEngine isSignalCollectionCompleted:self.commandDelegate callbackId:command.callbackId]; } - (void)setTransactionAsCritical:(CDVInvokedUrlCommand*)command { [_integrationEngine setTransactionAsCritical]; } @end -
src/ios/GAHRiskEngineIntegration.h* which is a helper class#import <Foundation/Foundation.h> #import <GAHRiskEngine/GAHRiskEngine.h> #import <GAHRiskEngine/GAHGemaltoSignalConfig.h> #import <GAHRiskEngine/BehavioSecIOSSDK.h> #import <Cordova/CDVPlugin.h> /** * This class is holding business logic to communicate with GAHRiskEngine * It initiates the App backend server call post getting response from GAHRiskEngine */ @interface GAHRiskEngineIntegration : NSObject /** * Initializes the GAH SDK. * * @param url * GAH back end url. * @param tmxOrgId * Thread Matrix SDK organization id. * @param tmxFpServerUrl * Thread Matrix SDK server url. */ - (void) initializeGAH: (NSString*) url tmxOrgId:(NSString*) tmxOrgId tmxFpServerUrl:(NSString*) tmxFpServerUrl; /** * Clears transaction data after every transaction */ -(void)clearResources; /*! * startPrefetchingCollections - Starts all provider signal collection prefetch */ - (void)startPrefetchingCollection; /** * Stops pre-fetching of signals */ - (void)stopPrefetchingCollection; /** * Requests the Visit ID value from GAHRiskEngine. * * @param delegate * Callback back to javascript. * @param callbackId Callback id. */ -(void)requestVisitID:(id <CDVCommandDelegate>) delegate callbackId:(NSString*) callbackId; /** * Sets the transaction as critical. */ - (void)setTransactionAsCritical; /** * Checks if signal collection is completed. * * @param delegate * Callback back to javascript. * @param callbackId Callback id. */ - (void)isSignalCollectionCompleted:(id <CDVCommandDelegate>) delegate callbackId:(NSString*) callbackId; @end -
src/ios/GAHRiskEngineIntegration.m#import "GAHRiskEngineIntegration.h" #import <GAHRiskEngine/GAHRiskEngine.h> #import <GAHRiskEngine/GAHCoreConfig.h> #import <GAHRiskEngine/GAHGemaltoSignalConfig.h> #import <GAHRiskEngine/GAHBSecConfig.h> #import <GAHRiskEngine/GAHTMXConfig.h> #import <GAHRiskEngine/GAHSignalGroupConstants.h> @implementation GAHRiskEngineIntegration - (void) initializeGAH: (NSString*) url tmxOrgId:(NSString*) tmxOrgId tmxFpServerUrl:(NSString*) tmxFpServerUrl { GAHCoreConfig * reConfig = [GAHCoreConfig sharedConfigurationWithUrl:url]; GAHGemaltoSignalConfig *signalConfig = [GAHGemaltoSignalConfig sharedConfiguration]; GAHBSecConfig * bsecConfig = [GAHBSecConfig sharedConfiguration]; NSSet* configObejcts; if ((tmxOrgId != nil && tmxOrgId.length > 0) && ((tmxFpServerUrl != nil && tmxFpServerUrl.length > 0))) { GAHTMXConfig * tmxConfig = [GAHTMXConfig sharedConfigurationWithOrgID:tmxOrgId andFingerprintServer:tmxFpServerUrl]; configObejcts = [NSSet setWithObjects:reConfig,signalConfig,bsecConfig,tmxConfig, nil]; } else { configObejcts = [NSSet setWithObjects:reConfig,signalConfig,bsecConfig, nil]; } [GAHCore initialize:configObejcts]; } -(void)requestVisitID:(id <CDVCommandDelegate>) delegate callbackId:(NSString*) callbackId { [GAHCore requestVisitID:^(NSString *visitID) { CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:visitID]; [delegate sendPluginResult:result callbackId:callbackId]; } failure:^(NSInteger errorCode, NSString *errorMessage) { NSString* error = [NSString stringWithFormat:@"Error message: %@, error code: %lu", errorMessage, (long) errorCode]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error]; [delegate sendPluginResult:result callbackId:callbackId]; }]; } - (void)startPrefetchingCollection { [GAHCore startPrefetchSignals]; } - (void)stopPrefetchingCollection { [GAHCore stopPrefetchSignals]; } - (void)setTransactionAsCritical { [GAHCore setTransactionAsCritical]; } - (void)isSignalCollectionCompleted:(id <CDVCommandDelegate>) delegate callbackId:(NSString*) callbackId { [GAHCore requestPrefetchStatus:^(NSInteger statusCode, NSString *statusMessage) { if (statusCode == 2100) { CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:statusMessage]; [delegate sendPluginResult:result callbackId:callbackId]; } else { CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:statusMessage]; [delegate sendPluginResult:result callbackId:callbackId]; } }]; } -( void)clearResources { [GAHCore clearTransactionResources]; } ` @end
Add Risk Management SDK
Copy the debug and release libraries into src/ios/libs/debug/ and src/ios/libs/release/.
Update the main plugin.xml file
After you add all the necessary files for the iOS platform, update the plugin.xml file.
<?xml version='1.0' encoding='utf-8'?>
<plugin id="com.gemalto.plugin.gah" version="0.2" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>GahPlugin</name>
<js-module name="GahPlugin" src="www/GahPlugin.js">
<clobbers target="GahPlugin" />
</js-module>
<!-- ios -->
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="GahPlugin">
<param name="ios-package" value="GahPlugin"/>
</feature>
</config-file>
<config-file parent="NSLocationWhenInUseUsageDescription" target="*-Info.plist">
<string>required this permission</string>
</config-file>
<!-- Objective-C source code -->
<header-file src="src/ios/GahPlugin.h"/>
<source-file src="src/ios/GahPlugin.m"/>
<header-file src="src/ios/GAHRiskEngineIntegration.h"/>
<source-file src="src/ios/GAHRiskEngineIntegration.m"/>
<!-- FPP SDK libraries -->
<framework src="src/ios/libs/debug/GAHRiskEngine.framework" embed="false" custom="true"/>
<!-- <framework src="src/ios/libs/release/GAHRiskEngine.framework" embed="false" custom="true"/> -->
</platform>
<!-- android -->
<platform name="android">
<!-- android permissions -->
<config-file target="AndroidManifest.xml" parent="/manifest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<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_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
</config-file>
<config-file target="res/xml/config.xml" parent="/*">
<feature name="GahPlugin" >
<param name="android-package" value="com.gemalto.plugin.gah.GahPlugin"/>
</feature>
</config-file>
<!-- java source code -->
<source-file src="src/android/GahPlugin.java" target-dir="src/com/gemalto/plugin/gah" />
<source-file src="src/android/GAHRiskEngineIntegration.java" target-dir="src/com/gemalto/plugin/gah" />
<!-- gradle file -->
<framework src="src/android/gahBuild.gradle" custom="true" type="gradleReference" />
<!-- FPP SDK jar file -->
<resource-file src="src/android/libs/debug/GAHRiskEngine.jar" target="libs/debug/GAHRiskEngine.jar" />
<resource-file src="src/android/libs/release/GAHRiskEngine.jar" target="libs/release/GAHRiskEngine.jar" />
<!-- FPP SDK native libraries -->
<resource-file src="src/android/libs/debug/arm64-v8a/libmedlc_shared.so" target="libs/debug/arm64-v8a/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/arm64-v8a/libmedlc_shared.so" target="libs/release/arm64-v8a/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/arm64-v8a/libtdm-5.4-73-jni.so" target="libs/debug/arm64-v8a/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/release/arm64-v8a/libtdm-5.4-73-jni.so" target="libs/release/arm64-v8a/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/debug/armeabi-v7a/libmedlc_shared.so" target="libs/debug/armeabi-v7a/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/armeabi-v7a/libmedlc_shared.so" target="libs/release/armeabi-v7a/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/armeabi-v7a/libtdm-5.4-73-jni.so" target="libs/debug/armeabi-v7a/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/release/armeabi-v7a/libtdm-5.4-73-jni.so" target="libs/release/armeabi-v7a/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/debug/x86/libmedlc_shared.so" target="libs/debug/x86/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/x86/libmedlc_shared.so" target="libs/release/x86/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/x86/libtdm-5.4-73-jni.so" target="libs/debug/x86/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/release/x86/libtdm-5.4-73-jni.so" target="libs/release/x86/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/debug/x86_64/libmedlc_shared.so" target="libs/debug/x86_64/libmedlc_shared.so" />
<resource-file src="src/android/libs/release/x86_64/libmedlc_shared.so" target="libs/release/x86_64/libmedlc_shared.so" />
<resource-file src="src/android/libs/debug/x86_64/libtdm-5.4-73-jni.so" target="libs/debug/x86_64/libtdm-5.4-73-jni.so" />
<resource-file src="src/android/libs/release/x86_64/libtdm-5.4-73-jni.so" target="libs/release/x86_64/libtdm-5.4-73-jni.so" />
</platform>
</plugin>
iOS limitations
The GahPlugin for the iOS platform currently has some limitations.
No automatic debug or release build
The Risk Management SDK has two library variants:
- debug
- release
For production, the Release version of the library should always be used. Unfortunately the GahPlugin does not switch the library version automatically based on the build type. This currently needs to be performed manually in the plugin. See the plugin.xml file and comment and uncomment these two lines based on the build type:
<!-- FPP SDK libraries -->
<framework src="src/ios/libs/debug/GAHRiskEngine.framework" embed="false" custom="true"/>
<!-- <framework src="src/ios/libs/release/GAHRiskEngine.framework" embed="false" custom="true"/> -->
Manual build settings
You must manually update the build settings with additional build flags and framework search path in the generated project.
Add the plugin to the app
Create the test application:
# create a new project folder and run the following command from it:
$ ionic start GahPluginTestApp blank
After the plugin is created, it can be integrated into the test application. Execute the following commands inside the generated test application folder:
# add the plugin to created project
$ ionic cordova plugin add ../path/to/plugin
# add the platforms
$ ionic cordova platform add android@9.1.0
$ ionic cordova platform add ios
# add android permission plugin
$ ionic cordova plugin add cordova-plugin-android-permissions
$ npm install @ionic-native/android-permissions
# add androidx support
$ ionic cordova plugin add cordova-plugin-androidx
$ ionic cordova plugin add cordova-plugin-androidx-adapter
This command should create the platforms folder inside the project directory. Due to an Ionic bug the folder might be generated elsewhere. In this case, the folder needs to be created manually before running the command.
Edit src/app/home/home.page.html to add the buttons to request the runtime permission and to request the visit ID.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Blank
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<div class="btn-wrapper">
<button ion-button full color="primary" (click)="getVisitId($event)">Get Visitor Id</button>
</div>
<div class="btn-wrapper">
<button ion-button full color="primary" (click)="requestPermissions()">Request Permissions</button>
</div>
</ion-content>
Next, edit the corresponding TypeScript class src/app/home/home.page.ts:
import { Component } from '@angular/core';
import { Platform } from '@ionic/angular';
import { AndroidPermissions } from '@ionic-native/android-permissions/ngx';
declare var GahPlugin: any;
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(private androidPermissions: AndroidPermissions, private platform: Platform) {
// initialize gah plugin
this.platform.ready().then(()=> {
GahPlugin.initialize("https://demo-signal-collector.rnd.gemaltodigitalbankingidcloud.com/api/v1/tenants/mybank9/signals",
"2rj4semg",
"h-sdk.online-metrix.net", function(result) {
alert("Success: " + result);
// start prefetch of signals
GahPlugin.startPrefetch(function(result) {
console.log("Start prefetch: " + result);
}, function(error) {
console.log("Error: " + error);
});
}, function(error) {
alert("Error: " + error);
});
});
}
getVisitId(event) {
// check if signals are collected
GahPlugin.isSignalCollectionCompleted(function(result) {
// get visit id
GahPlugin.getVisiId(function(result) {
alert("Visit id: " + result);
// perform login etc. to bank backend
// if transaction is critical (high ammount transfer etc.) - set transaction as critical
// GahPlugin.setTransactionAsCritical(...)
// login(visitID)
// after operation perform clear transaction resources
// GahPlugin.clearTransaction(...)
}, function(error) {
alert("Error: " + error);
});
}, function(error) {
alert("Error: " + error);
});
}
requestPermissions() {
this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.READ_PHONE_STATE).then(
result => {
console.log('Has permission?',result.hasPermission);
if (!result.hasPermission) {
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_PHONE_STATE);
}
}, err => this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_PHONE_STATE)
);
this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.READ_PHONE_NUMBERS).then(
result => {
console.log('Has permission?',result.hasPermission);
if (!result.hasPermission) {
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_PHONE_NUMBERS);
}
}, err => this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_PHONE_NUMBERS)
);
this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.ACCESS_FINE_LOCATION).then(
result => {
console.log('Has permission?',result.hasPermission);
if (!result.hasPermission) {
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.ACCESS_FINE_LOCATION);
}
}, err => this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.ACCESS_FINE_LOCATION)
);
}
exitApplication() {
// before exit stop prefetch of signals
GahPlugin.stopPrefetch(function(result) {
console.log("Success: " + result);
}, function(error) {
console.log("Error: " + error);
});
}
}
And update src/app/app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AndroidPermissions } from '@ionic-native/android-permissions/ngx';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
providers: [AndroidPermissions, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
After the source code is updated, the generated native Android and iOS projects must be updated from the root project folder.
# update android platform
$ ionic cordova prepare android
# update iOS platform
$ ionic cordova prepare ios
The generated native projects are located in platforms/android and platforms/ios. The projects can be built using the Ionic CLI, or by using Android Studio (gradle) and Xcode.
In Xcode Build Settings set:
- testability to false
- other linker flags:
ObjC -lc++ -all_load# build android platform $ ionic cordova build android # build iOS platform $ ionic cordova build ios
If the error export 'DOCUMENT' was not found in '@angular/platform-browser' occurs, fix the problem by referring to export-document-was-not-found-in-angular-platform-browser.