• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Call调用开发指导
2## 场景介绍
3Ability Call调用是Ability能力的扩展,它为Ability提供一种能够被外部调用的能力,使Ability既能被拉起到前台展示UI,也支持Ability在后台被创建并运行。应用开发者可通过Call调用,使用IPC通信实现不同Ability之间的数据共享。Call调用的场景主要包括:
4- 创建Callee被调用端。
5- 访问Callee被调用端。
6
7本文中的Caller和Callee分别表示调用者和被调用者,IPC表示进程间通信,Call调用流程示意图如下。
8
9![stage-call](figures/stage-call.png)
10
11> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
12> Callee被调用端所在的Ability,启动模式需要为单实例。
13> 当前仅支持系统应用及ServiceExtensionAbility使用Call访问Callee。
14
15## 接口说明
16Caller及Callee功能如下:具体的API详见[接口文档](../reference/apis/js-apis-application-ability.md#caller)。
17
18**表1** Call API接口功能介绍
19|接口名|描述|
20|:------|:------|
21|startAbilityByCall(want: Want): Promise\<Caller>|获取指定通用组件的Caller通信接口,拉起指定通用组件并将其切换到后台。|
22|on(method: string, callback: CaleeCallBack): void|通用组件Callee注册method对应的callback方法。|
23|off(method: string): void|通用组件Callee去注册method的callback方法。|
24|call(method: string, data: rpc.Sequenceable): Promise\<void>|向通用组件Callee发送约定序列化数据。|
25|callWithResult(method: string, data: rpc.Sequenceable): Promise\<rpc.MessageParcel>|向通用组件Callee发送约定序列化数据, 并将返回的约定序列化数据带回。|
26|release(): void|释放通用组件的Caller通信接口。|
27|onRelease(callback: OnReleaseCallBack): void|注册通用组件通信断开监听通知。|
28
29## 开发步骤
30> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
31> 开发步骤章节中的示例代码片段是开发过程的步骤化展示,部分代码可能无法单独运行,完整工程代码请参考[相关实例](#相关实例)。
32### 创建Callee被调用端
33Callee被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。
341. 配置Ability的启动模式
35
36  配置module.json5,将Callee被调用端所在的Ability配置为单实例"singleton"。
37
38|Json字段|字段说明|
39|:------|:------|
40|"launchType"|Ability的启动模式,设置为"singleton"类型。 |
41
42Ability配置标签示例如下:
43```json
44"abilities":[{
45    "name": ".CalleeAbility",
46    "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
47    "launchType": "singleton",
48    "description": "$string:CalleeAbility_desc",
49    "icon": "$media:icon",
50    "label": "$string:CalleeAbility_label",
51    "visible": true
52}]
53```
542. 导入Ability模块。
55```
56import Ability from '@ohos.application.Ability'
57```
583. 定义约定的序列化数据。
59
60  调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。具体示例代码如下:
61```ts
62export default class MySequenceable {
63    num: number = 0
64    str: String = ""
65
66    constructor(num, string) {
67        this.num = num
68        this.str = string
69    }
70
71    marshalling(messageParcel) {
72        messageParcel.writeInt(this.num)
73        messageParcel.writeString(this.str)
74        return true
75    }
76
77    unmarshalling(messageParcel) {
78        this.num = messageParcel.readInt()
79        this.str = messageParcel.readString()
80        return true
81    }
82}
83```
844. 实现Callee.on监听及Callee.off解除监听。
85
86  被调用端Callee的监听函数注册时机, 取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在Ability的onCreate注册'MSG_SEND_METHOD'监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下:
87```ts
88const TAG: string = '[CalleeAbility]'
89const MSG_SEND_METHOD: string = 'CallSendMsg'
90
91function sendMsgCallback(data) {
92    Logger.log(TAG, 'CalleeSortFunc called')
93
94    // 获取Caller发送的序列化数据
95    let receivedData = new MySequenceable(0, '')
96    data.readSequenceable(receivedData)
97    Logger.log(TAG, `receiveData[${receivedData.num}, ${receivedData.str}]`)
98
99    // 作相应处理
100    // 返回序列化数据result给Caller
101    return new MySequenceable(receivedData.num + 1, `send ${receivedData.str} succeed`)
102}
103
104export default class CalleeAbility extends Ability {
105    onCreate(want, launchParam) {
106        try {
107            this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
108        } catch (error) {
109            Logger.error(TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
110        }
111    }
112
113    onDestroy() {
114        try {
115            this.callee.off(MSG_SEND_METHOD)
116        } catch (error) {
117            console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`)
118        }
119    }
120}
121```
122
123### 访问Callee被调用端
1241. 导入Ability模块。
125```
126import Ability from '@ohos.application.Ability'
127```
1282. 获取Caller通信接口。
129
130  Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过`this.context`获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease监听。应用开发者根据实际需要做相应处理。具体示例代码如下:
131```ts
132async onButtonGetCaller() {
133    try {
134        this.caller = await context.startAbilityByCall({
135            bundleName: 'com.samples.CallApplication',
136            abilityName: 'CalleeAbility'
137        })
138        if (this.caller === undefined) {
139            Logger.error(TAG, 'get caller failed')
140            return
141        }
142        Logger.log(TAG, 'get caller success')
143        this.regOnRelease(this.caller)
144    } catch (error) {
145        Logger.error(TAG, `get caller failed with ${error}`)
146    }
147}.catch((error) => {
148    console.error(TAG + 'get caller failed with ' + error)
149})
150```
151  在跨设备场景下,需指定对端设备deviceId。具体示例代码如下:
152```ts
153let TAG = '[MainAbility] '
154var caller = undefined
155let context = this.context
156
157context.startAbilityByCall({
158    deviceId: getRemoteDeviceId(),
159    bundleName: 'com.samples.CallApplication',
160    abilityName: 'CalleeAbility'
161}).then((data) => {
162    if (data != null) {
163        caller = data
164        console.log(TAG + 'get remote caller success')
165        // 注册caller的release监听
166        caller.onRelease((msg) => {
167            console.log(TAG + 'remote caller onRelease is called ' + msg)
168        })
169        console.log(TAG + 'remote caller register OnRelease succeed')
170    }
171}).catch((error) => {
172    console.error(TAG + 'get remote caller failed with ' + error)
173})
174```
175  从DeviceManager获取指定设备的deviceId,getTrustedDeviceListSync接口仅对系统应用开放。具体示例代码如下:
176```ts
177import deviceManager from '@ohos.distributedHardware.deviceManager';
178var dmClass;
179function getRemoteDeviceId() {
180    if (typeof dmClass === 'object' && dmClass != null) {
181        var list = dmClass.getTrustedDeviceListSync();
182        if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') {
183            console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null");
184            return;
185        }
186        console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId);
187        return list[0].deviceId;
188    } else {
189        console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
190    }
191}
192```
193  在跨设备场景下,需要向用户申请数据同步的权限。具体示例代码如下:
194```ts
195let context = this.context
196let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']
197context.requestPermissionsFromUser(permissions).then((data) => {
198    console.log("Succeed to request permission from user with data: "+ JSON.stringify(data))
199}).catch((error) => {
200    console.log("Failed to request permission from user with error: "+ JSON.stringify(error))
201})
202```
2033. 发送约定序列化数据
204
205  向被调用端发送Sequenceable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。具体示例代码如下:
206```ts
207const MSG_SEND_METHOD: string = 'CallSendMsg'
208async onButtonCall() {
209    try {
210        let msg = new MySequenceable(1, 'origin_Msg')
211        await this.caller.call(MSG_SEND_METHOD, msg)
212    } catch (error) {
213        Logger.error(TAG, `caller call failed with ${error}`)
214    }
215}
216```
217
218  如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据`originMsg`,并将'CallSendMsg'方法处理完毕的数据赋值给`backMsg`。具体示例代码如下:
219```ts
220const MSG_SEND_METHOD: string = 'CallSendMsg'
221originMsg: string = ''
222backMsg: string = ''
223async onButtonCallWithResult(originMsg, backMsg) {
224    try {
225        let msg = new MySequenceable(1, originMsg)
226        const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg)
227        Logger.log(TAG, 'caller callWithResult succeed')
228
229        let result = new MySequenceable(0, '')
230        data.readSequenceable(result)
231        backMsg(result.str)
232        Logger.log(TAG, `caller result is [${result.num}, ${result.str}]`)
233    } catch (error) {
234        Logger.error(TAG, `caller callWithResult failed with ${error}`)
235    }
236}
237```
2384. 释放Caller通信接口
239
240  Caller不再使用后,应用开发者可以通过release接口释放Caller。具体示例代码如下:
241```ts
242try {
243    this.caller.release()
244    this.caller = undefined
245    Logger.log(TAG, 'caller release succeed')
246} catch (error) {
247    Logger.error(TAG, `caller release failed with ${error}`)
248}
249```
250
251