吴旭华 发表于 2024-9-10 18:01:15

鸿蒙——应用服务卡片显示图片和唤起指定页面

目次

1. 简介
服务卡片架构
亮点/特征
2. ArkTS卡片开发指导 
创建一个ArkTS卡片
 配置卡片的配置文件
卡片生命周期管理
3. 功能开发
3.1 刷新图片
方案一:官方文档思路
方案2 ,仅供参考(如有不对,请多指正。)
3.2 卡片动态更新内容
实现原理
实现步调
3.3 点击卡片唤起特定页
基础实现原理
 实现步调

总结 

1. 简介

Form Kit(卡片开发服务)提供一种界面展示情势,可以将应用的重要信息或操纵前置到服务卡片(以下简称“卡片”),以到达服务直达、镌汰跳转层级的体验结果。卡片常用于嵌入到其他应用(当前被嵌入方即卡片使用方只支持系统应用,例如桌面)中作为其界面显示的一部门,并支持拉起页面、发送消息等基础的交互能力。
服务卡片架构

图1 服务卡片架构
https://img-blog.csdnimg.cn/img_convert/a69bb7c5ab0a5b8a079ce8cd2db2d7c9.png
卡片的根本概念:


[*]卡片使用方:如上图中的桌面,显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。

[*]应用图标:应用入口图标,点击后可拉起应用历程,图标内容不支持交互
[*]卡片:具备不同规格巨细的界面展示,卡片的内容可以举行交互,如实现按钮举行界面的刷新、应用的跳转等。

[*]卡片提供方:包含卡片的应用,提供卡片的显示内容、控件结构以及控件点击处理逻辑。

[*]FormExtensionAbility:卡片业务逻辑模块,提供卡片创建、烧毁、刷新等生命周期回调。
[*]卡片页面:卡片UI模块,包含页面控件、结构、变乱等显示和交互信息。

卡片的常见使用步调如下:
图2 卡片常见使用步调 
https://img-blog.csdnimg.cn/img_convert/4c239361784b755225c2fe76d9547b27.png

[*]长按“桌面图标”,弹出操纵菜单。
[*]点击“服务卡片”选项,进入卡片预览界面。
[*]点击“添加到桌面”按钮,即可在桌面上看到新添加的卡片。
亮点/特征



[*]服务直达:将元服务/应用的重要信息以卡片情势展示在桌面,用户可以通过快捷手势使用卡片,通过轻量交互行为实现服务直达、镌汰层级跳转的目的。
[*]永久在线:提供定时、署理等多种卡片刷新机制,实现卡片永久在线。
[*]受限管控:卡片支持的组件、变乱、动效、数据管理、状态管理和API能力均举行了肯定限定,保障性能、功耗及安全可靠。
2. ArkTS卡片开发指导 

创建一个ArkTS卡片

在已有的应用工程中,可以通过右键新建ArkTS卡片,具体的操纵方式如下。
1,右键新建卡片。
https://img-blog.csdnimg.cn/direct/b0a39b7e9e274d5aafd377ccd4772bef.png
   说明:
在API 10 Stage模型的工程中,在Service Widget菜单可直接选择创建动态或静态服务卡片。创建服务卡片后,也可以在卡片的form_config.json配置文件中,通过isDynamic参数修改卡片类型:isDynamic置空或赋值为"true",则该卡片为动态卡片;isDynamic赋值为"false",则该卡片为静态卡片。
2,根据实际业务场景,选择一个卡片模板。
https://img-blog.csdnimg.cn/direct/58322c46f1be46639a5860b8dda5101d.png
 3,在选择卡片的开发语言类型(Language)时,选择ArkTS选项,然后单击“Finish”,即可完成ArkTS卡片创建。
https://img-blog.csdnimg.cn/direct/b58a7c4d0cb848c5bbc5f4c0c49241e9.png
4. ArkTS卡片创建完成后,工程中会新增如下卡片相干文件:卡片生命周期管理文件(EntryFormAbility.ets)、卡片页面文件(WidgetCard.ets)和卡片配置文件(form_config.json)。
https://img-blog.csdnimg.cn/direct/c5edccfd7c0c4237a3e5651c3408b0e1.png

 配置卡片的配置文件

本人开发时编辑器(DevEco Studio)会主动配置,无需手工配置!!!
假如有,请忽略这一步;没有的话,请按要求配置。
卡片相干的配置文件主要包含FormExtensionAbility的配置和卡片的配置两部门。

[*] 卡片需要在module.json5配置文件中的extensionAbilities标签下,配置FormExtensionAbility相干信息。FormExtensionAbility需要填写metadata元信息标签,其中键名称为固定字符串“ohos.extension.form”,资源为卡片的具体配置信息的索引。
配置示例如下:
[*]       {
  "module": {
    ...
    "extensionAbilities": [
      {
        "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"
          }
        ]
      }
    ]
  }
}
[*] 卡片的具体配置信息。在上述FormExtensionAbility的元信息(“metadata”配置项)中,可以指定卡片具体配置信息的资源索引。配置示例如下:
   {
  "forms": [
    {
      "name": "widget",
      "description": "This is a service widget.",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 1,
      "defaultDimension": "2*2",
      "supportDimensions": [
        "2*2"
      ],
      "formConfigAbility": "ability://com.example.entry.EntryAbility",
      "dataProxyEnabled": false,
      "isDynamic": true,
      "transparencyEnabled": false,
      "metadata": []
    }
  ]
}
卡片生命周期管理

在EntryFormAbility.ets中,实现FormExtensionAbility生命周期接口,其中在onAddForm的入参want中可以通过FormParam取出卡片的相干信息。
    
import { formBindingData, FormExtensionAbility, formInfo } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
export default class EntryFormAbility extends FormExtensionAbility {
 // 使用方创建卡片时触发,提供方需要返回卡片数据绑定类
   onAddForm(want: Want) {
      // Called to return a FormBindingData object.
      let formData = '';
      return formBindingData.createFormBindingData(formData);
   }
   // 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理
   onCastToNormalForm(formId: string) {
      // Called when the form provider is notified that a temporary form is successfully
      // converted to a normal form.
   }
   // 若卡片支持定时更新/定点更新/卡片使用方主动哀求更新功能,则提供方需要重写该方法以支持数据更新
   onUpdateForm(formId: string) {
      // Called to notify the form provider to update a specified form.
   }
   // 需要配置formVisibleNotify为true,且为系统应用才会回调
   onChangeFormVisibility(newStatus: Record<string, number>) {
      // Called when the form provider receives form events from the system.
   }
   // 若卡片支持触发变乱,则需要重写该方法并实现对变乱的触发
   onFormEvent(formId: string, message: string) {
      // Called when a specified message event defined by the form provider is triggered.
   }
   // 当对应的卡片删除时触发的回调,入参是被删除的卡片ID
   onRemoveForm(formId: string) {
      // Called to notify the form provider that a specified form has been destroyed.
   }
   // 卡片提供方接收查询卡片状态通知接口,默认返回卡片初始状态。
   onAcquireFormState(want: Want) {
      // Called to return a {@link FormState} object.
      return formInfo.FormState.READY;
   }
   //主动生成没有这个,有需求需要自己配
   onConfigurationUpdate(config: Configuration) {
   // 当前formExtensionAbility存活时更新系统配置信息时触发的回调。
   // 需留意:formExtensionAbility创建后5秒内无操纵将会被清理。
   console.info(' onConfigurationUpdate:' + JSON.stringify(config));
   }
};
这是编译器主动生成的文件,我们只需要明白每个生命周期钩子是何时触发的,知道在哪个钩子里完成我们的业务。
3. 功能开发

应用服务卡片功能很多,像卡片定时刷新和定点刷新,根据卡片状态刷新不同的内容,刷新本地和网络图片,卡片署理刷新等 ,另有router,call,message变乱。
本文篇幅有限,就主要介绍我使用过的加载网络图片,刷新图片和点击卡片唤起特定页。
3.1 刷新图片

1, 下载网络图片需要使用到网络能力,需要在main目次下的module.json5文件中配置申请ohos.permission.INTERNET权限。
   "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
]
  官方文档
2,在EntryFormAbility中的onAddForm生命周期回调中实现本地文件的刷新。
    
const TAG: string = 'WgtImgUpdateEntryFormAbility';
const DOMAIN_NUMBER: number = 0xFF00;
export default class WgtImgUpdateEntryFormAbility extends FormExtensionAbility {
  // 在添加卡片时,打开一个本舆图片并将图片内容通报给卡片页面显示
  onAddForm(want: Want): formBindingData.FormBindingData {
    // 假设在当前卡片应用的tmp目次下有一个本舆图片:head.PNG
    let tempDir = this.context.getApplicationContext().tempDir;
    // 打开本舆图片并获取其打开后的fd
    let file: fileFs.File;
    let imgBear: Record<string, number>;
    try {
      file = fs.openSync(tempDir + '/' + 'head.PNG');
      imgBear = {
        'imgBear': file.fd
      };
    } catch (e) {
      hilog.error(DOMAIN_NUMBER, TAG, `openSync failed: ${JSON.stringify(e as Base.BusinessError)}`);
    }
    class FormDataClass {
      text: string = 'Image: Bear';
      imgName: string = 'imgBear';
      loaded: boolean = true;
      formImages: Record<string, number> = imgBear;
    }
    let formData = new FormDataClass();
    // 将fd封装在formData中并返回至卡片页面
    return formBindingData.createFormBindingData(formData);
  }
  ...
}
3,在EntryFormAbility中的onFormEvent生命周期回调中实现网络文件的刷新。 
    
const TAG: string = 'WgtImgUpdateEntryFormAbility';
const DOMAIN_NUMBER: number = 0xFF00;
export default class WgtImgUpdateEntryFormAbility extends FormExtensionAbility {
  onFormEvent(formId: string, message: string): void {
    let param: Record<string, string> = {
      'text': '刷新中...'
    };
    let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param);
    formProvider.updateForm(formId, formInfo);
    // 留意:FormExtensionAbility在触发生命周期回调时被拉起,仅能在背景存在5秒
    // 建议下载能快速下载完成的小文件,如在5秒内未下载完成,则此次网络图片无法刷新至卡片页面上
    let netFile = 'https://cn-assets.gitee.com/assets/mini_app-e5eee5a21c552b69ae6bf2cf87406b59.jpg'; // 需要在此处使用真实的网络图片下载链接
    let tempDir = this.context.getApplicationContext().tempDir;
    let fileName = 'file' + Date.now();
    let tmpFile = tempDir + '/' + fileName;
    let httpRequest = http.createHttp()
    httpRequest.request(netFile, (err, data) => {
      if (!err && data.responseCode == http.ResponseCode.OK) {
        let imgFile = fs.openSync(tmpFile, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
        fs.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen: number) => {
          hilog.info(DOMAIN_NUMBER, TAG, "write data to file succeed and size is:" + writeLen);
        }).catch((err: Base.BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, "write data to file failed with error message: " + err.message + ", error code: " + err.code);
        }).finally(() => {
          fs.closeSync(imgFile);
        });
        hilog.info(DOMAIN_NUMBER, TAG, 'ArkTSCard download complete: %{public}s', tmpFile);
        let file: fileFs.File;
        let fileInfo: Record<string, string | number> = {};
        try {
          file = fs.openSync(tmpFile);
          fileInfo = file.fd;
        } catch (e) {
          hilog.error(DOMAIN_NUMBER, TAG, `openSync failed: ${JSON.stringify(e as Base.BusinessError)}`);
        }
        class FormDataClass {
          text: string = 'Image: Bear' + fileName;
          imgName: string = fileName;
          loaded: boolean = true;
          formImages: object = fileInfo;
        }
        let formData = new FormDataClass();
        let formInfo = formBindingData.createFormBindingData(formData);
        formProvider.updateForm(formId, formInfo).then(() => {
          hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'FormAbility updateForm success.');
        }).catch((error: Base.BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`);
        });
      } else {
        hilog.error(DOMAIN_NUMBER, TAG, `ArkTSCard download task failed. Cause: ${JSON.stringify(err)}`);
        let param: Record<string, string> = {
          'text': '刷新失败'
        };
        let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param);
        formProvider.updateForm(formId, formInfo);
      }
      httpRequest.destroy();
    })
  }
  ...
}
 4,在卡片页面通过backgroundImage属性展示EntryFormAbility通报过来的卡片内容。
    
let storageWidgetImageUpdate = new LocalStorage();
@Entry(storageWidgetImageUpdate)
@Component
struct WidgetImageUpdateCard {
   @LocalStorageProp('text') text: ResourceStr = $r('app.string.loading');
   @LocalStorageProp('loaded') loaded: boolean = false;
   @LocalStorageProp('imgName') imgName: ResourceStr = $r('app.string.imgName');
   build() {
      Column() {
         Column() {
            Text(this.text)
               .fontColor('#FFFFFF')
               .opacity(0.9)
               .fontSize(12)
               .textOverflow({ overflow: TextOverflow.Ellipsis })
               .maxLines(1)
               .margin({ top: '8%', left: '10%' })
         }.width('100%').height('50%')
         .alignItems(HorizontalAlign.Start)
         Row() {
            Button() {
               Text($r('app.string.update'))
                  .fontColor('#45A6F4')
                  .fontSize(12)
            }
            .width(120)
            .height(32)
            .margin({ top: '30%', bottom: '10%' })
            .backgroundColor('#FFFFFF')
            .borderRadius(16)
            .onClick(() => {
               postCardAction(this, {
                  action: 'message',
                  params: {
                     info: 'refreshImage'
                  }
               });
            })
         }.width('100%').height('40%')
         .justifyContent(FlexAlign.Center)
      }.width('100%').height('100%')
      .backgroundImage('memory://' + this.imgName)
      .backgroundImageSize(ImageSize.Cover)
   }
}
我的写法---仅供参考(如有不对,请多指正)
1,编写图片加载类
    
import type fileFs from '@ohos.file.fs'
import fs from '@ohos.file.fs'
// 作用:下载需要的图片资源 然后把图片资源处理为下发给card组件使用的标准格式
class FormData {
  fileNameList: string[]
  formImages: Record<string, string | number>
  constructor(fileNameList: string[], formImages: Record<string, string | number>) {
    this.fileNameList = fileNameList
    this.formImages = formImages
  }
}
class LoadImageForFormData {
  // 要下载的图片列表
  private imageUrls: string[]
  // 图片下载完毕执行函数
  private finishCb: (formInfo: formBindingData.FormBindingData) => void
  // 当前Ability
  private ability: FormExtensionAbility
  // 当前正在下载的图片下标
  private curIndex: number = 0
  // 本地地址
  private tempDir: string = ''
  // 内存中的图片对象
  private formImages: Record<string, string | number> = {}
  // 图片文件的名称列表
  private fileNameList: string[] = []
  // 初始FormData数据
  initialFormData = new FormData([], {})
  constructor(imageUrls: string[], finishCb: (formInfo: formBindingData.FormBindingData) => void,
    ability: FormExtensionAbility) {
    this.imageUrls = imageUrls
    this.finishCb = finishCb
    this.ability = ability
    this.tempDir = ability.context.getApplicationContext().tempDir
  }
  // 动态添加要下载的图片
  addImage (imageUrls: string[]){
    this.imageUrls = imageUrls
    return this
  }
  // 开始下载图片
  startLoad ()  {
    if (this.imageUrls.length === 0) {
      console.error('please provide download imglist')
      return
    }
    let netFile = this.imageUrls // 需要在此处使用真实的网络图片下载链接
    let fileName = 'file' + Date.now()
    let tmpFile = this.tempDir + '/' + fileName
    request.downloadFile(
      this.ability.context,
      {
        url: netFile,
        filePath: tmpFile,
        enableMetered: true,
        enableRoaming: true
      }
    ).then((task) => {
      task.on('complete', () => {
        let file: fileFs.File
        try {
          // fs资源读取模块
          file = fs.openSync(tmpFile)
          this.formImages = file.fd
        } catch (e) {
          console.error(`openSync failed: ${JSON.stringify(e)}`)
        }
        this.fileNameList.push(fileName)
        this.curIndex++
        if (this.curIndex < this.imageUrls.length) {
          // 假如还没下载完毕,继续下载
          this.startLoad()
        } else {
          // 全部下载完毕更新数据
          this.initialFormData.fileNameList = this.fileNameList
          this.initialFormData.formImages = this.formImages
          let formInfo = formBindingData.createFormBindingData(this.initialFormData)
          this.finishCb(formInfo)
        }
      })
    }).catch(() => {
    })
  }
}
2.,FormExtensionAbility中下发数据
    
// 要下载的图片
const goodsList = [
   'https://dongfangshuxing.oss-cn-beijing.aliyuncs.com/2023/03/14/yuxiangrousi.jpg',
   'https://dongfangshuxing.oss-cn-beijing.aliyuncs.com/2023/03/14/yuxiangrousi.jpg',
]
export default class EntryFormAbility extends FormExtensionAbility {
   // 手动补充返回值类型
   onAddForm(want: Want): formBindingData.FormBindingData {
      const  ImgData= new LoadImageForFormData(
         goodsList,
         (formInfo: formBindingData.FormBindingData) => {
            // 找到要更新的卡片id
            const formId = want.parameters && want.parameters['ohos.extra.param.key.form_identity'].toString()
            // 根据卡片id和信息更新卡片内容
            formProvider.updateForm(formId, formInfo)
         },
         this
      )
      ImgData.startLoad()
      // 必须要return
      return formBindingData.createFormBindingData(ImgData.initialFormData)
   }
}
 goodsList放的是我的网络图片,各位可以根据自己业务的需求安放自己的图片数据。
3,卡片组件消费数据
    
let storageWidgetImageUpdate = new LocalStorage()
@Entry(storageWidgetImageUpdate)
@Component
struct WidgetCard {
   @LocalStorageProp('fileNameList') fileNameList: string[] = []
   build() {
      Column() {
         Row() {
            ForEach(
               this.fileNameList,
               (url: string) => {
                  Row() {
                     Image('memory://'+url)
                        .borderRadius(12)
                        .width(50)
                        .aspectRatio(1)
                  }
                  .backgroundColor('#eee')
                  .borderRadius(12)
               }
            )
         }
         .justifyContent(FlexAlign.SpaceBetween)
         .width('100%')
         .layoutWeight(1)
         .padding({
            left: 20,
            right: 20
         })
         .backgroundColor('#fff')
         .borderRadius({
            topRight: 16,
            topLeft: 16
         })
         .onClick(() => {
         })
         Row() {
            Text('Hello World')
               .fontColor('#fff')
               .fontSize(16)
         }
         .height(40)
         .width('100%')
         .justifyContent(FlexAlign.Center)
      }
      .linearGradient({
         angle: '135',
         colors: [
            ,
           
         ]
      })
      .height('100%')
   }
}
具体结果如图:
https://img-blog.csdnimg.cn/direct/2a457ff1d0d14fcca43d371dd331e7e5.png
 由于篇幅有限,后面的卡片更新和跳转指定页面我就不官方展示官方方案了,有兴趣的请自行去官方文档查看。
文档地址:卡片变乱能力说明 (openharmony.cn)

3.2 卡片动态更新内容

在点击刷新按钮之后,期望可以更新卡片的商品内容,显示最新的推荐内容。
实现原理

在卡片组件中触发message变乱,在FormExtensionAblility的onForEvent钩子中监听变乱,然后执行卡片的updateForm生命周期方法传入要更新的数据即可

[*]卡片触发一个变乱 message
[*]FormAbility中监听变乱触发,监听到之后依旧按照标准的数据格式,把新的图片在此举行下载,继续处理成标准格式,继续调用卡片更新的固定方法传入新的图片内容
实现步调

1,更新UI结构
    Row() {
   Text('Hello World')
      .fontColor('#fff')
      .fontSize(16)
   Button('OK')
      .onClick(()=>{
         postCardAction(this,
            {
               action: 'message',
               abilityName:'EntryAbility'
            }
         )
      })
}
.height(40)
.width('100%')
.justifyContent(FlexAlign.Center)
2,FormExtensionAbility中监听变乱并更新卡片
    
const newGoodsList = [
   'https://dongfangshuxing.oss-cn-beijing.aliyuncs.com/2023/03/10/18988304-a76a-46c4-a39f-26ea31e7a179.jpg',
   'https://dongfangshuxing.oss-cn-beijing.aliyuncs.com/2023/03/10/18988304-a76a-46c4-a39f-26ea31e7a179.jpg',
]
   onFormEvent(formId: string, message: string) {
      const lF = new LoadImageForFormData(
         newGoodsList,
         (formInfo: formBindingData.FormBindingData) => {
            // 根据卡片id和信息更新卡片内容
            formProvider.updateForm(formId, formInfo)
         },
         this
      )
      lF.startLoad()
   }
 
实现结果图如下:
 https://img-blog.csdnimg.cn/direct/04a3f99aa78a4709a8de427bc5817a5e.png
3.3 点击卡片唤起特定页

当我们点击卡片主体内容的时候,期望可以唤起特定的落地页
基础实现原理


[*]卡片组件点击之后通过postCardAction触发router变乱并携带参数
[*]在应用的UIAbility中接收router变乱,解析参数完成跳转
https://img-blog.csdnimg.cn/direct/1601a83660ef4d4e979f4a57eb1cf13a.png
 实现步调


1. 准备落地页(新建一个页面Page)
   @Entry
@Component
struct RouterPage {
   @State message: string = 'Hello HarmonyOS';
   build() {
      Row() {
         Column() {
            Text(this.message)
               .fontSize(50)
               .fontWeight(FontWeight.Bold)
         }
         .width('100%')
      }
      .height('100%')
   }
}
点击之后通过方法通报参数
    .onClick(() => {
    postCardAction(this, {
      action: 'router',
      abilityName: 'EntryAbility',
      params: { targetPage: 'RouterPage' }
    })
  })
3. 在UIAbility中接收router变乱并获取参数,根据通报的params不同,选择拉起不同的页面
1-未启动应用的环境
    
export default class EntryAbility extends UIAbility {
  // 存放拉起页地址
  private selectPage: string = ''
  
  // UIAbility假如没有运行,会执行onCreate
  async onCreate(want, launchParam) {
    if (want.parameters !== undefined) {
      let params: Record<string, string> = JSON.parse(JSON.stringify(want.parameters))
      this.selectPage = params.targetPage
    }
  }
  onWindowStageCreate(windowStage: window.WindowStage) {
    let targetPage: string = this.selectPage ? `pages/${this.selectPage}` : 'pages/Index'
    
    windowStage.loadContent(targetPage, (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    })
  }
}
 2- 已经启动的环境
留意:已经启动时只执行 onNewWant钩子函数
第一次启动时存下来 windowStage实例,二次启动时直接在onNewWant钩子中通过windowState实例
手动调用onWindowStageCreate方法 执行判定逻辑
    
export default class EntryAbility extends UIAbility {
  private selectPage: string = ''
  private currentWindowStage: window.WindowStage | null = null
  // UIAbility假如已经运行 会执行onNewWant
  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.info("卡片 onNewWant:" + JSON.stringify(want))
    if (want.parameters?.params !== undefined) {
      let params: Record<string, string> = JSON.parse(JSON.stringify(want.parameters))
      this.selectPage = params.targetPage
    }
    if (this.currentWindowStage !== null) {
      this.onWindowStageCreate(this.currentWindowStage)
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
    let targetPage: string = this.selectPage ? `pages/${this.selectPage}` : 'pages/Index'
    if (this.currentWindowStage === null) {
      this.currentWindowStage = windowStage
    }
    windowStage.loadContent(targetPage, (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }
}
结果如下(视频上传不了,我就只能放图片了,歉仄)
https://img-blog.csdnimg.cn/direct/2474a5c20767413091de2e8b2fa65d2e.png  ------》(点击OK)
  https://img-blog.csdnimg.cn/direct/01e095aa65e342eda8b578df850a8d3e.png ------》(点击图片)https://img-blog.csdnimg.cn/direct/d67e73467cf947c1b5395b54b3d91099.png


总结 

开发者可以使用声明式范式开发ArkTS卡片页面。如下卡片页面由DevEco Studio模板主动生成,开发者可以根据自身的业务场景举行调整。
ArkTS卡片具备JS卡片的全量能力,而且新增了动效能力和自定义绘制的能力,支持声明式范式的部门组件、变乱、动效、数据管理、状态管理能力,
在功能开发中,主要显现的是我的写法,仅供参考。假如想要按照自己的思路完成功能,请参考官方文档:Form Kit简介 (openharmony.cn)


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙——应用服务卡片显示图片和唤起指定页面