使用 Kotlin Compose Multiplatform 构建跨平台密码管理器
·
使用 Kotlin Compose Multiplatform 构建跨平台密码管理器
项目概述
在现代数字化生活中,我们拥有越来越多的在线账户,管理这些账户的密码成为一个重要需求。本文将介绍如何使用 Kotlin Compose Multiplatform 构建一个现代化的密码管理器应用 —— Caddy。
项目源码:https://gitee.com/gomes/password-manager-kotlin
技术栈
核心技术
- Kotlin 2.3.10 - 现代化的 JVM 编程语言
- Compose Multiplatform 1.10.0 - JetBrains 推出的跨平台 UI 框架
- Material Design 3 - Google 最新的设计规范
- JDK 21 - 最新的 Java LTS 版本
- Gradle 9.2.1 - 构建工具
为什么选择 Compose Multiplatform?
- 声明式 UI:使用 Kotlin 代码描述 UI,代码简洁易读
- 跨平台能力:一套代码可运行在 macOS、Windows、Linux、Android、iOS 等平台
- Material 3 支持:提供现代化的 UI 组件
- 状态管理:内置响应式状态管理机制
- 热重载:开发效率高
项目架构
整体架构
password-manager-kotlin/
├── build.gradle.kts # 构建配置
├── settings.gradle.kts # 项目设置
├── icon.icns # 应用图标
├── run.sh # 运行脚本
└── src/main/kotlin/passwordmanager/
├── Account.kt # 数据模型
├── AccountRepository.kt # 数据存储层
├── Main.kt # 应用入口
├── MainScreen.kt # 主界面
└── AccountDialog.kt # 对话框组件
分层设计
┌─────────────────────────────────────┐
│ UI Layer (Compose) │
│ MainScreen.kt / AccountDialog.kt │
├─────────────────────────────────────┤
│ Business Logic Layer │
│ AccountRepository.kt │
├─────────────────────────────────────┤
│ Data Model Layer │
│ Account.kt │
├─────────────────────────────────────┤
│ Persistence Layer │
│ Properties File Storage │
└─────────────────────────────────────┘
核心功能实现
1. 数据模型设计
使用 Kotlin 的 data class 定义账号实体,简洁且功能强大:
data class Account(
var id: String = UUID.randomUUID().toString(),
var website: String = "",
var username: String = "",
var password: String = "",
var email: String = "",
var notes: String = "",
var createdAt: Long = System.currentTimeMillis(),
var updatedAt: Long = System.currentTimeMillis()
)
设计亮点:
- 使用
UUID自动生成唯一标识 - 默认参数简化对象创建
- 包含创建和更新时间戳
- 不可变数据结构保证线程安全
2. 数据持久化
采用 Properties 文件存储,简单可靠:
class AccountRepository {
private val dataFile: File
private val accounts: MutableList<Account> = mutableListOf()
init {
val home = System.getProperty("user.home")
dataFile = File(home, ".password-manager/accounts.properties")
loadAccounts()
}
fun addAccount(account: Account) {
accounts.add(account)
saveAccounts()
}
fun searchAccounts(query: String?): List<Account> {
if (query.isNullOrBlank()) return getAllAccounts()
val lowerQuery = query.lowercase()
return accounts.filter {
it.website.lowercase().contains(lowerQuery) ||
it.username.lowercase().contains(lowerQuery) ||
it.email.lowercase().contains(lowerQuery)
}
}
}
存储格式:
ids=uuid1,uuid2,uuid3
account.uuid1.website=example.com
account.uuid1.username=user1
account.uuid1.password=pass123
优点:
- 轻量级,无需数据库依赖
- 人类可读,便于调试
- 跨平台兼容
- 易于备份和迁移
3. UI 组件设计
主界面 (MainScreen)
使用 Compose 的声明式语法构建界面:
@Composable
fun MainScreen(repository: AccountRepository) {
var accounts by remember { mutableStateOf(repository.getAllAccounts()) }
var searchText by remember { mutableStateOf("") }
var selectedAccount by remember { mutableStateOf<Account?>(null) }
MaterialTheme(
colorScheme = lightColorScheme(
primary = AccentColor,
background = BgColor,
surface = CardColor
)
) {
Column(modifier = Modifier.fillMaxSize()) {
// 搜索栏
OutlinedTextField(
value = searchText,
onValueChange = { searchText = it },
placeholder = { Text("搜索账号...") }
)
// 账号列表
LazyColumn {
items(accounts) { account ->
AccountItem(account)
}
}
}
}
}
对话框组件
@Composable
fun AccountDialog(
account: Account?,
onDismiss: () -> Unit,
onSave: (Account) -> Unit
) {
Dialog(onDismissRequest = onDismiss) {
Surface(
modifier = Modifier.width(480.dp),
shape = RoundedCornerShape(16.dp)
) {
Column(modifier = Modifier.padding(24.dp)) {
// 表单字段
OutlinedTextField(
value = website,
onValueChange = { website = it },
label = { Text("网站 *") }
)
// 密码字段(支持显示/隐藏)
OutlinedTextField(
value = password,
visualTransformation = if (passwordVisible)
VisualTransformation.None
else
PasswordVisualTransformation()
)
}
}
}
}
4. 状态管理
Compose 的响应式状态管理:
// 使用 remember 保存状态
var accounts by remember { mutableStateOf(repository.getAllAccounts()) }
// 使用 derivedStateOf 计算派生状态
val totalPages by remember(filteredAccounts) {
mutableStateOf(maxOf(1, (filteredAccounts.size + pageSize - 1) / pageSize))
}
// 分页数据
val paginatedAccounts = remember(filteredAccounts, currentPage) {
val start = (currentPage - 1) * pageSize
val end = minOf(start + pageSize, filteredAccounts.size)
if (start < filteredAccounts.size) filteredAccounts.subList(start, end)
else emptyList()
}
UI 设计
配色方案
private val AccentColor = Color(0xFF5AC8FA) // 淡蓝色主色调
private val BgColor = Color(0xFFF6F6F6) // 浅灰背景
private val CardColor = Color.White // 卡片白色
private val BorderColor = Color(0xFFDCDCDC) // 边框灰色
private val TextColor = Color(0xFF333333) // 深色文字
private val SecondaryTextColor = Color(0xFF8E8E93) // 次要文字
功能特性
- 账号列表:支持分页显示,每页 10 条记录
- 搜索功能:支持网站名、用户名、邮箱模糊搜索
- CRUD 操作:添加、编辑、删除账号
- 密码复制:一键复制密码到剪贴板
- 密码显示/隐藏:对话框中可切换密码可见性
构建与运行
构建配置
// build.gradle.kts
plugins {
kotlin("jvm") version "2.3.10"
id("org.jetbrains.compose") version "1.10.0"
id("org.jetbrains.kotlin.plugin.compose") version "2.3.10"
}
compose.desktop {
application {
mainClass = "passwordmanager.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Pkg)
packageName = "Caddy"
packageVersion = "1.0.0"
macOS {
iconFile.set(file("icon.icns"))
}
}
}
}
运行命令
# 开发运行
./gradlew run
# 构建 JAR
./gradlew build
# 打包 macOS 应用
./gradlew packageDmg
./gradlew packagePkg
性能优化
1. 懒加载列表
使用 LazyColumn 实现虚拟滚动,只渲染可见项:
LazyColumn {
items(paginatedAccounts) { account ->
AccountItem(account)
}
}
2. 状态派生
使用 remember 缓存计算结果,避免重复计算:
val paginatedAccounts = remember(filteredAccounts, currentPage) {
// 只在 filteredAccounts 或 currentPage 变化时重新计算
}
3. 按需刷新
只在数据变化时刷新列表:
fun refreshAccounts() {
accounts = repository.getAllAccounts()
filteredAccounts = repository.searchAccounts(searchText)
}
安全考虑
当前实现
- 本地文件存储,数据不离开设备
- 密码字段默认隐藏显示
改进建议
- 加密存储:使用 AES 加密密码数据
- 主密码:添加主密码验证
- 自动锁定:闲置一段时间后自动锁定
- 剪贴板清理:复制后定时清理剪贴板
- 安全输入:防止截屏和录屏
跨平台展望
当前项目专注于桌面端(macOS),但 Compose Multiplatform 的优势在于:
Android 支持
// androidApp/build.gradle.kts
android {
namespace = "com.caddy.android"
compileSdk = 34
}
iOS 支持(实验性)
// iosApp/iosApp.swift
ComposeView()
.ignoresSafeArea(.all)
项目统计
- 代码行数:约 608 行 Kotlin 代码
- 文件数量:5 个 Kotlin 源文件
- 构建时间:首次约 3 分钟,后续约 10 秒
总结
本项目展示了如何使用 Kotlin Compose Multiplatform 构建一个现代化的桌面应用:
- 技术选型:Compose Multiplatform 提供了声明式 UI 和跨平台能力
- 架构设计:清晰的分层结构,便于维护和扩展
- 数据存储:使用 Properties 文件简单可靠
- UI 设计:遵循 Material Design 3 规范,界面简洁美观
- 性能优化:懒加载和状态派生确保流畅体验
未来规划
- 添加密码加密功能
- 支持密码生成器
- 添加分类管理
- 支持导入导出
- Android/iOS 客户端
- 云同步功能
参考资源
作者:gomes
项目地址:https://gitee.com/gomes/password-manager-kotlin
创建日期:2026年3月11日
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)