精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

鴻蒙HarmonyOS開發實戰:【分布式音樂播放】

jf_46214456 ? 來源:jf_46214456 ? 作者:jf_46214456 ? 2024-04-10 17:51 ? 次閱讀

分布式音樂播放

介紹

本示例使用fileIo獲取指定音頻文件,并通過AudioPlayer完成了音樂的播放完成了基本的音樂播放、暫停、上一曲、下一曲功能;并使用DeviceManager完成了分布式設備列表的顯示和分布式能力完成了音樂播放狀態的跨設備分享。

本示例用到了與用戶進行交互的Ability的能力接口[@ohos.ability.featureAbility]

文件存儲管理能力接口[@ohos.fileio]

屏幕屬性接口[@ohos.display]

媒體查詢接口[@ohos.mediaquery]

分布式數據管理接口[@ohos.data.distributedData]

音視頻相關媒體業務能力接口[@ohos.multimedia.media]

分布式設備管理能力接口(設備管理),實現設備之間的kvStore對象的數據傳輸交互[@ohos.distributedDeviceManager]

效果預覽

image.png

使用說明

  1. 音樂播放 ,點擊 播放暫停 、上 一曲 、下一曲按鈕可以對音樂進行操作。
  2. 跨設備分享 ,組網并且雙端均已授權條件下,點擊分享按鈕,選擇設備,拉起對端設備上的音樂,并將本端的播放狀態同步到對端上。
  3. 跨設備停止分享 ,分享成功前提條件下,點擊停止分享按鈕,將對端設備拉起的音樂應用停止退出。

相關概念

音頻播放:媒體子系統包含了音視頻相關媒體業務,通過AudioPlayer實現音頻播放的能力。

數據分享:分布式數據管理為應用程序提供不同設備間數據庫的分布式協同能力。通過調用分布式數據各個接口,應用程序可將數據保存到分布式數據庫中,并可對分布式數據庫中的數據進行增/刪/改/查等各項操作。

資料文檔參考

搜狗高速瀏覽器截圖20240326151450.png

具體實現

在分布式音樂播放器中,分布式設備管理包含了分布式設備搜索、分布式設備列表彈窗、遠端設備拉起三部分。
首先在分布式組網內搜索設備,然后把設備展示到分布式設備列表彈窗中,最后根據用戶的選擇拉起遠端設備。

分布式設備搜索

通過SUBSCRIBE_ID搜索分布式組網內的遠端設備,詳見registerDeviceListCallback(callback) {}模塊[源碼參考]。

/*

* Copyright (c) 2022 Huawei Device Co., Ltd.

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*     http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/



import deviceManager from '@ohos.distributedDeviceManager';

import Logger from '../model/Logger';



let SUBSCRIBE_ID: number = 100;

const RANDOM: number = 65536;

const TAG: string = 'RemoteDeviceModel';



export class RemoteDeviceModel {

  public deviceLists: Array< deviceManager.DeviceBasicInfo > = [];

  public discoverLists: Array< deviceManager.DeviceBasicInfo > = [];

  private callback: () = > void = null;

  private authCallback: () = > void = null;

  private deviceManager: deviceManager.DeviceManager = undefined;



  registerDeviceListCallback(callback) {

    if (typeof (this.deviceManager) === 'undefined') {

      Logger.info(TAG, 'deviceManager.createDeviceManager begin');

      try {

        this.deviceManager = deviceManager.createDeviceManager('ohos.samples.distributedmusicplayer');

        this.registerDeviceList(callback);

        Logger.info(TAG, `createDeviceManager callback returned, value= ${JSON.stringify(this.deviceManager)}`);

      } catch (error) {

        Logger.info(TAG, `createDeviceManager throw error, error=${error} message=${error.message}`);

      }

      Logger.info(TAG, 'deviceManager.createDeviceManager end');

    } else {

      this.registerDeviceList(callback);

    };

  };



  registerDeviceList(callback) {

    Logger.info(TAG, 'registerDeviceListCallback');

    this.callback = callback;

    if (this.deviceManager === undefined) {

      Logger.error(TAG, 'deviceManager has not initialized');

      this.callback();

      return;

    };



    Logger.info(TAG, 'getTrustedDeviceListSync begin');

    let list: deviceManager.DeviceBasicInfo[] = [];

    try {

      list = this.deviceManager.getAvailableDeviceListSync();

    } catch (error) {

      Logger.info(TAG, `getTrustedDeviceListSync throw error, error=${error} message=${error.message}`);

    };

    Logger.info(TAG, `getTrustedDeviceListSync end, deviceLists= ${JSON.stringify(list)}`);

    if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {

      this.deviceLists = list;

    };

    this.callback();

    Logger.info(TAG, 'callback finished');



    try {

      this.deviceManager.on('deviceStateChange', (data) = > {

        Logger.info(TAG, `deviceStateChange data= ${JSON.stringify(data)}`);

        switch (data.action) {

          case deviceManager.DeviceStateChange.AVAILABLE:

            this.discoverLists = [];

            this.deviceLists.push(data.device);

            Logger.info(TAG, `reday, updated device list= ${JSON.stringify(this.deviceLists)} `);

            let list: deviceManager.DeviceBasicInfo[] = [];

            try {

              list = this.deviceManager.getAvailableDeviceListSync();

            } catch (err) {

              Logger.info(TAG, `this err is ${JSON.stringify(err)}`);

            }

            Logger.info(TAG, `getTrustedDeviceListSync end, deviceList= ${JSON.stringify(list)}`);

            if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {

              this.deviceLists = list;

            }

            this.callback();

            break;

          case deviceManager.DeviceStateChange.UNAVAILABLE:

            if (this.deviceLists.length > 0) {

              let list = [];

              for (let i = 0; i < this.deviceLists.length; i++) {

                if (this.deviceLists[i].deviceId !== data.device.deviceId) {

                  list[i] = data.device;

                };

              };

              this.deviceLists = list;

            };

            Logger.info(TAG, `offline, updated device list= ${JSON.stringify(this.deviceLists)}`);

            this.callback();

            break;

          default:

            break;

        };

      });

      this.deviceManager.on('discoverSuccess', (data) = > {

        Logger.info(TAG, `discoverSuccess data= ${JSON.stringify(data)}`);

        Logger.info(TAG, `discoverSuccess this.deviceLists= ${this.deviceLists}, this.deviceLists.length= ${this.deviceLists.length}`);

        for (let i = 0;i < this.discoverLists.length; i++) {

          if (this.discoverLists[i].deviceId === data.device.deviceId) {

            Logger.info(TAG, 'device founded, ignored');

            return;

          };

        };

        this.discoverLists[this.discoverLists.length] = data.device;

        this.callback();

      });

      this.deviceManager.on('discoverFailure', (data) = > {

        Logger.info(TAG, `discoverFailure data= ${JSON.stringify(data)}`);

      });

      this.deviceManager.on('serviceDie', () = > {

        Logger.error(TAG, 'serviceDie');

      });

    } catch (error) {

      Logger.info(TAG, `on throw error, error=${error} message=${error.message}`);

    }



    let discoverParam = {

      'discoverTargetType': 1

    };

    let filterOptions = {

      'availableStatus': 0

    };

    Logger.info(TAG, `startDiscovering ${SUBSCRIBE_ID}`);

    try {

      if (this.deviceManager !== null) {

        this.deviceManager.startDiscovering(discoverParam, filterOptions);

      };

    } catch (error) {

      Logger.error(TAG, `startDiscovering throw error, error=${error} message=${error.message}`);

    };

  };



  authDevice(device, callback) {

    Logger.info(TAG, `authDevice ${device}`);

    if (device !== undefined) {

      for (let i = 0; i < this.discoverLists.length; i++) {

        if (this.discoverLists[i].deviceId === device.deviceId) {

          Logger.info(TAG, 'device founded, ignored');

          let bindParam = {

            bindType: 1,

            targetPkgName: 'ohos.samples.distributedmusicplayer',

            appName: 'Music',

          };

          Logger.info(TAG, `authenticateDevice ${JSON.stringify(this.discoverLists[i])}`);

          try {

            this.deviceManager.bindTarget(device.deviceId, bindParam, (err, data) = > {

              if (err) {

                Logger.error(TAG, `authenticateDevice error: ${JSON.stringify(err)}`);

                this.authCallback = () = > {

                };

                return;

              };

              Logger.info(TAG, `authenticateDevice succeed, data= ${JSON.stringify(data)}`);

              this.authCallback = callback;

            });

          } catch (error) {

            Logger.error(TAG, `authenticateDevice throw error, error=${JSON.stringify(error)} message=${error.message}`);

          }

        }

      }

    }

  };



  unregisterDeviceListCallback() {

    Logger.info(TAG, `stopDiscovering ${SUBSCRIBE_ID}`);

    if (this.deviceManager === undefined) {

      return;

    };

    try {

      this.deviceManager.stopDiscovering();

      this.deviceManager.off('deviceStateChange');

      this.deviceManager.off('discoverSuccess');

      this.deviceManager.off('discoverFailure');

      this.deviceManager.off('serviceDie');

    } catch (error) {

      Logger.info(TAG, `stopDeviceDiscovery throw error, error=${error} message=${error.message}`);

    }

    this.deviceLists = [];

  };

}

分布式設備列表彈窗

使用@CustomDialog彈出分布式設備列表彈窗,參考首頁。[源碼參考]。

/*

 * Copyright (c) 2022 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import deviceManager from '@ohos.distributedDeviceManager';

import Logger from '../model/Logger';



const TAG: string = 'DeviceDialog';



@CustomDialog

export struct DeviceDialog {

  controller?: CustomDialogController;

  private deviceLists: Array< deviceManager.DeviceBasicInfo > = [];

  private selectedIndex: number = 0;

  private selectedIndexChange: (selectedIndex: number) = > void = () = > {

  };



  build() {

    Column() {

      Text($r('app.string.choiceDevice'))

        .fontSize('32px')

        .width('434px')

        .fontColor(Color.Black)

        .textAlign(TextAlign.Start)

        .fontWeight(600)

      List() {

        ForEach(this.deviceLists, (item: deviceManager.DeviceBasicInfo, index: number | undefined) = > {

          ListItem() {

            Flex({

              direction: FlexDirection.Row,

              justifyContent: FlexAlign.SpaceBetween,

              alignItems: ItemAlign.Center

            }) {

              Text(item.deviceName)

                .fontSize(16)

                .width('86%')

                .fontColor(Color.Black)

                .textAlign(TextAlign.Start)

              Radio({ value: '', group: 'radioGroup' })

                .radioStyle({

                  checkedBackgroundColor: '#ff0d64fb'

                })

                .width('7%')

                .checked(index === this.selectedIndex ? true : false)

            }

            .height(55)

            .onClick(() = > {

              Logger.info(TAG, `select device: ${item.deviceId}`)

              if (index === this.selectedIndex) {

                Logger.info(TAG, 'index === this.selectedIndex')

                return

              }

              this.selectedIndex = index !== undefined ? index : 0

              if (this.controller !== undefined) {

                this.controller.close()

              }

              this.selectedIndexChange(this.selectedIndex)

            })

          }

          .width('434px')

          .height('80px')

        })

      }

      .margin({ top: 12 })

      .width('434px')

      .height('18%')



      Button() {

        Text($r('app.string.cancel'))

          .width('90%')

          .fontSize(21)

          .fontColor('#ff0d64fb')

          .textAlign(TextAlign.Center)

      }

      .margin({ bottom: 16 })

      .type(ButtonType.Capsule)

      .backgroundColor(Color.White)

      .onClick(() = > {

        if (this.controller !== undefined) {

          this.controller.close()

        }

      })

    }

    .margin({ bottom: 36 })

    .width('500px')

    .padding(10)

    .backgroundColor(Color.White)

    .border({ color: Color.White, radius: 20 })

  }

}

遠端設備拉起

通過startAbility(deviceId)方法拉起遠端設備的包,[源碼參考]。

/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';

import display from '@ohos.display';

import common from '@ohos.app.ability.common';

import mediaQuery from '@ohos.mediaquery';

import rpc from '@ohos.rpc';

import Want from '@ohos.app.ability.Want';

import PermissionRequestResult from 'security/PermissionRequestResult';

import KvStoreModel from '../model/KvStoreModel';

import Logger from '../model/Logger';

import PlayerModel from '../model/PlayerModel';

import deviceManager from '@ohos.distributedDeviceManager';

import ability from '@ohos.ability.ability';

import { RemoteDeviceModel } from '../model/RemoteDeviceModel';

import { DeviceDialog } from '../common/DeviceDialog';

import {

  APPLICATION_BUNDLE_NAME,

  APPLICATION_SERVICE_NAME,

  MusicSharedEventCode,

  MusicSharedStatus,

  MusicConnectEvent

} from '../common/MusicSharedDefinition';



const TAG: string = 'Index';

const DESIGN_WIDTH: number = 720.0;

const SYSTEM_UI_HEIGHT: number = 134;

const DESIGN_RATIO: number = 16 / 9;

const ONE_HUNDRED: number = 100;

const ONE_THOUSAND: number = 1000;

const SIXTY: number = 60;

const REMOTE_ABILITY_STARTED: string = 'remoteAbilityStarted';

const ABILITY_SHARED_BUTTON = 0;

const DEFAULT_NUM = -1;

const PREVIOUS_CLICK = 2;



interface Params {

  uri: string,

  seekTo: number,

  isPlaying: boolean

};



@Entry

@Component

 struct Index {

  private listener = mediaQuery.matchMediaSync('screen and (min-aspect-ratio: 1.5) or (orientation: landscape)');

  @State isLand: boolean = false;

  @State currentTimeText: string = '';

  @State currentProgress: number = 0;

  @State totalMs: number = 0;

  @State riscale: number = 1;

  @State risw: number = 720;

  @State rish: number = 1280;

  @State isSwitching: boolean = false;

  @State deviceLists: Array< deviceManager.DeviceBasicInfo > = [];

  @State isDialogShowing: boolean = false;

  @State isDistributed: boolean = false;

  @State title: string = '';

  @State totalTimeText: string = '00:00';

  @State albumSrc: Resource = $r('app.media.album');

  @State selectedIndex: number = 0;

  @State imageArrays: Array< Resource > = [$r('app.media.ic_hop'), $r('app.media.ic_play_previous'), $r('app.media.ic_play'), $r('app.media.ic_play_next')];

  private dialogController: CustomDialogController | null = null;

  @StorageLink('exitMusicApp') @Watch('exitMusicApp') isExitMusicApp: boolean = false;

  @StorageLink('remoteServiceExtensionConnectEvent') @Watch('remoteServiceExtensionConnectEvent') isRemoteServiceExtensionConnectEvent: boolean = false;

  @StorageLink('musicPlay') @Watch('musicPlay') isMusicPlay: boolean = false;

  @StorageLink('musicPause') @Watch('musicPause') isMusicPause: boolean = false;

  private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel();

  private context: common.UIAbilityContext | null = null;

  private deviceId: string | null = null;

  private clickFlag = MusicSharedStatus.MUSIC_SHARED;

  private localExtensionRemote: rpc.IRemoteObject | null = null;

  onLand = (mediaQueryResult: mediaQuery.MediaQueryResult) = > {

    Logger.info(TAG, `onLand: mediaQueryResult.matches= ${mediaQueryResult.matches}`);

    if (mediaQueryResult.matches) {

      this.isLand = true;

    } else {

      this.isLand = false;

    };

  };



  showDialog() {

    this.remoteDeviceModel.registerDeviceListCallback(() = > {

      Logger.info(TAG, 'registerDeviceListCallback, callback entered');

      this.deviceLists = [];

      this.deviceLists.push({

        deviceId: '0',

        deviceName: 'local device',

        deviceType: '0',

        networkId: ''

      });

      let deviceTempList = this.remoteDeviceModel.discoverLists.length > 0 ? this.remoteDeviceModel.discoverLists : this.remoteDeviceModel.deviceLists;

      for (let i = 0; i < deviceTempList.length; i++) {

        Logger.info(TAG, `device ${i}/${deviceTempList.length} deviceId= ${deviceTempList[i].deviceId},

         deviceName= ${deviceTempList[i].deviceName}, deviceType= ${deviceTempList[i].deviceType}`);

        this.deviceLists.push(deviceTempList[i]);

        Logger.info(TAG, 'deviceLists push end');

      };

      Logger.info(TAG, 'CustomDialogController start');

      if (this.dialogController !== null) {

        this.dialogController.close();

        this.dialogController = null;

      }

      this.dialogController = new CustomDialogController({

        builder: DeviceDialog({

          deviceLists: this.deviceLists,

          selectedIndex: this.selectedIndex,

          selectedIndexChange: this.selectedIndexChange

        }),

        autoCancel: true,

        customStyle: true

      });

      this.dialogController.open();

      Logger.info(TAG, 'CustomDialogController end');

    })

  };



  showPromptDialog(title: ResourceStr, str: ResourceStr) {

    AlertDialog.show({

      title: title,

      message: str,

      confirm: {

        value: $r('app.string.cancel'),

        action: () = > {

          Logger.info(TAG, `Button-clicking callback`);

        }

      },

      cancel: () = > {

        Logger.info(TAG, `Closed callbacks`);

      }

    });

  };



  remoteServiceExtensionConnectEvent(event: string) {

    if (typeof (event) === 'string') {

      let viewThis = AppStorage.get< Index >('viewThis');

      if (viewThis !== undefined) {

        if (event === MusicConnectEvent.EVENT_CONNECT) {

          viewThis.clickFlag = MusicSharedStatus.MUSIC_STOP_SHARED;

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          Logger.info(TAG, 'remote service on connect callbacked');

        } else if (event === MusicConnectEvent.EVENT_DISCONNECT) {

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.onDisconnectService'));

        } else if (event === MusicConnectEvent.EVENT_FAILED) {

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.onFailedService'));

        } else if (event === MusicConnectEvent.EVENT_TIMEOUT) {

          this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.ConnectionTimeout'));

        }

      }

    } else {

      Logger.info(TAG, 'event is not a string');

    };

  };



  musicPause() {

    Logger.info(TAG, 'music pause recv');

    PlayerModel.pause();

    let viewThis = AppStorage.get< Index >('viewThis');

    viewThis!.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

  };



  musicPlay() {

    Logger.info(TAG, 'music play recv');

    PlayerModel.play(DEFAULT_NUM, true);

    let viewThis = AppStorage.get< Index >('viewThis');

    viewThis!.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

  };



  exitMusicApp() {

    Logger.info(TAG, `exit music app called`);

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      this.localExtensionRemote.sendRequest(

        MusicSharedEventCode.STOP_LOCAL_SERIVCE,

        data,

        reply,

        option);

    } else {

      Logger.info(TAG, `Remote start type is error or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  connectLocalExtension() {

    let localServiceWant: Want = {

      bundleName: APPLICATION_BUNDLE_NAME,

      abilityName: APPLICATION_SERVICE_NAME,

    };

    let connectOptions: ability.ConnectOptions = {

      onConnect: (elementName, remote) = > {

        this.localExtensionRemote = remote;

        Logger.info(TAG, `onConnect called elementName is ${JSON.stringify(elementName)}`);

      },

      onDisconnect: (elementName) = > {

        if (this.context !== null) {

          this.context.terminateSelf();

          Logger.info(TAG, `OnDisconnect called elementName is ${JSON.stringify(elementName)}`);

        };

      },

      onFailed: (code) = > {

        if (this.context !== null) {

          this.context.terminateSelf();

          Logger.info(TAG, `OnFailed called code is ${JSON.stringify(code)}`);

        }

      }

    };

    if (this.context !== null) {

      this.context.connectServiceExtensionAbility(localServiceWant, connectOptions);

    };

  };



  startRemoteExtension(deviceId: string, params: object) {

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object' && typeof (deviceId) === 'string' && deviceId !== '') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      data.writeString(deviceId);

      data.writeString(JSON.stringify(params));

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.START_DISTRIBUTED_MUSIC_SERVICE, data, reply, option);

      this.deviceId = deviceId;

      this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

    } else {

      Logger.info(TAG, `Remote start type is error or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  stopRemoteExtension() {

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object' && typeof (this.deviceId) === 'string' && this.deviceId !== '') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      data.writeString(this.deviceId);

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.STOP_DISTRIBUTED_MUSIC_SERVICE, data, reply, option);

      this.deviceId = '';

    } else {

      Logger.info(TAG, `Remote stopped type is wrong or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  sendMessagePlay() {

    if (this.localExtensionRemote !== null) {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.PLAY_MUSIC_SERVICE, data, reply, option);

      Logger.info(TAG, `onPlayClick send mssage success`);

    } else {

      Logger.info(TAG, `can not get proxy`);

      return;

    };

  };



  sendMessagePause() {

    if (this.localExtensionRemote === null) {

      Logger.info(TAG, `can not get proxy`);

      return;

    };

    let option = new rpc.MessageOption();

    let data = new rpc.MessageParcel();

    let reply = new rpc.MessageParcel();



    this.localExtensionRemote.sendRequest(MusicSharedEventCode.PAUSE_MUSIC_SERVICE, data, reply, option);

    Logger.info(TAG, `onPauseClick send mssage success`);

  };



  onBackPress() {

    if (this.isDialogShowing === true) {

      this.dismissDialog();

      return true;

    };

    return false;

  };



  onPageHide() {

    if (this.isDialogShowing === true) {

      this.dismissDialog();

      return true;

    };

    return false;

  };



  dismissDialog() {

    if (this.dialogController !== null) {

      this.dialogController.close();

    }

    this.remoteDeviceModel.unregisterDeviceListCallback();

    this.isDialogShowing = false;

  };



  startAbilityContinuation(deviceId: string) {

    let params: Params = {

      uri: '',

      seekTo: 0,

      isPlaying: false

    };

    Logger.info(TAG, `startAbilityContinuation PlayerModel.index= ${PlayerModel.index}/${PlayerModel.playlist.audioFiles.length}`);

    if (PlayerModel.index >= 0 && PlayerModel.index <= PlayerModel.playlist.audioFiles.length) {

      params = {

        uri: PlayerModel.playlist.audioFiles[PlayerModel.index].fileUri,

        seekTo: PlayerModel.getCurrentMs(),

        isPlaying: PlayerModel.isPlaying

      };

    };

    Logger.info(TAG, `context.startAbility deviceId= ${deviceId}`);

    if (this.context !== null) {

      KvStoreModel.setOnMessageReceivedListener(this.context, REMOTE_ABILITY_STARTED, () = > {

        Logger.info(TAG, 'OnMessageReceived, terminateSelf');

      });

    };

    Logger.info(TAG, `context.startAbility start`);

    this.clickFlag = MusicSharedStatus.MUSIC_REMOTING;

    this.startRemoteExtension(deviceId, params);

    this.clearSelectState();

    Logger.info(TAG, 'context.startAbility end');

  };



  selectedIndexChange = (selectedIndex: number) = > {

    if (this.context !== null && selectedIndex === 0) {

      this.context.startAbility({ bundleName: 'ohos.samples.distributedmusicplayer',

        abilityName: 'ohos.samples.distributedmusicplayer.MainAbility',

        deviceId: this.deviceLists[selectedIndex].deviceId,

        parameters: {

          isFA: 'EXIT'

        }

      }).then(() = > {

        Logger.info(TAG, `startAbility finished`);

      }).catch((err: Error) = > {

        Logger.info(TAG, `startAbility filed error = ${JSON.stringify(err)}`);

      });

      this.isDistributed = false;

      this.selectedIndex = 0;

      if (this.dialogController !== null) {

        this.dialogController.close();

      }

      this.deviceLists = [];

      return;

    };

    this.selectedIndex = selectedIndex;

    this.selectDevice();

  };



  selectDevice() {

    Logger.info(TAG, 'start ability ......');

    if (this.selectedIndex !== undefined && (this.remoteDeviceModel === null || this.remoteDeviceModel.discoverLists.length <= 0)) {

      Logger.info(TAG, `start ability device:${JSON.stringify(this.deviceLists)}`);

      this.startAbilityContinuation(this.deviceLists[this.selectedIndex].networkId as string);

      this.clearSelectState();

      return;

    };

    Logger.info(TAG, 'start ability, needAuth');

    if (this.selectedIndex !== undefined){

      this.remoteDeviceModel.authDevice(this.deviceLists[this.selectedIndex], (device: deviceManager.DeviceBasicInfo) = > {

        Logger.info(TAG, 'auth and online finished');

        this.startAbilityContinuation(device.networkId);

      });

    }

    Logger.info(TAG, 'start ability2 ......');

    this.clearSelectState();

  };



  clearSelectState() {

    this.deviceLists = [];

    if (this.dialogController) {

      this.dialogController.close();

      this.dialogController = null;

    };

  };



  getShownTimer(ms: number) {

    let minStr: string;

    let secStr: string;

    let seconds = Math.floor(ms / ONE_THOUSAND);

    let sec = seconds % SIXTY;

    Logger.info(TAG, `getShownTimer sec = ${sec}`);

    let min = (seconds - sec) / SIXTY;

    Logger.info(TAG, `getShownTimer min = ${min}`);

    if (sec < 10) {

      secStr = '0' + sec;

    } else {

      secStr = sec.toString(10);

    };

    if (min < 10) {

      minStr = '0' + min;

    } else {

      minStr = min.toString(10);

    };

    Logger.warn(TAG, `getShownTimer = ${minStr}:${secStr}`);

    return minStr + ':' + secStr;

  };



  refreshSongInfo(index: number) {

    Logger.info(TAG, `refreshSongInfo ${index}/${PlayerModel.playlist.audioFiles.length}`);

    if (index >= PlayerModel.playlist.audioFiles.length) {

      Logger.warn(TAG, 'refreshSongInfo ignored');

      return;

    };

    // update song title

    this.title = PlayerModel.playlist.audioFiles[index].name;

    this.albumSrc = (index % 2 === 0) ? $r('app.media.album') : $r('app.media.album2');



    // update duration

    this.totalMs = PlayerModel.getDuration();

    this.totalTimeText = this.getShownTimer(this.totalMs);

    this.currentTimeText = this.getShownTimer(PlayerModel.getCurrentMs());

    Logger.info(TAG, `refreshSongInfo this.title= ${this.title}, this.totalMs= ${this.totalMs}, this.totalTimeText= ${this.totalTimeText},this.currentTimeText= ${this.currentTimeText}`);

  };



  onAppSharedClick() {

    if (this.clickFlag === MusicSharedStatus.MUSIC_SHARED) {

      Logger.info(TAG, `1start button is ${JSON.stringify(this.imageArrays[ABILITY_SHARED_BUTTON])}`);

      this.showDialog();

    } else if (this.clickFlag === MusicSharedStatus.MUSIC_STOP_SHARED) {

      Logger.info(TAG, `2start button is ${JSON.stringify(this.imageArrays[ABILITY_SHARED_BUTTON])}`);

      this.stopRemoteExtension();

      this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

    };

  };



  onPreviousClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onPreviousClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, 'onPreviousClick');

    PlayerModel.index--;

    if (PlayerModel.index < 0 && PlayerModel.playlist.audioFiles.length >= 1) {

      PlayerModel.index = PlayerModel.playlist.audioFiles.length - 1;

    };

    this.currentProgress = 0;

    this.isSwitching = true;



    PlayerModel.preLoad(PlayerModel.index, () = > {

      this.refreshSongInfo(PlayerModel.index);

      PlayerModel.play(0, true);

      if (PlayerModel.isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      };

      this.isSwitching = false;

    });

  };



  onNextClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onNextClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, 'onNextClick');

    PlayerModel.index++;

    if (PlayerModel.index >= PlayerModel.playlist.audioFiles.length) {

      PlayerModel.index = 0;

    };

    this.currentProgress = 0;

    this.isSwitching = true;

    PlayerModel.preLoad(PlayerModel.index, () = > {

      this.refreshSongInfo(PlayerModel.index);

      PlayerModel.play(0, true);

      if (PlayerModel.isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      };

      this.isSwitching = false;

    });

  };



  onPlayClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onPlayClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, `onPlayClick isPlaying= ${PlayerModel.isPlaying}`);

    if (PlayerModel.isPlaying) {

      PlayerModel.pause();

      this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

      this.sendMessagePause();

    } else {

      PlayerModel.preLoad(PlayerModel.index, () = > {

        PlayerModel.play(DEFAULT_NUM, true);

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

        this.sendMessagePlay();

      })

    };

  };



  restoreFromWant() {

    Logger.info(TAG, 'restoreFromWant');

    let status: Record< string, Object > | undefined = AppStorage.get('status');

    if (status !== undefined && status !== null && status.uri !== null) {

      KvStoreModel.broadcastMessage(this.context, REMOTE_ABILITY_STARTED);

      Logger.info(TAG, 'restorePlayingStatus');

      PlayerModel.restorePlayingStatus(status, (index: number) = > {

        Logger.info(TAG, `restorePlayingStatus finished, index= ${index}`);

        if (index >= 0) {

          this.refreshSongInfo(index);

        } else {

          PlayerModel.preLoad(0, () = > {

            this.refreshSongInfo(0);

          })

        }

        if (status !== undefined) {

          Logger.info(TAG, `Index PlayerModel.restorePlayingStatus this.totalMs = ${this.totalMs}, status.seekTo = ${status.seekTo}`);

          this.currentProgress = Math.floor(Number(status.seekTo) / this.totalMs * ONE_HUNDRED);

        }

      })

    } else {

      PlayerModel.preLoad(0, () = > {

        this.refreshSongInfo(0);

      });

    }

  };



  aboutToAppear() {

    Logger.info(TAG, `begin`);

    Logger.info(TAG, 'grantPermission');

    this.context = getContext(this) as common.UIAbilityContext;

    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    let permission: Array< Permissions > = ['ohos.permission.DISTRIBUTED_DATASYNC'];

    try {

      atManager.requestPermissionsFromUser(this.context, permission).then((data: PermissionRequestResult) = > {

        Logger.info(TAG, `data: ${JSON.stringify(data)}`);

      }).catch((err: object) = > {

        Logger.info(TAG, `err: ${JSON.stringify(err)}`);

      })

    } catch (err) {

      Logger.info(TAG, `catch err- >${JSON.stringify(err)}`);

    }

    display.getDefaultDisplay().then((dis: display.Display) = > {

      Logger.info(TAG, `getDefaultDisplay dis= ${JSON.stringify(dis)}`);

      let proportion = DESIGN_WIDTH / dis.width;

      let screenWidth = DESIGN_WIDTH;

      let screenHeight = (dis.height - SYSTEM_UI_HEIGHT) * proportion;

      this.riscale = (screenHeight / screenWidth) / DESIGN_RATIO;

      if (this.riscale < 1) {

        // The screen ratio is shorter than design ratio

        this.risw = screenWidth * this.riscale;

        this.rish = screenHeight;

      } else {

        // The screen ratio is longer than design ratio

        this.risw = screenWidth;

        this.rish = screenHeight / this.riscale;

      }

      Logger.info(TAG, `proportion=${proportion} , screenWidth= ${screenWidth},

      screenHeight= ${screenHeight} , riscale= ${this.riscale} , risw= ${this.risw} , rish= ${this.rish}`);

    })

    Logger.info(TAG, 'getDefaultDisplay end');

    this.currentTimeText = this.getShownTimer(0);

    PlayerModel.setOnStatusChangedListener((isPlaying: string) = > {

      Logger.info(TAG, `on player status changed, isPlaying= ${isPlaying} refresh ui`);

      PlayerModel.setOnPlayingProgressListener((currentTimeMs: number) = > {

        this.currentTimeText = this.getShownTimer(currentTimeMs);

        this.currentProgress = Math.floor(currentTimeMs / this.totalMs * ONE_HUNDRED);

      });

      if (isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      } else {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

      }

    });



    PlayerModel.getPlaylist(() = > {

      Logger.info(TAG, 'on playlist generated, refresh ui');

      this.restoreFromWant();

    });



    AppStorage.setOrCreate('viewThis', this);



    this.connectLocalExtension();

  };



  aboutToDisappear() {

    Logger.info(TAG, `aboutToDisappear begin`)

    if (PlayerModel === undefined) {

      return

    }

    PlayerModel.release()

    this.remoteDeviceModel.unregisterDeviceListCallback()

    this.dialogController = null

    KvStoreModel.deleteKvStore()

    Logger.info(TAG, `aboutToDisappear end`)

  };



  build() {

    Column() {

      Blank()

        .width('100%')

        .height(72)

      Text(this.title)

        .width('100%')

        .fontSize(28)

        .margin({ top: '10%' })

        .fontColor(Color.White)

        .textAlign(TextAlign.Center)

      Image(this.albumSrc)

        .width(this.isLand ? '60%' : '89%')

        .objectFit(ImageFit.Contain)

        .margin({ top: 50, left: 40, right: 40 })

      Row() {

        Text(this.currentTimeText)

          .fontSize(20)

          .fontColor(Color.White)

        Blank()

        Text(this.totalTimeText)

          .fontSize(20)

          .fontColor(Color.White)

      }

      .width('90%')

      .margin({ top: '12%' })



      Slider({ value: typeof (this.currentProgress) === 'number' ? this.currentProgress : 0 })

        .trackColor('#64CCE7FF')

        .width('90%')

        .selectedColor('#ff0c4ae7')

        .onChange((value: number, mode: SliderChangeMode) = > {

          this.currentProgress = value;

          if (typeof (this.totalMs) !== 'number') {

            this.currentProgress = 0;

            Logger.info(TAG, `setProgress ignored, totalMs= ${this.totalMs}`);

            return;

          };

          let currentMs = this.currentProgress / ONE_HUNDRED * this.totalMs;

          this.currentTimeText = this.getShownTimer(currentMs);

          if (mode === SliderChangeMode.End || mode === 3) {

            Logger.info(TAG, `player.seek= ${currentMs}`);

            PlayerModel.seek(currentMs);

          };

        })



      Row() {

        ForEach(this.imageArrays, (item: Resource, index: number | undefined) = > {

          Column() {

            Image(item)

              .size({ width: 74, height: 74 })

              .objectFit(ImageFit.Contain)

              .onClick(() = > {

                switch (index) {

                  case 0:

                    this.onAppSharedClick();

                    break;

                  case 1:

                    this.onPreviousClick();

                    break;

                  case 2:

                    this.onPlayClick();

                    break;

                  case 3:

                    this.onNextClick();

                    break;

                  default:

                    break;

                }

              })

          }

          .id('image' + (index !== undefined ? (index + 1) : 0))

          .width(100)

          .height(100)

          .alignItems(HorizontalAlign.Center)

          .justifyContent(FlexAlign.Center)

        })



      }

      .width('100%')

      .margin({ top: '4%' })

      .justifyContent(FlexAlign.SpaceEvenly)

    }

    .width('100%')

    .height('100%')

    .backgroundImage($r('app.media.bg_blurry'))

    .backgroundImageSize({ width: '100%', height: '100%' })

  }

}

分布式數據管理

(1) 管理分布式數據庫
創建一個KVManager對象實例,用于管理分布式數據庫對象。通過distributedData.createKVManager(config),并通過指定Options和storeId,創建并獲取KVStore數據庫,并通過Promise方式返回,此方法為異步方法,例如this.kvManager.getKVStore(STORE_ID, options).then((store) => {})
(2) 訂閱分布式數據變化
通過訂閱分布式數據庫所有(本地及遠端)數據變化實現數據協同[源碼參考]。

/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';

import display from '@ohos.display';

import common from '@ohos.app.ability.common';

import mediaQuery from '@ohos.mediaquery';

import rpc from '@ohos.rpc';

import Want from '@ohos.app.ability.Want';

import PermissionRequestResult from 'security/PermissionRequestResult';

import KvStoreModel from '../model/KvStoreModel';

import Logger from '../model/Logger';

import PlayerModel from '../model/PlayerModel';

import deviceManager from '@ohos.distributedDeviceManager';

import ability from '@ohos.ability.ability';

import { RemoteDeviceModel } from '../model/RemoteDeviceModel';

import { DeviceDialog } from '../common/DeviceDialog';

import {

  APPLICATION_BUNDLE_NAME,

  APPLICATION_SERVICE_NAME,

  MusicSharedEventCode,

  MusicSharedStatus,

  MusicConnectEvent

} from '../common/MusicSharedDefinition';



const TAG: string = 'Index';

const DESIGN_WIDTH: number = 720.0;

const SYSTEM_UI_HEIGHT: number = 134;

const DESIGN_RATIO: number = 16 / 9;

const ONE_HUNDRED: number = 100;

const ONE_THOUSAND: number = 1000;

const SIXTY: number = 60;

const REMOTE_ABILITY_STARTED: string = 'remoteAbilityStarted';

const ABILITY_SHARED_BUTTON = 0;

const DEFAULT_NUM = -1;

const PREVIOUS_CLICK = 2;



interface Params {

  uri: string,

  seekTo: number,

  isPlaying: boolean

};



@Entry

@Component

 struct Index {

  private listener = mediaQuery.matchMediaSync('screen and (min-aspect-ratio: 1.5) or (orientation: landscape)');

  @State isLand: boolean = false;

  @State currentTimeText: string = '';

  @State currentProgress: number = 0;

  @State totalMs: number = 0;

  @State riscale: number = 1;

  @State risw: number = 720;

  @State rish: number = 1280;

  @State isSwitching: boolean = false;

  @State deviceLists: Array< deviceManager.DeviceBasicInfo > = [];

  @State isDialogShowing: boolean = false;

  @State isDistributed: boolean = false;

  @State title: string = '';

  @State totalTimeText: string = '00:00';

  @State albumSrc: Resource = $r('app.media.album');

  @State selectedIndex: number = 0;

  @State imageArrays: Array< Resource > = [$r('app.media.ic_hop'), $r('app.media.ic_play_previous'), $r('app.media.ic_play'), $r('app.media.ic_play_next')];

  private dialogController: CustomDialogController | null = null;

  @StorageLink('exitMusicApp') @Watch('exitMusicApp') isExitMusicApp: boolean = false;

  @StorageLink('remoteServiceExtensionConnectEvent') @Watch('remoteServiceExtensionConnectEvent') isRemoteServiceExtensionConnectEvent: boolean = false;

  @StorageLink('musicPlay') @Watch('musicPlay') isMusicPlay: boolean = false;

  @StorageLink('musicPause') @Watch('musicPause') isMusicPause: boolean = false;

  private remoteDeviceModel: RemoteDeviceModel = new RemoteDeviceModel();

  private context: common.UIAbilityContext | null = null;

  private deviceId: string | null = null;

  private clickFlag = MusicSharedStatus.MUSIC_SHARED;

  private localExtensionRemote: rpc.IRemoteObject | null = null;

  onLand = (mediaQueryResult: mediaQuery.MediaQueryResult) = > {

    Logger.info(TAG, `onLand: mediaQueryResult.matches= ${mediaQueryResult.matches}`);

    if (mediaQueryResult.matches) {

      this.isLand = true;

    } else {

      this.isLand = false;

    };

  };



  showDialog() {

    this.remoteDeviceModel.registerDeviceListCallback(() = > {

      Logger.info(TAG, 'registerDeviceListCallback, callback entered');

      this.deviceLists = [];

      this.deviceLists.push({

        deviceId: '0',

        deviceName: 'local device',

        deviceType: '0',

        networkId: ''

      });

      let deviceTempList = this.remoteDeviceModel.discoverLists.length > 0 ? this.remoteDeviceModel.discoverLists : this.remoteDeviceModel.deviceLists;

      for (let i = 0; i < deviceTempList.length; i++) {

        Logger.info(TAG, `device ${i}/${deviceTempList.length} deviceId= ${deviceTempList[i].deviceId},

         deviceName= ${deviceTempList[i].deviceName}, deviceType= ${deviceTempList[i].deviceType}`);

        this.deviceLists.push(deviceTempList[i]);

        Logger.info(TAG, 'deviceLists push end');

      };

      Logger.info(TAG, 'CustomDialogController start');

      if (this.dialogController !== null) {

        this.dialogController.close();

        this.dialogController = null;

      }

      this.dialogController = new CustomDialogController({

        builder: DeviceDialog({

          deviceLists: this.deviceLists,

          selectedIndex: this.selectedIndex,

          selectedIndexChange: this.selectedIndexChange

        }),

        autoCancel: true,

        customStyle: true

      });

      this.dialogController.open();

      Logger.info(TAG, 'CustomDialogController end');

    })

  };



  showPromptDialog(title: ResourceStr, str: ResourceStr) {

    AlertDialog.show({

      title: title,

      message: str,

      confirm: {

        value: $r('app.string.cancel'),

        action: () = > {

          Logger.info(TAG, `Button-clicking callback`);

        }

      },

      cancel: () = > {

        Logger.info(TAG, `Closed callbacks`);

      }

    });

  };



  remoteServiceExtensionConnectEvent(event: string) {

    if (typeof (event) === 'string') {

      let viewThis = AppStorage.get< Index >('viewThis');

      if (viewThis !== undefined) {

        if (event === MusicConnectEvent.EVENT_CONNECT) {

          viewThis.clickFlag = MusicSharedStatus.MUSIC_STOP_SHARED;

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          Logger.info(TAG, 'remote service on connect callbacked');

        } else if (event === MusicConnectEvent.EVENT_DISCONNECT) {

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.onDisconnectService'));

        } else if (event === MusicConnectEvent.EVENT_FAILED) {

          viewThis.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.onFailedService'));

        } else if (event === MusicConnectEvent.EVENT_TIMEOUT) {

          this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

          viewThis.clickFlag = MusicSharedStatus.MUSIC_SHARED;

          viewThis.showPromptDialog($r('app.string.ConnectRemoteDevices'), $r('app.string.ConnectionTimeout'));

        }

      }

    } else {

      Logger.info(TAG, 'event is not a string');

    };

  };



  musicPause() {

    Logger.info(TAG, 'music pause recv');

    PlayerModel.pause();

    let viewThis = AppStorage.get< Index >('viewThis');

    viewThis!.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

  };



  musicPlay() {

    Logger.info(TAG, 'music play recv');

    PlayerModel.play(DEFAULT_NUM, true);

    let viewThis = AppStorage.get< Index >('viewThis');

    viewThis!.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

  };



  exitMusicApp() {

    Logger.info(TAG, `exit music app called`);

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      this.localExtensionRemote.sendRequest(

        MusicSharedEventCode.STOP_LOCAL_SERIVCE,

        data,

        reply,

        option);

    } else {

      Logger.info(TAG, `Remote start type is error or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  connectLocalExtension() {

    let localServiceWant: Want = {

      bundleName: APPLICATION_BUNDLE_NAME,

      abilityName: APPLICATION_SERVICE_NAME,

    };

    let connectOptions: ability.ConnectOptions = {

      onConnect: (elementName, remote) = > {

        this.localExtensionRemote = remote;

        Logger.info(TAG, `onConnect called elementName is ${JSON.stringify(elementName)}`);

      },

      onDisconnect: (elementName) = > {

        if (this.context !== null) {

          this.context.terminateSelf();

          Logger.info(TAG, `OnDisconnect called elementName is ${JSON.stringify(elementName)}`);

        };

      },

      onFailed: (code) = > {

        if (this.context !== null) {

          this.context.terminateSelf();

          Logger.info(TAG, `OnFailed called code is ${JSON.stringify(code)}`);

        }

      }

    };

    if (this.context !== null) {

      this.context.connectServiceExtensionAbility(localServiceWant, connectOptions);

    };

  };



  startRemoteExtension(deviceId: string, params: object) {

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object' && typeof (deviceId) === 'string' && deviceId !== '') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      data.writeString(deviceId);

      data.writeString(JSON.stringify(params));

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.START_DISTRIBUTED_MUSIC_SERVICE, data, reply, option);

      this.deviceId = deviceId;

      this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

    } else {

      Logger.info(TAG, `Remote start type is error or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  stopRemoteExtension() {

    if (this.localExtensionRemote !== null && typeof (this.localExtensionRemote) === 'object' && typeof (this.deviceId) === 'string' && this.deviceId !== '') {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      data.writeString(this.deviceId);

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.STOP_DISTRIBUTED_MUSIC_SERVICE, data, reply, option);

      this.deviceId = '';

    } else {

      Logger.info(TAG, `Remote stopped type is wrong or deviceID is empty, typeof= ${typeof (this.localExtensionRemote)}`);

    };

  };



  sendMessagePlay() {

    if (this.localExtensionRemote !== null) {

      let option = new rpc.MessageOption();

      let data = new rpc.MessageParcel();

      let reply = new rpc.MessageParcel();

      this.localExtensionRemote.sendRequest(MusicSharedEventCode.PLAY_MUSIC_SERVICE, data, reply, option);

      Logger.info(TAG, `onPlayClick send mssage success`);

    } else {

      Logger.info(TAG, `can not get proxy`);

      return;

    };

  };



  sendMessagePause() {

    if (this.localExtensionRemote === null) {

      Logger.info(TAG, `can not get proxy`);

      return;

    };

    let option = new rpc.MessageOption();

    let data = new rpc.MessageParcel();

    let reply = new rpc.MessageParcel();



    this.localExtensionRemote.sendRequest(MusicSharedEventCode.PAUSE_MUSIC_SERVICE, data, reply, option);

    Logger.info(TAG, `onPauseClick send mssage success`);

  };



  onBackPress() {

    if (this.isDialogShowing === true) {

      this.dismissDialog();

      return true;

    };

    return false;

  };



  onPageHide() {

    if (this.isDialogShowing === true) {

      this.dismissDialog();

      return true;

    };

    return false;

  };



  dismissDialog() {

    if (this.dialogController !== null) {

      this.dialogController.close();

    }

    this.remoteDeviceModel.unregisterDeviceListCallback();

    this.isDialogShowing = false;

  };



  startAbilityContinuation(deviceId: string) {

    let params: Params = {

      uri: '',

      seekTo: 0,

      isPlaying: false

    };

    Logger.info(TAG, `startAbilityContinuation PlayerModel.index= ${PlayerModel.index}/${PlayerModel.playlist.audioFiles.length}`);

    if (PlayerModel.index >= 0 && PlayerModel.index <= PlayerModel.playlist.audioFiles.length) {

      params = {

        uri: PlayerModel.playlist.audioFiles[PlayerModel.index].fileUri,

        seekTo: PlayerModel.getCurrentMs(),

        isPlaying: PlayerModel.isPlaying

      };

    };

    Logger.info(TAG, `context.startAbility deviceId= ${deviceId}`);

    if (this.context !== null) {

      KvStoreModel.setOnMessageReceivedListener(this.context, REMOTE_ABILITY_STARTED, () = > {

        Logger.info(TAG, 'OnMessageReceived, terminateSelf');

      });

    };

    Logger.info(TAG, `context.startAbility start`);

    this.clickFlag = MusicSharedStatus.MUSIC_REMOTING;

    this.startRemoteExtension(deviceId, params);

    this.clearSelectState();

    Logger.info(TAG, 'context.startAbility end');

  };



  selectedIndexChange = (selectedIndex: number) = > {

    if (this.context !== null && selectedIndex === 0) {

      this.context.startAbility({ bundleName: 'ohos.samples.distributedmusicplayer',

        abilityName: 'ohos.samples.distributedmusicplayer.MainAbility',

        deviceId: this.deviceLists[selectedIndex].deviceId,

        parameters: {

          isFA: 'EXIT'

        }

      }).then(() = > {

        Logger.info(TAG, `startAbility finished`);

      }).catch((err: Error) = > {

        Logger.info(TAG, `startAbility filed error = ${JSON.stringify(err)}`);

      });

      this.isDistributed = false;

      this.selectedIndex = 0;

      if (this.dialogController !== null) {

        this.dialogController.close();

      }

      this.deviceLists = [];

      return;

    };

    this.selectedIndex = selectedIndex;

    this.selectDevice();

  };



  selectDevice() {

    Logger.info(TAG, 'start ability ......');

    if (this.selectedIndex !== undefined && (this.remoteDeviceModel === null || this.remoteDeviceModel.discoverLists.length <= 0)) {

      Logger.info(TAG, `start ability device:${JSON.stringify(this.deviceLists)}`);

      this.startAbilityContinuation(this.deviceLists[this.selectedIndex].networkId as string);

      this.clearSelectState();

      return;

    };

    Logger.info(TAG, 'start ability, needAuth');

    if (this.selectedIndex !== undefined){

      this.remoteDeviceModel.authDevice(this.deviceLists[this.selectedIndex], (device: deviceManager.DeviceBasicInfo) = > {

        Logger.info(TAG, 'auth and online finished');

        this.startAbilityContinuation(device.networkId);

      });

    }

    Logger.info(TAG, 'start ability2 ......');

    this.clearSelectState();

  };



  clearSelectState() {

    this.deviceLists = [];

    if (this.dialogController) {

      this.dialogController.close();

      this.dialogController = null;

    };

  };



  getShownTimer(ms: number) {

    let minStr: string;

    let secStr: string;

    let seconds = Math.floor(ms / ONE_THOUSAND);

    let sec = seconds % SIXTY;

    Logger.info(TAG, `getShownTimer sec = ${sec}`);

    let min = (seconds - sec) / SIXTY;

    Logger.info(TAG, `getShownTimer min = ${min}`);

    if (sec < 10) {

      secStr = '0' + sec;

    } else {

      secStr = sec.toString(10);

    };

    if (min < 10) {

      minStr = '0' + min;

    } else {

      minStr = min.toString(10);

    };

    Logger.warn(TAG, `getShownTimer = ${minStr}:${secStr}`);

    return minStr + ':' + secStr;

  };



  refreshSongInfo(index: number) {

    Logger.info(TAG, `refreshSongInfo ${index}/${PlayerModel.playlist.audioFiles.length}`);

    if (index >= PlayerModel.playlist.audioFiles.length) {

      Logger.warn(TAG, 'refreshSongInfo ignored');

      return;

    };

    // update song title

    this.title = PlayerModel.playlist.audioFiles[index].name;

    this.albumSrc = (index % 2 === 0) ? $r('app.media.album') : $r('app.media.album2');



    // update duration

    this.totalMs = PlayerModel.getDuration();

    this.totalTimeText = this.getShownTimer(this.totalMs);

    this.currentTimeText = this.getShownTimer(PlayerModel.getCurrentMs());

    Logger.info(TAG, `refreshSongInfo this.title= ${this.title}, this.totalMs= ${this.totalMs}, this.totalTimeText= ${this.totalTimeText},this.currentTimeText= ${this.currentTimeText}`);

  };



  onAppSharedClick() {

    if (this.clickFlag === MusicSharedStatus.MUSIC_SHARED) {

      Logger.info(TAG, `1start button is ${JSON.stringify(this.imageArrays[ABILITY_SHARED_BUTTON])}`);

      this.showDialog();

    } else if (this.clickFlag === MusicSharedStatus.MUSIC_STOP_SHARED) {

      Logger.info(TAG, `2start button is ${JSON.stringify(this.imageArrays[ABILITY_SHARED_BUTTON])}`);

      this.stopRemoteExtension();

      this.imageArrays[ABILITY_SHARED_BUTTON] = $r('app.media.ic_hop');

    };

  };



  onPreviousClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onPreviousClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, 'onPreviousClick');

    PlayerModel.index--;

    if (PlayerModel.index < 0 && PlayerModel.playlist.audioFiles.length >= 1) {

      PlayerModel.index = PlayerModel.playlist.audioFiles.length - 1;

    };

    this.currentProgress = 0;

    this.isSwitching = true;



    PlayerModel.preLoad(PlayerModel.index, () = > {

      this.refreshSongInfo(PlayerModel.index);

      PlayerModel.play(0, true);

      if (PlayerModel.isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      };

      this.isSwitching = false;

    });

  };



  onNextClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onNextClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, 'onNextClick');

    PlayerModel.index++;

    if (PlayerModel.index >= PlayerModel.playlist.audioFiles.length) {

      PlayerModel.index = 0;

    };

    this.currentProgress = 0;

    this.isSwitching = true;

    PlayerModel.preLoad(PlayerModel.index, () = > {

      this.refreshSongInfo(PlayerModel.index);

      PlayerModel.play(0, true);

      if (PlayerModel.isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      };

      this.isSwitching = false;

    });

  };



  onPlayClick() {

    if (this.isSwitching) {

      Logger.info(TAG, 'onPlayClick ignored, isSwitching');

      return;

    };

    Logger.info(TAG, `onPlayClick isPlaying= ${PlayerModel.isPlaying}`);

    if (PlayerModel.isPlaying) {

      PlayerModel.pause();

      this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

      this.sendMessagePause();

    } else {

      PlayerModel.preLoad(PlayerModel.index, () = > {

        PlayerModel.play(DEFAULT_NUM, true);

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

        this.sendMessagePlay();

      })

    };

  };



  restoreFromWant() {

    Logger.info(TAG, 'restoreFromWant');

    let status: Record< string, Object > | undefined = AppStorage.get('status');

    if (status !== undefined && status !== null && status.uri !== null) {

      KvStoreModel.broadcastMessage(this.context, REMOTE_ABILITY_STARTED);

      Logger.info(TAG, 'restorePlayingStatus');

      PlayerModel.restorePlayingStatus(status, (index: number) = > {

        Logger.info(TAG, `restorePlayingStatus finished, index= ${index}`);

        if (index >= 0) {

          this.refreshSongInfo(index);

        } else {

          PlayerModel.preLoad(0, () = > {

            this.refreshSongInfo(0);

          })

        }

        if (status !== undefined) {

          Logger.info(TAG, `Index PlayerModel.restorePlayingStatus this.totalMs = ${this.totalMs}, status.seekTo = ${status.seekTo}`);

          this.currentProgress = Math.floor(Number(status.seekTo) / this.totalMs * ONE_HUNDRED);

        }

      })

    } else {

      PlayerModel.preLoad(0, () = > {

        this.refreshSongInfo(0);

      });

    }

  };



  aboutToAppear() {

    Logger.info(TAG, `begin`);

    Logger.info(TAG, 'grantPermission');

    this.context = getContext(this) as common.UIAbilityContext;

    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    let permission: Array< Permissions > = ['ohos.permission.DISTRIBUTED_DATASYNC'];

    try {

      atManager.requestPermissionsFromUser(this.context, permission).then((data: PermissionRequestResult) = > {

        Logger.info(TAG, `data: ${JSON.stringify(data)}`);

      }).catch((err: object) = > {

        Logger.info(TAG, `err: ${JSON.stringify(err)}`);

      })

    } catch (err) {

      Logger.info(TAG, `catch err- >${JSON.stringify(err)}`);

    }

    display.getDefaultDisplay().then((dis: display.Display) = > {

      Logger.info(TAG, `getDefaultDisplay dis= ${JSON.stringify(dis)}`);

      let proportion = DESIGN_WIDTH / dis.width;

      let screenWidth = DESIGN_WIDTH;

      let screenHeight = (dis.height - SYSTEM_UI_HEIGHT) * proportion;

      this.riscale = (screenHeight / screenWidth) / DESIGN_RATIO;

      if (this.riscale < 1) {

        // The screen ratio is shorter than design ratio

        this.risw = screenWidth * this.riscale;

        this.rish = screenHeight;

      } else {

        // The screen ratio is longer than design ratio

        this.risw = screenWidth;

        this.rish = screenHeight / this.riscale;

      }

      Logger.info(TAG, `proportion=${proportion} , screenWidth= ${screenWidth},

      screenHeight= ${screenHeight} , riscale= ${this.riscale} , risw= ${this.risw} , rish= ${this.rish}`);

    })

    Logger.info(TAG, 'getDefaultDisplay end');

    this.currentTimeText = this.getShownTimer(0);

    PlayerModel.setOnStatusChangedListener((isPlaying: string) = > {

      Logger.info(TAG, `on player status changed, isPlaying= ${isPlaying} refresh ui`);

      PlayerModel.setOnPlayingProgressListener((currentTimeMs: number) = > {

        this.currentTimeText = this.getShownTimer(currentTimeMs);

        this.currentProgress = Math.floor(currentTimeMs / this.totalMs * ONE_HUNDRED);

      });

      if (isPlaying) {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_pause');

      } else {

        this.imageArrays[PREVIOUS_CLICK] = $r('app.media.ic_play');

      }

    });



    PlayerModel.getPlaylist(() = > {

      Logger.info(TAG, 'on playlist generated, refresh ui');

      this.restoreFromWant();

    });



    AppStorage.setOrCreate('viewThis', this);



    this.connectLocalExtension();

  };



  aboutToDisappear() {

    Logger.info(TAG, `aboutToDisappear begin`)

    if (PlayerModel === undefined) {

      return

    }

    PlayerModel.release()

    this.remoteDeviceModel.unregisterDeviceListCallback()

    this.dialogController = null

    KvStoreModel.deleteKvStore()

    Logger.info(TAG, `aboutToDisappear end`)

  };



  build() {

    Column() {

      Blank()

        .width('100%')

        .height(72)

      Text(this.title)

        .width('100%')

        .fontSize(28)

        .margin({ top: '10%' })

        .fontColor(Color.White)

        .textAlign(TextAlign.Center)

      Image(this.albumSrc)

        .width(this.isLand ? '60%' : '89%')

        .objectFit(ImageFit.Contain)

        .margin({ top: 50, left: 40, right: 40 })

      Row() {

        Text(this.currentTimeText)

          .fontSize(20)

          .fontColor(Color.White)

        Blank()

        Text(this.totalTimeText)

          .fontSize(20)

          .fontColor(Color.White)

      }

      .width('90%')

      .margin({ top: '12%' })



      Slider({ value: typeof (this.currentProgress) === 'number' ? this.currentProgress : 0 })

        .trackColor('#64CCE7FF')

        .width('90%')

        .selectedColor('#ff0c4ae7')

        .onChange((value: number, mode: SliderChangeMode) = > {

          this.currentProgress = value;

          if (typeof (this.totalMs) !== 'number') {

            this.currentProgress = 0;

            Logger.info(TAG, `setProgress ignored, totalMs= ${this.totalMs}`);

            return;

          };

          let currentMs = this.currentProgress / ONE_HUNDRED * this.totalMs;

          this.currentTimeText = this.getShownTimer(currentMs);

          if (mode === SliderChangeMode.End || mode === 3) {

            Logger.info(TAG, `player.seek= ${currentMs}`);

            PlayerModel.seek(currentMs);

          };

        })



      Row() {

        ForEach(this.imageArrays, (item: Resource, index: number | undefined) = > {

          Column() {

            Image(item)

              .size({ width: 74, height: 74 })

              .objectFit(ImageFit.Contain)

              .onClick(() = > {

                switch (index) {

                  case 0:

                    this.onAppSharedClick();

                    break;

                  case 1:

                    this.onPreviousClick();

                    break;

                  case 2:

                    this.onPlayClick();

                    break;

                  case 3:

                    this.onNextClick();

                    break;

                  default:

                    break;

                }

              })

          }

          .id('image' + (index !== undefined ? (index + 1) : 0))

          .width(100)

          .height(100)

          .alignItems(HorizontalAlign.Center)

          .justifyContent(FlexAlign.Center)

        })



      }

      .width('100%')

      .margin({ top: '4%' })

      .justifyContent(FlexAlign.SpaceEvenly)

    }

    .width('100%')

    .height('100%')

    .backgroundImage($r('app.media.bg_blurry'))

    .backgroundImageSize({ width: '100%', height: '100%' })

  }

}

跨設備播放操作

(1)分布式設備管理器綁定應用包 deviceManager.createDeviceManager('ohos.samples.distributedmusicplayer') [源碼參考]。

/*

* Copyright (c) 2022 Huawei Device Co., Ltd.

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*     http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/



import deviceManager from '@ohos.distributedDeviceManager';

import Logger from '../model/Logger';



let SUBSCRIBE_ID: number = 100;

const RANDOM: number = 65536;

const TAG: string = 'RemoteDeviceModel';



export class RemoteDeviceModel {

  public deviceLists: Array< deviceManager.DeviceBasicInfo > = [];

  public discoverLists: Array< deviceManager.DeviceBasicInfo > = [];

  private callback: () = > void = null;

  private authCallback: () = > void = null;

  private deviceManager: deviceManager.DeviceManager = undefined;



  registerDeviceListCallback(callback) {

    if (typeof (this.deviceManager) === 'undefined') {

      Logger.info(TAG, 'deviceManager.createDeviceManager begin');

      try {

        this.deviceManager = deviceManager.createDeviceManager('ohos.samples.distributedmusicplayer');

        this.registerDeviceList(callback);

        Logger.info(TAG, `createDeviceManager callback returned, value= ${JSON.stringify(this.deviceManager)}`);

      } catch (error) {

        Logger.info(TAG, `createDeviceManager throw error, error=${error} message=${error.message}`);

      }

      Logger.info(TAG, 'deviceManager.createDeviceManager end');

    } else {

      this.registerDeviceList(callback);

    };

  };



  registerDeviceList(callback) {

    Logger.info(TAG, 'registerDeviceListCallback');

    this.callback = callback;

    if (this.deviceManager === undefined) {

      Logger.error(TAG, 'deviceManager has not initialized');

      this.callback();

      return;

    };



    Logger.info(TAG, 'getTrustedDeviceListSync begin');

    let list: deviceManager.DeviceBasicInfo[] = [];

    try {

      list = this.deviceManager.getAvailableDeviceListSync();

    } catch (error) {

      Logger.info(TAG, `getTrustedDeviceListSync throw error, error=${error} message=${error.message}`);

    };

    Logger.info(TAG, `getTrustedDeviceListSync end, deviceLists= ${JSON.stringify(list)}`);

    if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {

      this.deviceLists = list;

    };

    this.callback();

    Logger.info(TAG, 'callback finished');



    try {

      this.deviceManager.on('deviceStateChange', (data) = > {

        Logger.info(TAG, `deviceStateChange data= ${JSON.stringify(data)}`);

        switch (data.action) {

          case deviceManager.DeviceStateChange.AVAILABLE:

            this.discoverLists = [];

            this.deviceLists.push(data.device);

            Logger.info(TAG, `reday, updated device list= ${JSON.stringify(this.deviceLists)} `);

            let list: deviceManager.DeviceBasicInfo[] = [];

            try {

              list = this.deviceManager.getAvailableDeviceListSync();

            } catch (err) {

              Logger.info(TAG, `this err is ${JSON.stringify(err)}`);

            }

            Logger.info(TAG, `getTrustedDeviceListSync end, deviceList= ${JSON.stringify(list)}`);

            if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {

              this.deviceLists = list;

            }

            this.callback();

            break;

          case deviceManager.DeviceStateChange.UNAVAILABLE:

            if (this.deviceLists.length > 0) {

              let list = [];

              for (let i = 0; i < this.deviceLists.length; i++) {

                if (this.deviceLists[i].deviceId !== data.device.deviceId) {

                  list[i] = data.device;

                };

              };

              this.deviceLists = list;

            };

            Logger.info(TAG, `offline, updated device list= ${JSON.stringify(this.deviceLists)}`);

            this.callback();

            break;

          default:

            break;

        };

      });

      this.deviceManager.on('discoverSuccess', (data) = > {

        Logger.info(TAG, `discoverSuccess data= ${JSON.stringify(data)}`);

        Logger.info(TAG, `discoverSuccess this.deviceLists= ${this.deviceLists}, this.deviceLists.length= ${this.deviceLists.length}`);

        for (let i = 0;i < this.discoverLists.length; i++) {

          if (this.discoverLists[i].deviceId === data.device.deviceId) {

            Logger.info(TAG, 'device founded, ignored');

            return;

          };

        };

        this.discoverLists[this.discoverLists.length] = data.device;

        this.callback();

      });

      this.deviceManager.on('discoverFailure', (data) = > {

        Logger.info(TAG, `discoverFailure data= ${JSON.stringify(data)}`);

      });

      this.deviceManager.on('serviceDie', () = > {

        Logger.error(TAG, 'serviceDie');

      });

    } catch (error) {

      Logger.info(TAG, `on throw error, error=${error} message=${error.message}`);

    }



    let discoverParam = {

      'discoverTargetType': 1

    };

    let filterOptions = {

      'availableStatus': 0

    };

    Logger.info(TAG, `startDiscovering ${SUBSCRIBE_ID}`);

    try {

      if (this.deviceManager !== null) {

        this.deviceManager.startDiscovering(discoverParam, filterOptions);

      };

    } catch (error) {

      Logger.error(TAG, `startDiscovering throw error, error=${error} message=${error.message}`);

    };

  };



  authDevice(device, callback) {

    Logger.info(TAG, `authDevice ${device}`);

    if (device !== undefined) {

      for (let i = 0; i < this.discoverLists.length; i++) {

        if (this.discoverLists[i].deviceId === device.deviceId) {

          Logger.info(TAG, 'device founded, ignored');

          let bindParam = {

            bindType: 1,

            targetPkgName: 'ohos.samples.distributedmusicplayer',

            appName: 'Music',

          };

          Logger.info(TAG, `authenticateDevice ${JSON.stringify(this.discoverLists[i])}`);

          try {

            this.deviceManager.bindTarget(device.deviceId, bindParam, (err, data) = > {

              if (err) {

                Logger.error(TAG, `authenticateDevice error: ${JSON.stringify(err)}`);

                this.authCallback = () = > {

                };

                return;

              };

              Logger.info(TAG, `authenticateDevice succeed, data= ${JSON.stringify(data)}`);

              this.authCallback = callback;

            });

          } catch (error) {

            Logger.error(TAG, `authenticateDevice throw error, error=${JSON.stringify(error)} message=${error.message}`);

          }

        }

      }

    }

  };



  unregisterDeviceListCallback() {

    Logger.info(TAG, `stopDiscovering ${SUBSCRIBE_ID}`);

    if (this.deviceManager === undefined) {

      return;

    };

    try {

      this.deviceManager.stopDiscovering();

      this.deviceManager.off('deviceStateChange');

      this.deviceManager.off('discoverSuccess');

      this.deviceManager.off('discoverFailure');

      this.deviceManager.off('serviceDie');

    } catch (error) {

      Logger.info(TAG, `stopDeviceDiscovery throw error, error=${error} message=${error.message}`);

    }

    this.deviceLists = [];

  };

}

(2) 初始化播放器 構造函數中通過'@ohos.multimedia.media'組件對播放器進行實例化,并調用播放器初始化函數,通過播放器的on函數,監聽error、finish、timeUpdate
(3) 同步當前播放數據 播放器通過調用selectedIndexChange(),將當前播放的資源、時間、以及播放狀態同步給選中的設備。
(4) 接收當前播放數據 播放器通過在aboutToAppear()時調用this.restoreFromWant(), KvStoreModel組件獲取播放列表,playerModel組件重新加載播放器狀態和資源。

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 分布式
    +關注

    關注

    1

    文章

    879

    瀏覽量

    74466
  • 鴻蒙
    +關注

    關注

    57

    文章

    2310

    瀏覽量

    42742
  • HarmonyOS
    +關注

    關注

    79

    文章

    1967

    瀏覽量

    30017
收藏 人收藏

    評論

    相關推薦

    HarmonyOS應用開發-分布式任務調度

    1. 介紹本篇CodeLab將實現的內容HarmonyOS是面向全場景多終端的分布式操作系統,使得應用程序的開發打破了智能終端互通的性能和數據壁壘,業務邏輯原子化開發,適配多端。通過一
    發表于 09-18 09:21

    HarmonyOS應用開發-分布式設計

    設計理念HarmonyOS 是面向未來全場景智慧生活方式的分布式操作系統。對消費者而言,HarmonyOS 將生活場景中的各類終端進行能力整合,形成“One Super Device”,以實現
    發表于 09-22 17:11

    HarmonyOS分布式應用框架深入解讀

    設備、分布式的能力及應用,二者具有無限能力。從開發者角度看,HarmonyOS上基本的組件分為3+1,其中3代表三個Ability,分別是:PageAbility:負責用戶界面的顯示
    發表于 11-22 15:15

    如何高效完成HarmonyOS分布式應用測試?

    作者:liuxun,HarmonyOS測試架構師HarmonyOS是新一代的智能終端操作系統,給開發者提供了設備發現、設備連接、跨設備調用等豐富的分布式API。隨著越來越多的
    發表于 12-13 18:07

    基于潤和DAYU200開發套件的OpenHarmony分布式音樂播放

    RJ45以太網口,可滿足NVR、工業網關等多網口產品需求。分布式音樂播放器這里給大家分享一個樣例,分布式音樂
    發表于 03-14 09:07

    Hello HarmonyOS學習筆記:分布式新聞客戶端實戰(JS、eTS)

    源代碼下載地址:Codelabs: 分享知識與見解,一起探索HarmonyOS的獨特魅力。 - Gitee.com代碼講解視頻:華為開發者學堂-【Hello系列直播課】第5期:分布式新聞客戶端
    發表于 06-23 20:08

    求一種基于DAYU200開發套件的分布式音樂播放器設計方案

    、音頻、視頻和攝像頭等功能,擁有豐富的擴展接口,支持多種視頻輸入輸出接口;配置雙千兆自適應RJ45以太網口,可滿足NVR、工業網關等多網口產品需求。分布式音樂播放器這里給大家分享一個樣例,分布
    發表于 09-08 17:22

    HarmonyOS測試技術與實戰-HarmonyOS分布式應用特征與挑戰

     HDC 2021華為開發者大會HarmonyOS測試技術與實戰-HarmonyOS分布式應用特征與挑戰
    的頭像 發表于 10-23 14:41 ?1654次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>HarmonyOS</b><b class='flag-5'>分布式</b>應用特征與挑戰

    HarmonyOS測試技術與實戰-分布式應用測試解決方案

    HDC 2021華為開發者大會HarmonyOS測試技術與實戰-HarmonyOS分布式應用測試解決方案
    的頭像 發表于 10-23 14:48 ?1563次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>分布式</b>應用測試解決方案

    HarmonyOS測試技術與實戰-分布式UI測試框架

    HDC 2021華為開發者大會 HarmonyOS測試技術與實戰-分布式UI測試框架演示
    的頭像 發表于 10-23 14:49 ?1357次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>分布式</b>UI測試框架

    HarmonyOS測試技術與實戰-分布式業務音視頻測試場景分類

     HDC 2021華為開發者大會 HarmonyOS測試技術與實戰-分布式業務音視頻測試場景分類
    的頭像 發表于 10-23 15:54 ?1695次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>分布式</b>業務音視頻測試場景分類

    HarmonyOS測試技術與實戰-分布式業務音頻體驗關注點

    HDC 2021華為開發者大會 HarmonyOS測試技術與實戰-分布式業務音頻體驗關注點
    的頭像 發表于 10-23 15:59 ?1172次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>分布式</b>業務音頻體驗關注點

    HarmonyOS測試技術與實戰-分布式業務音視頻體驗測試全景

    HDC 2021華為開發者大會 HarmonyOS測試技術與實戰-分布式業務音視頻體驗測試全景
    的頭像 發表于 10-23 16:03 ?1730次閱讀
    <b class='flag-5'>HarmonyOS</b>測試技術與<b class='flag-5'>實戰</b>-<b class='flag-5'>分布式</b>業務音視頻體驗測試全景

    鴻蒙版JS如何實現分布式仿抖音應用

    ?? 之前大家看過了 Java 版的《 HarmonyOS 分布式之仿抖音應用 》,現在講講 JS 如何實現分布式仿抖音應用,通過 JS 方式開發視頻
    的頭像 發表于 11-15 09:44 ?2341次閱讀

    HarmonyOS分布式應用上架問題分析

    HarmonyOS是新一代的智能終端操作系統,給開發者提供了設備發現、設備連接、跨設備調用等豐富的分布式API。隨著越來越多的開發者投入到Harmo
    的頭像 發表于 12-24 17:56 ?1881次閱讀
    <b class='flag-5'>HarmonyOS</b><b class='flag-5'>分布式</b>應用上架問題分析