HarmonyOS元服务与卡片
元服务与卡片
文章目录
- 一、元服务
- 1.介绍
- 2.常见元服务项目步骤
- 二、卡片
- 1.介绍
- 2.卡片的创建
- 3.卡片的数据的变更
- 4.卡片的进程间通讯
- 4.1使用工具包
- 4.2使用步骤
- 5.卡片路由postCardAction:快速拉起后台
- 5.1格式
- 5.2快速拉起指定页面--router
- 5.3调用后台功能--call
- 5.3卡片内的数据获取(适合轻量级,限制在5s内)--message
一、元服务
1.介绍
元服务就是手机中自带的小组件类似。
是一种有独立入口、免安装、可为用户提供一个或多个服务的新型应用程序形态。它基于 HarmonyOS API 开发,支持运行在 “1+8+N” 设备上,让用户在合适的场景、合适的设备上便捷使用。
特点:
1.免下载安装:用户无需像传统应用那样经历下载、安装等繁琐过程,节省了设备存储空间和下载时间,能够快速使用服务。例如,用户在使用一些简单功能的应用服务时,无需等待下载安装,直接通过元服务即可快速获取相关功能。
2.即开即用、即用即走:使用非常便捷,用户在需要时可以快速打开使用,使用完毕后不需要专门去关闭或卸载,减少了操作步骤和使用负担。比如用户在查询某个信息时,通过元服务快速查询到结果后即可关闭,下次使用时再次快速打开。
3.多端部署:只需一次开发,就可以部署在各种 HarmonyOS 终端上,包括手机、平板、智能手表、智慧屏等,大大降低了开发者的开发成本和工作量,同时也为用户提供了跨设备的一致使用体验。
4.使用方式与入口:
用户可以通过负一屏、智慧搜索、小艺助手等入口唤起元服务。例如,在负一屏中搜索相关的元服务名称,或者通过语音指令让小艺助手打开相应的元服务。
元服务还可以以服务卡片的形式存在于用户的设备桌面,用户可以根据自己的需求添加、管理和使用服务卡片,方便快捷地获取服务信息和进行操作。
对开发者的优势:
5.开发相对简单,开发者可以快速加入鸿蒙生态。并且元服务代码 100% 可复用到原生应用开发,提高了开发效率和代码的复用性。
通过鸿蒙系统的服务分发能力,元服务可以获得更多的流量和曝光机会,有助于开发者的服务更好地推广和被用户使用。
总之,元服务是 HarmonyOS 生态中的一个重要组成部分,为用户提供了更加便捷、高效的服务体验,也为开发者提供了新的开发和推广机会。
2.常见元服务项目步骤
二、卡片
1.介绍
元服务与卡片开发之间的关联主要体现在:卡片作为元服务的展现形式之一,可以为用户提供与元服务交互的界面。通过卡片,用户可以方便地访问和控制后台的元服务,而开发者则可以利用元服务为卡片提供丰富的功能和数据。这种设计允许鸿蒙操作系统在不同设备上提供一致且高效的用户体验,同时也简化了跨设备服务的开发和维护。
总的来说,元服务和卡片开发是鸿蒙操作系统中支持分布式能力和提高用户体验的两个关键技术。通过元服务,鸿蒙能够在多种设备之间提供无缝的服务体验;而卡片开发则使得这些服务能够以一种简洁而直观的方式呈现给用户,从而促进了不同设备和场景下的信息流通和功能使用。
2.卡片的创建
元服务和普通项目都一致,项目的文件夹可以变更
3.卡片的数据的变更
使用的工具包,可以见首选项工具包:PreferencesUtil,主要用于存放卡片ID
思路:根据ID
1.在EntryFormAbility中获取卡片ID:
2.在特定位置触发,用于加载卡片显示的数据
3. 卡片接收方式: @LocalStorageProp(“title”) // 使用页面级别Ui接收
1.在EntryFormAbility中获取卡片ID:
private preference: PreferencesUtil = PreferencesUtil.getInstance()
onAddForm(want: Want) { // 请求不能超出5秒,否则自动断开
// 正常业务使用的情况 -- 进保存卡片ID,存在问题:有变更则所有的都变更 ---优化增加卡片name保存到首选项
let formData = {
"title": "加载中..."
} as Record<string, string>;
// 业务处理和返回无关
// 获取卡片ID
let id = want.parameters![formInfo.FormParam.IDENTITY_KEY]
// 获取卡片name // 可以根据name过滤非同一类的卡片,做到指定更新
let name = want.parameters![formInfo.FormParam.NAME_KEY]
console.log('system===>卡片ID:' + id+'卡片name:'+name)
// 首选项封装的工具,将ID,name保存至首选项
this.preference.addFormId(this.context, JSON.stringify({"id":id,"name":name}))
.then((res) => {
console.log('system===>添加')
})
.catch(() => {
console.error('system===>错误')
})
return formBindingData.createFormBindingData(formData);
}
2.在特定位置触发,用于加载卡片显示的数据。
以根据卡片名称,指定更新为例:
// 封装方法
getForm(formName: string) { // 传递的卡片的名称
// 根据首选项,获取所有的卡片ID
this.preference.getFormIds(getContext(this)).then((item) => { // 返回JSON数组
// 所要变更的成的数据
let formData = {
"title": "卡片延时加载" + formName
} as Record<string, string>;
// 获取索要的卡片ID
const arr = item.filter((formDataS) => {
const obj: Record<string,string|number> = JSON.parse(formDataS) as Record<string,string|number>
console.log('system===>'+JSON.parse(formDataS)+':'+obj.name)
return obj.name == formName
})
if (arr.length > 0) {
arr.forEach((son: string) => {
const obj: Record<string,string|number> = JSON.parse(son) as Record<string,string|number>
// 执行卡片ID,将数据变更
formProvider.updateForm(obj.id as string, formBindingData.createFormBindingData(formData))
// 执行固定函数
formBindingData.createFormBindingData(formData);
})
}
}).catch((err: BusinessError) => {
console.error('system===>更新' + JSON.stringify(err))
})
}
3. 卡片接收数据方式: @LocalStorageProp("title") // 使用页面级别Ui接收
@LocalStorageProp("title") // 使用页面级别Ui接收
readonly TITLE: string = '';
build() {
Row() {
Column() {
Text(this.TITLE)
.fontSize($r('app.float.font_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.item_title_font'))
}
}
}
4.卡片的进程间通讯
使用的原因:
原因是在App存在期间,卡片与App不是同一个进程,App中不能直接访问卡片保存在首选 项中的数据,即App读取不到添加到桌面的元卡片ID,所以导致更新ArkTS卡片数据失败。
当App关闭后,第二次打开时,就可以正常访问到卡片保存在首选项中的卡片ID数据了,所以再次点击更新卡片数据就能成功了。
卡片的加载数据与APP应用不是同一个进程,可能回导致数据刷新不到,此时需要进程间的通讯(发布和订阅)–进程间通信(IPC)的订阅-发布模式实现。
发布: 谁触发
订阅: 根据获取的ID指定更新
4.1使用工具包
import commonEventManager from '@ohos.commonEventManager'
// Publisher通讯事件类型
enum PublishEventType {
APP_PUBLISH = "APP_PUBLISH",
CARD_PUBLISH = "CARD_PUBLISH"
}
class IPCManagerClass {
static publishCount:number = 1
// 发布者
static publish(eventType:PublishEventType,data:string){
// commonEventManager作用:可用于进程间通讯
commonEventManager.publish(eventType,{data},(err)=>{
if(err){
// 失败只发3次
if(this.publishCount<=3){
this.publish(eventType,data)
}else{
this.publishCount = 1
}
}else{
this.publishCount = 1
}
})
}
// 订阅者
static subscribe(eventType:PublishEventType,subscriber,callback:(event:string)=>void){
commonEventManager.createSubscriber({ events: [eventType] }, (err, data) => {
if (err) {
return console.log('common-->', `创建订阅者error ${JSON.stringify(err)}`)
}
console.log('common-->', `创建订阅者success`)
subscriber = data
if (subscriber !== null) {
//订阅事件
commonEventManager.subscribe(subscriber, (err, data) => {
if (err) {
return console.error(`logData`, '订阅事件失败')
}
console.log('common-->',`接受订阅事件:${data.data}`)
callback(data.data)
})
} else {
console.error('common-->',`需要创建subscriber`);
}
})
}
}
export {IPCManagerClass,PublishEventType}
4.2使用步骤
发布:谁触发的就是发布者(卡片被触发)
订阅:端侧订阅
发布:
`src/main/ets/entryformability/EntryFormAbility.ets` 的 `onAddForm` 事件中增加如下代码:
PreferencesUtil.getInstance().addFormId(this.context, formid).then(res => {
console.log('hmlog-->', '保存卡片id成功');
// 增加一个发布卡片ID(formid)的消息
IPCManagerClass.publish(PublishEventType.APP_PUBLISH,formid)
}).catch(err => {
console.log('hmlog-->', '保存卡片id失败');
});
订阅:
`src/main/ets/pages/Index.ets` 中的 ` aboutToAppear` 事件的重构代码如下:
async aboutToAppear(): Promise<void> {
console.log('hmlog-->','aboutToAppear....')
IPCManagerClass.subscribe(PublishEventType.CARD_PUBLISH,undefined, async (formId)=>{
console.log('hmlog-->',' aboutToAppear,IPCManagerClass,formId = '+formId);
// this.cardIds.push(formId);
// 将接收到的formId保存到当前进程的首选项中
await PreferencesUtil.getInstance().addFormId(getContext(),formId);
this.getCardIds();
})
}
getCardIds(){
PreferencesUtil.getInstance().getFormIds(getContext()).then(formIds=>{
console.log('hmlog-->','cardids:'+JSON.stringify(formIds));
this.cardIds.length = 0;
this.cardIds.push(...formIds);
}).catch((err:BusinessError)=>{
console.error('hmlog-->','getCardIds Failed. Err:'+JSON.stringify(err));
})
}
5.卡片路由postCardAction:快速拉起后台
5.1格式
postCardAction(this, {
action: 'router', // 三种方式: router:拉起后台 /call:拉起后台 /message 卡片内的数据获取,受限大
abilityName: 'EntryAbility', // app的启动UiAbility
// 参数
params: {
// 传参JSON格式
message: '跳转B成功'
}
});
// 接收参数的方式:
在APP的EntryAbility文件中: let params = JSON.parse(want.parameters!.params as string) as Record<string, string>;
const message = params.message;
5.2快速拉起指定页面–router
思路:
在EntryAbility 定义变量用于接收路径path 和 windowStage
当用于被隐藏第二次不会再次调用onWindowStageCreate和onCreate 则需要使用 使用 onNewWant 并在调用时,重新调用onWindowStageCreate