SDK Swift
Lihat di GitHubPaket Swift TraciveSDK, versi 0.1.0, mode OAuth saja di Tahap 1. iOS 15 ke atas (juga macOS 12). Tanpa dependensi pihak ketiga sama sekali: HTTP, kripto, dan penyimpanan memakai fasilitas bawaan platform.
Pasang
// Package.swift
.package(url: "https://github.com/pleistocent/tracive-sdk-swift.git", from: "0.1.0")Di Xcode: File → Add Package Dependencies…, lalu tambahkan TraciveSDK ke target aplikasi Anda.
Setup aplikasi
SDK memeriksa apakah aplikasi Tracive terpasang sebelum mengarahkan ke mana pun, dan canOpenURL menjawab tidak untuk skema yang tidak dideklarasikan, tanpa pesan apa pun. Lewatkan langkah ini dan setiap pengguna tampak belum memasang Tracive:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tracive</string>
<string>tracivesandbox</string>
</array>- · Kedua skema, bukan hanya yang pertama. Di
.sandboxSDK memeriksatracivesandbox://, jadi tanpa entri itu penguji dikirim ke halaman install untuk aplikasi yang sedang mereka pegang. - · Redirect URI harus Universal Link https di domain milik Anda, dengan capability Associated Domains dan
apple-app-site-association. Skema kustom tidak bisa diterima: aplikasi mana pun bisa mengklaimnya dan mencegat authorization code. Server mencocokkannya persis, tanpa toleransi garis miring di akhir.
WKWebView. Universal Link tidak menyala dari WebView, jadi redirect-nya tidak pernah kembali.Membuat client
Sekali, saat aplikasi mulai, lalu dipegang sepanjang umur aplikasi. Pakai konstanta TraciveScopes, bukan string: server menolak seluruh permintaan consent kalau satu nama scope tidak dikenalnya. partnerUserId yang kosong atau hanya spasi menghentikan aplikasi lewat precondition, di build release juga.
import TraciveSDK
let tracive = TraciveClient(
mode: .oauth(
clientId: "trcvc_…", // dari portal
redirectUri: URL(string: "https://app-anda.example/oauth/tracive")!, // Universal Link, persis seperti terdaftar
scopes: [TraciveScopes.scammerCheck, TraciveScopes.profileRead],
partnerUserId: customerId, // id Anda sendiri, buram dan stabil
clientType: .public // aplikasi menukar code sendiri
),
environment: .sandbox // .production adalah bawaannya
)TraciveClient.init melakukan I/O yang memblokir: ia membuka, dan pada peluncuran pertama membuat, database SQLite cache. Kalau anggaran waktu peluncuran Anda ketat, bangun client di luar main thread lalu serahkan ke UI saat siap.Otorisasi
Berbeda dengan SDK Kotlin, Flutter, dan React Native, authorize() di sini menunggu hasil akhirnya. Tetapi redirect tetap harus Anda serahkan ke handleCallback, dan hasilnya ditangani dengan fungsi yang sama.
func handle(_ result: AuthResult) {
switch result {
case .authorized(let grantedScopes): onConnected(grantedScopes) // bisa lebih sempit dari yang diminta
case .appNotInstalled: showInstallHint() // halaman install sudah dibuka
case .denied: respectThat()
case .codeReceived(let code, let codeVerifier, let redirectUri):
sendToOwnBackend(code, codeVerifier, redirectUri) // client confidential saja
case .failed(let error): report(error)
}
}
handle(await tracive.authorize()).authorized bisa membawa scope yang lebih sempit dari yang diminta, jadi periksa grantedScopes sebelum menyalakan fitur. .appNotInstalled berarti SDK sudah membuka halaman install; tidak ada yang dilanjutkan otomatis.
Mengecek
TraciveQuery.phone(e164:) menolak nomor lokal, karena server tidak bisa menebak kode negaranya. normalizePhoneNumber menambahkannya, dari kode alpha-3 (IDN) atau kode telepon (+62). Builder lainnya: email(value:), bankAccount(countryAlpha3:bankCode:account:), iban(iban:), crypto(chain:address:), dan username(platform:handle:). Untuk menyebut bank dengan kode nasional atau BIC, pakai bankAccount(countryAlpha3:bankShortCode:account:) atau bankAccount(countryAlpha3:bic:account:). Kode yang tidak ada di daftar kode bank ditolak di perangkat dengan unknown_bank_code, jadi tidak pernah ditagih.
let query: TraciveQuery
do {
query = try TraciveQuery.phone(e164: normalizePhoneNumber("IDN", input)) // "0857-1860-9079" → +6285718609079
} catch let error as TraciveQueryError {
return showInputError(error.reason) // tidak ada yang terkirim, tidak ditagih
}
let result = try await tracive.checkScammer(query)
render(result.riskTier, result.reportTotal, result.disclaimer) // disclaimer wajib tampilValidasi dan pelipatan terjadi di klien, sebelum request apa pun, karena miss tetap ditagih. Aturannya ada di grammar input.
Cache
Cache persisten aktif tanpa konfigurasi: SQLite sistem, setiap baris dienkripsi AES-GCM dengan kunci di Keychain. Hit tidak menyentuh jaringan dan tidak memakan kredit. Kalau cache gagal dibuka, SDK tetap jalan tanpa cache dan errornya ada di cacheInitializationError; pantau itu, karena setiap pengecekan lalu ditagih.
Cache yang sama juga mencatat hasil yang ditunjukkan pada satu transaksi, supaya layar detail transaksi tetap bisa menampilkannya kemudian tanpa pengecekan kedua. Setiap catatan adalah snapshot dengan retensi 90 hari. Jangan kirim hasil ini ke server Anda: ketentuan partner melarangnya.
// Setelah transfer tercipta dan punya nomor referensi.
try tracive.cache.writeTransactionCheck(result, for: transfer.reference)
// Di detail transaksi, kapan pun kemudian. nil = tidak ada pengecekan; jangan tampilkan apa-apa.
if let shown = try tracive.cache.readTransactionCheck(for: transfer.reference) {
renderSecurityCheckCard(shown)
}Error & biaya
Semua error adalah TraciveError. Token kedaluwarsa tidak perlu Anda tangani: SDK me-refresh lalu mengulang sekali.
do {
let result = try await tracive.checkScammer(query, idempotencyKey: attemptId) // satu kunci per pengecekan
render(result)
} catch TraciveError.insufficientCredits {
promptTopUp() // 402: jangan cek credits() sebelum setiap pengecekan
} catch TraciveError.grantRevoked, TraciveError.invalidToken {
reauthorize() // grant hilang atau belum ada; jangan diulang
} catch TraciveError.rateLimited(let retryAfter, _) {
backOff(retryAfter) // tidak pernah diulang otomatis
}- · Setiap request yang sampai ke server ditagih, termasuk miss.
- · SDK hanya mengulang pengecekan yang gagal kalau Anda memberi
idempotencyKey: 5xx atau timeout tidak memberi tahu apakah pengecekan pertama sudah ditagih. - · Jangan panggil
credits()sebelum setiap pengecekan. Tangani 402-nya.
Keluar
signOut() juga mengosongkan cache: isinya adalah riwayat pencarian pengguna yang keluar, dan pengguna berikutnya di perangkat itu tidak boleh mewarisinya.
await tracive.signOut() // revoke best-effort, lalu token dan cache dihapus apa pun hasilnya