KMP 实现鸿蒙跨端:Kotlin 随机抽奖模拟工具
本文介绍了一个基于Kotlin Multiplatform(KMP)的随机抽奖模拟工具实现方案。该工具允许用户输入候选人列表和抽取人数,如"小明,小红,小刚,小李 2",核心Kotlin代码通过解析输入、验证约束条件,使用shuffled()和take()方法实现随机抽选功能,并生成包含中奖/未中奖名单的格式化结果。通过@JsExport注解将Kotlin函数暴露给JavaSc

目录
- 概述
- 功能设计
- Kotlin 实现代码(KMP)
- JavaScript 调用示例
- ArkTS 页面集成与调用
- 数据输入与交互体验
- 编译与自动复制流程
- 总结
概述
本案例在 Kotlin Multiplatform (KMP) 工程中实现了一个 随机抽奖模拟工具:
- 输入:一行文本,包含 候选人列表 和 抽取人数,例如:
小明,小红,小刚,小李 2。 - 输出:
- 中奖名单
- 未中奖名单
- 抽奖说明和提示
- 技术路径:Kotlin → Kotlin/JS → JavaScript 模块 → ArkTS 页面调用。
这个案例可以看作一个非常常见的“小工具”场景:
- 教学场景:在课堂上、培训中随机点名。
- 活动场景:小规模抽奖、随机分组。
- 学习场景:演示如何在 Kotlin 中操作字符串、列表和随机算法,并把结果跨端显示在 OpenHarmony 应用中。
功能设计
输入数据格式
随机抽奖工具的输入格式设计得尽量自然:
- 使用 逗号
,分隔候选人 名称。 - 使用 空格 将候选人列表和抽取人数分隔开。
- 示例:
小明,小红,小刚,小李 2
解析逻辑:
- 左边
小明,小红,小刚,小李解析为候选人列表。 - 右边
2解析为抽取人数。
基本约束
- 候选人列表不能为空。
- 抽取人数必须是正整数。
- 抽取人数不能大于候选人数。
如果不满足约束,工具会返回带有示例的错误提示文本,方便前端直接展示。
Kotlin 实现代码(KMP)
核心逻辑在 src/jsMain/kotlin/App.kt 中,通过 @JsExport 暴露给 JS/ArkTS 调用:
@OptIn(ExperimentalJsExport::class)
@JsExport
fun randomLotterySimulator(inputText: String = "小明,小红,小刚,小李 2"): String {
// 输入格式: "候选人1,候选人2,... 抽取人数",例如 "小明,小红,小刚,小李 2"
val parts = inputText.trim().split(" ")
if (parts.isEmpty()) {
return "❌ 错误: 请输入候选人列表和抽取人数,例如: 小明,小红,小刚,小李 2"
}
val namesPart = parts.first()
val countPart = parts.drop(1).firstOrNull() ?: "1"
val candidates = namesPart.split(",").map { it.trim() }.filter { it.isNotEmpty() }
val pickCount = countPart.toIntOrNull() ?: 1
if (candidates.isEmpty() || pickCount <= 0) {
return "❌ 错误: 候选人列表或抽取人数无效\n示例: 小明,小红,小刚,小李 2"
}
if (pickCount > candidates.size) {
return "❌ 错误: 抽取人数不能大于候选人数量\n当前候选人数量: ${candidates.size}"
}
// 打乱列表并抽取前 N 个
val shuffled = candidates.shuffled()
val winners = shuffled.take(pickCount)
val others = shuffled.drop(pickCount)
return "🎁 随机抽奖模拟工具\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"候选人列表: ${candidates.joinToString(", ")}\n" +
"抽取人数: ${pickCount}\n\n" +
"1️⃣ 中奖名单:\n" +
winners.joinToString("\n") { " - $it" } + "\n\n" +
"2️⃣ 未中奖名单:\n" +
if (others.isNotEmpty()) others.joinToString("\n") { " - $it" } else " (无)" + "\n\n" +
"3️⃣ 提示:\n" +
" • 每次调用都会随机打乱列表,结果仅供模拟演示使用\n" +
" • 如果需要可重复抽奖,可以多次点击按钮重新抽取\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 抽奖完成!"
}
这是随机抽奖模拟的核心实现函数,展示了完整的抽奖算法。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。函数首先进行输入解析,使用 split(" ") 分割输入字符串,分离候选人列表和抽取人数。使用 split(",") 按逗号拆分候选人,并通过 trim() 去除多余空格,使用 filter { it.isNotEmpty() } 排除空字符串。进行边界检查,验证候选人列表不为空、抽取人数为正数且不超过候选人数量。使用 shuffled() 随机打乱候选人列表,使用 take(pickCount) 取前 N 个作为中奖名单,剩余部分作为未中奖名单。最后使用字符串模板和 joinToString() 格式化输出完整的抽奖结果,包括候选人列表、中奖/未中奖名单和提示说明。这个函数展示了如何将随机抽奖算法转换为用户友好的输出。
代码说明
- 输入拆分:
- 使用
split(" ")将输入分割为最多两部分:候选人串 + 抽取人数。 - 如果缺少抽取人数,默认使用
1。
- 使用
- 候选人列表处理:
- 使用
split(",")按逗号拆分候选人,并通过trim()去除多余空格。 - 使用
filter { it.isNotEmpty() }排除空字符串,保证候选人列表有效。
- 使用
- 边界检查:
- 当候选人列表为空或抽取人数小于等于 0 时,返回错误提示。
- 当抽取人数大于候选人数时,同样返回带有候选人数信息的错误文本。
- 随机抽取:
- 使用
candidates.shuffled()打乱列表顺序。 - 使用
take(pickCount)取前 N 个作为中奖名单。 - 剩余部分作为未中奖名单。
- 使用
- 结果拼接:
- 将候选人列表、抽取人数、中奖/未中奖名单以及提示说明整合为一段多行文本,方便 ArkTS 页面直接显示。
JavaScript 调用示例
在 Kotlin/JS 编译完成后,randomLotterySimulator 会被导出到 hellokjs.mjs 模块中,可以在 Node.js 或浏览器环境中这样调用:
import { randomLotterySimulator } from './hellokjs.mjs';
// 使用默认示例
const result1 = randomLotterySimulator();
console.log(result1);
// 自定义候选人和抽取人数
const result2 = randomLotterySimulator('A,B,C,D,E 3');
console.log(result2);
这段代码展示了如何在 JavaScript 环境中调用编译后的 Kotlin 函数。首先使用 import 语句从编译后的 JavaScript 模块 hellokjs.mjs 中导入 randomLotterySimulator 函数。调用 randomLotterySimulator() 不带参数时使用默认值 “小明,小红,小刚,小李 2”。调用 randomLotterySimulator('A,B,C,D,E 3') 时传入自定义的候选人列表和抽取人数。使用 console.log() 输出结果。这展示了 KMP 的跨端能力,同一份 Kotlin 代码可以在 JavaScript 环境中无缝调用。编译器自动处理了 Kotlin 的类型系统到 JavaScript 的转换,使得调用方式和普通 JavaScript 函数完全相同。
输出示例(简化):
🎁 随机抽奖模拟工具
━━━━━━━━━━━━━━━━━━━━━
候选人列表: A, B, C, D, E
抽取人数: 3
1️⃣ 中奖名单:
- C
- A
- E
2️⃣ 未中奖名单:
- B
- D
3️⃣ 提示:
• 每次调用都会随机打乱列表,结果仅供模拟演示使用
• 如果需要可重复抽奖,可以多次点击按钮重新抽取
━━━━━━━━━━━━━━━━━━━━━
✅ 抽奖完成!
ArkTS 页面集成与调用
在 OpenHarmony 工程 kmp_ceshiapp 中,首页 Index.ets 已经改成随机抽奖工具页面,核心调用逻辑如下:
import { randomLotterySimulator } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '请输入候选人列表和抽取人数';
@State inputText: string = '小明,小红,小刚,小李 2';
@State resultText: string = '';
aboutToAppear(): void {
this.runLottery();
}
runLottery(): void {
try {
const input: string = this.inputText;
const result: string = randomLotterySimulator(input);
this.resultText = result;
this.message = '✓ 计算完成';
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
this.message = `✗ 错误: ${errorMessage}`;
}
}
build() {
// 省略 UI 细节,只保留调用关系
}
}
这段 ArkTS 代码是鸿蒙应用的用户界面实现,展示了如何在 ArkTS 中导入和调用编译后的 Kotlin 函数。首先使用 import 语句从编译后的 JavaScript 模块中导入 randomLotterySimulator 函数。使用 @State 装饰器定义三个响应式状态变量:message 用于显示状态信息,inputText 存储用户输入的候选人列表和抽取人数,resultText 存储抽奖结果。aboutToAppear() 生命周期函数在组件加载时自动调用 runLottery() 进行初始化。runLottery() 方法调用 Kotlin 编译的 JavaScript 函数 randomLotterySimulator(),将用户输入的文本传入,获取抽奖结果,然后更新 resultText 和 message。使用 try-catch 块捕获异常,如果发生错误则显示错误信息。build() 方法构建整个 UI 布局。这个结构实现了清晰的前后端职责划分:ArkTS 只负责收集输入和展示结果,所有抽奖逻辑都集中在 Kotlin 中。
ArkTS 侧只需要:
- 管理三个状态:
message、inputText、resultText。 - 在
aboutToAppear和按钮点击时调用runLottery(),内部通过randomLotterySimulator获取结果。 - 将
resultText绑定到一个Text组件显示多行文本即可。
数据输入与交互体验
首页 UI 保持与前几个案例一致的风格,只是文案换成了抽奖语义:
- 顶部标题栏:显示“KMP 鸿蒙跨端”和“随机抽奖模拟工具”。
- 输入区域:
Column() {
Text('输入候选人和抽取人数 (示例: 小明,小红,小刚,小李 2):')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#1f2937')
.margin({ bottom: 8 })
TextInput({ placeholder: '例如: 小明,小红,小刚,小李 2', text: this.inputText })
.width('100%')
.height(80)
.padding(8)
.border({ width: 1, color: '#d1d5db' })
.borderRadius(6)
.onChange((value: string) => {
this.inputText = value;
})
.margin({ bottom: 12 })
Button('开始抽奖')
.width('100%')
.height(40)
.margin({ top: 4 })
.backgroundColor('#f59e0b')
.fontColor(Color.White)
.onClick(() => {
this.runLottery();
})
}
这段 ArkTS 代码构建了用户输入区域的 UI 组件。使用 Column 布局容器垂直排列各个元素。第一个 Text 组件显示输入说明,设置字体大小为 14,加粗,颜色为深灰色。TextInput 组件用于接收用户输入,设置占位符文本为 “例如: 小明,小红,小刚,小李 2”,初始值为 this.inputText。设置宽度为 100%、高度为 80、内边距为 8。添加边框和圆角以提高视觉效果。使用 onChange 事件监听器实时更新 inputText 状态。Button 组件用于触发抽奖操作,设置宽度为 100%、高度为 40、背景色为橙色、文字颜色为白色。使用 onClick 事件监听器在点击时调用 runLottery() 方法。这个输入区域设计简洁直观,用户可以轻松输入候选人列表和抽取人数。
- 结果区域:使用
Scroll+Text展示多行文本结果。 - 底部按钮:
- “默认示例”:重置为
小明,小红,小刚,小李 2并调用runLottery(); - “清空”:清空输入和结果,把提示重置为“请输入候选人列表和抽取人数”。
- “默认示例”:重置为
整个交互流程非常简单:用户输入一行文本并点击按钮,就能看到一轮抽奖结果,点击多次可以模拟多轮抽奖。
编译与自动复制流程
和其它案例一样,Kotlin 代码更新后,只需在项目根目录执行 build-and-copy.bat 脚本,即可完成编译和文件复制:
cd d:\flutter_Obj\kmp_openharmony
.\build-and-copy.bat
这段代码展示了如何执行自动化构建脚本。首先使用 cd 命令切换到项目根目录 d:\flutter_Obj\kmp_openharmony。然后执行 build-and-copy.bat 脚本,该脚本会自动完成编译和文件复制的全部流程。
脚本会自动:
- 执行
gradlew build构建 Kotlin/JS。 - 在
build/js/packages/hellokjs/kotlin/下生成/更新:hellokjs.mjshellokjs.d.ts
- 将上述文件复制到 ArkTS pages 目录:
kmp_ceshiapp/entry/src/main/ets/pages/hellokjs.d.tskmp_ceshiapp/entry/src/main/ets/pages/hellokjs.js。
每次你在 App.kt 中修改 randomLotterySimulator 或其它导出函数后,只要重新执行这个脚本,ArkTS 端就会自动使用最新的实现。
总结
“随机抽奖模拟工具”是一个非常适合作为 KMP + ArkTS 教学的小案例:
- Kotlin 侧展示了字符串解析、列表处理和随机算法的基本用法。
- Kotlin/JS 将这段逻辑导出为 JS 模块,使其可以在 Node.js、Web、ArkTS 中反复复用。
- ArkTS 侧只需要少量代码即可构建一个可视化的抽奖界面,方便在 OpenHarmony 设备上演示。
配合之前的 BMI、贷款、成绩分析、个人预算、学习打卡、环境舒适度等案例,这个抽奖工具进一步丰富了你的跨端示例集,覆盖了日常工具、数据分析、学习/健康/环境等多个方向。
核心理念始终不变:把通用算法逻辑写在 Kotlin 中,用 KMP 输出到 JS,再让 ArkTS 专注界面和交互,通过一套代码服务多端。
更多推荐




所有评论(0)