Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration from platform views 🚧 #136

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5b0e16f
rough poc of platform views migration
CoderNamedHendrick Jan 5, 2025
44e4851
remove unncessary delegate controller
CoderNamedHendrick Jan 5, 2025
148ae75
resolve comments
CoderNamedHendrick Jan 8, 2025
b4c50e6
upgrade pigeon, get codegen improvements
CoderNamedHendrick Jan 8, 2025
cbaa035
Merge branch 'main' into feature/migration-from-platform-views
jumaallan Jan 8, 2025
1f14209
updated configurations
jumaallan Jan 8, 2025
947b04e
code formatting and linting
jumaallan Jan 8, 2025
484112f
- remove title bar
CoderNamedHendrick Jan 8, 2025
98e5446
- added smartSelfieEnrollment to SmileID class returning SmileIDSdkRe…
CoderNamedHendrick Jan 8, 2025
13abc1a
remove unnecessary format
CoderNamedHendrick Jan 8, 2025
f3a270d
remove unused didSubmitBiometricKycJob parameter
CoderNamedHendrick Jan 8, 2025
d861168
- added smile_id_smart_selfie_authentication method
CoderNamedHendrick Jan 13, 2025
f1624d4
refactor products api to separate implementation
CoderNamedHendrick Jan 13, 2025
97f3465
remove xcode file creation comments
CoderNamedHendrick Jan 13, 2025
81a157b
remove need for client to wrap application in a UINavigationController
CoderNamedHendrick Jan 14, 2025
b489320
fix linting issues flutter
CoderNamedHendrick Jan 14, 2025
dc7a369
resolve linting issues on android
CoderNamedHendrick Jan 14, 2025
617d3bd
- attend to issues with PR
CoderNamedHendrick Jan 21, 2025
4fddd84
remove portrait hosting controller attempt at locking iOS to portrait…
CoderNamedHendrick Jan 21, 2025
14c6800
Merge branch 'main' into feature/migration-from-platform-views
jumaallan Jan 23, 2025
47f5986
fix force light mode on ios
CoderNamedHendrick Jan 25, 2025
723bb6f
add back button
CoderNamedHendrick Jan 25, 2025
964664d
- added document verification product
CoderNamedHendrick Jan 29, 2025
2529d64
- added selfie capture product
CoderNamedHendrick Feb 9, 2025
3603378
linting code
jumaallan Feb 18, 2025
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
7 changes: 7 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,10 @@ ktlint {
exclude { it.file.path.contains(".g.kt") }
}
}

dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.activity:activity:1.8.0'
implementation 'androidx.activity:activity-compose:1.7.2'
}
11 changes: 10 additions & 1 deletion android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
<manifest />
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<activity
android:name=".SmileIDSmartSelfieEnrollmentActivity"
android:exported="false" />
</application>

</manifest>
103 changes: 83 additions & 20 deletions android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ import FlutterSmartSelfieJobStatusResponse
import FlutterSmartSelfieResponse
import FlutterUploadRequest
import FlutterValidDocumentsResponse
import SmartSelfieCaptureResult
import SmartSelfieEnrollmentCreationParams
import SmileFlutterError
import SmileIDApi
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.smileidentity.SmileID
import com.smileidentity.SmileIDOptIn
import com.smileidentity.flutter.enhanced.SmileIDSmartSelfieAuthenticationEnhanced
Expand All @@ -34,6 +39,7 @@ import com.smileidentity.networking.pollSmartSelfieJobStatus
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.PluginRegistry.ActivityResultListener
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -50,10 +56,11 @@ import kotlin.time.Duration.Companion.milliseconds
class SmileIDPlugin :
FlutterPlugin,
SmileIDApi,
ActivityAware {
ActivityAware, ActivityResultListener {
private var activity: Activity? = null
private lateinit var appContext: Context
private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO)
private var smartSelfieEnrollmentResult: ((Result<SmartSelfieCaptureResult>) -> Unit)? = null

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
SmileIDApi.setUp(flutterPluginBinding.binaryMessenger, this)
Expand Down Expand Up @@ -173,6 +180,31 @@ class SmileIDPlugin :
}
}

override fun smartSelfieEnrollment(
creationParams: SmartSelfieEnrollmentCreationParams,
callback: (Result<SmartSelfieCaptureResult>) -> Unit,
) {
val intent = Intent(activity, SmileIDSmartSelfieEnrollmentActivity::class.java)
intent.putExtra("userId", creationParams.userId)
intent.putExtra("allowNewEnroll", creationParams.allowNewEnroll)
intent.putExtra("allowAgentMode", creationParams.allowAgentMode)
intent.putExtra("showAttribution", creationParams.showAttribution)
intent.putExtra("showInstructions", creationParams.showInstructions)
intent.putExtra("skipApiSubmission", creationParams.skipApiSubmission)
intent.putExtra(
"extraPartnerParams",
Bundle().apply {
creationParams.extraPartnerParams?.forEach { (key, value) ->
putString(key, value)
}
},
)

smartSelfieEnrollmentResult = callback
activity?.startActivityForResult(intent, SmileIDSmartSelfieEnrollmentActivity.REQUEST_CODE)
}


override fun authenticate(
request: FlutterAuthenticationRequest,
callback: (Result<FlutterAuthenticationResponse>) -> Unit,
Expand Down Expand Up @@ -240,17 +272,17 @@ class SmileIDPlugin :
.doSmartSelfieEnrollment(
userId = userId,
selfieImage =
File(selfieImage).asFormDataPart(
partName = "selfie_image",
mediaType = "image/jpeg",
),
livenessImages =
livenessImages.map {
File(selfieImage).asFormDataPart(
partName = "selfie_image",
partName = "liveness_images",
mediaType = "image/jpeg",
),
livenessImages =
livenessImages.map {
File(selfieImage).asFormDataPart(
partName = "liveness_images",
mediaType = "image/jpeg",
)
},
)
},
partnerParams = convertNullableMapToNonNull(partnerParams),
callbackUrl = callbackUrl,
sandboxResult = sandboxResult?.toInt(),
Expand All @@ -277,17 +309,17 @@ class SmileIDPlugin :
.doSmartSelfieAuthentication(
userId = userId,
selfieImage =
File(selfieImage).asFormDataPart(
partName = "selfie_image",
mediaType = "image/jpeg",
),
livenessImages =
livenessImages.map {
File(selfieImage).asFormDataPart(
partName = "selfie_image",
partName = "liveness_images",
mediaType = "image/jpeg",
),
livenessImages =
livenessImages.map {
File(selfieImage).asFormDataPart(
partName = "liveness_images",
mediaType = "image/jpeg",
)
},
)
},
partnerParams = convertNullableMapToNonNull(partnerParams),
callbackUrl = callbackUrl,
sandboxResult = sandboxResult?.toInt(),
Expand Down Expand Up @@ -443,13 +475,44 @@ class SmileIDPlugin :
*/
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
this.activity = binding.activity
binding.addActivityResultListener(this)
}

override fun onDetachedFromActivityForConfigChanges() {}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}

override fun onDetachedFromActivity() {}
override fun onDetachedFromActivity() {
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
if (requestCode == SmileIDSmartSelfieEnrollmentActivity.REQUEST_CODE
&& smartSelfieEnrollmentResult != null
) {
if (resultCode == Activity.RESULT_OK) {
val apiResponseBundle = data?.getBundleExtra("apiResponse")
val apiResponse = apiResponseBundle?.keySet()?.associateWith {
apiResponseBundle.getString(it)
} as Map<String?, Any?>? ?: emptyMap()

val result = SmartSelfieCaptureResult(
selfieFile = data?.getStringExtra("selfieFile") ?: "",
livenessFiles = data?.getStringArrayListExtra("livenessFiles") ?: emptyList(),
apiResponse = apiResponse,
)
smartSelfieEnrollmentResult?.invoke(Result.success(result))
} else if (resultCode == Activity.RESULT_CANCELED) {
val error = data?.getStringExtra("error") ?: "Unknown error"
smartSelfieEnrollmentResult?.invoke(Result.failure(SmileFlutterError(error)))
}

smartSelfieEnrollmentResult = null
return true
}

return false
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.smileidentity.flutter

import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.smileidentity.SmileID
import com.smileidentity.compose.SmartSelfieEnrollment
import com.smileidentity.models.v2.SmartSelfieResponse
import com.smileidentity.results.SmileIDResult
import com.smileidentity.util.randomUserId
import kotlinx.collections.immutable.toImmutableMap
import java.io.File


class SmileIDSmartSelfieEnrollmentActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val userId = intent.getStringExtra("userId") ?: randomUserId()
val allowNewEnroll = intent.getBooleanExtra("allowNewEnroll", false)
val allowAgentMode = intent.getBooleanExtra("allowAgentMode", false)
val showAttribution = intent.getBooleanExtra("showAttribution", true)
val showInstructions = intent.getBooleanExtra("showInstructions", true)
val skipApiSubmission = intent.getBooleanExtra("skipApiSubmission", false)
val extraPartnerParamsBundle = intent.getBundleExtra("extraPartnerParams")
val extraPartnerParams = extraPartnerParamsBundle?.keySet()?.associateWith {
extraPartnerParamsBundle.getString(it)
} as? Map<String, String> ?: emptyMap()


setContent {
SmileID.SmartSelfieEnrollment(
userId = userId,
allowNewEnroll = allowNewEnroll,
allowAgentMode = allowAgentMode,
showAttribution = showAttribution,
showInstructions = showInstructions,
skipApiSubmission = skipApiSubmission,
extraPartnerParams = extraPartnerParams.toImmutableMap(),
) {
when (it) {
is SmileIDResult.Success -> {
val intent = Intent()
intent.putExtra("selfieFile", it.data.selfieFile.absolutePath)
intent.putStringArrayListExtra(
"livenessFiles",
it.data.livenessFiles.pathList(),
)

intent.putExtra(
"apiResponse",
it.data.apiResponse?.buildBundle(),
)

setResult(RESULT_OK, intent)
finish()
}

is SmileIDResult.Error -> {
val intent = Intent()
intent.putExtra("error", it.throwable.message)
setResult(RESULT_CANCELED, intent)
finish()
}
}
}
}

}

companion object {
const val REQUEST_CODE = 12
}
}

private fun List<File>.pathList(): ArrayList<String> {
val list = ArrayList<String>()
this.forEach {
list.add(it.absolutePath)
}
return list
}

private fun SmartSelfieResponse.buildBundle(): Bundle {
val bundle = Bundle()
bundle.putString("code", code)
bundle.putString("created_at", createdAt)
bundle.putString("job_id", jobId)
bundle.putString("job_type", jobType.name)
bundle.putString("message", message)
bundle.putString("partner_id", partnerId)
bundle.putBundle(
"partner_params",
Bundle().apply {
partnerParams.forEach {
putString(it.key, it.value)
}
},
)
bundle.putString("status", status.name)
bundle.putString("updated_at", updatedAt)
bundle.putString("user_id", userId)
return bundle
}
Loading