Tích hợp Android SDK
Hướng dẫn tích hợp SmartOTP Android SDK, phiên bản 0.4.0. Viết bằng Kotlin; entry point là object SdkSoft.
Cài đặt
Giải nén Cake_SOTP_SDK_v0.4.0_1.zip vào project của bạn — trong project mẫu, nó nằm dưới thư mục libs.
repositories {
maven { url rootDir.path + "/libs/" }
}implementation "xyz.be.cake.smartotpsdk:legacy:0.4.0"Khởi tạo
SdkSoft.initialize(
context = this,
baseURL = "<BASE_URL>",
networkConfig = NetworkConfig(),
isDebug = false) // không bao giờ phát hành bản release khi bật trace requestTham số:
| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
context | Context | Có | — | Android context. |
baseURL | String | Có | — | Base URL cho các lệnh gọi API của SDK. |
networkConfig | NetworkConfig | Có | — | Cấu hình network client. |
isDebug | Boolean | Không | false | Chế độ debug. Đặt true để trace log request. |
NetworkConfig
class NetworkConfig(
val readTimeoutSeconds: Long = 60,
val writeTimeoutSeconds: Long = 60,
val connectTimeoutSeconds: Long = 60,
val callTimeoutSeconds: Long = 0
)| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
readTimeoutSeconds | Long | Không | 60 | Timeout đọc cho kết nối mới. |
writeTimeoutSeconds | Long | Không | 60 | Timeout ghi cho kết nối mới. |
connectTimeoutSeconds | Long | Không | 60 | Timeout kết nối cho kết nối mới. |
callTimeoutSeconds | Long | Không | 0 | Timeout cho toàn bộ lệnh gọi. |
Các tham số này ánh xạ vào cấu hình OkHttpClient.
Header tùy chỉnh
SdkSoft.setRequestHeaders(
mapOf(
Pair("key", "value")
)
)| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
headers | Map<String,String> | Có | — | Header bổ sung được thêm vào mọi request API của SDK. |
Kích hoạt
Gọi sau khi Đăng ký thành công trên backend của bạn.
val activateBody = ActivateBody(
partnerId = "{{partner_id}}",
userId = "user_00000001",
username = "nguyenvana",
deviceId = "device_00000001",
deviceOs = "Android",
appVersion = "1.0.0",
registrationId = "reg_00000001",
activationKey = "fake_activation_key",
token = "fake_device_token",
pushToken = "fake_push_token",
)
SdkSoft.activate(activeBody = activateBody, overrideBaseUrl = overrideUrl, callback = {
// Không ghi log response — nó chứa client secret key.
})ActivateBody
| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
partnerId | String | Có | — | ID partner. |
deviceId | String | Có | — | UUID của thiết bị. |
userId | String | Có | — | ID người dùng. |
username | String | Không | — | Tên người dùng. |
pushToken | String | Có | — | Token Firebase dùng để push khóa challenge từ server đến client. |
token | String | Có | — | Token đăng ký từ Đăng ký. |
registrationId | String | Có | — | Registration id từ Đăng ký. |
activationKey | String | Có | — | Activation key từ Đăng ký. Chỉ dùng một lần — gọi lại Đăng ký để lấy key mới. |
deviceOs | String | Có | — | Hệ điều hành thiết bị dùng để theo dõi, ví dụ Android. |
appVersion | String | Có | — | Phiên bản ứng dụng hiện tại. |
Tham số lệnh gọi
| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
activateBody | ActivateBody | Có | — | Payload kích hoạt. |
overrideBaseUrl | String | Không | — | Base URL ghi đè cho lệnh gọi này. |
callback | Unit | Có | — | Nhận một ActivateResponse. |
Response
{
"success": true,
"code": 1,
"message": "success",
"data": {
"key": "fake_client_secret_key",
"period": "15",
"algorithm": "HmacSHA512",
"length": "6",
"type": "totp",
"issuer": "SOTP",
"id": "123456"
}
}| Trường | Kiểu | Mô tả |
|---|---|---|
key | String | Khóa bí mật dùng để tạo OTP. |
period | String | Số giây một OTP còn hiệu lực. |
length | String | Số chữ số của một OTP. |
issuer | String | Bên phát hành đã tạo OTP. |
type | String | Loại soft OTP. |
id | String | ID kích hoạt, còn gọi là số serial. |
SDK trả kết quả này dưới dạng ActivateResponse, gồm key, period, algorithm, length, type, issuer, code, message, id và unhandledException.
INFO
period và length được trả về dưới dạng string ở đây, trong khi Đồng bộ thời gian trả về cùng hai trường đó dưới dạng integer. Hãy parse một cách thận trọng.
| Mã | Mô tả |
|---|---|
3 | Parameter invalid |
103 | Thông tin Partner không chính xác — Partner details are incorrect. |
123 | Yêu cầu vượt giới hạn. Vui lòng thử lại sau ít phút — Request limit exceeded. |
124 | OTP không hợp lệ — Invalid OTP. |
125 | OTP hết hạn sử dụng — OTP expired. |
129 | Token không hợp lệ — Invalid token. |
-2 | Secret token decryption failed. |
PIN và lưu trữ
SdkSoft.storedSecureSmartOTP(pin = "1234") // Boolean
SdkSoft.isValidPin(pin = "1234") // Boolean| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
pin | String | Có | — | PIN của SmartOTP, 4 chữ số. |
storedSecureSmartOTP trả về true khi khóa bí mật được lưu thành công. Gọi hàm này một lần sau khi kích hoạt.
Đổi PIN
val result = SdkSoft.changePin(oldPin = oldPin, newPin = newPin)
when (result) {
ChangePinResult.UNKNOWN_FAILURE -> {}
ChangePinResult.INVALID_OLD_PIN -> {}
ChangePinResult.SUCCESS -> {}
}| Trường | Kiểu | Mô tả |
|---|---|---|
SUCCESS | ChangePinResult | PIN đã được đổi. |
INVALID_OLD_PIN | ChangePinResult | oldPin không khớp với PIN đã lưu. |
UNKNOWN_FAILURE | ChangePinResult | Xảy ra lỗi nội bộ của SDK. |
PIN mới không được trùng với hai PIN trước đó.
INFO
Android trả về ba giá trị ChangePinResult; iOS trả về năm giá trị, tách riêng sameOldAndNewPin và samePreviousPins. Trên Android, cả hai trường hợp đó đều gộp chung vào UNKNOWN_FAILURE, nên bạn không thể báo chính xác cho người dùng lý do PIN mới bị từ chối.
Tạo OTP
val otp = SdkSoft.generateSmartOTP() // cơ bản
val otp = SdkSoft.generateAdvancedSotp(challengeKey = "fake_challenge_key") // nâng cao| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
challengeKey | String | Có | — | Khóa challenge từ Tạo giao dịch. Chỉ dùng cho OTP nâng cao. |
Cả hai đều trả về một chuỗi 6 chữ số, hoặc một chuỗi rỗng nếu thất bại.
Lấy trạng thái
SdkSoft.getStatus(
userId = "user_00000001",
overrideBaseUrl = overrideUrl,
callback = {
Log.d("TAG", "${it?.code} ${it?.message} ${it?.status}")
}
)| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
userId | String? | Không | — | Người dùng cần kiểm tra. Khi là null, trả về trạng thái của người dùng đang được kích hoạt hiện tại. |
overrideBaseUrl | String | Không | — | Base URL ghi đè. |
callback | Unit | Có | — | Nhận một StatusResponse với code, message, status. |
Trả về một trong các giá trị NOT_REGISTERED, NOT_CURRENT_USER, NON_ACTIVATED, ACTIVATED, TEMPORARY_BLOCKED. Ý nghĩa thay đổi tùy vào việc bạn có truyền userId hay không — xem Tổng quan Mobile SDK § Các giá trị trạng thái.
Đồng bộ thời gian
val syncTimeBody = SyncTimeBody(appId = "app_00000001")
SdkSoft.syncTime(
syncTimeBody = syncTimeBody,
useOtp = false,
overrideBaseUrl = overrideUrl,
callback = { }
)| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
syncTimeBody | SyncTimeBody | Có | — | Mang theo appId, dùng để theo dõi. |
useOtp | Boolean | Có | — | Gửi OTP của chu kỳ hiện tại và chu kỳ trước để mở khóa tài khoản. SDK dùng PIN đã lưu để tạo chúng. |
overrideBaseUrl | String | Không | — | Base URL ghi đè. |
callback | Unit | Có | — | Nhận một SyncTimeResponse. |
useOtp = true là cách một tài khoản TEMPORARY_BLOCKED được mở khóa — cặp OTP liên tiếp chứng minh thiết bị vẫn giữ đúng khóa bí mật.
| Mã | Mô tả |
|---|---|
103 | Thông tin Partner không chính xác — Partner details are incorrect. |
129 | Token không hợp lệ — Invalid token. |
190108 | Tài khoản chưa hoạt động — Account not activated. |
190302 | OTP không chính xác — Incorrect OTP. |
-1 | Thông tin không hợp lệ — Invalid information. |
Hủy kích hoạt
SdkSoft.retire(
overrideBaseUrl = overrideUrl,
callback = {
Log.d("TAG", "${it?.code} ${it?.message}")
}
)Hủy kích hoạt SmartOTP đang hoạt động hiện tại. Xem Hủy kích hoạt để biết thao tác này làm gì ở phía server.
Giao dịch mới nhất
SdkSoft.getLatestTransaction(
overrideBaseUrl = overrideUrl,
callback = { }
)Trả về một TransactionResponse mang theo challengeKey cùng các trường giao dịch — appId, transactionId, transactionDesc, transactionAmount, receiverAccount, senderAccount, currency, type, transactionDate, createdAt, transactionMetadata.
Tương đương với Lấy giao dịch mới nhất; áp dụng cùng lưu ý về việc nó trả về giao dịch mới nhất bất kể đó là giao dịch nào.
Polling trạng thái
SdkSoft.startStatusPolling(
interval = 30,
appId = "app_00000001"
)
SdkSoft.cancelStatusPolling()| Tham số | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
interval | Int | Không | 30 | Số giây giữa các lần kiểm tra trạng thái. |
appId | String | Không | — | App ID dùng trong lệnh gọi đồng bộ thời gian. |
Job này kiểm tra trạng thái SmartOTP ở mỗi tick và chạy đồng bộ thời gian bất cứ khi nào trạng thái là ACTIVATED. Luôn đi kèm với cancelStatusPolling khi teardown.
Accessor
| Trường | Kiểu | Mô tả |
|---|---|---|
getRegistrationId() | String | Registration id được lưu khi kích hoạt. |
getSerialId() | String | Serial ID đã đăng ký. Rỗng nếu chưa đăng ký hoặc có lỗi. |
getCurrentUserId() | String? | User ID đã đăng ký. Null nếu chưa đăng ký hoặc có lỗi. |
getCurrentUsername() | String | Username đã đăng ký. Rỗng nếu chưa đăng ký. |
isSmartOtpRegistered() | Boolean | Thiết bị này đã đăng ký SmartOTP hay chưa. |
getTime() | Long | Timestamp của server. |
getPeriod() | Int | Cấu hình chu kỳ hiện tại tính bằng giây. |
getRemainingValidityTime() | Int | Số giây còn lại của OTP hiện tại. |
INFO
ActivateResponse.length có kiểu String?.
Bước tiếp theo
- Tổng quan Mobile SDK — các khái niệm dùng chung với iOS
- Xác minh OTP — xác minh mã từ backend của bạn
- Mã lỗi — bảng lỗi đầy đủ