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