HarmonyOS 鸿蒙Next中webview能否打开屏幕共享

HarmonyOS 鸿蒙Next中webview能否打开屏幕共享 我现在使用webview打开一个页面,页面中使用webrtc实现视频会议,如果此时我想在页面共享手机屏幕,即录屏为mediastream发给视频会议的其它参与者,有没有权限问题?如何实现?

6 回复

【背景知识】:当H5中的JavaScript代码调用getDisplayMedia尝试进行屏幕捕获时,系统会触发onScreenCaptureRequest回调。

【解决方案】:在H5调用getDisplayMedia发起屏幕共享,触发Web组件中onScreenCaptureRequest回调,在回调中通过event.handler.grant完成屏幕捕获权限申请。

Index.ets界面示例参考如下:

import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl } from '@kit.AbilityKit';

const AtManager = abilityAccessCtrl.createAtManager();

@Entry
@Component
struct Index {
  controller: webview.WebviewController = new webview.WebviewController();
  private context: Context = this.getUIContext().getHostContext() as Context;
  aboutToAppear() {
    AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.MICROPHONE'])
      .then(data => {
        let result: Array<number> = data.authResults;
        let hasPermissions1 = true;
        result.forEach(item => {
          if (item === -1) {
            hasPermissions1 = false;
          }
        })
        if (hasPermissions1) {
          console.info('hasPermissions1')
        } else {
          console.info('not hasPermissions1')
        }
      }).catch((error:BusinessError) => {});
  }
  build() {
    Column() {
      Row() {
        Button('refresh')
          .onClick(() => {
            this.controller.refresh()
          })
      }
      Row() {
        Web({
          src: $rawfile('demo.html'), controller: this.controller
        })
          .domStorageAccess(true)
          .databaseAccess(true)
          .imageAccess(true)
          .onlineImageAccess(true)
          .javaScriptAccess(true)
          .onScreenCaptureRequest((event) => {
            if (!event) {
              return;
            }
            console.info('on onScreenCaptureRequest Origin:' + event.handler.getOrigin());
            AlertDialog.show({
              title: 'title',
              message: '请求权限' + event.handler.getOrigin(),
              confirm: {
                value: 'ok',
                action: () => {
                  event.handler.grant({ captureMode: WebCaptureMode.HOME_SCREEN });
                }
              },
              cancel: () => {
                event.handler.deny();
              }
            })
          })
      }
    }
  }
}

demo.html界面示例参考如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #video {
        width: 200px;
        height: 400px;
        border: 2px solid red;
    }
  </style>
</head>
<body>
<script>
  function share() {
    navigator.mediaDevices.getDisplayMedia({video: true}).then(stream => {
        // 创建一个video元素
        var video = document.getElementById('video');
        // 设置video元素的srcObject为获取到的流
        video.srcObject = stream;
        console.info(stream, video)
        // 播放视频
        video.play();
        }).catch(res => {
            document.getElementById('res').innerText = res
        })
    }
    var script = document.createElement("script")
    script.src = "https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js"
    script.onload = function(){
        window.vconsole = new VConsole()
    }
    document.body.appendChild(script)
</script>
<button onclick="share()">投屏</button>
<video id="video"></video>
<span id="res"></span>
</body>
</html>

参考文档:Web组件如何实现屏幕共享功能-行业常见问题-教育类行业实践-行业实践 - 华为HarmonyOS开发者

更多关于HarmonyOS 鸿蒙Next中webview能否打开屏幕共享的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS中使用WebView加载的Web页面通过WebRTC实现屏幕共享时,需要处理以下权限:

屏幕捕获权限:必须声明ohos.permission.CAPTURE_SCREEN权限,用于允许应用捕获屏幕内容。

动态权限申请:用户首次触发屏幕共享时,需通过弹窗动态申请权限。

在module.json5中添加屏幕捕获权限:

// module.json5
"requestPermissions": [
  {
    "name": "ohos.permission.CAPTURE_SCREEN",
    "reason": "$string:reason_for_screen_capture",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "always"
    }
  }
]

在ArkTS中监听onScreenCaptureRequest回调,动态申请权限并响应用户操作:

// WebComponent.ets
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();

  aboutToAppear() {
    // 设置屏幕共享请求回调
    this.controller.onScreenCaptureRequest((event) => {
      // 弹出确认弹窗
      AlertDialog.show({
        title: '屏幕共享请求',
        message: '允许应用录制屏幕吗?',
        primaryButton: {
          value: '允许',
          action: () => {
            event.handler.grant(); // 授权屏幕捕获
          }
        },
        secondaryButton: {
          value: '拒绝',
          action: () => {
            event.handler.deny(); // 拒绝请求
          }
        }
      });
    });
  }

  build() {
    Column() {
      Web({ controller: this.controller })
        .width('100%')
        .height('100%')
        .onScreenCaptureRequest((event) => {})
        .src('https://your-webrtc-page.html')
    }
  }
}

// 前端JavaScript代码
navigator.mediaDevices.getDisplayMedia({ video: true })
  .then(stream => {
    const videoElement = document.getElementById('screenShareVideo');
    videoElement.srcObject = stream;
    // 将stream发送给其他WebRTC参与者
    sendStreamToPeer(stream);
  })
  .catch(error => {
    console.error('屏幕共享失败:', error);
  });

当H5页面调用navigator.mediaDevices.getDisplayMedia发起屏幕共享时,系统会触发onScreenCaptureRequest回调。你需在此回调中通过event.handler.grant()主动授予权限,无需在module.json5中预先声明特殊权限。

实现步骤

1/在ETS文件中注册onScreenCaptureRequest回调函数,示例:

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  aboutToAppear() {
    // 注册屏幕共享请求回调
    this.controller.setOnScreenCaptureRequest((event) => {
      // 授权屏幕捕获
      event.handler.grant();
      // 可在此处添加用户确认逻辑(如弹窗提示)
    });
  }
  build() {
    Column() {
      Web({ 
        controller: this.controller, 
        src: "www.example.com" 
      })
    }
  }
}

2/在HTML页面中使用WebRTC标准API发起屏幕共享:

<button onclick="startScreenShare()">共享屏幕</button>
<video id="screenVideo" autoplay></video>
<script>
async function startScreenShare() {
  try {
    const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
    const videoElement = document.getElementById('screenVideo');
    videoElement.srcObject = stream;
  } catch (error) {
    console.error('屏幕共享失败:', error);
  }
}
</script>

Web组件是可以实现屏幕共享功能的。

需要这两个权限就可以了

"requestPermissions":[
    {
      "name" : "ohos.permission.CAMERA",
      "reason": "$string:reason_for_camera",
      "usedScene": {
        "abilities": [
          "EntryAbility"
        ],
        "when":"inuse"
      }
    },
    {
      "name" : "ohos.permission.MICROPHONE",
      "reason": "$string:reason_for_microphone",
      "usedScene": {
        "abilities": [
          "EntryAbility"
        ],
        "when":"inuse"
      }
    }
  ]

在H5调用getDisplayMedia发起屏幕共享,触发Web组件中onScreenCaptureRequest回调,在回调中通过event.handler.grant完成屏幕捕获权限申请,示例代码如下:

import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl } from '@kit.AbilityKit';

const AtManager = abilityAccessCtrl.createAtManager();

@Entry
@Component
struct Index {
  controller: webview.WebviewController = new webview.WebviewController();
  private context: Context = this.getUIContext().getHostContext() as Context;
  aboutToAppear() {
    AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.MICROPHONE'])
      .then(data => {
        let result: Array<number> = data.authResults;
        let hasPermissions1 = true;
        result.forEach(item => {
          if (item === -1) {
            hasPermissions1 = false;
          }
        })
        if (hasPermissions1) {
          console.info("hasPermissions1")
        } else {
          console.info("not hasPermissions1")
        }
      }).catch((error:BusinessError) => {});
  }
  build() {
    Column() {
      Row() {
        Button('refresh')
          .onClick(() => {
            this.controller.refresh()
          })
      }
      Row() {
        Web({
          src: $rawfile('demo.html'), controller: this.controller
        })
          .domStorageAccess(true)
          .databaseAccess(true)
          .imageAccess(true)
          .onlineImageAccess(true)
          .javaScriptAccess(true)
          .onScreenCaptureRequest((event) => {
            if (!event) {
              return;
            }
            console.info("on onScreenCaptureRequest Origin:" + event.handler.getOrigin());
            AlertDialog.show({
              title: 'title',
              message: '请求权限' + event.handler.getOrigin(),
              confirm: {
                value: 'ok',
                action: () => {
                  event.handler.grant({ captureMode: WebCaptureMode.HOME_SCREEN });
                }
              },
              cancel: () => {
                event.handler.deny();
              }
            })
          })
      }
    }
  }
}

demo.html代码如下:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #video {
            width: 200px;
            height: 400px;
            border: 2px solid red;
        }
    </style>
</head>
<body>
<script>
    function share() {
        navigator.mediaDevices.getDisplayMedia({video: true}).then(stream => {
            // 创建一个video元素
            var video = document.getElementById('video');
            // 设置video元素的srcObject为获取到的流
            video.srcObject = stream;
            console.info(stream, video)
            // 播放视频
            video.play();
            }).catch(res => {
                document.getElementById('res').innerText = res
            })
        }
        var script = document.createElement("script")
        script.src = "https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js"
        script.onload = function(){
            window.vconsole = new VConsole()
        }
        document.body.appendChild(script)
</script>
<button onclick="share()">投屏</button>
<video id="video"></video>
<span id="res"></span>
</body>
</html>

HarmonyOS NEXT的WebView组件基于系统级能力构建,支持调用屏幕共享功能。通过WebRTC标准接口实现,需在应用中配置相应权限并调用系统媒体投影服务。具体实现依赖ArkTS/ArkUI框架的API调用,无需依赖外部浏览器内核。

在HarmonyOS Next中,WebView默认不支持直接通过WebRTC进行屏幕共享,因为涉及系统权限和隐私保护机制。需要通过HarmonyOS的屏幕捕获API(如ScreenCapture)获取屏幕数据,转换为MediaStream后注入到WebView的WebRTC上下文中。具体步骤包括:

  1. 申请ohos.permission.CAPTURE_SCREEN权限,并在代码中动态请求用户授权。
  2. 使用@ohos.screen模块的createScreenCapture方法获取屏幕数据流。
  3. 将获取的屏幕数据转换为WebRTC可识别的MediaStream格式(可能需要通过Native侧桥接)。
  4. 通过WebView的JavaScript接口(如runJavaScript)将MediaStream传递到页面中,供WebRTC使用。

注意:需确保WebView与原生能力交互的桥梁(如WebJavaScriptProxy)已正确配置,且屏幕共享功能需在真机调试(模拟器可能受限)。权限申请和数据处理需严格遵循HarmonyOS的安全规范。

回到顶部