Chuyển tới nội dung chính

XMDT — iOS

SDK native, không dùng WebView. Swift Package, module AlogameKycKit (class chính là AlogameKycSdk — xem Khởi tạo — nhưng thứ bạn import là AlogameKycKit). Độc lập với SDK v2 — không trộn với import OegSdkV2 hay kỳ vọng chúng chia sẻ state.

Các môi trường
Môi trườngBase URL
Devhttps://api-xmdt.dev.alogame.vn
Prodhttps://api-xmdt.alogame.vn

Cả hai đều đang hoạt động. gameId của bạn phải được Alogame Operations bật XMDT trước khi dùng được ở cả hai — xem Tích hợp phía Server.

Đọc phần này trước

Tích hợp Server mô tả lệnh gọi duy nhất phía server của bạn để mint sessionToken. Client của bạn không bao giờ gọi trực tiếp API danh tính của Alogame và không bao giờ thấy secret HMAC của bạn.

Deployment target: iOS 15+. Dùng được từ cả Swift lẫn Objective-C — xem Objective-C bên dưới cho API phía Objective-C.

1. Thêm package​

Xcode → File → Add Package Dependencies…

https://github.com/alo-game/alogame-kyc-sdk-ios

Ở Dependency Rule, chọn Up to Next Major bắt đầu từ 0.2.0 (hoặc bất kỳ tag mới hơn — xem releases). Khi trình chọn hỏi product nào cần thêm vào target, chọn AlogameKycKit.

Nếu bạn đang ở 0.1.x

"Up to Next Major" của SPM coi thành phần khác-0 đầu tiên của version 0.x là major — một rule ghim ở 0.1.1 sẽ resolve thành >=0.1.1, <0.2.0 và sẽ không bao giờ tự lấy 0.2.0 (bản có Objective-C). Cần nâng cận dưới của version rule lên 0.2.0 để lấy được.

Đây là xcframework đã compile, không phải source repo

Đây là một repo release riêng, công khai, phát hành sẵn một .xcframework cho mỗi tag — không phải source repo riêng tư gitlab.oeg.vn (mà Xcode của bạn cũng không có quyền truy cập). Mỗi release được build bởi scripts/deploy_ios_spm.sh trong dev repo.

Package này khai báo zero dependency bên thứ ba — chỉ link Foundation, UIKit, và SafariServices, không có gì xung đột với dependency tree hiện tại của app bạn.

2. Khởi tạo​

Một lần, lúc app khởi động:

Swift
import AlogameKycKit

AlogameKycSdk.shared.initialize(
AlogameKycConfig(env: .dev)
)
Game thương hiệu OEG

AlogameKycConfig có thêm tham số tùy chọn brand — .alo (mặc định) hoặc .oeg. Nó chỉ đổi logo hiển thị ở phần header của màn hình; env vẫn là thứ duy nhất quyết định endpoint mạng.

Swift
AlogameKycConfig(env: .dev, brand: .oeg)

3. Set game role​

Sau khi bạn có sessionToken từ server của mình (xem Tích hợp Server):

Swift
AlogameKycSdk.shared.setGameRole(
uid: "player_account_name", // phải khớp với `username` mà server bạn dùng để mint session
sessionToken: sessionToken,
serverId: "server_01", // tùy chọn — bỏ qua nếu không áp dụng
roleId: "character_123" // tùy chọn
)

uid và sessionToken luôn đến cùng nhau từ cùng một response của server — không bao giờ gọi hàm này với một trong hai mà thiếu cái còn lại. Đổi sang uid khác sẽ xóa mọi trạng thái đã-xác-thực được cache của uid trước đó.

4. Hiện màn hình​

Swift
import AlogameKycKit

class YourViewController: UIViewController, AlogameKycListener {

func startXmdt() {
AlogameKycSdk.shared.show(from: self, listener: self)
}

func onResult(_ result: AlogameKycResult) {
switch result {
case .success:
break // Chỉ là tín hiệu giao diện — xem cảnh báo dưới đây trước khi unlock bất cứ thứ gì
case .failed(let reason, let message):
print("XMDT failed: \(reason)" + (message.map { " (\($0))" } ?? ""))
case .cancelled:
break // Người chơi đóng form — chỉ xảy ra khi xmdtRequired là false
}
}

func onSessionTokenNeeded(uid: String) {
// xem "Làm mới token đã hết hạn" dưới đây
}
}
onResult là tín hiệu giao diện, không phải bằng chứng

.success ở đây chỉ có nghĩa là thiết bị người chơi báo rằng luồng đã hoàn tất — một client bị mod có thể tạo ra callback này mà chưa từng xác thực gì cả. Trước khi cho người chơi qua bất cứ thứ gì phụ thuộc vào XMDT, hãy gọi lại POST /xmdt/session từ server của bạn và tin vào trường xmdtCompleted trong response đó. Xem Tích hợp Server.

AlogameKycListener được SDK giữ dưới dạng weak — một strong reference từ singleton tới view controller của bạn sẽ tạo ra retain cycle mà bạn không thấy được cũng không phá được, nên hãy đảm bảo thứ bạn truyền vào tuân thủ protocol này và sống đủ lâu trong suốt luồng (một view controller đang present màn hình đã tự nhiên làm điều đó).

SDK tự quản lý toàn bộ màn hình của nó — họ tên, ngày sinh, nhập số điện thoại, OTP, và consent đều được xử lý nội bộ, và không có gì người chơi nhập vào từng hiện ra trước app của bạn. onResult chỉ fire đúng một lần cho mỗi lệnh show(), trên main queue, sau khi màn hình đã dismiss — an toàn để present UI của bạn ngay lập tức.

Gọi show() lần nữa khi một luồng đang mở sẽ bị bỏ qua (có log, không crash).

Xử lý .failed​

Swift
switch reason {
case .notInitialized, .noGameRole:
// Lỗi tích hợp phía bạn — initialize()/setGameRole() chưa được
// gọi trước. Không bao giờ hiện cái này cho người chơi; sửa lại thứ tự gọi.
break
case .sessionUnavailable, .sessionInvalid:
// Không lấy được session token dùng được. Mint một token mới và thử lại
// show() từ đầu.
break
case .otpAttemptsExceeded, .otpUnavailable, .rateLimited:
// Người chơi (hoặc mạng của họ) chạm giới hạn chống lạm dụng. Hiện thông báo chung
// "thử lại sau" — không tiết lộ giới hạn nào bị chạm.
break
case .serviceUnavailable:
// Dịch vụ danh tính của Alogame bị down sau khi người chơi đã
// tự thử lại một lần trong màn hình. Cho họ thử show() lại sau.
break
case .unknownError:
// Catch-all để tương thích về sau. Không bao giờ crash.
break
}

Các lỗi có thể phục hồi (nhập sai OTP, lỗi validate, mạng chập chờn tạm thời) được xử lý ngay trong màn hình riêng của SDK và không bao giờ tới onResult — mọi lý do .failed ở trên đều là trường hợp luồng không thể tiếp tục, không phải trường hợp người chơi lỡ gõ nhầm.

Làm mới token đã hết hạn​

Hai cách để cấp một sessionToken mới khi token từ setGameRole hết hạn giữa luồng — chọn một trong hai:

Dùng closure (dùng được nếu app của bạn giữ được closure qua ranh giới SDK):

Swift
AlogameKycSdk.shared.initialize(
AlogameKycConfig(env: .dev, tokenProvider: { uid, callback in
// Gọi lại endpoint mint của server bạn cho uid này, rồi:
callback(newSessionTokenOrNil)
})
)

Dùng delegate (cho lớp bridge/engine không truyền được closure qua ranh giới ngôn ngữ — không set tokenProvider, cài đặt hàm dưới đây thay vào đó):

Swift
func onSessionTokenNeeded(uid: String) {
// Mint token mới cho `uid`, rồi:
AlogameKycSdk.shared.provideSessionToken(newToken)
// hoặc, nếu không lấy được:
AlogameKycSdk.shared.abortPendingToken()
}

Nếu bạn không cài đặt cách nào, một token hết hạn sẽ kết thúc luồng với .sessionUnavailable thay vì treo mãi.

Xoay màn hình​

Màn hình hỗ trợ cả dọc và ngang — không cần cấu hình gì phía bạn.

Objective-C​

Cùng một package, cùng singleton AlogameKycSdk — không cần thêm gì riêng. AlogameKycResult không thể đi qua ranh giới Objective-C được (nó là enum Swift mang payload khác nhau theo từng case — .failed(reason:, message:) — và Objective-C không có khái niệm tương đương), nên phần bề mặt hướng Objective-C dùng một protocol listener song song nhỏ, cộng hai enum backing Int, thay vì cố ép nguyên dạng Swift qua:

Objective-C
#import <AlogameKycKit/AlogameKycKit-Swift.h>

@interface MyKycListener : NSObject <AlogameKycObjcListener>
@end

@implementation MyKycListener

- (void)onResultWithStatus:(AlogameKycResultStatus)status
reason:(AlogameKycFailReasonCode)reason
message:(NSString * _Nullable)message {
switch (status) {
case AlogameKycResultStatusSuccess:
break; // Chỉ là tín hiệu giao diện — xem cảnh báo ở trên trước khi unlock bất cứ thứ gì
case AlogameKycResultStatusFailed:
NSLog(@"XMDT failed, reason=%ld", (long)reason);
break;
case AlogameKycResultStatusCancelled:
break;
}
}

- (void)onSessionTokenNeededForUid:(NSString *)uid {
// xem "Làm mới token đã hết hạn" ở trên
}

@end
Objective-C
[[AlogameKycSdk shared] initializeWithEnv:AlogameKycEnvDev tokenProvider:nil];

// Game thương hiệu OEG — một selector riêng, nên call site 2 tham số
// hiện có không bị hỏng:
[[AlogameKycSdk shared] initializeWithEnv:AlogameKycEnvDev tokenProvider:nil brand:AlogameKycBrandOeg];

[[AlogameKycSdk shared] setGameRoleWithUid:@"player_account_name"
sessionToken:sessionToken
serverId:nil
roleId:nil];

MyKycListener *listener = [MyKycListener new];
[[AlogameKycSdk shared] showFromViewController:self objcListener:listener];
Cái gì thật sự đã được xác nhận ở đây

AlogameKycSdk.shared, showFromViewController:objcListener:, initializeWithEnv:tokenProvider:, initializeWithEnv:tokenProvider:brand:, và các enum/protocol ở trên đã được xác nhận bằng một lần build-và-test thật bằng xcodebuild nhắm vào iOS Simulator SDK, bao gồm đúng file AlogameKycKit-Swift.h được sinh ra mà các đoạn code trên lấy từ đó. Cái chưa được kiểm chứng là một app Objective-C thật gọi vào trọn luồng — nếu gặp gì không khớp trang này, báo lại cho chúng tôi.

Tham khảo​

TypeMục đích
AlogameKycSdk.sharedToàn bộ API công khai — initialize, setGameRole, setPrefill, isVerified, show, provideSessionToken, abortPendingToken
AlogameKycConfig(env:tokenProvider:brand:)Truyền một lần vào initialize — brand tùy chọn, mặc định .alo
AlogameKycEnv.dev | .prod
AlogameKycBrand.alo | .oeg — chỉ thay đổi giao diện, không ảnh hưởng tới việc chọn env/endpoint
AlogameKycResult.success | .failed(reason:message:) | .cancelled
AlogameKycFailReason9 case cố định — xem phần trên
AlogameKycListeneronResult(_:), tùy chọn onSessionTokenNeeded(uid:)
AlogameKycObjcListenerListener phía Objective-C — onResultWithStatus:reason:message:, tùy chọn onSessionTokenNeededForUid:
AlogameKycResultStatusBản mirror backing Int của AlogameKycResult — Success | Failed | Cancelled
AlogameKycFailReasonCodeBản mirror backing Int của AlogameKycFailReason, cùng 9 case

AlogameKycSdk.shared.setPrefill(_:) là tùy chọn — nếu lớp đăng nhập của bạn đã có sẵn tên người chơi (ví dụ từ Sign in with Apple), truyền vào đây trước khi gọi show() để prefill field trong form. Nó chỉ giữ trong memory và không bao giờ được gửi đi đâu cho tới khi người chơi đã thấy và có thể sửa nó.

fullName của Sign in with Apple chỉ đến đúng một lần

ASAuthorizationAppleIDCredential.fullName chỉ có giá trị ở lần authorization đầu tiên cho một Apple ID cụ thể. Hãy lấy nó ngay lúc đó và truyền vào setPrefill — nó sẽ trống ở mọi lần đăng nhập sau, cho tới khi người chơi revoke app của bạn trong Settings.

AlogameKycSdk.shared.isVerified đọc từ một cache trong memory của lần chạy thành công gần nhất — không phải một nguồn để authorize, cùng lưu ý như onResult ở trên. Chỉ dùng nó cho trạng thái UI (ví dụ: ẩn nút "Xác thực ngay"), không bao giờ dùng làm cổng chặn thực sự.