Nhảy tới nội dung

Tích hợp Android

Yêu cầu
  • Yêu cầu Android SDK >= 6.0 (API level 23).

Bước 1: Tải SDK và cấu hình Project

  • Tải về bộ tích hợp SDK tại https://github.com/VNPT-SmartCA/vnpt_smartca_sdk_android và giải nén ra thư mục.
  • Sau khi giải nén, copy các file .aar, thư mục repo vào thư mục libs trong app (1)
  • Thêm thông tin cấu hình vào file app/settings.gradle như dưới:
pluginManagement {  
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}

String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
jcenter()
maven { url "https://jitpack.io" }

// Bỏ qua nếu tích hợp với Flutter app thì
maven {
//Đường dẫn thư mục chứa **repo** ở bước 1
url 'app/libs/repo'
}
// Bỏ qua nếu tích hợp với Flutter app
maven {
url "$storageUrl/download.flutter.io"
}

}
}
  • Thêm các thông tin cấu hình vào app/build.gradle
//...
aaptOptions {
noCompress "bic"
}

dependencies {
//...
implementation 'com.vnpt.smartca.module.vnpt_smartca_module:flutter_release:1.0' // Bỏ qua nếu tích hợp với Flutter app

//Đường dẫn tới các file aar (xem bước 1)
implementation files('libs/vnpt_smartca_sdk_lib-release.aar')
implementation files('libs/ekyc_sdk-release-v3.2.7.aar')
implementation files('libs/eContract-v3.1.0.aar')

implementation 'androidx.core:core-ktx:1.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0"
// SDK eContract
implementation "androidx.multidex:multidex:2.0.1"
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.test.espresso:espresso-idling-resource:3.5.1'
implementation 'com.squareup.okhttp3:okhttp:4.7.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
//noinspection GradleCompatible
implementation 'com.android.support:exifinterface:28.0.0'
implementation 'com.google.code.gson:gson:2.10'
implementation 'net.steamcrafted:load-toast:1.0.12'

implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.12'
}

//..
  • Thêm FlutterActivity trong file AndroidManifest.xml như sau:
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
//......
<application
//......

// Bỏ qua nếu tích hợp với Flutter app
<activity android:name="io.flutter.embedding.android.FlutterFragmentActivity"
android:theme="@style/Theme.Smartca_android_example"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"/>

</application>
  • Bổ sung thuộc tính dưới đây vào file gradle.properties
    android.enableJetifier=true

newArchEnabled=true // Nếu tích hợp với React Natvie
  • Bổ sung thuộc tính dưới đây vào file proguard-rules.pro
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontwarn android.support.**
-dontwarn com.squareup.**
-dontwarn com.google.android.**
-verbose

# -keepattributes *Annotation*
-dontwarn lombok.**
-dontwarn io.realm.**

-dontwarn java.awt.**

# okhttp3
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Application classes that will be serialized/deserialized over Gson
-keep class vnpt.it3.econtract.data.model.** { *; }
-keep class vnpt.it3.econtract.data.** { *; }

# Java 8
-dontwarn java.lang.invoke.*
-dontwarn **$$Lambda$*

# Retrofit 2
-dontnote retrofit2.Platform
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions
-keepclassmembernames,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement


# pdf lib
-keep class com.shockwave.**

#To remove debug logs:
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** w(...);
public static *** i(...);
}

-keep public enum vnpt.it3.econtract.data.**{
*;
}

-keepclassmembers class **.R$* {
public static <fields>;
}
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keep class com.vnptit.innovation.sample.model.** { *; }
-keep class ai.icenter.face3d.native_lib.Face3DConfig { *; }
-keep class ai.icenter.face3d.native_lib.CardConfig { *; }

Bước 2: Khởi tạo SDK tại nơi muốn bắt đầu kết nối

  • Thêm đoạn code dưới đây tại Activity muốn kết nối với SDK trước khi sử dụng các chức năng:
import com.vnpt.smartca.ConfigSDK  
import com.vnpt.smartca.SmartCAEnvironment
import com.vnpt.smartca.SmartCALanguage
import com.vnpt.smartca.SmartCAResultCode
import com.vnpt.smartca.VNPTSmartCASDK

class MainActivity : AppCompatActivity() {
var VNPTSmartCA = VNPTSmartCASDK()
lateinit var editTextTrans: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
val btnActiveAccount = findViewById<Button>(R.id.btnActiveAccount)
editTextTrans = findViewById(R.id.plain_text_input)

val btnConfirmTrans = findViewById<Button>(R.id.btnConfirmTrans)
val bntMainInfo = findViewById<Button>(R.id.btnMainInfo)

val config = ConfigSDK()
config.context = this
//clientId của đối tác được VNPTSmartCA cung cấp khi yêu cầu tích hợp
config.partnerId = "clientId"
//Cấu hình môi trường Dev-test hay Production cùa SmartCA
config.environment = SmartCAEnvironment.DEMO_ENV
//Cấu hình ngôn ngữ app (vi/en)
config.lang = SmartCALanguage.VI
//Cấu hình chọn project là Flutter hay không
config.isFlutter = false
VNPTSmartCA.initSDK(config)
//..
}

Bước 3: Sử dụng các hàm chính

  • Quản lý tài khoản: Đăng ký tài khoản, Quản lý chứng thư, Lịch sử giao dịch, Tài khoản,...
  • Lấy thông tin xác thực người dùng (accessToken & credentiald)
  • Xác nhận/Hủy giao dịch ký số
  • Hủy kết nối SDK

📦 Hàm quản lý tài khoản

  • Đối tác tạo 1 menu liên kết chức năng riêng trên app của mình để người dùng sử dụng các chức năng của SDK như: Đăng ký tài khoản, Quản lý chứng thư, Lịch sử giao dịch, Tài khoản,...
private fun getMainInfo() {
try {
VNPTSmartCA.getMainInfo { result ->
when (result.status) {
SmartCAResultCode.SUCCESS_CODE -> {
// Xử lý khi thành công
}
else -> {
// Xử lý khi có lỗi
}
}
}
} catch (ex: java.lang.Exception) {
throw ex;
}
}

📦 Lấy thông tin xác thực người dùng (accessToken & credentiald)

  • SDK sẽ thực hiện kiểm tra trạng thái tài khoản và chứng thư của khách hàng như: đã kích hoạt hay chưa, chứng thư hợp lệ hay không, tự động làm mới token khi hết hạn,.... Thành công SDK sẽ trả về accessTokencredentialId của người dùng
private fun getAuthentication() {
try {
VNPTSmartCA.getAuthentication { result ->
when (result.status) {
SmartCAResultCode.SUCCESS_CODE -> {
val obj: CallbackResult = Json.decodeFromString(
CallbackResult.serializer(), result.data.toString()
)
// SDK trả lại token, credential của khách hàng
val token = obj.accessToken
val credentialId = obj.credentialId

// Đối tác tạo transaction cho khách hàng để lấy transId, sau đó gọi getWaitingTransaction

}
else -> {
// Xử lý lỗi
val builder = AlertDialog.Builder(this)
builder.setTitle("Thông báo")
builder.setMessage("status: ${result.status}; statusDesc: ${result.statusDesc}")
builder.setPositiveButton(
"Close"
) { dialog, _ -> dialog.dismiss() }
builder.show()
}
}
}
} catch (ex: Exception) {
throw ex;
}
}

📦 Hàm xác nhận/Hủy giao dịch

  • Sau khi lấy được accessToken và credentialId của người dùng từ getAuthentication, từ phía Backend của Đối tác tạo giao dịch ký số cho khách hàng, lấy tranId sau đó gọi hàm xác nhận/hủy giao dịch Ký số.
// tạo giao dịch từ backend, lấy tranId từ hệ thống VNPT SmartCA trả về
private fun getWaitingTransaction(transId: String) {
try {
if (transId.isNullOrEmpty()) {
editTextTrans.setError("Vui lòng điền Id giao dịch");
return
}

VNPTSmartCA.getWaitingTransaction(transId) { result ->
val builder = AlertDialog.Builder(this)
builder.setTitle("Thông báo")
builder.setMessage("status: ${result.status}; statusDesc: ${result.statusDesc}")
builder.setPositiveButton("Close") { dialog, _ -> dialog.dismiss() }
builder.show()

when (result.status) {
SmartCAResultCode.SUCCESS_CODE -> {
// Xử lý khi thành công
}
else -> {
// Xử lý khi thất bại
}
}

}
} catch (ex: Exception) {
throw ex;
}
}

📦 Hàm hủy kết nối SDK

override fun onDestroy() {
VNPTSmartCA.destroySDK()
super.onDestroy()
}