#2023盲盒+码# OpenHarmony分布式屏幕开发参考示例 原创
【本文正在参加 2023「盲盒」+码有奖征文活动】 https://ost.51cto.com/posts/25284
简介
分布式屏幕功能早在OpenHarmony-3.1-Release就已经发布,详情可参考官方仓库的介绍。
本示例基于OpenHarmony自带的分布式屏幕相关API,并简单实现了屏幕镜像(或扩展)投屏相关应用功能。示例主要分为ArkTS版本和C++版本,ArkTS版本目前主要基于API9版本分布式屏幕功能的API进行开发,API详细说明可参考:@ohos.screen。开发者可自行基于API10开发,其中API10版本增加了停止屏幕镜像(或扩展)的API。
源码下载
源码详细说明及下载可参考
https://gitee.com/algoideas/DistributedScreen
效果预览
| 首页 | 菜单 | 设备管理 | 虚拟屏幕 | 
|---|---|---|---|
![]()  | 
![]()  | 
![]()  | 
![]()  | 
使用说明
应用界面中展示可以点击镜像投屏或扩展投屏,为了添加分布式设备,可以在菜单中进入设备管理页面进行添加。此外,开发者可创建虚拟屏幕,在本机预览投屏后的效果(开启虚拟屏幕会增加系统负荷)。
工程目录
entry/src/main/
|-- ets
|   |-- common
|   |   |-- Constant.ets
|   |   |-- Logger.ts             // 日志工具
|   |   |-- TitleBar.ets
|   |-- entryability
|   |   |-- EntryAbility.ets
|   |-- model
|   |   |-- RemoteDeviceModel.ets
|   |-- pages
|   |   |-- DeviceManager.ets
|   |   |-- FilterOption.ets
|   |   |-- Index.ets            // 首页
|   |   |-- ListDeviceView.ets
|   |-- utils
|       |-- Permission.ts
...
docs
|-- distributed_screen
|   |-- BUILD.gn
|   |-- include
|   |-- src
|       |-- dscreen_expand.cpp  // 扩展投屏C++实现
|       |-- dscreen_mirror.cpp  // 镜像投屏C++实现
具体实现
ArkTS实现
通过在IDE中创建工程,并调用@ohos.screen中相关API进行实现,主要实现如下:
makeScreenMirror() {
    logger.info('makeScreenMirror')
    let mainScreenId = 0;
    let mirrorScreenIds: Array<number> = [];
    if (this.enableVirtualScreen) {
      mirrorScreenIds.push(this.virtualScreenId);
    }
    for (let i = this.allScreens.length - 1; i >= 0; i--) {
      if ((this.allScreens[i].id != 0) && (this.allScreens[i].id != 1)) {
        mirrorScreenIds.push(this.allScreens[i].id);
      }
    }
    if (mirrorScreenIds.length == 0) {
      constant.showToast("No found Screen!")
      return;
    }
    try {
      logger.info('mirrorScreenIds:' + JSON.stringify(mirrorScreenIds))
      screen.makeMirror(mainScreenId, mirrorScreenIds, (err, data) => {
        if (err.code) {
          constant.showToast("Failed to makeMirror")
          console.error('Failed to set screen mirroring. Code: ' + JSON.stringify(err));
          return;
        }
        constant.showToast("Succeeded to makeMirror")
        console.info('Succeeded in setting screen mirroring. Data: ' + JSON.stringify(data));
      });
    } catch (exception) {
      constant.showToast("Failed to makeMirror")
      console.error('Failed to set screen mirroring. Code: ' + JSON.stringify(exception));
    }
  }
  makeScreenExpand() {
    logger.info('makeScreenExpand')
    let mainScreenId = 0;
    let startX = display.getDefaultDisplaySync().width;
    let startY = 0;
    let expandExpandOption: Array<screen.ExpandOption> = [];
    expandExpandOption.push({ screenId: mainScreenId, startX: 0, startY: 0 });
    if (this.enableVirtualScreen) {
      expandExpandOption.push({ screenId: this.virtualScreenId, startX: startX, startY: startY });
    }
    for (let i = this.allScreens.length - 1; i >= 0; i--) {
      if ((this.allScreens[i].id != 0) && (this.allScreens[i].id != 1)) {
        expandExpandOption.push({ screenId: this.allScreens[i].id, startX: startX, startY: startY });
      }
    }
    if (expandExpandOption.length <= 1) {
      constant.showToast("No found Screen!")
      return;
    }
    try {
      screen.makeExpand(expandExpandOption)
        .then((data) => {
          constant.showToast("Succeeded to makeExpand")
          console.info('Succeeded in expanding the screen. Data: ' + JSON.stringify(data));
        })
        .catch((err) => {
          constant.showToast("Failed to makeExpand")
          console.error('Failed to expand the screen. Code:' + JSON.stringify(err));
        });
    } catch (exception) {
      constant.showToast("Failed to makeExpand")
      console.error('Failed to expand the screen. Code: ' + JSON.stringify(exception));
    }
  }
主要使用到@ohos.screen中的相关API如下:
| 方法名称 | 描述 | 
|---|---|
| screen.getAllScreens | 获取所有的屏幕,可以是本地屏幕和其他设备的屏幕 | 
| screen.makeMirror | 将屏幕设置为镜像模式 | 
| screen.makeExpand | 将屏幕设置为扩展模式 | 
C/C++实现
基于分布式屏幕的C/C++相关API实现一个简单的程序,并增加BUILD.gn用于开发者自行编译验证参考。
说明:源码及BUILD.gn在OpenHarmony-3.2-Release版本有验证,OpenHarmony-4.x版本,需要修改BUILD.gn
参考源码和BUILD.gn内容如下。
- dscreen_mirror.cpp
 
#include "display.h"
#include "display_manager.h"
#include "screen.h"
#include "screen_client.h"
#include "screen_client_common.h"
#include "screen_manager.h"
// ... (省略部分源码)
using namespace std;
using namespace OHOS;
using namespace OHOS::DistributedHardware;
using namespace OHOS::Rosen;
using namespace OHOS::Media;
int main(int argc, char **argv)
{
    uint64_t remoteScreenId;
    std::string remoteScreenName;
    std::vector<uint64_t> mirrorIds;
    // 获取 screen 列表
    std::vector<sptr<Screen>> allScreens = ScreenManager::GetInstance().GetAllScreens();
    // 选择待镜像的远程目标 screen
    // IsReal 返回true时 代表为本地screen / false为远程screen
    // GetName 当返回screen的id 包含远程设备信息
    // GetId 返回screenId
    for (auto screen: allScreens) {
        mirrorIds.push_back(screen->GetId());
    }
    for (auto screen: allScreens) {
        if (!screen->IsReal()) {
          // 仅找第一个远程screen
          remoteScreenId = screen->GetId();
          remoteScreenName = screen->GetName();
          break;
        }
    }
    printf("[DscreenMirror] remoteScreenId : %lu.\n", remoteScreenId);
    printf("[DscreenMirror] remoteScreenName : %s.\n", remoteScreenName.c_str());
    // 选择待镜像的本地screen
    sptr<OHOS::Rosen::Display> defaultDisplay = OHOS::Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
    uint64_t localScreenId = defaultDisplay->GetScreenId();
    printf("[DscreenMirror] localScreenId : %lu...\n", localScreenId);
    // 调用接口并启动镜像投屏
    ScreenManager::GetInstance().MakeMirror(localScreenId, mirrorIds);
    printf("[DscreenMirror] Wait MakeMirror Stop.\n");
    getchar();
    // 停止
    std::vector<uint64_t> stopMirrorIds;
    stopMirrorIds.push_back(remoteScreenId);
    ScreenManager::GetInstance().RemoveVirtualScreenFromGroup(stopMirrorIds);
}
- dscreen_expand.cpp
 
#include "display.h"
#include "display_manager.h"
#include "screen.h"
#include "screen_client.h"
#include "screen_client_common.h"
#include "screen_manager.h"
// ... (省略部分源码)
int main(int argc, char **argv)
{
    uint64_t remoteScreenId;
    std::string remoteScreenName;
    // 获取 screen列表
    std::vector<sptr<Screen>> allScreens = ScreenManager::GetInstance().GetAllScreens();
    // 选择待镜像的远程目标 screen
    // IsReal 返回true时 代表为本地screen / false为远程screen
    // GetName 当返回screen的id 包含远程设备信息
    // GetId 返回screenId
    for (auto screen: allScreens) {
        if (!screen->IsReal()) {
          // 仅找第一个远程screen
          remoteScreenId = screen->GetId();
          remoteScreenName = screen->GetName();
          break;
        }
    }
    printf("[DscreenExpand] remoteScreenId : %lu.\n", remoteScreenId);
    printf("[DscreenExpand] remoteScreenName : %s.\n", remoteScreenName.c_str());
    // 选择待拓展的本地screen
    sptr<OHOS::Rosen::Display> defaultDisplay = OHOS::Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
    uint64_t localScreenId = defaultDisplay->GetScreenId();
    printf("[DscreenExpand] localScreenId : %lu...\n", localScreenId);
    // 拓展屏幕与本地屏幕的位置关系
    std::vector<ExpandOption> options = {
        {localScreenId, 0, 0},
        {remoteScreenId, defaultDisplay->GetWidth(), 0}
    };
    // 调用结构启动拓展投屏
    ScreenManager::GetInstance().MakeExpand(options);
    printf("[DscreenExpand] Wait MakeExpand Stop.\n");
    getchar();
    // 停止投屏
    std::vector<uint64_t> stopExpandIds;
    stopExpandIds.push_back(remoteScreenId);
    ScreenManager::GetInstance().RemoveVirtualScreenFromGroup(stopExpandIds);
    return 0;
}
- 
BUILD.gn(仅供参考)
import("//build/ohos.gni") import("//build/ohos_var.gni") import("//foundation/distributedhardware/distributed_screen/distributedscreen.gni") ohos_executable("dscreen_mirror") { sources = ["src/dscreen_mirror.cpp"] include_dirs = [ ".", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_source/include", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_source/include/callback", "//foundation/distributedhardware/distributed_hardware_fwk/common/utils/include", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_sink/include", "//foundation/distributedhardware/distributed_screen/common/include/", "//foundation/distributedhardware/distributed_screen/services/screenclient/include/", ] cflags = [ "-Wall", "-Werror", "-Wno-cast-qual", "-Wno-pointer-arith", "-Wno-unused-parameter", "-Wno-unused-variable", "-Wno-delete-incomplete", ] deps = [ "${common_path}:distributed_screen_utils", "${interfaces_path}/innerkits/native_cpp/screen_sink:distributed_screen_sink_sdk", "${interfaces_path}/innerkits/native_cpp/screen_source:distributed_screen_source_sdk", "${services_path}/screenclient:distributed_screen_client", "${windowmanager_path}/dm:libdm", "${windowmanager_path}/wm:libwm", "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", "//foundation/communication/dsoftbus/adapter:softbus_adapter", "//foundation/communication/dsoftbus/sdk:softbus_client", "//foundation/graphic/graphic_2d:libsurface", "//foundation/graphic/graphic_2d/rosen/modules/2d_graphics:2d_graphics", "//foundation/graphic/graphic_2d/rosen/modules/render_service_base/src/platform:platform", "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", "//foundation/systemabilitymgr/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", ] external_deps = [ "hiviewdfx_hilog_native:libhilog", "multimedia_player_framework:media_client", ] install_enable = true install_images = [ "vendor" ] part_name = "rockchip_products" # 根据实际编译的产品调整part_name } ohos_executable("dscreen_expand") { sources = ["src/dscreen_expand.cpp"] include_dirs = [ ".", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_source/include", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_source/include/callback", "//foundation/distributedhardware/distributed_hardware_fwk/common/utils/include", "//foundation/distributedhardware/distributed_screen/interfaces/innerkits/native_cpp/screen_sink/include", "//foundation/distributedhardware/distributed_screen/common/include/", "//foundation/distributedhardware/distributed_screen/services/screenclient/include/", ] cflags = [ "-Wall", "-Werror", "-Wno-cast-qual", "-Wno-pointer-arith", "-Wno-unused-parameter", "-Wno-unused-variable", "-Wno-delete-incomplete", ] deps = [ "${common_path}:distributed_screen_utils", "${interfaces_path}/innerkits/native_cpp/screen_sink:distributed_screen_sink_sdk", "${interfaces_path}/innerkits/native_cpp/screen_source:distributed_screen_source_sdk", "${services_path}/screenclient:distributed_screen_client", "${windowmanager_path}/dm:libdm", "${windowmanager_path}/wm:libwm", "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", "//foundation/communication/dsoftbus/adapter:softbus_adapter", "//foundation/communication/dsoftbus/sdk:softbus_client", "//foundation/graphic/graphic_2d:libsurface", "//foundation/graphic/graphic_2d/rosen/modules/2d_graphics:2d_graphics", "//foundation/graphic/graphic_2d/rosen/modules/render_service_base/src/platform:platform", "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", "//foundation/systemabilitymgr/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", ] external_deps = [ "hiviewdfx_hilog_native:libhilog", "multimedia_player_framework:media_client", ] install_enable = true install_images = [ "vendor" ] part_name = "rockchip_products" # 根据实际编译的产品调整part_name } group("distributed_screen") { deps = [ ":dscreen_mirror", ":dscreen_expand", ] } 
相关权限
默认添加以下权限
| 权限名称 | 描述 | 
|---|---|
| ohos.permission.CAPTURE_SCREEN | 允许应用截取屏幕图像 | 
| ohos.permission.DISTRIBUTED_DATASYNC | 允许不同设备间的数据交换 | 
| ohos.permission.GET_BUNDLE_INFO | 允许应用查询其他应用的信息。该权限仅适用于三方应用。 | 
| ohos.permission.INTERNET | 允许使用Internet网络 | 
说明:应用需采用系统签名,部分权限可根据是否使用相关模块进行删除
视频演示
【OpenHarmony分布式屏幕,屏幕镜像功能体验】 https://www.bilibili.com/video/BV1dr4y1R74p/?share_source=copy_web&vd_source=5130b770dd48ecf758ca620cb4b9e34b
























