diff --git a/demo-app-threeds/.gitignore b/demo-app-threeds/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/demo-app-threeds/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/demo-app-threeds/build.gradle b/demo-app-threeds/build.gradle new file mode 100644 index 00000000..cb3ffce2 --- /dev/null +++ b/demo-app-threeds/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'io.hyperswitch.demo_app_threeds' + compileSdk 36 + + defaultConfig { + applicationId "io.hyperswitch.demo_app_threeds" + minSdk 24 + targetSdk 36 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation (project(":hyperswitch-sdk-android-threeDS-trident")) + implementation (project(":hyperswitch-sdk-android-authentication")) + + implementation("com.squareup.okhttp3:okhttp:4.12.0") + + + implementation libs.fuel + implementation libs.kotlin.coroutines + implementation libs.androidx.preference + implementation 'org.slf4j:slf4j-nop:2.0.17' + androidTestImplementation('com.wix:detox:+') +} \ No newline at end of file diff --git a/demo-app-threeds/proguard-rules.pro b/demo-app-threeds/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/demo-app-threeds/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..72b74d32 --- /dev/null +++ b/demo-app-threeds/src/androidTest/java/io/hyperswitch/demo_app_threeds/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package io.hyperswitch.demo_app_threeds + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("io.hyperswitch.demo_app_threeds", appContext.packageName) + } +} \ No newline at end of file diff --git a/demo-app-threeds/src/main/AndroidManifest.xml b/demo-app-threeds/src/main/AndroidManifest.xml new file mode 100644 index 00000000..aea25576 --- /dev/null +++ b/demo-app-threeds/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt new file mode 100644 index 00000000..47e1dd0c --- /dev/null +++ b/demo-app-threeds/src/main/java/io/hyperswitch/demo_app_threeds/MainActivity.kt @@ -0,0 +1,538 @@ +package io.hyperswitch.demo_app_threeds + +import android.app.Activity +import android.os.Bundle +import android.util.Log +import android.widget.Button +import android.widget.TextView +import io.hyperswitch.threeds.models.ThreeDSEnvironment +import io.hyperswitch.threeds.api.* +import io.hyperswitch.threeds.models.ChallengeParameters +import io.hyperswitch.threeds.provider.ProviderRegistry +import io.hyperswitch.threeds.trident.TridentProviderFactory +import io.hyperswitch.authentication.AuthenticationSession +import okhttp3.* +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.RequestBody.Companion.toRequestBody +import org.json.JSONObject +import java.io.IOException + +class MainActivity : Activity() { + + private lateinit var statusText: TextView + private var publishKey: String = "" + private var paymentIntentClientSecret: String = "" + + // New merchant-facing API objects + private lateinit var authenticationSession: AuthenticationSession + private var service: ThreeDSService? = null + private var transaction: ThreeDSTransaction? = null + private var aReqParams: AuthenticationRequestParameters? = null + private var challengeParameters: ChallengeParameters? = null + + + private val apiKey = "" + private val profileId = "" + private val baseUrl = "" + private var authenticationId: String? = null + // Eligibility response data + private var threeDsServerTransactionId: String? = null + private var messageVersion: String? = null + private var directoryServerId: String? = null + + // HTTP client - use singleton to avoid creating multiple instances + private val httpClient by lazy { + OkHttpClient.Builder() + .connectTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .readTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .writeTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .build() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + statusText = findViewById(R.id.statusText) + + // Register providers for testing + ProviderRegistry.registerProvider(TridentProviderFactory()) + + + authenticationSession = AuthenticationSession( + activity = this, + publishableKey = publishKey + ) + + setupButtons() + } + + override fun onDestroy() { + super.onDestroy() + // Clean up resources to prevent memory leaks + service = null + transaction = null + aReqParams = null + challengeParameters = null + + Log.d("ThreeDSTest", "Cleared activity references") + + // Cancel any pending HTTP calls + try { + httpClient.dispatcher.executorService.shutdown() + } catch (e: Exception) { + Log.w("ThreeDSTest", "Error shutting down HTTP client: ${e.message}") + } + } + + private fun setupButtons() { + findViewById