1# ContinuationManager开发指导 2 3> 说明:本模块接口用于拉起系统中的设备选择模块,由于该模块功能暂不完备,因此**流转能力整体暂不支持用于应用开发**。 4 5## 场景简介 6随着全场景多设备生活方式的不断深入,用户拥有的设备越来越多,每个设备都能在适合的场景下提供良好的体验,但是,每个设备也有使用场景的局限。流转能力致力于打破设备界限,多设备联动,使用户应用程序可分可合、可流转,实现体验升级。 7 8continuationManager作为流转能力的入口,主要用于拉起系统中的设备选择模块供用户选择,待选择设备后,会给用户返回已选择的远端设备信息,用户可以根据远端设备信息发起跨端迁移或多端协同操作。 9 10![continuationManager](figures/continuationManager.png) 11 12## 接口说明 13| 接口名 | 接口描述 | 14| ---------------------------------------------------------------------------------------------- | ----------- | 15| registerContinuation(callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token,无过滤条件(AsyncCallback)。 | 16| registerContinuation(options: ContinuationExtraParams, callback: AsyncCallback\<number>): void | 注册流转管理服务,并获取对应的注册token(AsyncCallback)。 | 17| registerContinuation(options?: ContinuationExtraParams): Promise\<number> | 连接流转管理服务,并获取对应的注册token(Promise)。 | 18| on(type: "deviceSelected", token: number, callback: Callback\<Array\<ContinuationResult>>): void | 监听设备连接状态(Callback)。 | 19| on(type: "deviceUnselected", token: number, callback: Callback\<Array\<ContinuationResult>>): void | 监听设备断开状态(Callback)。 | 20| off(type: "deviceSelected", token: number): void | 取消监听设备连接状态。 | 21| off(type: "deviceUnselected", token: number): void | 取消监听设备断开状态。 | 22| startContinuationDeviceManager(token: number, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息,无过滤条件(AsyncCallback)。 | 23| startContinuationDeviceManager(token: number, options: ContinuationExtraParams, callback: AsyncCallback\<void>): void | 拉起设备选择模块,可显示组网内可选择设备列表信息(AsyncCallback)。 | 24| startContinuationDeviceManager(token: number, options?: ContinuationExtraParams): Promise\<void> | 拉起设备选择模块,可显示组网内可选择设备列表信息(Promise)。 | 25| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState, callback: AsyncCallback\<void>): void | 通知设备选择模块,更新当前的流转状态(AsyncCallback)。 | 26| updateContinuationState(token: number, deviceId: string, status: DeviceConnectState): Promise\<void> | 通知设备选择模块,更新当前的流转状态(Promise)。 | 27| unregisterContinuation(token: number, callback: AsyncCallback\<void>): void | 取消注册流转管理服务,传入注册时获取的token进行取消注册(AsyncCallback)。 | 28| unregisterContinuation(token: number): Promise\<void> | 取消注册流转管理服务,传入注册时获取的token进行取消注册(Promise)。 | 29 30## 开发步骤 311. 导入continuationManager模块。 32 33 ```ts 34 import continuationManager from '@ohos.continuation.continuationManager'; 35 ``` 36 372. 申请分布式权限 DISTRIBUTED_DATASYNC。 38 39 权限申请在FA平台和Stage平台有区别,FA平台需要在`config.json`里面进行配置请求权限,示例代码如下: 40 41 ```json 42 { 43 "module": { 44 "reqPermissions": [ 45 { 46 "name": "ohos.permission.DISTRIBUTED_DATASYNC" 47 } 48 ] 49 } 50 } 51 ``` 52 53 这个权限还需要在应用首次启动的时候弹窗获取用户授权,可以通过如下代码实现: 54 55 ```ts 56 import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; 57 import bundle from '@ohos.bundle'; 58 import featureAbility from '@ohos.ability.featureAbility'; 59 60 async function requestPermission() { 61 let permissions: Array<string> = [ 62 "ohos.permission.DISTRIBUTED_DATASYNC" 63 ]; 64 let needGrantPermission: boolean = false; 65 let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); 66 let applicationInfo = await bundle.getApplicationInfo('ohos.samples.etsDemo', 0, 100); 67 for (let i = 0; i < permissions.length; i++) { 68 let result = await atManager.verifyAccessToken(applicationInfo.accessTokenId, permissions[i]); 69 //判断是否未申请该权限 70 if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 71 needGrantPermission = true; 72 break; 73 } 74 } 75 // 如果未申请该权限,则需要调用requestPermissionsFromUser接口申请权限 76 if (needGrantPermission) { 77 await featureAbility.getContext().requestPermissionsFromUser(permissions, 1); 78 } else { 79 console.info('app permission already granted'); 80 } 81 } 82 ``` 83 84 Stage平台需要在`module.json5`里面进行配置请求权限,示例代码如下: 85 86 ```json 87 { 88 "module": { 89 "requestPermissions": [ 90 { 91 "name": "ohos.permission.DISTRIBUTED_DATASYNC" 92 } 93 ] 94 } 95 } 96 ``` 97 98 ```ts 99 import abilityAccessCtrl from "@ohos.abilityAccessCtrl"; 100 import bundle from '@ohos.bundle'; 101 102 async function requestPermission() { 103 let permissions: Array<string> = [ 104 "ohos.permission.DISTRIBUTED_DATASYNC" 105 ]; 106 let needGrantPermission: boolean = false; 107 let atManger: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); 108 let applicationInfo = await bundle.getApplicationInfo('ohos.samples.continuationmanager', 0, 100); 109 for (const permission of permissions) { 110 try { 111 let grantStatus = await atManger.verifyAccessToken(applicationInfo.accessTokenId, permission); 112 //判断是否未申请该权限 113 if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { 114 needGrantPermission = true; 115 break; 116 } 117 } catch (err) { 118 console.error('app permission query grant status error' + JSON.stringify(err)); 119 needGrantPermission = true; 120 break; 121 } 122 } 123 // 如果未申请该权限,则需要调用requestPermissionsFromUser接口申请权限 124 if (needGrantPermission) { 125 try { 126 // globalThis.context即Ability.context,需提前在MainAbility.ts文件中赋值 127 await atManger.requestPermissionsFromUser(globalThis.context, permissions); 128 } catch (err) { 129 console.error('app permission request permissions error' + JSON.stringify(err)); 130 } 131 } else { 132 console.info('app permission already granted'); 133 } 134 } 135 ``` 136 1373. 注册流转管理服务,获取对应的注册token。 138 139 注册流转管理服务的代码示例如下: 140 141 ```ts 142 let token: number = -1; // 用于保存注册成功并返回的token,后续使用其完成监听设备连接/断开状态、拉起设备选择模块以及更新流转状态的动作 143 try { 144 continuationManager.registerContinuation().then((data) => { 145 console.info('registerContinuation finished, ' + JSON.stringify(data)); 146 token = data; // 获取到对应的注册token,并赋值给token变量 147 }).catch((err) => { 148 console.error('registerContinuation failed, cause: ' + JSON.stringify(err)); 149 }); 150 } catch (err) { 151 console.error('registerContinuation failed, cause: ' + JSON.stringify(err)); 152 } 153 ``` 154 1554. 监听设备状态。 156 157 监听设备连接状态的代码示例如下: 158 159 ```ts 160 let remoteDeviceId: string = ""; // 用于保存用户选择的远端设备信息,后续使用其完成跨端迁移或多端协同操作 161 162 try { 163 // 参数token为注册token 164 continuationManager.on("deviceSelected", token, (continuationResults) => { 165 console.info('registerDeviceSelectedCallback len: ' + continuationResults.length); 166 if (continuationResults.length <= 0) { 167 console.info('no selected device'); 168 return; 169 } 170 remoteDeviceId = continuationResults[0].id; // 将选择的第一个远端设备deviceId赋值给remoteDeviceId变量 171 172 // 将remoteDeviceId参数传给want 173 let want = { 174 deviceId: remoteDeviceId, 175 bundleName: 'ohos.samples.continuationmanager', 176 abilityName: 'MainAbility' 177 }; 178 globalThis.abilityContext.startAbility(want).then((data) => { 179 console.info('StartRemoteAbility finished, ' + JSON.stringify(data)); 180 }).catch((err) => { 181 console.error('StartRemoteAbility failed, cause: ' + JSON.stringify(err)); 182 }); 183 }); 184 } catch (err) { 185 console.error('on failed, cause: ' + JSON.stringify(err)); 186 } 187 ``` 188 189 上述多端协同操作为Stage平台的跨设备拉起,FA平台详情见[PageAbility开发指导](fa-pageability.md)。 190 191 同时用户还可通知设备选择模块,更新当前的流转状态,代码示例如下: 192 193 ```ts 194 // 设置设备流转状态 195 let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.CONNECTED; 196 197 // 参数token为注册token,参数remoteDeviceId为获取到的remoteDeviceId 198 try { 199 continuationManager.updateContinuationState(token, remoteDeviceId, deviceConnectStatus).then((data) => { 200 console.info('updateContinuationState finished, ' + JSON.stringify(data)); 201 }).catch((err) => { 202 console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); 203 }); 204 } catch (err) { 205 console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); 206 } 207 ``` 208 209 监听设备断开状态,方便用户终止跨端迁移或多端协同操作,代码示例如下: 210 211 ```ts 212 try { 213 // 参数token为注册token 214 continuationManager.on("deviceUnselected", token, (continuationResults) => { 215 console.info('onDeviceUnselected len: ' + continuationResults.length); 216 if (continuationResults.length <= 0) { 217 console.info('no unselected device'); 218 return; 219 } 220 221 // 更新设备流转状态 222 let unselectedDeviceId: string = continuationResults[0].id; // 将取消选择的第一个远端设备deviceId赋值给unselectedDeviceId变量 223 let deviceConnectStatus: continuationManager.DeviceConnectState = continuationManager.DeviceConnectState.DISCONNECTING; // 设备断开状态 224 225 // 参数token为注册token,参数unselectedDeviceId为获取到的unselectedDeviceId 226 continuationManager.updateContinuationState(token, unselectedDeviceId, deviceConnectStatus).then((data) => { 227 console.info('updateContinuationState finished, ' + JSON.stringify(data)); 228 }).catch((err) => { 229 console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); 230 }); 231 }); 232 } catch (err) { 233 console.error('updateContinuationState failed, cause: ' + JSON.stringify(err)); 234 } 235 ``` 236 2375. 拉起设备选择模块,可显示组网内可选择设备列表信息,供用户选择。 238 239 拉起设备选择模块的代码示例如下: 240 241 ```ts 242 // 过滤参数 243 let continuationExtraParams = { 244 deviceType: ["00E"], // 设备类型 245 continuationMode: continuationManager.ContinuationMode.COLLABORATION_SINGLE // 设备选择模块单选模式 246 }; 247 248 try { 249 // 参数token为注册token 250 continuationManager.startContinuationDeviceManager(token, continuationExtraParams).then((data) => { 251 console.info('startContinuationDeviceManager finished, ' + JSON.stringify(data)); 252 }).catch((err) => { 253 console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err)); 254 }); 255 } catch (err) { 256 console.error('startContinuationDeviceManager failed, cause: ' + JSON.stringify(err)); 257 } 258 ``` 259 2606. 当用户不打算再进行跨端迁移或多端协同操作时,可以传入注册时获取的token进行取消注册。 261 262 取消注册流转管理服务的代码示例如下: 263 264 ```ts 265 try { 266 // 参数token为注册token 267 continuationManager.unregisterContinuation(token).then((data) => { 268 console.info('unregisterContinuation finished, ' + JSON.stringify(data)); 269 }).catch((err) => { 270 console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err)); 271 }); 272 } catch (err) { 273 console.error('unregisterContinuation failed, cause: ' + JSON.stringify(err)); 274 } 275 ```