桌面端进阶 (Mac/Win/Linux)
开发跨平台桌面应用时,仅仅靠 Compose Multiplatform 的 UI 是不够的。本章将展示如何调用各操作系统的深层 API,实现系统集成、底层优化和硬件交互。
macOS 深度集成:Cocoa 框架实战
macOS 拥有强大的 AppKit 框架。通过 Kotlin/Native 的 Objective-C 互操作,我们可以直接调用它。
实战:调用原生文件选择器 (NSSavePanel)
kotlin
// macosMain
import platform.AppKit.*
import platform.Foundation.*
fun showNativeSavePanel(onFileSelected: (String) -> Unit) {
val panel = NSSavePanel.savePanel()
panel.title = "请选择保存位置"
panel.allowedFileTypes = listOf("txt", "json")
if (panel.runModal() == NSModalResponseOK) {
val path = panel.URL?.path
if (path != null) onFileSelected(path)
}
}Windows 深度集成:Win32 API 与注册表
Windows 应用往往需要通过 注册表 (Registry) 来存储配置或实现开机自启。
实战:读写注册表 (Win32)
kotlin
// mingwMain
import platform.windows.*
import kotlinx.cinterop.*
fun setAutoStart(appName: String, exePath: String) {
memScoped {
val hKey = alloc<HKEYVar>()
val subKey = "Software\Microsoft\Windows\CurrentVersion\Run"
// 打开注册表项
if (RegOpenKeyExW(HKEY_CURRENT_USER, subKey, 0u, KEY_WRITE, hKey.ptr) == ERROR_SUCCESS) {
val pathPtr = exePath.wcstr // 转换为宽字符指针
// 设置键值
RegSetValueExW(hKey.value, appName, 0u, REG_SZ.toUInt(),
pathPtr.ptr.reinterpret(), (exePath.length * 2 + 2).toUInt())
RegCloseKey(hKey.value)
}
}
}Linux 深度集成:POSIX 与 /proc 文件系统
在 Linux 环境下,获取系统状态最准确的方式是直接读取 /proc 虚拟文件系统。
实战:获取系统 CPU 负载 (C 标准库 + POSIX)
kotlin
// linuxMain
import platform.posix.*
fun getCpuLoad(): Double {
val file = fopen("/proc/loadavg", "r") ?: return -1.0
val buffer = ByteArray(64)
// 直接读取 POSIX 文件流
fgets(buffer.refTo(0), buffer.size, file)
fclose(file)
val content = buffer.toKString()
return content.split(" ").firstOrNull()?.toDouble() ?: -1.0
}跨平台系统托盘 (System Tray) 的实现思路
虽然各平台实现不同,但我们可以在 commonMain 定义统一接口:
kotlin
// commonMain
expect class SystemTrayManager() {
fun setIcon(resourceName: String)
fun showNotification(title: String, message: String)
}- macOS: 使用
NSStatusBar。 - Windows: 使用
Shell_NotifyIconW(Win32)。 - Linux: 使用
libappindicator(通过 cinterop)。
性能清单:桌面端优化建议
- 减少内存占用: 桌面应用往往长时间运行。在 Kotlin/Native 中,注意利用
memScoped及时释放 C 指针。 - 避免主线程阻塞: 桌面应用的 UI 线程(如 Compose 的 EDT)对延迟极其敏感。执行上述 Win32 或 POSIX 阻塞调用时,务必切换到
Dispatchers.IO。 - 多窗口通信: 在大型桌面应用中,利用
SharedFlow或AtomicFU构建一个进程内的全局事件总线。