鸿蒙卡片开发保姆级教程

发布于:2025-07-24 ⋅ 阅读:(14) ⋅ 点赞:(0)

卡片

1. 卡片概念

  1. 什么是卡片?

    卡片用来显示或者提示一些基本信息或者进行一些基本操作。注意不能做重逻辑,所有重要逻辑全部交给应用

  2. 如果是元服务如何唤醒?

    因为元服务不提供桌面应用图标,我们可以通过用户手动的方式在桌面上添加一张卡片,通过点击卡片来唤起元服务。

2. 创建卡片

  1. 在编辑器中创建
    卡片创建步骤

  2. 选择动态卡片
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    卡片的特点
    1.卡片只能承载少量的内容和交互
    2. 卡片可以充当元服务icon作为入口,默认提供一张服务卡片作为入口
    3. 普通应用也可以添加服务卡片,但默认没有添加卡片

    元服务和普通应用的区别
    在这里插入图片描述

  3. 添加卡片
    在这里插入图片描述
    在这里插入图片描述

3. ArkTS卡片实现原理

在这里插入图片描述

4. ArkTS卡片渲染服务运行原理

在这里插入图片描述

5. 卡片的服务通信

5.1 卡片-------> 应用
  • 使用postCardAction方法
  1. 在卡片pages中书写代码
// 卡片的应用
@Entry
@Component
struct WidgetCard {
  @State count: number = 10;
  build() {
    Column() {
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;

            postCardAction(this, {
              action: 'call',
              abilityName: 'EntryAbility',
              params: {
                method: 'updateFormCount',
                num: this.count
              }
            })
          })

        Text(this.count.toString())
          .fontSize(18)

        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
              postCardAction(this,{
                action:'call',
                abilityName: 'EntryAbility',
                params:{
                  method:'updateFormCount',
                  num:this.count
                }
              })
            }
          })
      }
    }
    .width('100%')
    .height('100%')
    .onClick(() => {
    	// 点击唤醒应用
      postCardAction(this, {
        action: 'router',
        abilityName: 'EntryAbility'
      })
    })
  }
}
  1. module.json5添加-保持应用在后台权限
 "requestPermissions": [{
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
    }],
  1. 应用的entryability中进行接收
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { rpc } from '@kit.IPCKit';
import { JSON } from '@kit.ArkTS';
import { preferences } from '@kit.ArkData';
import { formBindingData, formProvider } from '@kit.FormKit';

const DOMAIN = 0x0000;

//必须是rpc.Parcelable类型
class Params implements rpc.Parcelable {
  marshalling(dataOut: rpc.MessageSequence): boolean {
    return true;
  }

  unmarshalling(dataIn: rpc.MessageSequence): boolean {
    return true;
  }
}

class CardParams {
  count: number = 0
  formId:string = ""
}

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
    this.callee.on("updateFormCount", (data) => {
      const res = JSON.parse(data.readString()) as CardParams;
      AppStorage.setOrCreate('count', res.count);


	//必须返回一个rpc.Parcelable类型
      return new Params();
    })
  }

  onDestroy(): void {
  	//销毁时解除监听
    this.callee.off("updateFormCount")
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

  1. 主页Index.ets
import { preferences } from '@kit.ArkData'
import { formBindingData, formProvider } from '@kit.FormKit'

@Component
@Entry
struct Index {
  @StorageLink('count')
  count:number = 0
  build() {
    Column(){
      Text('课程太多了')
        .fontSize(18)
        .fontColor(Color.Orange)
        .fontWeight(700)
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;
          })

        Text(this.count.toString())
          .fontSize(18)

        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
            }
          })
      }
    }
    .backgroundColor(Color.Pink)
    .width('100%')
    .height('100%')
  }
}

总结:如图示
在这里插入图片描述

5.2 应用----------->卡片
  1. 卡片的ability的entryformability的onAddForm方法中添加
onAddForm(want: Want) {
    // Called to return a FormBindingData object.
    return formBindingData.createFormBindingData({
      formId: want.parameters!["ohos.extra.param.key.form_identity"] as string
    });
  }
  1. 卡片:WidgetCard.ets 监听formId ,当formId发生变化时,发送至应用
 @LocalStorageProp("formId")
  @Watch("updateFormId")
  formId: string = ""

  updateFormId () {
    postCardAction(this, {
      action: 'call',
      abilityName: 'EntryAbility', // 只能跳转到当前应用下的UIAbility
      params: {
        method: 'updateFormId',
        formId: this.formId
      }
    })
  }
  1. 在ability中通过callee监听方法,将formId存入持久化
 this.callee.on("updateFormId", (data) => {
      const res = JSON.parse(data.readString()) as CardParams
      const store = preferences.getPreferencesSync(this.context, {
        name: 'formIdList'
      })
      const list = JSON.parse(store.getSync("formIdList", "[]") as string) as string[]
      if(!list.includes(res.formId)) {
        list.push(res.formId)
      }
      store.putSync("formIdList", JSON.stringify(list))
      store.flush()
      formProvider.updateForm(res.formId, formBindingData.createFormBindingData({
        num: AppStorage.get("num")
      }))
      return new Params()
    })
  1. 卸载时解除
  onDestroy(): void {
    this.callee.off("updateNum")
    this.callee.off("updateFormId")
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }
  1. Index.ets
@StorageLink("num")
  @Watch("pushCard")
  num: number = 0

  pushCard() {
    const store = preferences.getPreferencesSync(getContext(), {
      name: 'formIdList'
    })
    const formIdList = JSON.parse(store.getSync("formIdList", "[]") as string) as string[]
    if (formIdList && formIdList.length) {
      formIdList.forEach((formId) => {
        formProvider.updateForm(formId, formBindingData.createFormBindingData({
          num: this.num
        }))
      })

    }
  }
  1. 卡片:从推送的数据中从新获取
@Entry
@Component
struct WidgetCard {
  //修改成@LocalStorageProp
  @LocalStorageProp("count")  
  count: number = 0;
  @LocalStorageProp("formId")
  @Watch("updateFormId")
  formId:string = ""
  //应用===》卡片  需要把formId给到应用
  updateFormId(){
    postCardAction(this,{
      action:'call',
      abilityName: 'EntryAbility',
        params:{
          method:'updateFormId',
          formId:this.formId
        }
    })
  }

  build() {
    Column() {
      Row({ space: 20 }) {
        Button('++')
          .onClick(() => {
            this.count++;

            postCardAction(this, {
              action: 'call',
              abilityName: 'EntryAbility',
              params: {
                method: 'updateFormCount',
                count: this.count
              }
            })
          })

        Text(this.count.toString())
          .fontSize(18)
        Button('--')
          .onClick(() => {
            if (this.count > 0) {
              this.count--;
              postCardAction(this,{
                action:'call',
                abilityName: 'EntryAbility',
                params:{
                  method:'updateFormCount',
                  count:this.count
                }
              })
            }
          })
      }
    }
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .width('100%')
    .height('100%')
    .onClick(() => {
      postCardAction(this, {
        action: 'router',
        abilityName: 'EntryAbility'
      })
    })
  }
}

总结:如图示:

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到