Integration via App to App call
Integration via App to App call
For app-to-app launch mode, the Neurogine n2Tap SoftPOS App accepts android Intent for various requests.
We provide a wrapper library - n2applib that wraps the essential APIs and data classes for the ease of integration.
Prerequisite
Before start integrating with the Neurogine n2Tap SoftPOS app, you'll need:
- Neurogine n2Tap SoftPOS: Get it from Play Store
- n2app Lib
v1.0.0
Gradle setup
In your machine/ environment, set up the credential for downloading the sdk package:
# neurogine client registry
NEUROGINE_REGISTRY_LOGIN=neurogine-product-support
NEUROGINE_REGISTRY_TOKEN={token-value}Please seek our customer support for the token.
In your project, (usually) the settings.gradle or settings.gradle.kts, setup the maven registry like the following:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Neurogine's maven registry
maven {
val NEUROGINE_REGISTRY_LOGIN: String? by settings
val NEUROGINE_REGISTRY_TOKEN: String? by settings
requireNotNull(NEUROGINE_REGISTRY_LOGIN) {
"""
Please set your Neurogine Github credential in `gradle.properties`.
On local machine,
** DO NOT **
** DO NOT **
** DO NOT **
Do not put it in the project's file. (and accidentally commit and push)
** DO **
Do set it in your machine's global (~/.gradle/gradle.properties)
""".trimIndent()
}
requireNotNull(NEUROGINE_REGISTRY_TOKEN)
name = "NeurogineMavenClientRegistry"
url = uri("<your-neurogine-maven-registry-url>")
credentials {
username = NEUROGINE_REGISTRY_LOGIN
password = NEUROGINE_REGISTRY_TOKEN
}
}
}
}
dependencies {
// ... other deps
implementation("com.neurogine.app:poslib:1.0.0")
}PosLib Setups
Setting Up AndroidManifest.xml
Android 11 (API level 30) and later require a <queries> element in the manifest to enable package visibility queries.
Edit android/app/src/main/AndroidManifest.xml: add the <queries> element outside the <application> element, and add a <meta-data> entry inside <application> to record the SoftPOS package name for your environment.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Allow querying for the SoftPOS package -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
<package android:name="com.neurogine.softpos.stage" />
</queries>
<application>
<!-- Set SoftPOS package name for the environment -->
<meta-data
android:name="softposName"
android:value="com.neurogine.softpos.stage" />
<!-- existing application config -->
</application>
</manifest>Create the POS API
Pass the n2Tap package name into N2applib (provided by the poslib):
private val n2appLibApi = N2applib(N2TAP_PACKAGE_NAME)Example helper to read a metadata value (for example softposName) from your app manifest:
fun getValue(context: Context, key: String): String? {
return try {
val appInfo = context.packageManager.getApplicationInfo(
context.packageName,
PackageManager.GET_META_DATA
)
appInfo.metaData?.getString(key)
} catch (e: Exception) {
null
}
}Check if SoftPOS is Installed
After updating the manifest and initializing the API, use the library to check whether the SoftPOS app is installed on the device:
// require a Context (e.g. Activity or Compose LocalContext)
n2appLibApi.isSoftPosInstalled(context)Important Notes:
- Update the package name to match your SoftPOS environment:
- Use
com.neurogine.softposfor production - Use
com.neurogine.softpos.stagefor staging/testing
- Use
Call gesture
The POS lib currently provides the ActivityResultContract for the following app operations:
- Activation: to activate the app and load configs from the backend
- WarmUp: to warm up the SoftPOS app, perform the runtime checking on device and application
- Transaction: to perform a transaction like sale, void, or refund
- Enquiry: to check the previous transaction status
- Settlement: to settle all the batch under the merchant
Generally you'll want to register for the activity result in either your activity or in compose scope with:
// [Activity] Register with the contract first
val someOperationLauncher = registerForActivityResult(operationContract) { result ->
// handle the activity result here
when (warmUpResult) {
is AppResponse.Failed -> {
/* handle failed */
}
is AppResponse.Success -> {
/* handle success */
}
}
}
// [Compose Scope] Remember the launcher to avoid redundant instantiation during re-composition
val someOperationLauncher =
rememberLauncherForActivityResult(operationContract) { result ->
// handle the activity result here
when (warmUpResult) {
is AppResponse.Failed -> { /* handle failed */
}
is AppResponse.Success -> { /* handle success */
}
}
}
// in call site
fun triggerOperation() {
// optional data required for specific operation like the transaction amount
someOperationLauncher.launch(requiredData)
}Warm Up
The WarmUp calls the app to perform a series of runtime checking. It takes no argument.
// activity
private val warmUpLauncher = registerForActivityResult(n2appLibApi.warmUpContract()) {
// handle the activity result here
}
// compose scope
val warmUpLauncher = rememberLauncherForActivityResult(n2appLibApi.warmUpContract()) {
// handle the activity result here
}
// call site
fun triggerWarmUp() {
warmUpLauncher.launch()
}Activation
The Activation calls the app to activate the app, loads the necessary configs, like store information and EMV configs for later transaction.
Required the activationCode
// activity
private val activationLauncher = registerForActivityResult(n2appLibApi.activationContract()) {
// handle the activity result here
}
// compose scope
val activationLauncher = rememberLauncherForActivityResult(n2appLibApi.activationContract()) {
// handle the activity result here
}
// call site
fun triggerActivation(code: String) {
activationLauncher.launch(AppRequest.Activation(activationCode = code))
}Transaction
Initiate a transaction request, including the SALE, VOID, or REFUND.
For new transaction SALE, requires amount field.
For VOID & REFUND request, requires the orgTranId.
// activity
private val transactionLauncher = registerForActivityResult(n2appLibApi.transactionContract()) {
// handle the activity result here
}
// compose scope
val transactionLauncher = rememberLauncherForActivityResult(n2appLibApi.transactionContract()) {
// handle the activity result here
}
// call site
// card sale request
fun triggerSaleTransaction(amount: BigDecimal, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.Sale(
amount = amount,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId,
// auto dismiss the SoftPOS transaction result screen and return to Business App
autoDismissResult = true
)
)
}
// QR payment(Merchant Scan) request
fun triggerSaleTransaction(amount: BigDecimal, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.Sale(
amount = amount,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId,
// auto dismiss the SoftPOS transaction result screen and return to Business App
autoDismissResult = true,
// initiate QR transaction with merchant scan mode
preferredInstrument = PreferredInstrument.QR_MERCHANT_SCAN
)
)
}
// QR payment(Guest Scan) request
fun triggerSaleTransaction(amount: BigDecimal, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.Sale(
amount = amount,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId,
// auto dismiss the SoftPOS transaction result screen and return to Business App
autoDismissResult = true,
// initiate QR transaction with guest scan mode
preferredInstrument = PreferredInstrument.QR_GUEST_SCAN,
// optional,in QR guest scan mode, if no QR payment method is specified, the app will display a list of supported QR payment methods for the user to select from
qrPaymentMethods = QRPaymentMethods.ALIPAY_PLUS
)
)
}
// void request
fun triggerVoidTransaction(originalTransactionId: String, passcode: String, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.Void(
orgTranId = originalTransactionId,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId,
// merchant admin passcode for void/ refund
adminPwd = passcode
)
)
}
// Pre-Auth request
fun triggerPreAuthTransaction(amount: BigDecimal, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.Auth(
amount = amount,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId,
// auto dismiss the SoftPOS transaction result screen and return to Business App
autoDismissResult = true
)
)
}
// Auth completion(Capture) request
fun triggerAuthCompletionTransaction(originalTransactionId: String, amount: BigDecimal, posMessageId: String) {
transactionLauncher.launch(
AppRequest.Transaction.AuthCompletion(
orgTranId = originalTransactionId,
amount = amount,
// posMessageId - a reference from POS system, that will pass to n2Tap backend for later query
posMessageId = posMessageId
)
)
}
Enquiry Transaction Status with orignalTranId
To enquiry previous transaction by the transaction ID
// activity
private val enquiryTranLauncher = registerForActivityResult(n2appLibApi.enquiryTranStatusContract()) {
// handle the activity result here
}
// compose scope
val enquiryTranLauncher = rememberLauncherForActivityResult(n2appLibApi.enquiryTranStatusContract()) {
// handle the activity result here
}
// call site
fun triggerEnquiryTranStatus(orignalTranId: String) {
enquiryTranLauncher.launch(AppRequest.EnquiryTranStatus(orgTranId = orignalTranId))
}Enquiry Transaction Status with posMessageId
To enquiry previous transaction by the posMessageId
// activity
private val enquiryTranLauncher = registerForActivityResult(n2appLibApi.enquiryTranStatusWithMessageIdContract()) {
// handle the activity result here
}
// compose scope
val enquiryTranLauncher = rememberLauncherForActivityResult(n2appLibApi.enquiryTranStatusWithMessageIdContract()) {
// handle the activity result here
}
// call site
fun triggerEnquiryTranStatus(posMsgId: String) {
enquiryTranLauncher.launch(AppRequest.EnquiryTranStatusWithMessageId(posMessageId = posMsgId))
}Reload configuration
Force to reload EMV configurations and payment keys
// activity
private val reloadConfigurationLauncher = registerForActivityResult(n2appLibApi.reloadConfigurationContract()) {
// handle the activity result here
}
// compose scope
val reloadConfigurationLauncher = rememberLauncherForActivityResult(n2appLibApi.reloadConfigurationContract()) {
// handle the activity result here
}
// call site
fun reloadConfiguration() {
reloadConfigurationLauncher.launch()
}Enquiry Bluetooth Connection Status
Obtain the Bluetooth connection status between phone and MPOS D177 device
// activity
private val enquiryBTConnectStatusLauncher = registerForActivityResult(n2appLibApi.enquiryBTConnectStatusContract()) {
// handle the activity result here
}
// compose scope
val enquiryBTConnectStatusLauncher = rememberLauncherForActivityResult(n2appLibApi.enquiryBTConnectStatusContract()) {
// handle the activity result here
}
// call site
fun enquiryBTConnectStatus() {
enquiryBTConnectStatusLauncher.launch()
}Settlement
To settle all available batches:
// activity
private val settlementLauncher = registerForActivityResult(n2appLibApi.settlementContract()) {
// handle the activity result here
}
// compose scope
val settlementLauncher = rememberLauncherForActivityResult(n2appLibApi.settlementContract()) {
// handle the activity result here
}
// call site
fun triggerSettlement(posMessageId: String) {
settlementLauncher.launch(AppRequest.Settlement(posMessageId = posMessageId))
}Response Code & Data Model
Refer to Response Code for more details
Refer to Data Model for more details