HarmonyOS 鸿蒙Next服务卡片
HarmonyOS 鸿蒙Next服务卡片
介绍
服务卡片指导文档位于“开发/应用模型/Stage模型开发指导/Stage模型应用组件”路径下,说明其极其重要。
本篇文章将分享实现服务卡片的过程和代码
准备
- 请参照官方指导,创建一个Demo工程,选择Stage模型
- 熟读HarmonyOS 官方指导 “创建一个ArkTS卡片”
实践总结
- 应用打包时,不能选择“Deploy Muti Hap Packages”方式, 否则服务卡片不会显示任何内容
- 官方指导中没有提示添加权限“ohos.permission.KEEP_BACKGROUND_RUNNING”,如果不添加,则无法使用call方式来刷新卡片数据
- 卡片首次创建时,卡片Id无法传入到卡片中,需通过延时机制,二次更新
效果
卡片元素说明
- 卡片共有使用到了7个控件
- 5个Text, 1个Image, 1个Rect
- Text(‘call’) : 可点击,实验call事件刷新卡片内容
- Text(‘router’): 可点击,实验router事件刷新卡片内容
- Text(‘message’): 可点击,实验message事件刷新卡片内容
- Rect(): 实验卡片动画效果
服务卡片教程
1. 请完全按照“创建一个ArkTS卡片”
2. 修改生成的卡片代码(WidgetCard.ets)
let storageCard = new LocalStorage()
@Entry(storageCard) @Component struct WidgetCard { /*
- The mini title. */ readonly MINI_TITLE: string = ‘Title’;
/*
- The item title. */ @LocalStorageProp(‘ITEM_TITLE’)ITEM_TITLE: string = ‘标题’;
/*
- The item content. */ @LocalStorageProp(‘ITEM_CONTENT’) ITEM_CONTENT: string = ‘天气不错’;
/*
- The action type. */ readonly ACTION_TYPE: string = ‘router’;
/*
- The ability name. */ readonly ABILITY_NAME: string = ‘EntryAbility’;
/*
- The message. */ readonly MESSAGE: string = ‘来自服务卡片’;
/*
- The mini display priority. */ readonly MINI_DISPLAY_PRIORITY: number = 2;
/*
- The max line. */ readonly MAX_LINES: number = 1;
/*
- The with percentage setting. */ readonly FULL_WIDTH_PERCENT: string = ‘100%’;
/*
- The height percentage setting. */ readonly FULL_HEIGHT_PERCENT: string = ‘100%’;
/*
- Image height percentage setting. */ readonly IMAGE_HEIGHT_PERCENT: string = ‘64%’; @State mini: boolean = false;
@State rectWidth: string = ‘30%’
@LocalStorageProp(‘formId’) formId: string = ‘0’;
build() { Row() { Column() { if (this.mini) { Column() { Text(this.MINI_TITLE) .fontSize($r(‘app.float.mini_title_font_size’)) .fontColor($r(‘app.color.mini_text_font_color’)) .margin({ left: $r(‘app.float.mini_title_margin’), bottom: $r(‘app.float.mini_title_margin’) }) } .width(this.FULL_WIDTH_PERCENT) .alignItems(HorizontalAlign.End) .backgroundImageSize(ImageSize.Cover) .backgroundImage($r(“app.media.ic_widget”), ImageRepeat.NoRepeat) .displayPriority(this.MINI_DISPLAY_PRIORITY) } Stack(){ Image($r(“app.media.ic_widget”)) .width(this.FULL_WIDTH_PERCENT) .height(‘100%’) .objectFit(ImageFit.Cover) .borderRadius($r(‘app.float.image_border_radius’)) Rect() .width(this.rectWidth) .height(‘100%’) .fill(’#60ff0000’) .animation({ duration: 3000, curve: Curve.Linear, playMode: PlayMode.Normal, iterations: -1, onFinish:()=>{ if(this.rectWidth == ‘30%’){ this.rectWidth = ‘50%’ } else { this.rectWidth = ‘30%’ } }}) Row(){ Column({space: 20}){ Text(‘call’) .fontColor(Color.Red) .onClick(()=>{ console.log('formId: '+this.formId) postCardAction(this, { ‘action’: ‘call’, ‘abilityName’: ‘EntryAbility’, ‘params’: { ‘method’: ‘funA’, ‘formId’: this.formId } }); })
Text(<span class="hljs-string"><span class="hljs-string">'router'</span></span>) .onClick(()=>{ postCardAction(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>, { <span class="hljs-string"><span class="hljs-string">'action'</span></span>: <span class="hljs-string"><span class="hljs-string">'router'</span></span>, <span class="hljs-string"><span class="hljs-string">'abilityName'</span></span>: <span class="hljs-string"><span class="hljs-string">'EntryAbility'</span></span>, <span class="hljs-string"><span class="hljs-string">'params'</span></span>: { <span class="hljs-string"><span class="hljs-string">'msgTest'</span></span>: <span class="hljs-string"><span class="hljs-string">'messageEvent'</span></span> } }); }) } Column(){ Text(<span class="hljs-string"><span class="hljs-string">'message'</span></span>) .fontColor(Color.Green) .onClick(()=>{ postCardAction(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>, { <span class="hljs-string"><span class="hljs-string">'action'</span></span>: <span class="hljs-string"><span class="hljs-string">'message'</span></span>, <span class="hljs-string"><span class="hljs-string">'params'</span></span>: { <span class="hljs-string"><span class="hljs-string">'msgTest'</span></span>: <span class="hljs-string"><span class="hljs-string">'messageEvent'</span></span> } }); }) } }.height(<span class="hljs-string"><span class="hljs-string">'100%'</span></span>) } .width(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.FULL_WIDTH_PERCENT) .height(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.IMAGE_HEIGHT_PERCENT) Blank() Text(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.ITEM_TITLE) .fontSize($r(<span class="hljs-string"><span class="hljs-string">'app.float.normal_title_font_size'</span></span>)) Text(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.ITEM_CONTENT) .maxLines(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.MAX_LINES) .fontSize($r(<span class="hljs-string"><span class="hljs-string">'app.float.normal_content_font_size'</span></span>)) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .width(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.FULL_WIDTH_PERCENT) .height(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.FULL_HEIGHT_PERCENT) .alignItems(HorizontalAlign.Start) .backgroundColor($r(<span class="hljs-string"><span class="hljs-string">'app.color.start_window_background'</span></span>)) } .height(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.FULL_HEIGHT_PERCENT) .alignItems(VerticalAlign.Top) .padding($r(<span class="hljs-string"><span class="hljs-string">'app.float.row_padding'</span></span>)) .onClick(() => { postCardAction(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>, { <span class="hljs-string"><span class="hljs-string">"action"</span></span>: <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.ACTION_TYPE, <span class="hljs-string"><span class="hljs-string">"abilityName"</span></span>: <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.ABILITY_NAME, <span class="hljs-string"><span class="hljs-string">"params"</span></span>: { <span class="hljs-string"><span class="hljs-string">"message"</span></span>: <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.MESSAGE } }); })
} }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
3. 修改应用入口EntryAbility.ets
import window from ‘@ohos.window’; import UIAbility from ‘@ohos.app.ability.UIAbility’; import formBindingData from ‘@ohos.app.form.formBindingData’; import formProvider from ‘@ohos.app.form.formProvider’; import formInfo from ‘@ohos.app.form.formInfo’;
export default class EntryAbility extends UIAbility { storage: LocalStorage
onCreate(want, launchParam) { try{ let params = JSON.parse(want.parameters.params);
console.log(<span class="hljs-string"><span class="hljs-string">'onCreate '</span></span> + params[<span class="hljs-string"><span class="hljs-string">'message'</span></span>]) <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.storage = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> LocalStorage({<span class="hljs-string"><span class="hljs-string">'ext'</span></span>: params[<span class="hljs-string"><span class="hljs-string">'message'</span></span>]}) } <span class="hljs-keyword"><span class="hljs-keyword">catch</span></span> (e){ console.log(e) } <span class="hljs-keyword"><span class="hljs-keyword">try</span></span>{ <span class="hljs-comment"><span class="hljs-comment">// 监听call事件所需的方法</span></span> <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.callee.on(<span class="hljs-string"><span class="hljs-string">'funA'</span></span>, FunACall); } <span class="hljs-keyword"><span class="hljs-keyword">catch</span></span> (e){ console.log(e) } <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== <span class="hljs-literal"><span class="hljs-literal">undefined</span></span>) { <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY]; updateCardContent(curFormId, <span class="hljs-string"><span class="hljs-string">"EntryAbility"</span></span>, <span class="hljs-string"><span class="hljs-string">"router-welcome"</span></span>) }
}
onNewWant(want, launchParam) { try{ let params = JSON.parse(want.parameters.params); console.log('onNewWant ’ + params[‘message’]) this.storage = new LocalStorage({‘ext’: params[‘message’]}) } catch (e){ console.log(e) }
}
onWindowStageCreate(windowStage: window.WindowStage) { windowStage.loadContent(‘pages/Index’, this.storage, (err, data) => { }); }
onDestroy(){ console.log(‘onDestroy’) // this.callee.off(‘funA’) }
}
// 在收到call事件后会触发callee监听的方法 function FunACall(data) { // 获取call事件中传递的所有参数 try{ let params = JSON.parse(data.readString()) if (params.formId !== undefined) { let curFormId = params.formId; updateCardContent(curFormId, “EntryAbility”, “caller-welcome”) } } catch (e){ console.log(e) }
return null; }
function updateCardContent(formId, method, content){ let formData = { ‘ITEM_TITLE’: method, // 和卡片布局中对应 ‘ITEM_CONTENT’: content, // 和卡片布局中对应 }; let formInfo = formBindingData.createFormBindingData(formData)
formProvider.updateForm(formId, formInfo).then((data) => { console.info(‘FormAbility updateForm success.’ + JSON.stringify(data)); }).catch((error) => { console.error('FormAbility updateForm failed: ’ + JSON.stringify(error)); }) }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
4. 修改应用入入口页面Index.ets
let storage = new LocalStorage()
@Entry(storage) @Component struct Page { @State message: string = ‘Hello World’ @LocalStorageProp(‘ext’) extLocalStorageParms: string = ‘’;
aboutToAppear(){
console.log(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.extLocalStorageParms) <span class="hljs-keyword"><span class="hljs-keyword">if</span></span>(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.extLocalStorageParms){ <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.message = <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.extLocalStorageParms }
}
build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) } .width(‘100%’) } .height(‘100%’) }
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
5. 修改EntryFormAbility.ets
import formInfo from ‘@ohos.app.form.formInfo’; import formBindingData from ‘@ohos.app.form.formBindingData’; import FormExtensionAbility from ‘@ohos.app.form.FormExtensionAbility’; import formProvider from ‘@ohos.app.form.formProvider’;
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want) { // Called to return a FormBindingData object. let formId = want.parameters[“ohos.extra.param.key.form_identity”];
<span class="hljs-keyword"><span class="hljs-keyword">let</span></span> formData: Record<string, string> = { <span class="hljs-string"><span class="hljs-string">'formId'</span></span>: formId }; console.log(<span class="hljs-string"><span class="hljs-string">'onAddForm '</span></span>+formId) <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> data = formBindingData.createFormBindingData(formData); setTimeout(()=>{ formProvider.updateForm(formId, data).then((data) => { console.info(<span class="hljs-string"><span class="hljs-string">'FormAbility updateForm success.'</span></span> + <span class="hljs-built_in"><span class="hljs-built_in">JSON</span></span>.stringify(data)); }).catch((error) => { console.error(<span class="hljs-string"><span class="hljs-string">'FormAbility updateForm failed: '</span></span> + <span class="hljs-built_in"><span class="hljs-built_in">JSON</span></span>.stringify(error)); }) }, <span class="hljs-number"><span class="hljs-number">1500</span></span>) <span class="hljs-keyword"><span class="hljs-keyword">return</span></span> data
}
onCastToNormalForm(formId) { // Called when the form provider is notified that a temporary form is successfully // converted to a normal form. console.log(‘onCastToNormalForm’) }
onUpdateForm(formId) { // Called to notify the form provider to update a specified form. console.log(‘onUpdateForm’) }
onChangeFormVisibility(newStatus) { // Called when the form provider receives form events from the system. console.log(‘onChangeFormVisibility’) }
onFormEvent(formId, message) { // Called when a specified message event defined by the form provider is triggered. console.log(message)
<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.updateCardContent(formId)
}
onRemoveForm(formId) { // Called to notify the form provider that a specified form has been destroyed. console.log(‘onRemoveForm’) }
onAcquireFormState(want) { // Called to return a {@link FormState} object. return formInfo.FormState.READY; }
updateCardContent(formId){ let formData = { ‘ITEM_TITLE’: ‘EntryFormAbility’, // 和卡片布局中对应 ‘ITEM_CONTENT’: ‘welcome’, // 和卡片布局中对应 }; let formInfo = formBindingData.createFormBindingData(formData)
formProvider.updateForm(formId, formInfo).then((data) => { console.info(<span class="hljs-string"><span class="hljs-string">'FormAbility updateForm success.'</span></span> + <span class="hljs-built_in"><span class="hljs-built_in">JSON</span></span>.stringify(data)); }).catch((error) => { console.error(<span class="hljs-string"><span class="hljs-string">'FormAbility updateForm failed: '</span></span> + <span class="hljs-built_in"><span class="hljs-built_in">JSON</span></span>.stringify(error)); })
} };
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
6. 在module.json5中添加权限
“requestPermissions”: [
{
“name”: “ohos.permission.KEEP_BACKGROUND_RUNNING”,
“usedScene”: {
“abilities”: [“EntryAbility”],
“when”: “inuse”
}
}
]
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
7. 最后一步,请确认你的打包方式没有选择“Deploy Multi Hap Packages”, 否则将无法看到服务卡片内容
更多关于HarmonyOS 鸿蒙Next服务卡片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
取消勾选“Deploy Multi Hap Packages”,卡片内容还是空白。
运行时,选OpenHarmony App 》entry ,卡片内容才可见,与是否勾选Deploy Multi Hap Packages 没关系。
更多关于HarmonyOS 鸿蒙Next服务卡片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS 鸿蒙Next服务卡片是一种轻量级的服务组件,允许用户快速访问应用的特定功能或服务信息。这些卡片通常放置在设备桌面上,展示实时更新的信息或快速操作入口。开发者可以定义卡片的布局、内容以及交互方式,并通过HarmonyOS提供的API进行实现。卡片背后连接服务,实现数据动态更新。如需了解更多开发细节,请参考官方文档或教程。如果问题依旧没法解决请加我微信,我的微信是itying888。
更多关于HarmonyOS 鸿蒙Next服务卡片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html