HarmonyOS技术精讲-Form Kit(卡片开发服务)第2篇:搭建ArkTS卡片开发环境与创建第一个卡片

📅 2026/7/1 7:55:45
HarmonyOS技术精讲-Form Kit(卡片开发服务)第2篇:搭建ArkTS卡片开发环境与创建第一个卡片
先搞清楚卡片开发要解决什么问题卡片的核心价值是“在桌面或负一屏以轻量级、低功耗的方式快速呈现用户关心的信息”。它不是应用主界面的替代品而是应用核心功能的精华摘录。适用场景天气、时钟、日历等需要实时刷新信息的桌面小组件。音乐播放器的快捷控制面板。待办事项、记步数等无需打开应用即可查看的信息卡片。不适用场景需要复杂用户交互如多级页面跳转的场景。对性能要求极高需要大量GPU渲染的效果。ArkTS卡片是当前推荐的开发方式相比JS卡片它拥有更好的开发体验和性能表现。如果你还在用老的JS卡片方案建议尽快迁移。环境说明DevEco Studio 版本DevEco Studio 6.1.0 及以上HarmonyOS SDK 版本HarmonyOS 6.1.0(23) 及以上目标设备手机、平板推荐使用模拟器或真机进行调试注意如果你使用的是早期版本的DevEco Studio可能无法找到卡片模板或者创建成功后编译报错。确保你的开发环境是最新的能省去很多麻烦。核心实现从零创建你的第一个ArkTS卡片第一步选择正确的项目模板打开DevEco Studio创建一个新项目。这里有个常见的坑很多人直接选择“Empty Ability”模板然后手动往里面加卡片代码结果发现配置死活不对。正确做法是选择“Empty Ability”模板后在“Device”选项卡里务必勾选“Show in Service Center”和“Widget”。勾选“Widget”后IDE会自动在工程里为你生成卡片相关的代码和资源配置文件这一步能节省大量手动配置的时间。项目创建成功后的目录结构里你会看到entry/src/main/ets/FormAbility这个文件夹里面就是我们操作卡片的核心文件。第二步理解卡片模块的文件结构一个标准的ArkTS卡片项目核心文件包括form_config.json卡片配置信息决定了卡片的外观尺寸、是否可刷新等。FormAbility.ets卡片生命周期管理入口负责监听卡片的创建、更新、销毁等事件。card.ets卡片的UI界面使用ArkTS编写。第三步编写第一个卡片UIcard.ets这是你最关心的部分。我们写一个最简单的“Hello World”卡片包含一个文本和一个按钮但注意卡片内按钮只能触发点击事件不能直接做跳转。// entry/src/main/ets/FormAbility/pages/card.etsEntryComponentstruct CardWidget{Statemessage:stringHello HarmonyOS Card!// 点击事件回调onWidgetClick(){this.messageYou clicked me!;}build(){// 这里用了一个栈容器让文字居中显示Stack(){Column(){Text(this.message).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#FFFFFF).textAlign(TextAlign.Center)}.width(100%).height(100%).justifyContent(FlexAlign.Center)}.width(100%).height(100%).backgroundColor(#007DFF)// 卡片背景色// 绑定点击事件.onClick((){this.onWidgetClick();})}}代码说明Entry和Component是ArkTS组件的基本装饰器没什么好说的。State message是卡片的状态变量当它改变时UI会自动更新。这一点非常关键它决定了卡片能否实时响应用户操作或数据更新。卡片内部的onClick事件是可行的但注意它只能执行简单的状态切换或调用postCardAction用于向应用发送消息不能做页面跳转。第四步配置卡片生命周期入口FormAbility.etsIDE生成的FormAbility.ets已经包含了基本框架但为了让卡片能够正确运行我们需要理解并修改几个关键回调。// entry/src/main/ets/FormAbility/FormAbility.etsimportAbilityConstantfromohos.app.ability.AbilityConstant;importhilogfromohos.hilog;importwindowfromohos.window;importWantfromohos.app.ability.Want;exportdefaultclassFormAbilityextendsAbilityConstant.Ability{// 卡片创建时调用onCreate(want:Want,abilityParam:AbilityConstant.AbilityStartParams){hilog.info(0x0000,testTag,%{public}s,FormAbility onCreate);// 这里可以对卡片进行初始化设置比如从网络拉取数据}// 当卡片需要更新时调用比如设置了定时刷新onUpdate(formId:string){hilog.info(0x0000,testTag,%{public}s,FormAbility onUpdate);// 更新卡片数据this.updateForm(formId);}// 卡片被销毁时调用onDestroy(formId:string){hilog.info(0x0000,testTag,%{public}s,FormAbility onDestroy);}// 这是一个自定义方法用于更新卡片UI// 实际开发中需要在这里调用 widget.getWidget().updateForm() 来更新卡片数据// 但本示例为了简化不做数据更新privateupdateForm(formId:string){// 更新代码}}重点onCreate方法里拿到的want参数里包含了卡片ID、卡片名称等信息。在onUpdate回调里你需要通过updateForm方法来刷新卡片UI。但很多初学者会发现在onUpdate里直接调用widget对象会报错因为这个对象需要在UI线程中获取。这个问题我们在踩坑章节细说。第五步配置卡片信息form_config.json这个文件告诉系统你的卡片长什么样有什么行为。{forms:[{name:HelloCard,description:这是第一个卡片,src:./pages/card.ets,// 指向我们的UI文件window:{designWidth:720,// 设计稿宽度autoDesignWidth:true},formConfig:{landscapeLayout:default,// 横屏布局portraitLayout:default// 竖屏布局},updateEnabled:true,// 允许卡片定时更新scheduledUpdateTime:10:30,// 每天10:30更新需要配合updateDuration使用updateDuration:2,// 更新周期单位小时最少2小时defaultDimension:2*2,// 卡片尺寸2x2 网格supportDimensions:[2*2]// 支持的尺寸}]}踩坑点updateDuration的最小值是2即最少每2小时更新一次。如果你想实现更快的刷新比如天气卡片每分钟刷新这种卡片上的定时刷新机制是达不到的。你需要用到coprocessor协处理器或者应用后台跑到前台时手动更新。第六步在module.json5中声明卡片这一步很多人会忽略导致卡片在桌面上找不到。在entry/src/main/module.json5文件中你需要将FormAbility声明进去。{module:{// ... 其他配置abilities:[{name:FormAbility,srcEntry:./ets/FormAbility/FormAbility.ets,description:卡片能力,icon:$media:icon,label:$string:entry_FormAbility,startWindowIcon:$media:icon,startWindowBackground:$color:start_window_background,visible:true,skills:[{entities:[entity.system.home],actions:[action.system.home]}]}]}}关键点在于visible: true和skills字段。skills定义了该Ability可以处理action.system.home动作这表示它可以在桌面显示。第七步运行和调试在模拟器或真机上运行你的应用。应用安装成功后不要直接点击应用图标。正确的做法是回到桌面。长按桌面空白处点击“服务卡片”。在卡片列表中找到你的应用然后选择“HelloCard”。卡片就会被添加到桌面。如果卡片没有出现检查编译是否成功控制台有无报错。module.json5配置是否正确。模拟器是否支持卡片功能大部分模拟器是支持的。真正有价值的踩坑坑1卡片UI更新不生效现象在FormAbility的onUpdate回调中通过widget.getWidget()获取Widget对象并调用updateForm但UI没有任何变化。原因onUpdate方法运行在卡片的生命周期线程中并不是UI线程。直接在该线程里调用UI更新API是不被允许的或者调用时机不对。解决方案正确的做法是在FormAbility中通过widget模块的updateFormByKeyValue或updateForm方法来异步更新。而且确保你已经正确获取了widget对象。// 正确的更新方式importwidgetfromohos.arkui.widget;exportdefaultclassFormAbilityextendsAbilityConstant.Ability{onUpdate(formId:string){// 构造新的数据letformData{message:更新后的文本// 这里的key必须与card.ets中State变量名对应};// 异步更新widget.updateForm(formId,{formData:JSON.stringify(formData)},(err,data){if(err){hilog.error(0x0000,testTag,Failed to update form. Cause: %{public}s,JSON.stringify(err));}else{hilog.info(0x0000,testTag,Succeeded in updating form. Data: %{public}s,JSON.stringify(data));}});}}关键点formData的key必须和card.ets中的State状态变量名完全一致否则UI不会刷新。这是ArkTS卡片状态同步的机制官方文档虽然提了但没强调这个一致性要求很多人踩坑。坑2卡片状态在返回后丢失现象从应用跳转到卡片滑动一下卡片再回到桌面卡片的message状态又变回了Hello HarmonyOS Card!。原因卡片的State状态是存放在内存中的当卡片被销毁或资源回收后状态就丢失了。卡片不像应用有完整的saveState机制。解决方案将需要持久化的状态写入到LocalStorage或AppStorage中在卡片初始化时恢复。// card.etsEntryComponentstruct CardWidget{Statemessage:stringAppStorage.get(cardMessage)||Hello HarmonyOS Card!;onWidgetClick(){this.messageYou clicked me!;AppStorage.set(cardMessage,this.message);}}注意AppStorage的读写虽然简单但它是一个全局存储不同卡片之间的数据可能会污染。更推荐的做法是使用LocalStorage在FormAbility创建卡片时为每个卡片创建一个独立的LocalStorage实例。最佳实践不要在build()中创建复杂对象build()方法在UI需要刷新时会被频繁调用。如果里面创建了复杂的对象或进行了耗时计算会直接拖垮UI性能导致掉帧。尽量将这类操作放到State变量变化时的回调或FormAbility的onUpdate中。优先使用updateFormByKeyValue相比updateForm前者是更细粒度的更新。你只需要传入改变的状态值框架会帮你完成diff从而减少不必要的UI重绘。合理设置updateDuration不要为了实时性把这个值设成1或0系统会忽略。请根据你的业务场景选择合理的更新周期比如22小时或44小时。如果要求更高频率考虑使用其他后台同步方案。FAQQ为什么我在模拟器上看到卡片是空白的A最常见的原因是card.ets文件中没有正确导出Entry装饰器或者form_config.json里的src路径写错了。另外检查模拟器是否成功创建了卡片有时候模拟器会崩溃导致卡片无法加载。Q为什么onCreate里拿到的want参数是空的A这在早期版本的DevEco Studio中比较常见。通常是由于want的序列化出现问题。可以尝试在module.json5中给FormAbility添加launchType为singleton但这并不是一个根治的方法。如果遇到建议升级DevEco Studio和SDK到最新版。Q卡片可以添加列表吗可以异步加载图片吗A可以。ArkTS卡片完全支持List、Grid等复杂布局也支持通过Image组件异步加载网络图片但需要配置networkAccess权限。性能优化是关键不要在卡片主线程中做过多网络操作否则容易导致卡片卡死。示例代码地址项目地址