OpenHarmony分布式屏幕开发参考示例

简介

分布式屏幕功能早在OpenHarmony-3.1-Release就已经发布。

本示例基于OpenHarmony自带的分布式屏幕相关API,并简单实现了屏幕镜像(或扩展)投屏相关应用功能。示例主要分为ArkTS版本和C++版本,ArkTS版本目前主要基于API9版本分布式屏幕功能的API进行开发。开发者可自行基于API10开发,其中API10版本增加了停止屏幕镜像(或扩展)的API。

效果预览

首页

菜单

设备管理

*虚拟屏幕

应用界面中展示可以点击镜像投屏或扩展投屏,为了添加分布式设备,可以在菜单中进入设备管理页面进行添加。此外,开发者可创建虚拟屏幕,在本机预览投屏后的效果(开启虚拟屏幕会增加系统负荷)。

工程目录

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中创建工程,并调用https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/apis/js-apis-screen.md中相关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));
    }
  }

主要使用到https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/apis/js-apis-screen.md 中的相关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内容如下。

  1. 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);

}
  1. 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;
}
  1. 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网络

说明:应用需采用系统签名,部分权限可根据是否使用相关模块进行删除

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容