π μ½λ°± μ²λ¦¬νκΈ°
Test Solution SDKλ ν μ€νΈ μ§ν μ€ λ°μνλ μ£Όμ μ΄λ²€νΈλ λ‘κ·Έ λ°μ΄ν°λ₯Ό Host μ±μΌλ‘ λΉλκΈ°μ μΌλ‘ μ λ¬ν©λλ€. μ΄ ν΅μ μ μ½λ°±(Callback) 맀컀λμ¦μ ν΅ν΄ μ΄λ£¨μ΄μ§λλ€.
Host μ±μμλ onResult, onLog, onInfo μΈ κ°μ§ μ½λ°±μ ν΅ν΄ SDKμ μνλ₯Ό μμ νκ³ νμν νμ μ‘°μΉλ₯Ό μ·¨ν μ μμ΅λλ€.
onResult μ½λ°±β
onResultλ ν
μ€νΈμ ν΅μ¬μ μΈ μν λ³κ²½μ΄ λ°μνμ λ νΈμΆλ©λλ€. μλ₯Ό λ€μ΄, μ¬μ©μκ° λͺ¨λ λ¬Ένμ μλ£νκ±°λ, μ€κ°μ ν
μ€νΈλ₯Ό μ’
λ£νκ±°λ, λλ μκΈ°μΉ μμ μ€λ₯κ° λ°μν κ²½μ°κ° ν΄λΉλ©λλ€.
β οΈ μ€μ:
onResultμ½λ°±μ μ±κ²© μ ν λΆμ κ²°κ³Όλ₯Ό λ°ννμ§ μμ΅λλ€. ν μ€νΈμ μλ£ μ¬λΆμ κ°μ μν κ°μ μ λ¬νλ μ©λμ λλ€.
λ°μ΄ν° ꡬ쑰β
onResultλ μλμ κ°μ ꡬ쑰μ JSON κ°μ²΄(λλ κ° νλ«νΌμ λ§λ Map/Dictionary νν)λ₯Ό μ λ¬ν©λλ€.
| νλλͺ | νμ | μ€λͺ |
|---|---|---|
status | String | νμ. μ½λ°±μ μμΈμ λνλ΄λ μν μ½λμ
λλ€. ('COMPLETED', 'USERCANCELLED', 'ERROR') |
data | Object | νμ. μνμ λν μ¬λμ΄ μ½μ μ μλ λ©μμ§μ λλ€. λλ²κΉ μ΄λ μ¬μ©μ μλ΄μ νμ©ν μ μμ΅λλ€. |
sdkVersion | String | νμ. SDKμ λ²μ μ 보μ λλ€. |
customData | Object | νμ. startTest νΈμΆ μ μ λ¬νλ customData κ°μ²΄λ₯Ό κ·Έλλ‘ λ°νν©λλ€. Host μ±μ μΈμ
μ 보 λ±μ μ μ§νλ λ° μ μ©ν©λλ€. |
μν(Status) μ½λ μ’ λ₯β
'COMPLETED': μ¬μ©μκ° 180κ° λ¬Ένμ λͺ¨λ μλ£νκ³ SDKκ° μ μμ μΌλ‘ μ’ λ£λμμμ μλ―Έν©λλ€.'USERCANCELLED': μ¬μ©μκ° ν μ€νΈλ₯Ό μλ£νκΈ° μ μ μλμ μΌλ‘ 'λκ°κΈ°'μ κ°μ UIλ₯Ό ν΅ν΄ μ’ λ£νμμ μλ―Έν©λλ€.'ERROR': μ ν¨νμ§ μμ νλΌλ―Έν° μ λ¬, λ€νΈμν¬ μ€λ₯ λ± μκΈ°μΉ μμ λ¬Έμ λ‘ ν μ€νΈκ° μ€λ¨λμμμ μλ―Έν©λλ€.
λ°μ΄ν° μμβ
1. ν μ€νΈ μ μ μλ£ μ
{
"status": "COMPLETED",
"data": {
"suid": "[SUID]",
"goodsId": "[GOODS_ID]",
"language": "[LANGUAGE]",
"completedAt": "2025-01-01T00:00:00.000000"
},
"sdkVersion": "1.0.0+10000",
"customData": { "internalUserId": "user-1234" }
}
2. μ€λ₯ λ°μ μ
{
"status": "USERCANCELLED",
"data": { "errorCode": "N005", "errorMessage": "DATA_PARSE_FAILED" },
"sdkVersion": "1.0.0+10000",
"customData": { "internalUserId": "user-1234" }
}
onLog μ½λ°±β
onLogλ SDK λ΄λΆμ μμΈ λμ λ‘κ·Έλ₯Ό Host μ±μΌλ‘ μ λ¬νκΈ° μν λλ²κΉ
μ© μ½λ°±μ
λλ€. μ΄ μ½λ°±μ startTest νΈμΆ μ isDevelopment μ enableHostLogging κ°μ trueλ‘ μ€μ ν΄μΌλ§ νμ±νλ©λλ€.
π‘ Tip: κ°λ° λ° ν μ€νΈ λ¨κ³μμλ
enableHostLoggingμ νμ±ννμ¬ λ¬Έμ μ μμΈμ λΉ λ₯΄κ² νμ νκ³ , νλ‘λμ (릴리μ¦) λ²μ μμλ λΉνμ±ννλ κ²μ κΆμ₯ν©λλ€.
λ°μ΄ν° ꡬ쑰β
| νλλͺ | νμ | μ€λͺ |
|---|---|---|
level | String | νμ. λ‘κ·Έ λ 벨μ
λλ€. ('INFO', 'WARNING', 'ERROR') |
message | String | νμ. μ€μ λ‘κ·Έ λ©μμ§ λ΄μ©μ λλ€. |
error | String | μ€λ₯ μ 보μ λλ€. |
timestamp | String | νμ. λ‘κ·Έκ° λ°μν μκ° (ISO 8601 νμ) |
λ°μ΄ν° μμβ
{
"level": "INFO",
"message": "κ°λ° λͺ¨λλ‘ μ€μ λμμ΅λλ€.",
"error": null,
"timestamp": "2025-01-01T00:00:00.000000"
}
onInfo μ½λ°±β
onInfoλ SDKμ λ²μ μ 보λ₯Ό Host μ±μΌλ‘ μ λ¬νκΈ° μν μ½λ°±μ
λλ€.
λ°μ΄ν° ꡬ쑰β
| νλλͺ | νμ | μ€λͺ |
|---|---|---|
version | String | νμ. SDK λ²μ μ 보μ λλ€. |
λ°μ΄ν° μμβ
{
"version": "1.0.0+10000"
}
ꡬν μμ β
μλλ κ° λ€μ΄ν°λΈ νλ«νΌμμ μ½λ°±μ μμ νκ³ μ²λ¦¬νλ μ½λ μμμ λλ€.
π€ Android (Kotlin)β
Flutterμμ ν΅μ μ μν΄ MethodChannelμ μ€μ νκ³ setMethodCallHandlerλ₯Ό ν΅ν΄ μ½λ°±μ 리μ€λν©λλ€.
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.mscbrain.sdk.test_solution_sdk/channel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
channel.setMethodCallHandler { call, result ->
when (call.method) {
"onResult" -> {
val resultMap = call.arguments as? Map<String, Any>
val status = resultMap?.get("status") as? String
Log.d("TestSolutionSDK", "onResult received: $resultMap")
when (status) {
"COMPLETED" -> {
// ν
μ€νΈ μλ£ ν μ²λ¦¬ λ‘μ§
showCompletionDialog()
}
"USERCANCELLED" -> {
// μ¬μ©μ μ΄ν μ²λ¦¬ λ‘μ§
}
"ERROR" -> {
// μ€λ₯ μ²λ¦¬ λ‘μ§
val data = resultMap?.get("data") as? Map<*, *>?
val errorMsg = data?.get("errorMessage") as? String
showErrorToast(errorMsg)
}
}
}
"onInfo" -> {
val versionMap = call.arguments as? Map<String, Any>
Log.d("TestSolutionSDK_VERSION", "$versionMap") // λ²μ μ 보 μΆλ ₯
result.success(null)
}
"onLog" -> {
val logMap = call.arguments as? Map<String, Any>
Log.d("TestSolutionSDK_LOG", "$logMap") // λλ²κ·Έ λ‘κ·Έ μΆλ ₯
}
else -> {
result.notImplemented()
}
}
}
// ...
}
// ...
}
π iOS (Swift)β
- UIKit (Storyboard)
- SwiftUI
AppDelegate λλ νλ©΄μ νμνλ UIViewControllerμμ FlutterMethodChannelμ μ€μ νμ¬ μ½λ°±μ μ²λ¦¬ν©λλ€.
import UIKit
import Flutter
class ViewController: UIViewController {
private let CHANNEL: String = "com.mscbrain.sdk.test_solution_sdk/channel"
override func viewDidLoad() {
super.viewDidLoad()
guard let flutterEngine = (UIApplication.shared.delegate as? AppDelegate)?.flutterEngine else { return }
let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: flutterEngine.binaryMessenger)
channel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "onResult":
guard let resultMap = call.arguments as? [String: Any],
let status = resultMap["status"] as? String else {
return
}
print("onResult received: \(resultMap)")
if status == "COMPLETED" {
// ν
μ€νΈ μλ£ ν μ²λ¦¬ λ‘μ§
} else if status == "ERROR" {
// μ€λ₯ μ²λ¦¬ λ‘μ§
}
break
case "onInfo":
guard let versionMap = call.arguments as? [String: Any] else { return }
print("TestSolutionSDK_VERSION: \(versionMap)") // λ²μ μ 보 μΆλ ₯
break
case "onLog":
guard let logMap = call.arguments as? [String: Any] else { return }
print("TestSolutionSDK_LOG: \(logMap)") // λλ²κ·Έ λ‘κ·Έ μΆλ ₯
break
default:
result(FlutterMethodNotImplemented)
}
})
}
// ...
}
FlutterViewμμ FlutterMethodChannelμ μ€μ νμ¬ μ½λ°±μ μ²λ¦¬ν©λλ€.
import SwiftUI
import Flutter
struct FlutterView: UIViewControllerRepresentable {
@Environment(FlutterEngineManager.self) private var flutterEngineManager
private let CHANNEL: String = "com.mscbrain.sdk.test_solution_sdk/channel"
func makeUIViewController(context: Context) -> some UIViewController {
let flutterViewController = FlutterViewController(engine: flutterEngineManager.engine, nibName: nil, bundle: nil)
let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: flutterViewController.binaryMessenger)
channel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "onResult":
guard let resultMap = call.arguments as? [String: Any],
let status = resultMap["status"] as? String else {
return
}
print("onResult received: \(resultMap)")
if status == "COMPLETED" {
// ν
μ€νΈ μλ£ ν μ²λ¦¬ λ‘μ§
} else if status == "ERROR" {
// μ€λ₯ μ²λ¦¬ λ‘μ§
}
break
case "onInfo":
guard let versionMap = call.arguments as? [String: Any] else { return }
print("TestSolutionSDK_VERSION: \(versionMap)") // λ²μ μ 보 μΆλ ₯
break
case "onLog":
guard let logMap = call.arguments as? [String: Any] else { return }
print("TestSolutionSDK_LOG: \(logMap)") // λλ²κ·Έ λ‘κ·Έ μΆλ ₯
break
default:
result(FlutterMethodNotImplemented)
}
})
let startData: [String: Any] = [
"suid": "[SUID]", // μ¬μ©μλ₯Ό μλ³ν μ μλ κ³ μ IDλ₯Ό μ
λ ₯νμΈμ.
"goodsId": "[GOODS_ID]", // λ°κΈλ°μ μν IDλ₯Ό μ
λ ₯νμΈμ.
"language": "[LANGUAGE]" // μ§μ μΈμ΄ μ½λλ₯Ό μ
λ ₯νμΈμ.
]
channel.invokeMethod("startTest", arguments: startData)
return flutterViewController
}
// ...
}