Commit 52262fce authored by Javohir Savriy's avatar Javohir Savriy
Browse files

Initial commit

parents
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: f1875d570e39de09040c8f79aa13cc56baab8db1
channel: stable
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: android
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
- platform: ios
create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
## 1.0.5
* Initial release.
## 1.0.4
* Initial release.
The MIT License (MIT)
Copyright (c) 2020
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# MyID Android SDK
## Table of contents
- [Changelog](CHANGELOG.md)
- [Important](#important)
- [Getting started](#getting-started)
- [Before you begin](#11-before-you-begin)
- [Setup MyID Android SDK](#12-setup-myid-android-sdk)
- [Permissions](#13-permissions)
- [Usage](#usage)
- [Methods](#11-methods)
- [Handling callbacks](#12-handling-callbacks)
- [SDK error codes](#sdk-error-codes)
- [UI customization](CUSTOMIZATION.md)
## Important
**Note:** When you update the version of MyID SDK in your application, check the version of the
libraries in [dependencies](#12-setup-myid-android-sdk) and update them too!
## Getting started
### 1.1 Before you begin
Install or update Android Studio to its latest version.
The SDK supports API level 21 and above
Make sure that your app meets the following requirements:
- `minSdkVersion = 21`
- `targetSdkVersion = 33`
- `android.useAndroidX = true`
``` gradle
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
```
- myid-sdk-***.aar, has been provided to you, it contains SDK public interface and implementation.
Archive name contains ever increasing release version number.
### 1.2 Setup MyID Android SDK
Create new project in AndroidStudio. Inside mobile application folder create new folder to store SDK
libraries (For example libs) and copy MyID SDK provided libraries.
Add reference to library to module **_build.gradle_**:
``` gradle
implementation(files("libs/myid-sdk-2.1.7-release.aar"))
```
**Note:** You can get `myid-sdk-2.1.7-release.aar` file
from [here](app/libs/myid-sdk-2.1.7-release.aar)
After synchronization, You should be able to access to SDK classes from your source code.
MyID Android SDK also requires following libraries to be added:
``` gradle
dependencies {
implementation(files("libs/myid-sdk-2.1.7-release.aar"))
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
def cameraVersion = "1.2.2"
implementation("androidx.camera:camera-camera2:$cameraVersion")
implementation("androidx.camera:camera-lifecycle:$cameraVersion")
implementation("androidx.camera:camera-view:$cameraVersion")
// Use these dependencies if your app supports Google Play Services
implementation("com.google.android.gms:play-services-mlkit-face-detection:17.1.0")
implementation("com.google.android.gms:play-services-mlkit-text-recognition:18.0.2")
implementation("com.google.android.gms:play-services-mlkit-barcode-scanning:18.2.0")
// Use these dependencies if your app doesn't support Google Play Services
implementation("com.google.mlkit:face-detection:16.1.5")
implementation("com.google.mlkit:text-recognition:16.0.0-beta6")
implementation("com.google.mlkit:barcode-scanning:17.1.0")
implementation("io.ktor:ktor-client-android:2.1.2")
}
```
### 1.3 Permissions
Add following lines to the **_AndroidManifest.xml_**:
``` xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
```
## Usage
### With Activity Result API
``` kotlin
class ExampleActivity : AppCompatActivity(), MyIdResultListener {
private val myIdClient = MyIdClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startMyId()
}
private fun startMyId() {
val organizationDetails = MyIdOrganizationDetails(
phoneNumber = "1234567",
logo = R.drawable.image_logo
)
val myIdConfig = MyIdConfig.builder(clientId = /* Your client id */)
.withPassportData(passportData)
.withBirthDate(dateOfBirth)
.withSdkHash(sdkHash)
.withExternalId(externalId)
.withThreshold(threshold)
.withBuildMode(MyIdBuildMode.PRODUCTION)
.withEntryType(MyIdEntryType.AUTH)
.withResidency(MyIdResidentType.RESIDENT)
.withLocale(Locale("en"))
.withCameraShape(MyIdCameraShape.CIRCLE)
.withResolution(MyIdResolution.RESOLUTION_480)
.withImageFormat(MyIdImageFormat.PNG)
.withOrganizationDetails(organizationDetails)
.withPhoto(false)
.build()
val intent = client.createIntent(activity = this, myIdConfig = myIdConfig)
result.launch(intent)
}
private val result = takeUserResult(listener = this)
}
```
### With `onActivityResult` method
``` kotlin
class ExampleActivity : AppCompatActivity(), MyIdResultListener {
private val myIdClient = MyIdClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startMyId()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
myIdClient.handleActivityResult(resultCode, this)
}
private fun startMyId() {
val organizationDetails = MyIdOrganizationDetails(
phoneNumber = "1234567",
logo = R.drawable.image_logo
)
val myIdConfig = MyIdConfig.builder(clientId = /* Your client id */)
.withPassportData(passportData)
.withBirthDate(dateOfBirth)
.withSdkHash(sdkHash)
.withExternalId(externalId)
.withThreshold(threshold)
.withBuildMode(MyIdBuildMode.PRODUCTION)
.withEntryType(MyIdEntryType.AUTH)
.withResidency(MyIdResidentType.RESIDENT)
.withLocale(Locale("en"))
.withCameraShape(MyIdCameraShape.CIRCLE)
.withResolution(MyIdResolution.RESOLUTION_480)
.withImageFormat(MyIdImageFormat.PNG)
.withOrganizationDetails(organizationDetails)
.withPhoto(false)
.build()
/*
Start the flow. 1 should be your request code (customize as needed).
Must be an Activity or Fragment (support library).
This request code will be important for you on onActivityResult() to identify the MyIdResultListener.
*/
myIdClient.startActivityForResult(this, 1, myIdConfig)
}
}
```
### 1.1 Methods
Method | Notes | Default
--- | --- | ---
`withPassportData(value: String)` | Passport serial number or PINFL data | Optional
`withBirthDate(value: String)` | Date of birth in. Format: `dd.MM.yyyy` | Optional
`withSdkHash(value: String)` | 32 characters long string | Optional
`withExternalId(value: String)` | 36 characters long. Should match with UUID4 regex | Optional
`withThreshold(value: Float)` | The value can be in the range of `0.50` - `0.99` | 0.50
`withBuildMode(value: MyIdBuildMode)` | Build mode | MyIdBuildMode.PRODUCTION
`withEntryType(value: MyIdEntryType)` | Customizing the SDK Entry types | MyIdEntryType.AUTH
`withResidency(value: MyIdResidentType)` | To set a specific resident type | MyIdResidentType.RESIDENT
`withLocale(value: Locale)` | To set a specific locale | Locale("uz")
`withCameraShape(value: MyIdCameraShape)` | To set a specific camera shape | MyIdCameraShape.CIRCLE
`withResolution(value: MyIdResolution)` | To set a specific camera resolution | MyIdResolution.480
`withImageFormat(value: MyIdImageFormat)` | To set a specific image format | MyIdImageFormat.PNG
`withOrganizationDetails(value: MyIdOrganizationDetails)` | Custom Organization Details | Optional
`withPhoto(value: Boolean)` | Return SDK face bitmap | false
**Note 1.1.** You can customize the screen for entering passport data and date of birth in your
application, in which case you can pass these parameters during initialization to the SDK, otherwise
the SDK requires the input of passport data and date of birth for user identification.
**Note 1.2.** If the `sdk_hash` is empty, blank or string with length other than 32 has been
provided, we will continue showing the credentials screen.
**Note 1.3.** If the `externalId` is not empty, has a length of 36 characters and corresponds to the
regular expression UUID4, we will display a [recommendation](images/screen01.jpg) screen in case the
sdk detects a blurry photo.
**Note 1.4.** `MyIdBuildMode` contains **DEBUG** and **PRODUCTION** modes.
- **DEBUG** is used to sandbox.
- **PRODUCTION** is used to production.
**Note 1.5.** `MyIdEntryType` contains **AUTH** and **FACE** types.
- **AUTH** is used to identify the user through the MyID services.
- **FACE** is used to detect a face and returns a picture (bitmap).
**Note 1.6.** `MyIdCameraShape` contains **[CIRCLE](images/screen03.jpg)**
and **[ELLIPSE](images/screen04.jpg)** types.
### 1.2 Handling callbacks
```kotlin
val myIdResultListener: MyIdResultListener = object : MyIdResultListener {
override fun onSuccess(result: MyIdResult) {
// Get face bitmap and result code
val bitmap = result.bitmap
val code = result.code
val comparison = result.comparison
}
override fun onUserExited() {
// User left the SDK
}
override fun onError(e: MyIdException) {
// Get error message and code:
val message = e.message
val code = e.code
}
}
```
| Attribute | Notes |
| -----|-------|
| `onSuccess` | `MyIdResult` contains information about the face captures made during the flow, result code and comparison value. |
| `onUserExited` | User left the SDK flow without completing it. |
| `onError` | Some error happened. `MyIdException` contains information about the error message and code |
## SDK error codes
The error code in the following list may appear during the call of SDK. The list below is for your
reference.
| Code | Error message
|:----:|:-------------
| 2 | Паспортные данные введены неправильно
| 3 | Не удалось подтвердить жизненность
| 4 | Не удалось распознать
| 5 | Внешний сервис недоступен или работает некорректно
| 6 | Запрашиваемый пользовател скончался
| 7 | Фото с ресурсов не получено
| 8 | Внутренняя ошибка MyID
| 9 | Срок выполнения задачи истек
| 10 | Срок ожидания задачи в очереди истек
| 11 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 12 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 13 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 14 | Не удалось подтвердить жизненность. Некорректная фотография
| 15 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 16 | Сервис MyID не может обработать запрос. Попробуйте повторить позже
| 17 | Не удалось распознать. Некорректная фотография
| 18 | Сервис проверки жизненности не может обработать запрос
| 19 | Сервис распознования не может обработать запрос
| 20 | Размытая фотография
| 21 | Лицо не полностью изображено
| 22 | Обнаружено несколько лиц
| 23 | Представленное изображение в градациях серого, требуется цветное изображение
| 24 | Обнаружены затемненные очки
| 25 | Тип фотографии не поддерживается
| 26 | Глаза закрыты либо не видны
| 27 | Обнаружено вращение головы
| 28 | Не удалось обнаружить все ориентиры
| 101 | Непредвиденная ошибка
| 102 | Доступ к камере запрещен
| 103 | Ошибка при получении данных с сервера
| 120 | Размытое фото обнаружено в SDK
\ No newline at end of file
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx
group "uz.aigroup.myid"
version "1.0.4"
buildscript {
ext.kotlin_version = "1.7.21"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:7.1.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
maven {
url "https://artifactory.aigroup.uz:443/artifactory/myid"
credentials {
username "rshimbergenov"
password "cmVmdGtuOjAxOjE3MjE1NjQ3OTA6N1pYOGFSWVRvclNTS09mUjRieTZnVUNwYXB6"
}
}
}
}
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
compileSdk 33
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
sourceSets {
main.java.srcDirs += "src/main/kotlin"
}
defaultConfig {
minSdk 21
}
}
dependencies {
implementation("uz.myid.sdk.capture:myid-capture-sdk:2.1.9")
implementation("com.google.code.gson:gson:2.10")
}
\ No newline at end of file
rootProject.name = "myid"
<manifest package="uz.aigroup.myid" />
\ No newline at end of file
package uz.aigroup.myid
import android.content.Context
import androidx.annotation.NonNull
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.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import uz.myid.android.sdk.capture.MyIdClient
class MyIdPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var myIdSdk: MyIdSdk
private lateinit var activityListener: MyIdSdkActivityListener
private lateinit var methodChannel: MethodChannel
private lateinit var applicationContext: Context
private lateinit var pluginBinding: ActivityPluginBinding
private val myIdClient = MyIdClient()
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
onAttachedToEngine(
flutterPluginBinding.applicationContext,
flutterPluginBinding.binaryMessenger
)
}
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val instance = MyIdPlugin()
instance.onAttachedToEngine(registrar.context(), registrar.messenger())
instance.myIdSdk.setActivity(registrar.activity())
registrar.addActivityResultListener(instance.activityListener)
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "startSdk") {
val config = call.arguments as HashMap<*, *>
@Suppress("UNCHECKED_CAST")
myIdSdk.start(config["config"] as? HashMap<String, Any?>, result)
} else {
result.notImplemented()
}
}
private fun onAttachedToEngine(context: Context, messenger: BinaryMessenger) {
applicationContext = context
methodChannel = MethodChannel(messenger, "myid")
methodChannel.setMethodCallHandler(this)
activityListener = MyIdSdkActivityListener(myIdClient)
myIdSdk = MyIdSdk(myIdClient, activityListener)
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
methodChannel.setMethodCallHandler(null)
}
override fun onDetachedFromActivity() {
myIdSdk.setActivity(null)
pluginBinding.removeActivityResultListener(activityListener)
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
onReattachedToActivityForConfigChanges(binding)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
myIdSdk.setActivity(binding.activity)
pluginBinding = binding
pluginBinding.addActivityResultListener(activityListener)
}
override fun onDetachedFromActivityForConfigChanges() {
onDetachedFromActivityForConfigChanges()
}
}
package uz.aigroup.myid
import android.app.Activity
import android.os.Build
import io.flutter.plugin.common.MethodChannel
import uz.myid.android.sdk.capture.MyIdClient
import uz.myid.android.sdk.capture.MyIdConfig
import uz.myid.android.sdk.capture.model.MyIdBuildMode
import uz.myid.android.sdk.capture.model.MyIdCameraShape
import uz.myid.android.sdk.capture.model.MyIdEntryType
import uz.myid.android.sdk.capture.model.MyIdImageFormat
import uz.myid.android.sdk.capture.model.MyIdOrganizationDetails
import uz.myid.android.sdk.capture.model.MyIdResidentType
import uz.myid.android.sdk.capture.model.MyIdResolution
import java.util.Locale
class MyIdSdk(
private val client: MyIdClient,
private val activityListener: MyIdSdkActivityListener,
) {
private var currentFlutterResult: MethodChannel.Result? = null
private var currentActivity: Activity? = null
private fun setFlutterResult(result: MethodChannel.Result?) {
currentFlutterResult = result
activityListener.setCurrentFlutterResult(result)
}
fun setActivity(activity: Activity?) {
if (activity != null) {
currentActivity = activity
}
}
fun start(
config: HashMap<String, Any?>?,
result: MethodChannel.Result?
) {
setFlutterResult(result)
try {
if (config == null) {
currentFlutterResult?.error(
"error",
"MyID config is null",
null
)
setFlutterResult(null)
return
}
val clientId: String
val passportData: String
val dateOfBirth: String
val sdkHash: String
val externalId: String
val threshold: Float
val buildMode: MyIdBuildMode
val entryType: MyIdEntryType
val residency: MyIdResidentType
val locale: Locale
val cameraShape: MyIdCameraShape
val resolution: MyIdResolution
val imageFormat: MyIdImageFormat
val organizationDetails: MyIdOrganizationDetails
val withPhoto: Boolean
try {
clientId = config.fetch("clientId")
passportData = config.fetch("passportData")
dateOfBirth = config.fetch("dateOfBirth")
sdkHash = config.fetch("sdkHash")
externalId = config.fetch("externalId")
threshold = config.fetch("threshold").toFloatOrNull() ?: 0.6f
buildMode = when (config.fetch("buildMode").uppercase()) {
MyIdBuildMode.DEBUG.name -> MyIdBuildMode.DEBUG
else -> MyIdBuildMode.PRODUCTION
}
entryType = when (config.fetch("entryType").uppercase()) {
MyIdEntryType.FACE.name -> MyIdEntryType.FACE
else -> MyIdEntryType.AUTH
}
residency = when (config.fetch("residency").uppercase()) {
MyIdResidentType.USER_DEFINED.name -> MyIdResidentType.USER_DEFINED
MyIdResidentType.NON_RESIDENT.name -> MyIdResidentType.NON_RESIDENT
else -> MyIdResidentType.RESIDENT
}
locale = when (config.fetch("locale").uppercase()) {
"ENG" -> Locale("en")
"RUS" -> Locale("ru")
else -> Locale("uz")
}
cameraShape = when (config.fetch("cameraShape").uppercase()) {
MyIdCameraShape.ELLIPSE.name -> MyIdCameraShape.ELLIPSE
else -> MyIdCameraShape.CIRCLE
}
resolution = when (config.fetch("resolution").uppercase()) {
MyIdResolution.RESOLUTION_720.name -> MyIdResolution.RESOLUTION_720
else -> MyIdResolution.RESOLUTION_480
}
imageFormat = when (config.fetch("imageFormat").uppercase()) {
MyIdImageFormat.JPG.name -> MyIdImageFormat.JPG
else -> MyIdImageFormat.PNG
}
val orgMap = config["organizationDetails"] as? HashMap<String, Any?>
organizationDetails = MyIdOrganizationDetails(
phoneNumber = orgMap?.fetch("phone")
)
withPhoto = config.fetch("withPhoto").toBooleanStrictOrNull() ?: false
} catch (e: Exception) {
currentFlutterResult?.error(
"error",
"MyID config error: ${e.message}",
null
)
setFlutterResult(null)
return
}
if (currentActivity == null) {
currentFlutterResult?.error(
"error",
"Android activity does not exist",
null
)
setFlutterResult(null)
return
}
try {
val myIdConfig = MyIdConfig.builder(clientId)
.withPassportData(passportData)
.withBirthDate(dateOfBirth)
.withSdkHash(sdkHash)
.withExternalId(externalId)
.withThreshold(threshold)
.withBuildMode(buildMode)
.withEntryType(entryType)
.withResidency(residency)
.withLocale(locale)
.withCameraShape(cameraShape)
.withResolution(resolution)
.withImageFormat(imageFormat)
.withOrganizationDetails(organizationDetails)
.withPhoto(withPhoto)
.build()
currentActivity?.let {
client.startActivityForResult(it, 1, myIdConfig)
}
} catch (e: Exception) {
currentFlutterResult?.error(
"error",
"Failed to show MyID page: ${e.message}",
null
)
setFlutterResult(null)
return
}
} catch (e: Exception) {
currentFlutterResult?.error(
"error",
"Unexpected error starting MyID page: ${e.message}",
null
)
setFlutterResult(null)
return
}
}
private fun <T> HashMap<String, T>.fetch(key: String): String {
val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
getOrDefault(key, "")
} else {
if (containsKey(key)) {
this[key] ?: ""
} else {
""
}
}
return result?.toString().orEmpty()
}
}
\ No newline at end of file
package uz.aigroup.myid
import android.content.Intent
import android.graphics.Bitmap
import android.util.Base64
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import uz.myid.android.sdk.capture.MyIdClient
import uz.myid.android.sdk.capture.MyIdException
import uz.myid.android.sdk.capture.MyIdResult
import uz.myid.android.sdk.capture.MyIdResultListener
import uz.myid.android.sdk.capture.model.MyIdImageFormat
import java.io.ByteArrayOutputStream
import java.io.IOException
class MyIdSdkActivityListener(
private val client: MyIdClient
) : PluginRegistry.ActivityResultListener {
private var flutterResult: MethodChannel.Result? = null
fun setCurrentFlutterResult(result: MethodChannel.Result?) {
this.flutterResult = result
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
client.handleActivityResult(resultCode, object : MyIdResultListener {
override fun onSuccess(result: MyIdResult) {
if (flutterResult != null) {
try {
val response = Response(
code = result.code,
comparison = result.comparison,
base64 = result.bitmap?.toBase64()
)
flutterResult?.success(response.toMap())
} catch (e: Exception) {
if (result.code != null) {
val response = Response(
code = result.code,
comparison = result.comparison
)
flutterResult?.success(response.toMap())
} else {
flutterResult?.error("error", e.message, null)
}
} finally {
flutterResult = null
}
}
}
override fun onError(e: MyIdException) {
if (flutterResult != null) {
flutterResult?.error(
"error",
"${e.code} - ${e.message}",
null
)
flutterResult = null
}
}
override fun onUserExited() {
if (flutterResult != null) {
flutterResult?.error(
"cancel",
"User exited by clicking the back button.",
null
)
flutterResult = null
}
}
})
return true
}
private fun Bitmap?.toBase64(
format: MyIdImageFormat = MyIdImageFormat.JPG
): String? {
this ?: return null
return try {
"data:image/png;base64,${
Base64.encodeToString(toByteArray(format), Base64.DEFAULT)
}"
} catch (_: Throwable) {
null
}
}
private fun Bitmap.toByteArray(
format: MyIdImageFormat,
quality: Int = 100
): ByteArray? {
var baos: ByteArrayOutputStream? = null
return try {
val compressFormat = when (format) {
MyIdImageFormat.JPG -> Bitmap.CompressFormat.JPEG
MyIdImageFormat.PNG -> Bitmap.CompressFormat.PNG
}
baos = ByteArrayOutputStream()
compress(compressFormat, quality, baos)
baos.toByteArray()
} finally {
if (baos != null) {
try {
baos.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
}
\ No newline at end of file
package uz.aigroup.myid
data class Response(
val code: String? = null,
val comparison: Double? = null,
val base64: String? = null
) {
fun toMap(): HashMap<String, Any> {
val map: HashMap<String, Any> = HashMap()
code?.let { map["code"] = it }
comparison?.let { map["comparison"] = it }
base64?.let { map["base64"] = it }
return map
}
}
\ No newline at end of file
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# myid_example
Demonstrates how to use the myid plugin.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 33
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.myid_example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myid_example">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment