| 能搞定(commonMain 内) | 搞不定(必须调原生) |
|---|---|
| UI 描述 / 布局 | 调用相机 / 相册 |
| 业务逻辑 / 数据处理 | 推送(FCM / APNs / 鸿蒙) |
| HTTP 请求(HttpModule) | 设备信息 / 权限 |
| 路由跳转 | 音视频 SDK |
| 本地存储(StorageModule) | 第三方 SDK(支付、登录、IM) |
KMP 原生方案,静态绑定,编译期确定实现
// commonMain
expect fun currentPlatform(): String
// androidMain
actual fun currentPlatform() = "Android ${Build.VERSION.RELEASE}"
框架封装的通信层,动态注册,运行时按 name 查找
acquireModule<CameraModule>(MODULE_NAME)
.takePhoto { path -> updateUI(path) }
💡 简单粗暴:一次性调用 → expect/actual;持续/双向 → Module
// commonMain
expect fun getCurrentTimeMillis(): Long
// androidMain
actual fun getCurrentTimeMillis(): Long = System.currentTimeMillis()
// iosMain
actual fun getCurrentTimeMillis(): Long =
(NSDate().timeIntervalSince1970 * 1000).toLong()
// commonMain
expect class FileStorage(name: String) {
fun put(key: String, value: String)
fun get(key: String): String?
}
// androidMain
actual class FileStorage actual constructor(name: String) {
private val sp = appContext.getSharedPreferences(name, MODE_PRIVATE)
actual fun put(key: String, value: String) { sp.edit().putString(key, value).apply() }
actual fun get(key: String): String? = sp.getString(key, null)
}
// commonMain
expect interface Logger {
fun debug(tag: String, msg: String)
fun error(tag: String, msg: String, throwable: Throwable? = null)
}
// commonMain
expect object DeviceInfo {
val osName: String
val osVersion: String
fun isTablet(): Boolean
}
// commonMain
expect suspend fun fetchLocation(): Pair<Double, Double>
// androidMain
actual suspend fun fetchLocation() = suspendCancellableCoroutine { cont ->
LocationServices.getFusedLocationProviderClient(appContext)
.lastLocation
.addOnSuccessListener { cont.resume(it.latitude to it.longitude) }
}
| Module | 作用 | 常用方法 |
|---|---|---|
| HttpModule | 网络请求 | request(url, method, params, callback) |
| RouterModule | 路由跳转(含原生页面) | openUrl("kuikly://...") |
| PageRouterModule | Pager 间跳转 | openPage(name, data) |
| SharedPreferencesModule | 本地 KV 存储 | setItem / getItem / removeItem |
| ToastModule | Toast 提示 | showToast(text) |
| TimerModule | 定时器 | schedule(delay, interval, callback) |
| ImagePreviewModule | 大图预览 | preview(urls, index) |
| LogModule | 日志输出 | i / d / e |
| NotificationModule | 跨页面广播 | postNotification / addListener |
| CalendarModule | 日历 | addEvent / queryEvents |
// 姿势 1:每次都 acquire
acquireModule<ToastModule>(ToastModule.MODULE_NAME).showToast("hi")
// 姿势 2:缓存到字段(推荐)
private val toast by lazy {
acquireModule<ToastModule>(ToastModule.MODULE_NAME)
}
toast.showToast("hi")
val http = acquireModule<HttpModule>(HttpModule.MODULE_NAME)
http.request(
url = "https://api.example.com/articles",
method = "GET",
params = JSONObject().apply { put("page", 1) },
headers = JSONObject().apply { put("Authorization", "Bearer xxx") },
) { result ->
val data = result?.optJSONArray("data") ?: return@request
val list = (0 until data.length()).map { i ->
val o = data.getJSONObject(i)
Article(o.getString("id"), o.getString("title"))
}
articles.clear()
articles.addAll(list)
}
expect class CameraModule() : Module {
fun takePhoto(onComplete: (String?) -> Unit)
fun pickFromAlbum(maxCount: Int, onComplete: (List<String>) -> Unit)
companion object {
const val MODULE_NAME = "Camera"
}
}
actual class CameraModule actual constructor() : Module() {
actual fun takePhoto(onComplete: (String?) -> Unit) {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
currentActivity.launchForResult(intent) { code, _ ->
onComplete(if (code == OK) tempFile.absolutePath else null)
}
}
}
actual class CameraModule actual constructor() : Module() {
actual fun takePhoto(onComplete: (String?) -> Unit) {
val picker = UIImagePickerController().apply {
sourceType = UIImagePickerControllerSourceTypeCamera
delegate = createDelegate(onComplete)
}
currentVC?.presentViewController(picker, true, null)
}
}
// Android Application
ModuleRegistry.register(CameraModule.MODULE_NAME) { CameraModule() }
// 业务 Pager
event {
click {
acquireModule<CameraModule>(CameraModule.MODULE_NAME)
.takePhoto { path -> ctx.photoPath = path }
}
}
点击下面的按钮,模拟 Kuikly 业务侧调 Module → 触发原生层动作 → 回调结果。下面会显示日志。