1# 拉起卡片提供方的UIAbility到后台(call事件) 2 3 4许多应用希望借助卡片的能力,实现和应用在前台时相同的功能。例如音乐卡片,卡片上提供播放、暂停等按钮,点击不同按钮将触发音乐应用的不同功能,进而提高用户的体验。在卡片中使用[postCardAction](../reference/apis-arkui/js-apis-postCardAction.md#postcardaction)接口的call能力,能够将卡片提供方应用的指定的UIAbility拉到后台。同时,call能力提供了调用应用指定方法、传递数据的功能,使应用在后台运行时可以通过卡片上的按钮执行不同的功能。 5 6> **说明:** 7> 8> 本文主要介绍动态卡片的事件开发。对于静态卡片,请参见[FormLink](../reference/apis-arkui/arkui-ts/ts-container-formlink.md)。 9 10## 开发步骤 111. 创建动态卡片 12 13 新建一个名为WidgetEventCallCardArkTs动态卡片。 14 152. 页面布局代码实现 16 17 在卡片页面中布局两个按钮,点击其中一个按钮时调用postCardAction向指定UIAbility发送call事件,并在事件内定义需要调用的方法和传递的数据。需要注意的是,method参数为必选参数,且类型需要为string类型,用于触发UIAbility中对应的方法。 18 ```ts 19 //src/main/ets/widgeteventcallcard/pages/WidgetEventCallCardCard.ets 20 @Entry 21 @Component 22 struct WidgetEventCallCard { 23 @LocalStorageProp('formId') formId: string = '12400633174999288'; 24 25 build() { 26 Column() { 27 //... 28 Row() { 29 Column() { 30 Button() { 31 //... 32 } 33 //... 34 .onClick(() => { 35 postCardAction(this, { 36 action: 'call', 37 abilityName: 'WidgetEventCallEntryAbility', // 只能跳转到当前应用下的UIAbility,与module.json5中定义保持 38 params: { 39 formId: this.formId, 40 method: 'funA' // 在EntryAbility中调用的方法名 41 } 42 }); 43 }) 44 45 Button() { 46 //... 47 } 48 //... 49 .onClick(() => { 50 postCardAction(this, { 51 action: 'call', 52 abilityName: 'WidgetEventCallEntryAbility', // 只能跳转到当前应用下的UIAbility,与module.json5中定义保持 53 params: { 54 formId: this.formId, 55 method: 'funB', // 在EntryAbility中调用的方法名 56 num: 1 // 需要传递的其他参数 57 } 58 }); 59 }) 60 } 61 }.width('100%').height('80%') 62 .justifyContent(FlexAlign.Center) 63 } 64 .width('100%') 65 .height('100%') 66 .alignItems(HorizontalAlign.Center) 67 } 68 } 69 ``` 703. 创建指定的UIAbility 71 72 在UIAbility中接收call事件并获取参数,根据传递的method不同,执行不同的方法。其余数据可以通过[readString](../reference/apis-ipc-kit/js-apis-rpc.md#readstring)方法获取。需要注意的是,UIAbility需要onCreate生命周期中监听所需的方法。 73 ```ts 74 //src/main/ets/widgeteventcallcard/WidgetEventCallEntryAbility/WidgetEventCallEntryAbility.ets 75 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 76 import { promptAction } from '@kit.ArkUI'; 77 import { BusinessError } from '@kit.BasicServicesKit'; 78 import { rpc } from '@kit.IPCKit'; 79 import { hilog } from '@kit.PerformanceAnalysisKit'; 80 81 const TAG: string = 'WidgetEventCallEntryAbility'; 82 const DOMAIN_NUMBER: number = 0xFF00; 83 const CONST_NUMBER_1: number = 1; 84 const CONST_NUMBER_2: number = 2; 85 86 class MyParcelable implements rpc.Parcelable { 87 num: number; 88 str: string; 89 90 constructor(num: number, str: string) { 91 this.num = num; 92 this.str = str; 93 } 94 95 marshalling(messageSequence: rpc.MessageSequence): boolean { 96 messageSequence.writeInt(this.num); 97 messageSequence.writeString(this.str); 98 return true; 99 } 100 101 unmarshalling(messageSequence: rpc.MessageSequence): boolean { 102 this.num = messageSequence.readInt(); 103 this.str = messageSequence.readString(); 104 return true; 105 } 106 } 107 108 export default class WidgetEventCallEntryAbility extends UIAbility { 109 // 如果UIAbility第一次启动,在收到call事件后会触发onCreate生命周期回调 110 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 111 try { 112 // 监听call事件所需的方法 113 this.callee.on('funA', (data: rpc.MessageSequence) => { 114 // 获取call事件中传递的所有参数 115 hilog.info(DOMAIN_NUMBER, TAG, `FunACall param: ${JSON.stringify(data.readString())}`); 116 promptAction.showToast({ 117 message: 'FunACall param:' + JSON.stringify(data.readString()) 118 }); 119 return new MyParcelable(CONST_NUMBER_1, 'aaa'); 120 }); 121 this.callee.on('funB', (data: rpc.MessageSequence) => { 122 // 获取call事件中传递的所有参数 123 hilog.info(DOMAIN_NUMBER, TAG, `FunBCall param: ${JSON.stringify(data.readString())}`); 124 promptAction.showToast({ 125 message: 'FunBCall param:' + JSON.stringify(data.readString()) 126 }); 127 return new MyParcelable(CONST_NUMBER_2, 'bbb'); 128 }); 129 } catch (err) { 130 hilog.error(DOMAIN_NUMBER, TAG, `Failed to register callee on. Cause: ${JSON.stringify(err as BusinessError)}`); 131 } 132 } 133 134 // 进程退出时,解除监听 135 onDestroy(): void | Promise<void> { 136 try { 137 this.callee.off('funA'); 138 this.callee.off('funB'); 139 } catch (err) { 140 hilog.error(DOMAIN_NUMBER, TAG, `Failed to register callee off. Cause: ${JSON.stringify(err as BusinessError)}`); 141 } 142 } 143 } 144 ``` 1454. 配置后台运行权限 146 147 call事件含有约束限制:提供方应用需要在module.json5顶层对象module下添加后台运行权限([ohos.permission.KEEP_BACKGROUND_RUNNING](../security/AccessToken/permissions-for-all.md#ohospermissionkeep_background_running))。 148 ```ts 149 //src/main/module.json5 150 "requestPermissions":[ 151 { 152 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" 153 } 154 ] 155 ``` 1565. 配置指定的UIAbility 157 158 在module.json5顶层对象module的abilities数组内添加WidgetEventCallEntryAbility对应的配置信息。 159 ```ts 160 //src/main/module.json5 161 "abilities": [ 162 { 163 "name": 'WidgetEventCallEntryAbility', 164 "srcEntry": './ets/widgeteventcallcard/WidgetEventCallEntryAbility/WidgetEventCallEntryAbility.ets', 165 "description": '$string:WidgetEventCallCard_desc', 166 "icon": "$media:app_icon", 167 "label": "$string:WidgetEventCallCard_label", 168 "startWindowIcon": "$media:app_icon", 169 "startWindowBackground": "$color:start_window_background" 170 } 171 ] 172 ```