一鸿蒙生态
- 鸿蒙操作系统: 采用
分布式架构设计和微内核架构 - 分布式软总线技术: 切换设备
七十 服务卡片介绍及创建
70.1 卡片概念
抽取应用中你关注的功能, 放到卡片上, 以便添加到桌面上快捷使用
长按app图标 -> 获取卡片列表/点击卡片 -> 进入卡片详情 -> 直接使用卡片
-> 添加卡片到桌面 -> 以后便捷使用
70.2 卡片类型
静态卡片
- 例如名言警句, 特点只能看, 最多点击跳转其他
动态卡片
- 例如卡片页面 图片/内容刷新
互动卡片
- 例如: 桌面卡片游戏
70.3 卡片相关文件及配置
// 1 定义卡片声明周期
entry/src/main/ets/entryformability/EntryFormAbility.ets
// 2 定义卡片样式
entry/src/main/ets/widget/pages/WidgetCard.ets
// 3 卡片配置信息 卡片名称 简介 刷新配置等
entry/src/main/resources/base/profile/form_config.json
{
"forms": [
{
// want参数中的名称
"name": "widget",
// 展示页面标题
"displayName": "$string:widget_display_name",
// 展示页面描述(灰色)
"description": "$string:widget_desc",
// UI页配置路径
"src": "./ets/widget/pages/WidgetCard.ets",
// 语法类型
"uiSyntax": "arkts",
// 设计尺寸基准
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"isDynamic": true,
"isDefault": true,
"updateEnabled": false,
"scheduledUpdateTime": "10:30", // 卡片内容刷新时间间隔
"updateDuration": 1,
"defaultDimension": "1*2",
"supportDimensions": [ // 适配不同尺寸
"1*2",
"2*2"
]
}
]
}
// 4 让卡片与entry模块管关联, 让当前应用具备服务卡片能力
entry/src/main/module.json5
"module": {
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
],
},
{
"name": "EntryFormAbility",
"srcEntry": "./ets/entryformability/EntryFormAbility.ets",
"label": "$string:EntryFormAbility_label",
"description": "$string:EntryFormAbility_desc",
"type": "form",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
70.4 服务卡片与页面交互
- router事件
- message事件
- call事件
70.4.1 router事件
- 点击卡片跳转至应用内页面的功能
- 进入应用看看
// UI 页创建两个按钮 A,B
// 点击按钮分别跳转到PageA, PageB页面
@Entry
@Component
struct WidgetCard {
build() {
Row() {
Text('跳转A')
.fontSize($r('app.float.font_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.font'))
.onClick(() => {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { targetPage: 'PageA' }
});
})
Text('跳转B')
.fontSize($r('app.float.font_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.font'))
.onClick(() => {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { targetPage: 'PageB' }
});
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height('100%')
.backgroundColor($r('sys.color.comp_background_primary'))
}
}
// EntryAbility页面 配置跳转流程
export default class EntryAbility extends UIAbility {
private selectPage = ''
private currentWindowStage: window.WindowStage | null = null; // 保存 windowStage 引用
// 根据卡片传递的参数计算目标页面路径
private getPagePath(): string {
let path = 'view/pages/Index';
if (this.selectPage === 'PageA') {
path = 'view/pages/ServicePage/PageA';
}
if (this.selectPage === 'PageB') {
path = 'view/pages/ServicePage/PageB';
}
return path;
}
// 获取服务卡片参数及跳转逻辑
getServerCardParamAndJump(want: Want){
if (want?.parameters?.params) { // 获取服务卡片参数
let parmas: Record<string, Object> = JSON.parse(want?.parameters?.params as string) as Record<string, Object>
this.selectPage = parmas.targetPage as string;
console.log('-----onCreat---' + this.selectPage);
// 关键:应用已在后台运行时,主动切换页面
if (this.currentWindowStage !== null) {
// 获取路径
let path = this.getPagePath();
// 路径跳转
this.currentWindowStage.loadContent(path, (err: BusinessError) => {
if (err.code) {
return;
}
});
}
}
}
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 服务卡片回调
this.getServerCardParamAndJump(want)
}
// 点击卡片会触发
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 服务卡片回调
this.getServerCardParamAndJump(want)
}
}
70.4.2 message事件
- 可以使用router事件跳转到指定UIAbility,可以使用message拉起FormExtensionAbility,通过onFormEvent接口回调通知,以完成点击卡片控件后传递消息给应用的功能。
// UI页 发送 message 消息,
// 调用 FormExtensionAbility类的 onFormEvent 方法,更新数据类实现UI页面的更新
@Entry
@Component
struct WidgetCard {
@LocalStorageProp('title') face: number = 1
@LocalStorageProp('content') message: string = 'messgae-00'
build() {
Column() {
this.messageBuild()
}
.size({width: '100%', height: '100%'})
}
@Builder
messageBuild(){
Text(this.message)
Button().onClick(()=>{
postCardAction(this, {
action: 'message',
abilityName: 'EntryAbility',
params: {msgTest: 'messageEvent'}
})
})
}
}
// 据说请求等操作不能放在这里写
// FormExtensionAbility类
export default class EntryFormAbility extends FormExtensionAbility {
// 发送message消息会调用这个方法
onFormEvent(formId: string, message: string) {
// 定义数据类
class FormDataClass {
title: number = 2
content: string = ''
}
// 初始化数据类
let formData = new FormDataClass()
const param: Record<string, Object> = JSON.parse(message) as Record<string, Object>
// formData.content = param['msgTest'] as string
formData.content = message
let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData)
formProvider.updateForm(formId,formInfo) // 更新
.then(()=>{
})
.catch(()=>{
})
}
}
ps: 坑爹的是断点不好使 onFormEvent~ 抓不到
70.4.3 call事件
- 可以使用
call事件拉起指定UIAbility到后台,再通过UIAbility申请对应后台长时任务完成音乐播放等功能。 - 对比
router前者需要打开应用,call则可以让应用在后台干活
// 注意 module.json5 打开后台权限!!!
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // 后台权限
}
],
// UI页面添加俩按钮 发送call消息
// EntryAbility 监听call消息
@Entry
@Component
struct WidgetCard {
build() {
Column() {
this.callBuild()
}
.size({width: '100%', height: '100%'})
}
@Builder
callBuild(){
Row() {
Text('callA')
.fontSize($r('app.float.font_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.font'))
.onClick(() => {
postCardAction(this, {
action: 'call',
abilityName: 'EntryAbility',
params: {
num: 1,
method: 'funA' }
});
})
Text('callB')
.fontSize($r('app.float.font_size'))
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.font'))
.onClick(() => {
postCardAction(this, {
action: 'call',
abilityName: 'EntryAbility',
params: {
num: 1,
method: 'funB' }
});
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.height('100%')
.backgroundColor($r('sys.color.comp_background_primary'))
}
}
// EntryAbility
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 监听服务卡片 call消息
try {
// 服务卡片回到 call
this.callee.on('funA',(data: rpc.MessageSequence) => {
console.log('funA触发了', JSON.stringify(data.readString()));// 注意这个readString必须加
return new MyParcelable(1, '')
})
this.callee.on('funB',(data: rpc.MessageSequence) => {
console.log('funB触发了', JSON.stringify(data.readString()));// 注意这个readString必须加
return new MyParcelable(1, '')
})
} catch (error){
}
}
70.4.4 应用内也可以调出服务卡片弹框
- API18及以上, 可以应用内通过代码调出服务卡片
- 等同于长按应用展示卡片弹框