halo-sdk-react-native 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/README.md +163 -0
  2. package/android/build.gradle +89 -0
  3. package/android/libs/VisaSensoryBranding.aar +0 -0
  4. package/android/libs/sonic-sdk-release-1.5.0.aar +0 -0
  5. package/android/settings.gradle +1 -0
  6. package/android/src/main/AndroidManifest.xml +9 -0
  7. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/AnimationActivity.kt +160 -0
  8. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/Const.kt +15 -0
  9. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/HaloCallbacks.kt +126 -0
  10. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/HaloReactActivity.kt +61 -0
  11. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/HaloSdkImplementation.kt +81 -0
  12. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/HaloSdkModule.kt +71 -0
  13. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/HaloSdkPackage.kt +16 -0
  14. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/UIContext.kt +20 -0
  15. package/android/src/main/kotlin/za/co/synthesis/halo/sdkreactnativeplugin/Utils.kt +154 -0
  16. package/android/src/main/res/drawable/amex.png +0 -0
  17. package/android/src/main/res/raw/amex_confirm.mp3 +0 -0
  18. package/dist/HaloSdk.d.ts +36 -0
  19. package/dist/HaloSdk.d.ts.map +1 -0
  20. package/dist/HaloSdk.js +105 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +5 -0
  24. package/dist/types.d.ts +86 -0
  25. package/dist/types.d.ts.map +1 -0
  26. package/dist/types.js +2 -0
  27. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # halo-sdk-react-native
2
+
3
+ React Native plugin for the Halo SDK, enabling Android NFC card-present payment transactions.
4
+
5
+ ## Requirements
6
+
7
+ - React Native 0.73+
8
+ - Android SDK 29+ (minSdkVersion 29)
9
+ - NFC-capable Android device
10
+
11
+ ## Installation
12
+
13
+ ### 1. Install the package
14
+
15
+ Add the package to your project using npm or yarn:
16
+
17
+ ```bash
18
+ npm install halo-sdk-react-native
19
+ ```
20
+
21
+ ```bash
22
+ yarn add halo-sdk-react-native
23
+ ```
24
+
25
+ ### 2. Configure AWS credentials for the Halo Maven repository
26
+
27
+ The plugin fetches the Halo SDK from an S3-backed Maven repo. Provide credentials in `android/local.properties`:
28
+
29
+ ```properties
30
+ aws.accesskey=YOUR_ACCESS_KEY
31
+ aws.secretkey=YOUR_SECRET_KEY
32
+ aws.token=YOUR_SESSION_TOKEN # optional
33
+ ```
34
+
35
+ Or set environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
36
+
37
+ ### 3. Register the native module
38
+
39
+ In your `MainApplication`, add `HaloSdkPackage` to `getPackages()`:
40
+
41
+ ```kotlin
42
+ override fun getPackages(): List<ReactPackage> = listOf(
43
+ MainReactPackage(),
44
+ HaloSdkPackage(),
45
+ )
46
+ ```
47
+
48
+ ### 4. Extend HaloReactActivity
49
+
50
+ In `MainActivity`, extend `HaloReactActivity` instead of `ReactActivity`:
51
+
52
+ ```kotlin
53
+ import za.co.synthesis.halo.sdkreactnativeplugin.HaloReactActivity
54
+
55
+ class MainActivity : HaloReactActivity() {
56
+ override fun getMainComponentName(): String = "YourAppName"
57
+ override fun createReactActivityDelegate() =
58
+ DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
59
+ }
60
+ ```
61
+
62
+ This ensures Halo SDK lifecycle management works correctly.
63
+
64
+ ## Usage
65
+
66
+ ```typescript
67
+ import {
68
+ HaloSdk,
69
+ type IHaloCallbacks,
70
+ type HaloInitializationResult,
71
+ type HaloTransactionResult,
72
+ type HaloUIMessage,
73
+ type HaloAttestationHealthResult,
74
+ } from 'halo-sdk-react-native';
75
+
76
+ const callbacks: IHaloCallbacks = {
77
+ onInitializationResult(result: HaloInitializationResult) {
78
+ console.log('Initialized:', result.resultType);
79
+ },
80
+ onHaloTransactionResult(result: HaloTransactionResult) {
81
+ console.log('Transaction:', result.resultType, result.errorCode);
82
+ },
83
+ onHaloUIMessage(message: HaloUIMessage) {
84
+ console.log('UI Message:', message.msgID);
85
+ },
86
+ onAttestationError(details: HaloAttestationHealthResult) {
87
+ console.error('Attestation error:', details.errorCode);
88
+ },
89
+ onRequestJWT(jwtCallback: (jwt: string) => void) {
90
+ const jwt = getJwtFromYourServer();
91
+ jwtCallback(jwt);
92
+ },
93
+ onSecurityError(errorCode: string) {
94
+ console.error('Security error:', errorCode);
95
+ },
96
+ onCameraControlLost() {
97
+ console.warn('Camera control lost');
98
+ },
99
+ };
100
+
101
+ // Initialize once (e.g. on app start)
102
+ await HaloSdk.initialize(
103
+ callbacks,
104
+ 'com.your.package.name',
105
+ '1.0.0',
106
+ 300000, // transaction timeout in ms (optional, default 300000)
107
+ true, // enable scheme animations (optional)
108
+ );
109
+
110
+ // Start a purchase
111
+ const result = await HaloSdk.startTransaction(10.50, 'REF-001', 'ZAR');
112
+
113
+ // Start a card refund
114
+ const refund = await HaloSdk.cardRefundTransaction(10.50, 'REF-001', 'ZAR');
115
+
116
+ // Cancel current transaction
117
+ await HaloSdk.cancelTransaction();
118
+ ```
119
+
120
+ ## API
121
+
122
+ ### `HaloSdk.initialize(callbacks, packageName, version, timeout?, animations?)`
123
+
124
+ Initialises the SDK. Must be called before any transaction methods.
125
+
126
+ | Parameter | Type | Description |
127
+ |-----------|------|-------------|
128
+ | `callbacks` | `IHaloCallbacks` | Event handler object |
129
+ | `applicationPackageName` | `string` | Your app's package name |
130
+ | `applicationVersion` | `string` | Your app's version string |
131
+ | `onStartTransactionTimeOut` | `number?` | Tap timeout in ms (default 300000) |
132
+ | `enableSchemeAnimations` | `boolean?` | Show Visa/Mastercard/Amex animations on approval |
133
+
134
+ ### `HaloSdk.startTransaction(amount, reference, currency)`
135
+
136
+ Starts a purchase transaction. Resolves with a `HaloStartTransactionResult` once the card tap is accepted or rejected.
137
+
138
+ ### `HaloSdk.cardRefundTransaction(amount, reference, currency)`
139
+
140
+ Starts a card-present refund transaction.
141
+
142
+ ### `HaloSdk.cancelTransaction()`
143
+
144
+ Requests cancellation of the current in-progress transaction.
145
+
146
+ ## Callbacks (`IHaloCallbacks`)
147
+
148
+ | Callback | Description |
149
+ |----------------------------|-----------------------------------------------------------------------|
150
+ | `onInitializationResult` | SDK initialisation complete or failed |
151
+ | `onHaloTransactionResult` | Final transaction outcome |
152
+ | `onHaloUIMessage` | Prompt to display to the cardholder (e.g. "Present card") |
153
+ | `onRequestJWT` | SDK needs a fresh JWT; call the provided `jwtCallback` with the token |
154
+ | `onAttestationError` | Device attestation failed |
155
+ | `onSecurityError` | Security check failed |
156
+ | `onCameraControlLost` | SDK released camera control |
157
+
158
+ ## Building the plugin
159
+
160
+ ```bash
161
+ npm install
162
+ npm run build
163
+ ```
@@ -0,0 +1,89 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
3
+
4
+ group 'za.co.synthesis.halo.sdkreactnativeplugin'
5
+ version '1.0-SNAPSHOT'
6
+
7
+ Properties properties = new Properties()
8
+ if (rootProject.file("local.properties").exists()) {
9
+ properties.load(project.rootProject.file("local.properties").newDataInputStream())
10
+ }
11
+
12
+ rootProject.allprojects {
13
+ repositories {
14
+ google()
15
+ mavenCentral()
16
+ maven { url 'https://jitpack.io' }
17
+
18
+ def repos = [
19
+ 'releases',
20
+ 'snapshots'
21
+ ]
22
+
23
+ flatDir {
24
+ dirs project(':halo_sdk_react_native_plugin').file('libs')
25
+ }
26
+
27
+ repos.each { repo ->
28
+ maven {
29
+ name = repo
30
+ url = "s3://synthesis-halo-artifacts/$repo"
31
+ credentials(AwsCredentials) {
32
+ def localAccessKey = properties.getProperty('aws.accesskey')
33
+ def systemEnvAccessKey = System.getenv('AWS_ACCESS_KEY_ID')
34
+
35
+ def localSecretKey = properties.getProperty('aws.secretkey')
36
+ def systemEnvSecretKey = System.getenv('AWS_SECRET_ACCESS_KEY')
37
+
38
+ def localToken = properties.getProperty('aws.token')
39
+ def systemEnvToken = System.getenv('AWS_SESSION_TOKEN')
40
+
41
+ accessKey = localAccessKey != null ? localAccessKey : systemEnvAccessKey
42
+ secretKey = localSecretKey != null ? localSecretKey : systemEnvSecretKey
43
+
44
+ if (systemEnvToken != null) {
45
+ sessionToken = systemEnvToken
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ android {
54
+ compileSdk 35
55
+ namespace 'za.co.synthesis.halo.sdkreactnativeplugin'
56
+
57
+ compileOptions {
58
+ sourceCompatibility JavaVersion.VERSION_17
59
+ targetCompatibility JavaVersion.VERSION_17
60
+ }
61
+
62
+ kotlinOptions {
63
+ jvmTarget = '17'
64
+ }
65
+
66
+ sourceSets {
67
+ main.java.srcDirs += 'src/main/kotlin'
68
+ }
69
+
70
+ defaultConfig {
71
+ minSdkVersion 29
72
+ }
73
+ }
74
+
75
+ def sdkVersion = "4.0.12"
76
+
77
+ dependencies {
78
+ // React Native is provided by the host app — do not bundle it
79
+ compileOnly 'com.facebook.react:react-native:+'
80
+ implementation 'androidx.core:core-ktx:1.9.0'
81
+ implementation 'androidx.appcompat:appcompat:1.6.1'
82
+
83
+ // Halo SDK
84
+ releaseImplementation group: "za.co.synthesis.halo", name: "sdk", version: "$sdkVersion", changing: true
85
+ debugImplementation group: "za.co.synthesis.halo", name: "sdk", version: "$sdkVersion-debug", changing: true
86
+
87
+ implementation(name: 'VisaSensoryBranding', ext: 'aar')
88
+ implementation(name: 'sonic-sdk-release-1.5.0', ext: 'aar')
89
+ }
@@ -0,0 +1 @@
1
+ rootProject.name = 'halo_sdk_react_native_plugin'
@@ -0,0 +1,9 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="za.co.synthesis.halo.sdkreactnativeplugin">
3
+ <application>
4
+ <activity
5
+ android:name=".AnimationActivity"
6
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar"
7
+ android:screenOrientation="portrait" />
8
+ </application>
9
+ </manifest>
@@ -0,0 +1,160 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.graphics.Color
4
+ import android.media.MediaPlayer
5
+ import android.os.Bundle
6
+ import android.os.Handler
7
+ import android.os.Looper
8
+ import android.util.Log
9
+ import android.view.Gravity
10
+ import android.view.HapticFeedbackConstants
11
+ import android.view.ViewGroup
12
+ import android.widget.ImageView
13
+ import android.widget.LinearLayout
14
+ import androidx.appcompat.app.AppCompatActivity
15
+ import com.mastercard.sonic.controller.SonicController
16
+ import com.mastercard.sonic.controller.SonicEnvironment
17
+ import com.mastercard.sonic.controller.SonicType
18
+ import com.mastercard.sonic.listeners.OnCompleteListener
19
+ import com.mastercard.sonic.listeners.OnPrepareListener
20
+ import com.mastercard.sonic.model.SonicMerchant
21
+ import com.mastercard.sonic.widget.SonicBackground
22
+ import com.mastercard.sonic.widget.SonicView
23
+ import com.visa.SensoryBrandingView
24
+
25
+ class AnimationActivity : AppCompatActivity() {
26
+ private val TAG = "AnimationActivity"
27
+
28
+ private lateinit var sonicView: SonicView
29
+ private var sonicController: SonicController? = null
30
+ private lateinit var amexView: ImageView
31
+ private var mediaPlayer: MediaPlayer? = null
32
+
33
+ override fun onCreate(savedInstanceState: Bundle?) {
34
+ super.onCreate(savedInstanceState)
35
+ supportRequestWindowFeature(android.view.Window.FEATURE_NO_TITLE)
36
+ window.setFlags(
37
+ android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN,
38
+ android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN
39
+ )
40
+
41
+ val maskedPAN = intent.getStringExtra(Const.MASKED_PAN)
42
+ val cardAssociation: CardAssociations = try {
43
+ intent.getStringExtra(Const.CARD_ASSOCIATION)?.let {
44
+ CardAssociations.valueOf(it.uppercase())
45
+ }
46
+ } catch (e: Exception) {
47
+ getCardTypeFromPan(maskedPAN)
48
+ } ?: CardAssociations.UNKNOWN
49
+
50
+ when (cardAssociation) {
51
+ CardAssociations.VISA -> {
52
+ val animationView = SensoryBrandingView(this, null).apply {
53
+ layoutParams = ViewGroup.LayoutParams(
54
+ ViewGroup.LayoutParams.MATCH_PARENT,
55
+ ViewGroup.LayoutParams.MATCH_PARENT
56
+ )
57
+ gravity = android.view.Gravity.CENTER
58
+ }
59
+ setContentView(animationView)
60
+ animationView.setConstrainedFlags(true)
61
+ animationView.isSoundEnabled = true
62
+ animationView.isHapticFeedbackEnabled = true
63
+ animationView.isCheckMarkShown = true
64
+ animationView.setBackdropColor(Color.parseColor("#FFFFFF"))
65
+ animationView.post {
66
+ animationView.animate { closeAnimation() }
67
+ }
68
+ }
69
+
70
+ CardAssociations.MASTERCARD -> {
71
+ sonicView = SonicView(this).apply {
72
+ layoutParams = ViewGroup.LayoutParams(
73
+ ViewGroup.LayoutParams.MATCH_PARENT,
74
+ ViewGroup.LayoutParams.MATCH_PARENT
75
+ )
76
+ }
77
+ sonicController = SonicController()
78
+ val sonicMerchant = SonicMerchant.Builder()
79
+ .merchantName("Halo")
80
+ .city("Pretoria")
81
+ .merchantCategoryCodes(arrayOf("MCC 5122"))
82
+ .countryCode("RSA")
83
+ .merchantId("halo-merc-1")
84
+ .build()
85
+ sonicController?.prepare(
86
+ sonicType = SonicType.SOUND_AND_ANIMATION,
87
+ sonicCue = "checkout",
88
+ sonicEnvironment = SonicEnvironment.SANDBOX,
89
+ merchant = sonicMerchant,
90
+ isHapticsEnabled = true,
91
+ context = this,
92
+ onPrepareListener = object : OnPrepareListener {
93
+ override fun onPrepared(statusCode: Int) { playSonic() }
94
+ }
95
+ )
96
+ sonicView.background = SonicBackground.WHITE
97
+ setContentView(sonicView)
98
+ }
99
+
100
+ CardAssociations.AMEX -> {
101
+ val layout = LinearLayout(this).apply {
102
+ orientation = LinearLayout.VERTICAL
103
+ gravity = Gravity.CENTER
104
+ }
105
+ amexView = ImageView(this).apply {
106
+ layoutParams = LinearLayout.LayoutParams(500, 500)
107
+ setImageResource(R.drawable.amex)
108
+ }
109
+ layout.addView(amexView)
110
+ setContentView(layout)
111
+ mediaPlayer = MediaPlayer.create(this, R.raw.amex_confirm)
112
+ mediaPlayer?.isLooping = false
113
+ mediaPlayer?.start()
114
+ mediaPlayer?.setOnCompletionListener {
115
+ mediaPlayer?.release()
116
+ amexView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
117
+ closeAnimation()
118
+ }
119
+ }
120
+
121
+ else -> finish()
122
+ }
123
+ }
124
+
125
+ private fun playSonic() {
126
+ sonicController?.play(sonicView, object : OnCompleteListener {
127
+ override fun onComplete(statusCode: Int) { closeAnimation() }
128
+ })
129
+ }
130
+
131
+ private fun closeAnimation() {
132
+ Handler(Looper.getMainLooper()).postDelayed({ finish() }, 3000)
133
+ }
134
+
135
+ private fun getCardTypeFromPan(maskedPan: String?): CardAssociations {
136
+ return if (maskedPan != null) {
137
+ when (maskedPan[0]) {
138
+ '2' -> CardAssociations.MASTERCARD
139
+ '5' -> CardAssociations.MASTERCARD
140
+ '4' -> CardAssociations.VISA
141
+ '3' -> CardAssociations.AMEX
142
+ else -> CardAssociations.UNKNOWN
143
+ }
144
+ } else {
145
+ CardAssociations.UNKNOWN
146
+ }
147
+ }
148
+
149
+ @Deprecated("Use onBackPressedDispatcher")
150
+ override fun onBackPressed() {
151
+ // Prevent back press during animation
152
+ }
153
+ }
154
+
155
+ enum class CardAssociations(val association: String) {
156
+ VISA("VISA"),
157
+ MASTERCARD("MASTERCARD"),
158
+ AMEX("AMERICAN EXPRESS"),
159
+ UNKNOWN("UNKNOWN ASSOCIATION")
160
+ }
@@ -0,0 +1,15 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ object Const {
4
+ const val APPLICATION_PACKAGE_NAME = "applicationPackageName"
5
+ const val APPLICATION_VERSION = "applicationVersion"
6
+ const val ON_START_TRANSACTION_TIME_OUT = "onStartTransactionTimeOut"
7
+ const val ENABLE_SCHEME_ANIMATIONS = "enableSchemeAnimations"
8
+
9
+ const val TRANSACTION_AMOUNT = "transactionAmount"
10
+ const val MERCHANT_TRANSACTION_REFERENCE = "merchantTransactionReference"
11
+ const val TRANSACTION_CURRENCY = "transactionCurrency"
12
+
13
+ const val CARD_ASSOCIATION = "cardAssociation"
14
+ const val MASKED_PAN = "maskedPAN"
15
+ }
@@ -0,0 +1,126 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.content.Intent
4
+ import android.os.Looper
5
+ import android.util.Log
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.modules.core.DeviceEventManagerModule
10
+ import za.co.synthesis.halo.haloCommonInterface.HaloErrorCode
11
+ import za.co.synthesis.halo.haloCommonInterface.HaloTransactionResult
12
+ import za.co.synthesis.halo.haloCommonInterface.HaloTransactionResultType
13
+ import za.co.synthesis.halo.sdk.model.HaloAttestationHealthResult
14
+ import za.co.synthesis.halo.sdk.model.HaloInitializationResult
15
+ import za.co.synthesis.halo.sdk.model.HaloUIMessage
16
+ import za.co.synthesis.halo.sdk.model.IHaloCallbacks
17
+
18
+ const val HALO_SDK_EVENT = "haloSdkEvent"
19
+
20
+ class HaloCallbacks(
21
+ private val reactContext: ReactApplicationContext
22
+ ) : IHaloCallbacks() {
23
+ private val TAG = "HaloCallbacks"
24
+ private val handler = android.os.Handler(Looper.getMainLooper())
25
+ private var _jwtCallback: ((String) -> Unit)? = null
26
+
27
+ private fun sendEvent(params: WritableMap) {
28
+ handler.post {
29
+ if (reactContext.hasActiveCatalystInstance()) {
30
+ reactContext
31
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
32
+ .emit(HALO_SDK_EVENT, params)
33
+ }
34
+ }
35
+ }
36
+
37
+ override fun onAttestationError(details: HaloAttestationHealthResult) {
38
+ Log.d(TAG, "onAttestationError: $details")
39
+ val params = Arguments.createMap().apply {
40
+ putString("eventType", "attestation")
41
+ putMap("data", makeWritableMap(details))
42
+ }
43
+ sendEvent(params)
44
+ }
45
+
46
+ override fun onHaloTransactionResult(result: HaloTransactionResult) {
47
+ Log.d(TAG, "onHaloTransactionResult: $result")
48
+ val association = "${result.receipt?.association}"
49
+ val maskedPAN = "${result.receipt?.maskedPAN}"
50
+ val transactionApproved = result.resultType == HaloTransactionResultType.Approved
51
+
52
+ val params = Arguments.createMap().apply {
53
+ putString("eventType", "transaction")
54
+ putMap("data", makeWritableMap(result))
55
+ }
56
+
57
+ handler.post {
58
+ val context = UIContext.getActivity()
59
+ val showSchemeAnimations = UIContext.areSchemeAnimationsEnabled()
60
+ if (context != null && transactionApproved && showSchemeAnimations) {
61
+ val intent = Intent(context, AnimationActivity::class.java)
62
+ intent.putExtra(Const.CARD_ASSOCIATION, association)
63
+ intent.putExtra(Const.MASKED_PAN, maskedPAN)
64
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
65
+ context.startActivity(intent)
66
+ }
67
+
68
+ if (reactContext.hasActiveCatalystInstance()) {
69
+ reactContext
70
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
71
+ .emit(HALO_SDK_EVENT, params)
72
+ }
73
+ }
74
+ }
75
+
76
+ override fun onHaloUIMessage(message: HaloUIMessage) {
77
+ Log.d(TAG, "onHaloUIMessage: $message")
78
+ val params = Arguments.createMap().apply {
79
+ putString("eventType", "ui")
80
+ putMap("data", makeWritableMap(message))
81
+ }
82
+ sendEvent(params)
83
+ }
84
+
85
+ override fun onInitializationResult(result: HaloInitializationResult) {
86
+ Log.d(TAG, "onInitializationResult resultType: ${result.resultType}")
87
+ Log.d(TAG, "onInitializationResult errorCode: ${result.errorCode}")
88
+
89
+ val params = Arguments.createMap().apply {
90
+ putString("eventType", "initialization")
91
+ putMap("data", makeWritableMap(result))
92
+ }
93
+ sendEvent(params)
94
+ }
95
+
96
+ override fun onRequestJWT(callback: (String) -> Unit) {
97
+ Log.d(TAG, "onRequestJWT")
98
+ _jwtCallback = callback
99
+ val params = Arguments.createMap().apply {
100
+ putString("eventType", "onJwtRequest")
101
+ }
102
+ sendEvent(params)
103
+ }
104
+
105
+ override fun onSecurityError(errorCode: HaloErrorCode) {
106
+ Log.d(TAG, "onSecurityError: $errorCode")
107
+ val params = Arguments.createMap().apply {
108
+ putString("eventType", "security")
109
+ putString("data", errorCode.name)
110
+ }
111
+ sendEvent(params)
112
+ }
113
+
114
+ override fun onCameraControlLost() {
115
+ Log.d(TAG, "onCameraControlLost")
116
+ val params = Arguments.createMap().apply {
117
+ putString("eventType", "camera")
118
+ putString("data", "onCameraControlLost")
119
+ }
120
+ sendEvent(params)
121
+ }
122
+
123
+ fun jwtCallback(jwt: String) {
124
+ _jwtCallback?.invoke(jwt)
125
+ }
126
+ }
@@ -0,0 +1,61 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.nfc.NfcAdapter
4
+ import android.os.Bundle
5
+ import android.util.Log
6
+ import com.facebook.react.ReactActivity
7
+ import za.co.synthesis.halo.sdk.HaloSDK
8
+
9
+ /**
10
+ * Abstract base activity for React Native apps using Halo SDK.
11
+ *
12
+ * Your app's MainActivity should extend HaloReactActivity instead of ReactActivity:
13
+ *
14
+ * ```kotlin
15
+ * class MainActivity : HaloReactActivity() {
16
+ * override fun getMainComponentName() = "YourAppName"
17
+ * }
18
+ * ```
19
+ *
20
+ * This class handles the full HaloSDK lifecycle (onCreate, onStart, onResume, onPause, onStop),
21
+ * mirroring the Flutter plugin's HaloActivity.
22
+ */
23
+ abstract class HaloReactActivity : ReactActivity() {
24
+ private val TAG = "HaloReactActivity"
25
+
26
+ private val nfcAdapter: NfcAdapter? by lazy {
27
+ NfcAdapter.getDefaultAdapter(this)
28
+ }
29
+
30
+ override fun onCreate(savedInstanceState: Bundle?) {
31
+ Log.d(TAG, "onCreate")
32
+ super.onCreate(savedInstanceState)
33
+ if (nfcAdapter?.isEnabled == true) {
34
+ HaloSDK.onCreate(this, this, savedInstanceState, null)
35
+ }
36
+ }
37
+
38
+ override fun onStart() {
39
+ Log.d(TAG, "onStart")
40
+ super.onStart()
41
+ HaloSDK.onStart()
42
+ }
43
+
44
+ override fun onResume() {
45
+ Log.d(TAG, "onResume")
46
+ super.onResume()
47
+ HaloSDK.onResume()
48
+ }
49
+
50
+ override fun onPause() {
51
+ Log.d(TAG, "onPause")
52
+ HaloSDK.onPause()
53
+ super.onPause()
54
+ }
55
+
56
+ override fun onStop() {
57
+ Log.d(TAG, "onStop")
58
+ HaloSDK.onStop()
59
+ super.onStop()
60
+ }
61
+ }
@@ -0,0 +1,81 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.Promise
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import za.co.synthesis.halo.haloCommonInterface.HaloException
7
+ import za.co.synthesis.halo.haloCommonInterface.TransactionType
8
+ import za.co.synthesis.halo.sdk.HaloSDK
9
+ import za.co.synthesis.halo.sdk.model.HaloInitializationParameters
10
+
11
+ class HaloSdkImplementation(reactContext: ReactApplicationContext) {
12
+ private val TAG = "HaloSdkImplementation"
13
+ private val ON_START_TRANSACTION_TIME_OUT = 300000L
14
+ private val haloCallbacks: HaloCallbacks = HaloCallbacks(reactContext)
15
+
16
+ fun initializeHaloSDK(promise: Promise, args: HashMap<String, Any>) {
17
+ Log.d(TAG, "initializeHaloSDK: $args")
18
+ try {
19
+ HaloSDK.initialize(
20
+ HaloInitializationParameters(
21
+ haloCallbacks,
22
+ (args[Const.ON_START_TRANSACTION_TIME_OUT] as? Number)?.toLong()
23
+ ?: ON_START_TRANSACTION_TIME_OUT,
24
+ args[Const.APPLICATION_PACKAGE_NAME] as String,
25
+ args[Const.APPLICATION_VERSION] as String
26
+ )
27
+ )
28
+ UIContext.enableSchemeAnimations(
29
+ (args[Const.ENABLE_SCHEME_ANIMATIONS] as Boolean?) ?: false
30
+ )
31
+ promise.resolve(null)
32
+ } catch (e: Exception) {
33
+ if (e is HaloException) {
34
+ promise.reject("sdkreactnativeplugin error", e.message, e)
35
+ } else {
36
+ promise.reject("sdkreactnativeplugin error", e.message, e)
37
+ }
38
+ }
39
+ }
40
+
41
+ fun startTransaction(
42
+ promise: Promise,
43
+ args: HashMap<String, Any>,
44
+ transactionType: TransactionType = TransactionType.Purchase
45
+ ) {
46
+ Log.d(TAG, "startTransaction: $args")
47
+ try {
48
+ val extraFields = getRest<String>(
49
+ args,
50
+ listOf(
51
+ Const.TRANSACTION_AMOUNT,
52
+ Const.MERCHANT_TRANSACTION_REFERENCE,
53
+ Const.TRANSACTION_CURRENCY
54
+ )
55
+ )
56
+ val result = HaloSDK.startTransaction(
57
+ (args[Const.TRANSACTION_AMOUNT] as Double).toBigDecimal(),
58
+ args[Const.MERCHANT_TRANSACTION_REFERENCE] as String,
59
+ args[Const.TRANSACTION_CURRENCY] as String,
60
+ extraFields,
61
+ null,
62
+ transactionType
63
+ )
64
+ promise.resolve(makeWritableMap(result))
65
+ } catch (e: Exception) {
66
+ promise.reject("sdkreactnativeplugin error", e.message, e)
67
+ }
68
+ }
69
+
70
+ fun cancelTransaction(promise: Promise) {
71
+ Log.d(TAG, "cancelTransaction")
72
+ HaloSDK.requestTransactionCancellation()
73
+ promise.resolve(null)
74
+ }
75
+
76
+ fun jwtCallback(promise: Promise, jwt: String) {
77
+ Log.d(TAG, "jwtCallback")
78
+ haloCallbacks.jwtCallback(jwt)
79
+ promise.resolve(null)
80
+ }
81
+ }
@@ -0,0 +1,71 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.LifecycleEventListener
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
8
+ import com.facebook.react.bridge.ReactMethod
9
+ import com.facebook.react.bridge.ReadableMap
10
+ import za.co.synthesis.halo.haloCommonInterface.TransactionType
11
+
12
+ class HaloSdkModule(reactContext: ReactApplicationContext) :
13
+ ReactContextBaseJavaModule(reactContext),
14
+ LifecycleEventListener {
15
+
16
+ private val TAG = "HaloSdkModule"
17
+ private val haloSdkImplementation: HaloSdkImplementation = HaloSdkImplementation(reactContext)
18
+
19
+ init {
20
+ reactContext.addLifecycleEventListener(this)
21
+ }
22
+
23
+ override fun getName(): String = "HaloSdk"
24
+
25
+ @ReactMethod
26
+ fun initializeHaloSDK(args: ReadableMap, promise: Promise) {
27
+ haloSdkImplementation.initializeHaloSDK(promise, args.toHashMap())
28
+ }
29
+
30
+ @ReactMethod
31
+ fun startTransaction(args: ReadableMap, promise: Promise) {
32
+ haloSdkImplementation.startTransaction(promise, args.toHashMap())
33
+ }
34
+
35
+ @ReactMethod
36
+ fun cardRefundTransaction(args: ReadableMap, promise: Promise) {
37
+ haloSdkImplementation.startTransaction(promise, args.toHashMap(), TransactionType.Refund)
38
+ }
39
+
40
+ @ReactMethod
41
+ fun jwtCallback(jwt: String, promise: Promise) {
42
+ haloSdkImplementation.jwtCallback(promise, jwt)
43
+ }
44
+
45
+ @ReactMethod
46
+ fun cancelTransaction(promise: Promise) {
47
+ haloSdkImplementation.cancelTransaction(promise)
48
+ }
49
+
50
+ // Required for RN NativeEventEmitter
51
+ @ReactMethod
52
+ fun addListener(eventName: String) {}
53
+
54
+ @ReactMethod
55
+ fun removeListeners(count: Int) {}
56
+
57
+ // Keep UIContext activity reference up to date
58
+ override fun onHostResume() {
59
+ Log.d(TAG, "onHostResume")
60
+ UIContext.updateActivity(currentActivity)
61
+ }
62
+
63
+ override fun onHostPause() {
64
+ Log.d(TAG, "onHostPause")
65
+ }
66
+
67
+ override fun onHostDestroy() {
68
+ Log.d(TAG, "onHostDestroy")
69
+ UIContext.updateActivity(null)
70
+ }
71
+ }
@@ -0,0 +1,16 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class HaloSdkPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf(HaloSdkModule(reactContext))
11
+ }
12
+
13
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
+ return emptyList()
15
+ }
16
+ }
@@ -0,0 +1,20 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.app.Activity
4
+ import java.lang.ref.WeakReference
5
+
6
+ object UIContext {
7
+ private var activityRef: WeakReference<Activity>? = null
8
+ private var enableSchemeAnimations: Boolean = false
9
+
10
+ fun updateActivity(activity: Activity?) {
11
+ activityRef = activity?.let { WeakReference(it) }
12
+ }
13
+
14
+ fun enableSchemeAnimations(enable: Boolean) {
15
+ enableSchemeAnimations = enable
16
+ }
17
+
18
+ fun getActivity(): Activity? = activityRef?.get()
19
+ fun areSchemeAnimationsEnabled(): Boolean = enableSchemeAnimations
20
+ }
@@ -0,0 +1,154 @@
1
+ package za.co.synthesis.halo.sdkreactnativeplugin
2
+
3
+ import android.util.Base64
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.WritableArray
6
+ import com.facebook.react.bridge.WritableMap
7
+ import za.co.synthesis.halo.haloCommonInterface.HaloTransactionReceipt
8
+ import za.co.synthesis.halo.haloCommonInterface.HaloTransactionResult
9
+ import za.co.synthesis.halo.sdk.model.HaloAttestationHealthResult
10
+ import za.co.synthesis.halo.sdk.model.HaloCurrencyValue
11
+ import za.co.synthesis.halo.sdk.model.HaloInitializationResult
12
+ import za.co.synthesis.halo.sdk.model.HaloStartTransactionResult
13
+ import za.co.synthesis.halo.sdk.model.HaloUIMessage
14
+ import za.co.synthesis.halo.sdk.model.HaloWarning
15
+ import java.util.Currency
16
+
17
+ internal fun <T> getRest(args: Map<String, Any>, keys: List<String>): Map<String, T> {
18
+ val rest = HashMap<String, T>()
19
+ for (key in args.keys) {
20
+ try {
21
+ if (key !in keys) {
22
+ rest[key] = args[key] as T
23
+ }
24
+ } catch (e: TypeCastException) {
25
+ throw TypeCastException("The value of $key is not of type T")
26
+ }
27
+ }
28
+ return rest
29
+ }
30
+
31
+ internal fun makeWritableMap(data: HaloAttestationHealthResult): WritableMap {
32
+ return Arguments.createMap().apply {
33
+ putString("resultType", data.resultType.name)
34
+ putString("errorCode", data.errorCode.name)
35
+ }
36
+ }
37
+
38
+ internal fun makeWritableMap(data: HaloTransactionResult): WritableMap {
39
+ return Arguments.createMap().apply {
40
+ putString("resultType", data.resultType.name)
41
+ putString("merchantTransactionReference", data.merchantTransactionReference)
42
+ putString("haloTransactionReference", data.haloTransactionReference)
43
+ putString("paymentProviderReference", data.paymentProviderReference)
44
+ putString("errorCode", data.errorCode.name)
45
+ putArray("errorDetails", data.errorDetails.toWritableArray())
46
+ putMap("receipt", makeWritableMap(data.receipt))
47
+ putMap("customTags", data.customTags?.toWritableMap())
48
+ }
49
+ }
50
+
51
+ internal fun makeWritableMap(data: HaloTransactionReceipt?): WritableMap? {
52
+ if (data == null) return null
53
+ return Arguments.createMap().apply {
54
+ putString("signature", Base64.encodeToString(data.signature, Base64.NO_WRAP))
55
+ putString("transactionDate", data.transactionDate)
56
+ putString("transactionTime", data.transactionTime)
57
+ putString("aid", data.aid)
58
+ putString("applicationLabel", data.applicationLabel)
59
+ putString("applicationPreferredName", data.applicationPreferredName)
60
+ putString("tvr", data.tvr)
61
+ putString("cvr", data.cvr)
62
+ putString("cryptogramType", data.cryptogramType?.name)
63
+ putString("cryptogram", data.cryptogram)
64
+ putString("maskedPAN", data.maskedPAN)
65
+ putString("authorizationCode", data.authorizationCode)
66
+ putString("ISOResponseCode", data.ISOResponseCode)
67
+ putString("association", data.association)
68
+ putString("expiryDate", data.expiryDate)
69
+ putString("mid", data.mid)
70
+ putString("merchantName", data.merchantName)
71
+ putString("tid", data.tid)
72
+ putString("stan", data.stan)
73
+ putString("panEntry", data.panEntry)
74
+ putString("cardType", data.cardType)
75
+ putString("panSequenceNumber", data.panSequenceNumber)
76
+ putString("effectiveDate", data.effectiveDate)
77
+ putString("disposition", data.disposition)
78
+ putString("currencyCode", data.currencyCode?.toString())
79
+ putString("amountAuthorised", data.amountAuthorised?.toString())
80
+ putString("amountOther", data.amountOther?.toString())
81
+ }
82
+ }
83
+
84
+ internal fun makeWritableMap(data: HaloUIMessage): WritableMap {
85
+ return Arguments.createMap().apply {
86
+ putString("msgID", data.msgID.name)
87
+ putInt("holdTimeMS", data.holdTimeMS)
88
+ putArray("languagePreference", data.languagePreference?.toWritableArray())
89
+ putMap("offlineBalance", makeWritableMap(data.offlineBalance))
90
+ putMap("transactionAmount", makeWritableMap(data.transactionAmount))
91
+ }
92
+ }
93
+
94
+ internal fun makeWritableMap(data: HaloCurrencyValue?): WritableMap? {
95
+ if (data == null) return null
96
+ return Arguments.createMap().apply {
97
+ putMap("currency", makeWritableMap(data.currency))
98
+ putDouble("amount", data.amount.toDouble())
99
+ }
100
+ }
101
+
102
+ internal fun makeWritableMap(data: Currency?): WritableMap? {
103
+ if (data == null) return null
104
+ return Arguments.createMap().apply {
105
+ putString("currencyCode", data.currencyCode)
106
+ putInt("defaultFractionDigits", data.defaultFractionDigits)
107
+ putInt("numericCode", data.numericCode)
108
+ putString("displayName", data.displayName)
109
+ }
110
+ }
111
+
112
+ internal fun makeWritableMap(data: HaloInitializationResult): WritableMap {
113
+ return Arguments.createMap().apply {
114
+ putString("resultType", data.resultType.name)
115
+ putMap("terminalCurrency", makeWritableMap(data.terminalCurrency))
116
+ putArray("terminalLanguageCodes", data.terminalLanguageCodes?.toWritableArray())
117
+ putString("terminalCountryCode", data.terminalCountryCode)
118
+ putString("errorCode", data.errorCode.name)
119
+ putArray("warnings", data.warnings.toWritableArray { makeWritableMap(it) })
120
+ }
121
+ }
122
+
123
+ internal fun makeWritableMap(data: HaloWarning): WritableMap {
124
+ return Arguments.createMap().apply {
125
+ putString("errorCode", data.errorCode.name)
126
+ putArray("details", data.details?.toWritableArray())
127
+ }
128
+ }
129
+
130
+ internal fun makeWritableMap(data: HaloStartTransactionResult): WritableMap {
131
+ return Arguments.createMap().apply {
132
+ putString("resultType", data.resultType.name)
133
+ putString("errorCode", data.errorCode.name)
134
+ }
135
+ }
136
+
137
+ private fun Map<String, String>.toWritableMap(): WritableMap {
138
+ return Arguments.createMap().apply {
139
+ this@toWritableMap.forEach { (key, value) -> putString(key, value) }
140
+ }
141
+ }
142
+
143
+ private fun List<String>.toWritableArray(): WritableArray {
144
+ return Arguments.createArray().apply {
145
+ this@toWritableArray.forEach { pushString(it) }
146
+ }
147
+ }
148
+
149
+
150
+ private fun <T> List<T>.toWritableArray(transform: (T) -> WritableMap): WritableArray {
151
+ return Arguments.createArray().apply {
152
+ this@toWritableArray.forEach { pushMap(transform(it)) }
153
+ }
154
+ }
@@ -0,0 +1,36 @@
1
+ import type { IHaloCallbacks, HaloStartTransactionResult } from './types';
2
+ export declare const HaloSdk: {
3
+ /**
4
+ * Initialize the Halo SDK. Must be called before any transactions.
5
+ *
6
+ * @param callbacks - Object implementing IHaloCallbacks to receive SDK events.
7
+ * @param applicationPackageName - Your app's package name.
8
+ * @param applicationVersion - Your app's version string.
9
+ * @param onStartTransactionTimeOut - Timeout in ms for starting a transaction (default 300000).
10
+ * @param enableSchemeAnimations - Whether to show Visa/Mastercard/Amex animations on approval.
11
+ */
12
+ initialize(callbacks: IHaloCallbacks, applicationPackageName: string, applicationVersion: string, onStartTransactionTimeOut?: number, enableSchemeAnimations?: boolean): Promise<void>;
13
+ /**
14
+ * Start a purchase transaction.
15
+ *
16
+ * @param transactionAmount - Amount to charge (e.g. 10.50).
17
+ * @param merchantTransactionReference - Unique reference for this transaction.
18
+ * @param transactionCurrency - ISO 4217 currency code (e.g. "ZAR").
19
+ * @returns HaloStartTransactionResult indicating whether the tap was accepted.
20
+ */
21
+ startTransaction(transactionAmount: number, merchantTransactionReference: string, transactionCurrency: string): Promise<HaloStartTransactionResult>;
22
+ /**
23
+ * Start a card refund transaction.
24
+ *
25
+ * @param transactionAmount - Amount to refund.
26
+ * @param merchantTransactionReference - Unique reference for this transaction.
27
+ * @param transactionCurrency - ISO 4217 currency code (e.g. "ZAR").
28
+ * @returns HaloStartTransactionResult indicating whether the tap was accepted.
29
+ */
30
+ cardRefundTransaction(transactionAmount: number, merchantTransactionReference: string, transactionCurrency: string): Promise<HaloStartTransactionResult>;
31
+ /**
32
+ * Request cancellation of the current transaction.
33
+ */
34
+ cancelTransaction(): Promise<void>;
35
+ };
36
+ //# sourceMappingURL=HaloSdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HaloSdk.d.ts","sourceRoot":"","sources":["../src/HaloSdk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,0BAA0B,EAC3B,MAAM,SAAS,CAAC;AAyDjB,eAAO,MAAM,OAAO;IAClB;;;;;;;;OAQG;0BAEU,cAAc,0BACD,MAAM,sBACV,MAAM,8BACE,MAAM,2BACT,OAAO,GAC/B,OAAO,CAAC,IAAI,CAAC;IAUhB;;;;;;;OAOG;wCAEkB,MAAM,gCACK,MAAM,uBACf,MAAM,GAC1B,OAAO,CAAC,0BAA0B,CAAC;IAQtC;;;;;;;OAOG;6CAEkB,MAAM,gCACK,MAAM,uBACf,MAAM,GAC1B,OAAO,CAAC,0BAA0B,CAAC;IAQtC;;OAEG;yBACkB,OAAO,CAAC,IAAI,CAAC;CAGnC,CAAC"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HaloSdk = void 0;
4
+ const react_native_1 = require("react-native");
5
+ const LINKING_ERROR = `The package 'halo-sdk-react-native' doesn't seem to be linked. Make sure to: \n\n` +
6
+ `1. Add HaloSdkPackage to your MainApplication's getPackages() list.\n` +
7
+ `2. Extend HaloReactActivity instead of ReactActivity in MainActivity.\n` +
8
+ `3. Copy the Halo AAR libs to your android/libs folder.`;
9
+ const HaloSdkNative = react_native_1.NativeModules.HaloSdk
10
+ ? react_native_1.NativeModules.HaloSdk
11
+ : new Proxy({}, {
12
+ get() {
13
+ throw new Error(LINKING_ERROR);
14
+ },
15
+ });
16
+ const eventEmitter = new react_native_1.NativeEventEmitter(HaloSdkNative);
17
+ const HALO_SDK_EVENT = 'haloSdkEvent';
18
+ let _subscription = null;
19
+ function _setupEventListener(callbacks) {
20
+ _subscription === null || _subscription === void 0 ? void 0 : _subscription.remove();
21
+ _subscription = eventEmitter.addListener(HALO_SDK_EVENT, (event) => {
22
+ switch (event.eventType) {
23
+ case 'attestation':
24
+ callbacks.onAttestationError(event.data);
25
+ break;
26
+ case 'transaction':
27
+ callbacks.onHaloTransactionResult(event.data);
28
+ break;
29
+ case 'ui':
30
+ callbacks.onHaloUIMessage(event.data);
31
+ break;
32
+ case 'initialization':
33
+ callbacks.onInitializationResult(event.data);
34
+ break;
35
+ case 'onJwtRequest':
36
+ callbacks.onRequestJWT(_jwtCallback);
37
+ break;
38
+ case 'security':
39
+ callbacks.onSecurityError(event.data);
40
+ break;
41
+ case 'camera':
42
+ callbacks.onCameraControlLost();
43
+ break;
44
+ }
45
+ });
46
+ }
47
+ function _jwtCallback(jwt) {
48
+ HaloSdkNative.jwtCallback(jwt);
49
+ }
50
+ exports.HaloSdk = {
51
+ /**
52
+ * Initialize the Halo SDK. Must be called before any transactions.
53
+ *
54
+ * @param callbacks - Object implementing IHaloCallbacks to receive SDK events.
55
+ * @param applicationPackageName - Your app's package name.
56
+ * @param applicationVersion - Your app's version string.
57
+ * @param onStartTransactionTimeOut - Timeout in ms for starting a transaction (default 300000).
58
+ * @param enableSchemeAnimations - Whether to show Visa/Mastercard/Amex animations on approval.
59
+ */
60
+ initialize(callbacks, applicationPackageName, applicationVersion, onStartTransactionTimeOut, enableSchemeAnimations) {
61
+ _setupEventListener(callbacks);
62
+ return HaloSdkNative.initializeHaloSDK({
63
+ applicationPackageName,
64
+ applicationVersion,
65
+ onStartTransactionTimeOut: onStartTransactionTimeOut !== null && onStartTransactionTimeOut !== void 0 ? onStartTransactionTimeOut : null,
66
+ enableSchemeAnimations: enableSchemeAnimations !== null && enableSchemeAnimations !== void 0 ? enableSchemeAnimations : false,
67
+ });
68
+ },
69
+ /**
70
+ * Start a purchase transaction.
71
+ *
72
+ * @param transactionAmount - Amount to charge (e.g. 10.50).
73
+ * @param merchantTransactionReference - Unique reference for this transaction.
74
+ * @param transactionCurrency - ISO 4217 currency code (e.g. "ZAR").
75
+ * @returns HaloStartTransactionResult indicating whether the tap was accepted.
76
+ */
77
+ startTransaction(transactionAmount, merchantTransactionReference, transactionCurrency) {
78
+ return HaloSdkNative.startTransaction({
79
+ transactionAmount,
80
+ merchantTransactionReference,
81
+ transactionCurrency,
82
+ });
83
+ },
84
+ /**
85
+ * Start a card refund transaction.
86
+ *
87
+ * @param transactionAmount - Amount to refund.
88
+ * @param merchantTransactionReference - Unique reference for this transaction.
89
+ * @param transactionCurrency - ISO 4217 currency code (e.g. "ZAR").
90
+ * @returns HaloStartTransactionResult indicating whether the tap was accepted.
91
+ */
92
+ cardRefundTransaction(transactionAmount, merchantTransactionReference, transactionCurrency) {
93
+ return HaloSdkNative.cardRefundTransaction({
94
+ transactionAmount,
95
+ merchantTransactionReference,
96
+ transactionCurrency,
97
+ });
98
+ },
99
+ /**
100
+ * Request cancellation of the current transaction.
101
+ */
102
+ cancelTransaction() {
103
+ return HaloSdkNative.cancelTransaction();
104
+ },
105
+ };
@@ -0,0 +1,3 @@
1
+ export { HaloSdk } from './HaloSdk';
2
+ export type { IHaloCallbacks, HaloStartTransactionResult, HaloAttestationHealthResult, HaloInitializationResult, HaloTransactionResult, HaloTransactionReceipt, HaloUIMessage, HaloCurrencyValue, HaloCurrencyInfo, HaloWarning, } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EACV,cAAc,EACd,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HaloSdk = void 0;
4
+ var HaloSdk_1 = require("./HaloSdk");
5
+ Object.defineProperty(exports, "HaloSdk", { enumerable: true, get: function () { return HaloSdk_1.HaloSdk; } });
@@ -0,0 +1,86 @@
1
+ export interface HaloStartTransactionResult {
2
+ resultType: string;
3
+ errorCode: string;
4
+ }
5
+ export interface HaloAttestationHealthResult {
6
+ resultType: string;
7
+ errorCode: string;
8
+ }
9
+ export interface HaloCurrencyInfo {
10
+ currencyCode: string;
11
+ defaultFractionDigits: number;
12
+ numericCode: number;
13
+ displayName: string;
14
+ }
15
+ export interface HaloCurrencyValue {
16
+ currency?: HaloCurrencyInfo;
17
+ amount?: number;
18
+ }
19
+ export interface HaloWarning {
20
+ errorCode: string;
21
+ details?: string;
22
+ }
23
+ export interface HaloInitializationResult {
24
+ resultType: string;
25
+ terminalCurrency?: HaloCurrencyInfo;
26
+ terminalLanguageCodes?: string[];
27
+ terminalCountryCode?: string;
28
+ errorCode: string;
29
+ warnings: HaloWarning[];
30
+ }
31
+ export interface HaloTransactionReceipt {
32
+ signature?: string;
33
+ transactionDate?: string;
34
+ transactionTime?: string;
35
+ aid?: string;
36
+ applicationLabel?: string;
37
+ applicationPreferredName?: string;
38
+ tvr?: string;
39
+ cvr?: string;
40
+ cryptogramType?: string;
41
+ cryptogram?: string;
42
+ maskedPAN?: string;
43
+ authorizationCode?: string;
44
+ ISOResponseCode?: string;
45
+ association?: string;
46
+ expiryDate?: string;
47
+ mid?: string;
48
+ merchantName?: string;
49
+ tid?: string;
50
+ stan?: string;
51
+ panEntry?: string;
52
+ cardType?: string;
53
+ panSequenceNumber?: string;
54
+ effectiveDate?: string;
55
+ disposition?: string;
56
+ currencyCode?: string;
57
+ amountAuthorised?: string;
58
+ amountOther?: string;
59
+ }
60
+ export interface HaloTransactionResult {
61
+ resultType: string;
62
+ merchantTransactionReference?: string;
63
+ haloTransactionReference?: string;
64
+ paymentProviderReference?: string;
65
+ errorCode: string;
66
+ errorDetails?: string;
67
+ receipt?: HaloTransactionReceipt;
68
+ customTags?: Record<string, string>;
69
+ }
70
+ export interface HaloUIMessage {
71
+ msgID: string;
72
+ holdTimeMS?: number;
73
+ languagePreference?: string;
74
+ offlineBalance?: HaloCurrencyValue;
75
+ transactionAmount?: HaloCurrencyValue;
76
+ }
77
+ export interface IHaloCallbacks {
78
+ onAttestationError: (details: HaloAttestationHealthResult) => void;
79
+ onHaloTransactionResult: (result: HaloTransactionResult) => void;
80
+ onHaloUIMessage: (message: HaloUIMessage) => void;
81
+ onInitializationResult: (result: HaloInitializationResult) => void;
82
+ onRequestJWT: (jwtCallback: (jwt: string) => void) => void;
83
+ onSecurityError: (errorCode: string) => void;
84
+ onCameraControlLost: () => void;
85
+ }
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "halo-sdk-react-native",
3
+ "version": "1.0.0",
4
+ "description": "React Native plugin for Halo SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "android/src",
10
+ "android/libs",
11
+ "android/build.gradle",
12
+ "android/settings.gradle",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc"
17
+ },
18
+ "keywords": [
19
+ "halo",
20
+ "sdk",
21
+ "react-native",
22
+ "nfc",
23
+ "payment"
24
+ ],
25
+ "license": "MIT",
26
+ "peerDependencies": {
27
+ "react-native": "*"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.0.0",
31
+ "@types/react-native": "^0.73.0"
32
+ }
33
+ }