Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,15 @@ dependencies {
implementation("org.greenrobot:eventbus")
implementation project(':hyperswitch-sdk-android-lite')
implementation('com.squareup.okhttp3:okhttp')
compileOnly project(':react-native-hyperswitch-unified-3ds')

constraints {
implementation("com.squareup.okhttp3:okhttp") {
version {
prefer '3.3.0'
}
}

implementation("androidx.appcompat:appcompat") {
version {
prefer '1.6.1'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.hyperswitch.authentication

import android.app.Activity
import io.hyperswitch.modular_3ds.api.ThreeDSAuthenticationSession


class AuthenticationSession(
private val activity: Activity,
private val publishKey: String
) {
companion object {
/**
* Check if the 3DS library is available at runtime
*
* @return true if modular_3ds library is available, false otherwise
*/
@JvmStatic
fun isAvailable(): Boolean {
return try {
Class.forName("io.hyperswitch.modular_3ds.api.ThreeDSAuthenticationSession")
true
} catch (e: ClassNotFoundException) {
false
}
}
}

private val internalAuthSession: ThreeDSAuthenticationSession

init {
if (!isAvailable()) {
throw IllegalStateException(
"3DS library not found. Please add the following dependency to your build.gradle:\n" +
"implementation 'io.hyperswitch:modular-3ds-api:x.x.x'\n" +
"You can check availability using AuthenticationSession.isAvailable() before instantiation."
)
}
internalAuthSession = ThreeDSAuthenticationSession(activity, publishKey)
}

/**
* Initialize a 3DS session
*
* @param authIntentClientSecret The authentication intent client secret
* @param configuration Authentication configuration (use AuthenticationConfiguration from this package)
* @param callback Callback to receive authentication result (use AuthenticationResult from this package)
* @return Session object if initialization is successful, null otherwise
*/
fun initThreeDsSession(
authIntentClientSecret: String,
configuration: AuthenticationConfiguration,
callback: (AuthenticationResult) -> Unit
): Session? {
return internalAuthSession.initThreeDsSession(
authIntentClientSecret = authIntentClientSecret,
configuration = configuration
) { modularResult ->
// Convert modular_3ds result to wrapper result
callback(AuthenticationResult.from(modularResult))
}
}
}
58 changes: 58 additions & 0 deletions app/src/main/java/io/hyperswitch/authentication/TypeAliases.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.hyperswitch.authentication

/**
* Type aliases and wrappers for 3DS authentication types
*
* These allow merchants to use io.hyperswitch.authentication.* namespace
* while the actual implementation comes from io.hyperswitch.modular_3ds
*/

// Session and Transaction types
typealias Session = io.hyperswitch.modular_3ds.api.ThreeDSSession
typealias Transaction = io.hyperswitch.modular_3ds.api.ThreeDSTransaction

// Configuration and Parameters
typealias AuthenticationConfiguration = io.hyperswitch.modular_3ds.api.AuthenticationConfiguration
typealias AuthenticationRequestParameters = io.hyperswitch.modular_3ds.api.AuthenticationRequestParameters
typealias ChallengeParameters = io.hyperswitch.modular_3ds.models.ChallengeParameters

// Callbacks
typealias ChallengeStatusReceiver = io.hyperswitch.modular_3ds.api.ChallengeStatusReceiver

// Events
typealias CompletionEvent = io.hyperswitch.modular_3ds.api.CompletionEvent
typealias ProtocolErrorEvent = io.hyperswitch.modular_3ds.api.ProtocolErrorEvent
typealias RuntimeErrorEvent = io.hyperswitch.modular_3ds.api.RuntimeErrorEvent
typealias ErrorMessage = io.hyperswitch.modular_3ds.api.ErrorMessage

// Environment and Customization
typealias ThreeDSEnvironment = io.hyperswitch.modular_3ds.models.ThreeDSEnvironment
typealias UiCustomization = io.hyperswitch.modular_3ds.models.UiCustomization
typealias ToolbarCustomization = io.hyperswitch.modular_3ds.models.ToolbarCustomization

// Provider Registration
typealias ProviderRegistry = io.hyperswitch.modular_3ds.provider.ProviderRegistry
typealias ProviderFactory = io.hyperswitch.modular_3ds.provider.ProviderFactory

/**
* Wrapper for AuthenticationResult sealed class
* This is needed because type aliases don't work well with sealed classes and their nested types
*/
sealed class AuthenticationResult {
object Success : AuthenticationResult()
data class Error(val message: String) : AuthenticationResult()
object Challenge : AuthenticationResult()

companion object {
/**
* Convert from modular_3ds AuthenticationResult to wrapper AuthenticationResult
*/
internal fun from(result: io.hyperswitch.modular_3ds.api.AuthenticationResult): AuthenticationResult {
return when (result) {
is io.hyperswitch.modular_3ds.api.AuthenticationResult.Success -> Success
is io.hyperswitch.modular_3ds.api.AuthenticationResult.Error -> Error(result.message)
is io.hyperswitch.modular_3ds.api.AuthenticationResult.Challenge -> Challenge
}
}
}
}
5 changes: 3 additions & 2 deletions demo-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ dependencies {
implementation 'com.github.kittinunf.fuel:fuel-json:2.3.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
implementation project(':app')
implementation project(':app')
implementation ('com.wix:detox:+')
androidTestImplementation('com.wix:detox:+')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation project(':hyperswitch-sdk-android-lite')
implementation(project(":hyperswitch-scan-card-lite"))
implementation project(':react-native-hyperswitch-unified-3ds')
implementation ('io.hyperswitch:modular-3ds-trident:1.0.0')
compileOnly 'com.facebook.react:react-android'
implementation 'org.slf4j:slf4j-nop:2.0.9'
}
10 changes: 9 additions & 1 deletion demo-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Network permissions for API calls -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:allowBackup="true"
android:extractNativeLibs="true"
Expand All @@ -24,7 +28,11 @@
<activity android:name=".WidgetActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
>
</activity>
</activity>
<activity android:name=".ThreeDSTestActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
>
</activity>
</application>

</manifest>
6 changes: 6 additions & 0 deletions demo-app/src/main/java/io/hyperswitch/demoapp/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,12 @@ class MainActivity : Activity() {
startActivity(intent)
}

findViewById<View>(R.id.launchAuthenticationButton).setOnClickListener{
val intent = Intent(this, ThreeDSTestActivity::class.java)
intent.putExtra("publishKey", publishKey)
intent.putExtra("clientSecret", paymentIntentClientSecret)
startActivity(intent)
}
}

private fun setStatus(error: String) {
Expand Down
Loading