你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

快速入门:向 WebView 客户端应用添加视频通话

Webview 技术是一种可嵌入的浏览器,可直接集成到本机移动应用程序中。 如果希望直接开发 Azure 通信服务呼叫应用程序作为本机 Android 应用程序,除了使用 Azure 通信呼叫 Android SDK 外,还可以在 Android WebView 上使用 Azure 通信呼叫 Web SDK。 本快速入门介绍如何在 Android WebView 环境中运行使用 Azure 通信呼叫 Web SDK 开发的 Web 应用。

先决条件

重要

本文中所述的功能目前提供公共预览版。 此预览版在提供时没有附带服务级别协议,我们不建议将其用于生产工作负荷。 某些功能可能不受支持或者受限。 有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款

本快速入门指南假定你已安装了 Android WebView 应用程序。 如果没有,可以下载 WebViewQuickstart 示例应用

如果使用 WebViewQuickstart 示例应用,则所有必要的配置和权限处理均已实施到位。 可以跳到已知问题。 你所要做的就是将 MainActivity 中的 defaultUrl 更新为你部署的调用 Web 应用程序的 url 并构建该应用程序。

将权限添加到应用程序清单

若要请求进行呼叫所需的权限,必须在应用程序清单中声明权限。 (app/src/main/AndroidManifest.xml) 请确保向应用程序清单中添加了以下权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />

在运行时请求权限

向应用程序清单添加权限还不够。 还必须在运行时请求危险权限才能访问相机和麦克风。

必须调用 requestPermissions() 并重写 onRequestPermissionsResult。 除了应用权限外,你还需通过重写 WebChromeClient.onPermissionRequest 来处理浏览器权限请求

WebViewQuickstart 示例应用还演示如何处理来自浏览器的权限请求以及如何在运行时请求应用权限。

WebView 配置

Azure 通信呼叫 Web SDK 需要启用 JavaScript。 在某些情况下,我们在 Android WebView 环境中看到 play() can only be initiated by a user gesture 错误消息,并且用户无法听到传入的音频。 因此,建议将 MediaPlaybackRequiresUserGesture 设置为 false。

WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setMediaPlaybackRequiresUserGesture(false);

已知问题

MediaDevices.enumerateDevices() API 返回空标签

这是 Android WebView 上的已知问题。 这个将影响 Web SDK 中的以下 API:

  • DeviceManager.getCameras()

  • DeviceManager.getMicrophones()

  • DeviceManager.getSpeakers()(如果设备支持扬声器枚举)

    结果对象中 name 字段的值将是一个空字符串。 这个不会影响视频通话中的流式传输功能,但应用程序用户将无法知道他们选择用于发送视频的相机标签。 若要提供更好的 UI 体验,可以在 Web 应用程序中使用以下解决方法来获取设备标签,并通过 deviceId 映射标签。

    尽管无法从 MediaDevices.enumerateDevices() 获取设备标签,但可以从 MediaStreamTrack 获取标签。 此解决方法要求 Web 应用程序使用 getUserMedia 获取流并映射 deviceId。 如果 Android 设备上有多个头和麦克风,可能需要一段时间才能收集标签。

async function getDeviceLabels() {
    const devices = await navigator.mediaDevices.enumerateDevices();
    const result = {};
    for (let i = 0; i < devices.length; i++) {
        const device = devices[i];
        if(device.kind != 'audioinput' && device.kind != 'videoinput') continue;
        if(device.label) continue;
        const deviceId = device.deviceId;
        const deviceConstraint = {
            deviceId: {
                exact: deviceId
            }
        };		
        const constraint = (device.kind == 'audioinput') ?
                { audio: deviceConstraint } :
                { video: deviceConstraint };
		try {
            const stream =  await navigator.mediaDevices.getUserMedia(constraint);
            stream.getTracks().forEach(track => {
                let namePrefix = '';
                if (device.kind == 'audioinput') {
                    namePrefix = 'microphone:';
                } else if(device.kind == 'videoinput') {
                    namePrefix = 'camera:';
                }
                if (track.label === '' && deviceId == 'default') {
                    result[namePrefix + deviceId] = 'Default';
                } else {
                    result[namePrefix + deviceId] = track.label;
                }
                track.stop();
            });
		} catch(e) {
		    console.error(`get stream failed: ${device.kind} ${deviceId}`, e);
		}
    }
    return result;
}

Screenshot of getDeviceLabels() result.

获取 deviceId 和标签之间的映射后,可以使用它来将标签与 DeviceManager.getCameras()DeviceManager.getMicrophones() 中的 id 相关联

Screenshot showing the device name workaround.

iOS WKWebView 允许将 Web 内容无缝嵌入到应用 UI 中。 如果要在 iOS 上开发 Azure 通信服务呼叫应用程序,除了使用 Azure 通信呼叫 iOS SDK 之外,还可以使用具有 iOS WKWebView 的 Azure 通信呼叫 Web SDK。 本快速入门介绍如何在 iOS WKWebView 环境中运行使用 Azure 通信呼叫 Web SDK 开发的 webapps。

先决条件

重要

本文中所述的功能目前提供公共预览版。 此预览版在提供时没有附带服务级别协议,我们不建议将其用于生产工作负荷。 某些功能可能不受支持或者受限。 有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款

本快速入门指南假定你熟悉 iOS 应用程序开发。 我们将在为 Azure 通信服务呼叫 SDK 开发 iOS WKWebView 应用程序时提及必要的配置和提示。

在 Info.plist 中添加键

若要进行视频通话,请确保将以下键添加到 Info.plist 中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSMicrophoneUsageDescription</key>
	<string>Camera access is required to make a video call</string>
	<key>NSCameraUsageDescription</key>
	<string>Microphone access is required to make an audio call</string>
</dict>
</plist>

处理权限提示

在 iOS Safari 上,用户可能会比在其他平台上更频繁地看到权限提示。 这是因为 Safari 不会长时间保留权限,除非获得了流。

WKWebView 提供了一种使用 WKUIDelegate.webView 处理浏览器权限提示的方法。 此 API 仅在 iOS 15.0+ 上可用。

下面是一个示例。 在此示例中,浏览器权限是在 decisionHandler 中授予的,因此用户在授予应用权限后不会看到浏览器权限提示。

import WebKit
import SwiftUI

struct WebView: UIViewRepresentable {
    private(set) var url: URL
    private var webView: WKWebView

    init(url: String) {
        self.url = URL(string: url)!

        let prefs = WKWebpagePreferences()
        prefs.allowsContentJavaScript = true
        prefs.preferredContentMode = .recommended

        let configuration = WKWebViewConfiguration()
        configuration.defaultWebpagePreferences = prefs
        configuration.allowsInlineMediaPlayback = true
        configuration.mediaTypesRequiringUserActionForPlayback = []
        let webView = WKWebView(frame: CGRect(), configuration: configuration)
        self.webView = webView
    }

    class Coordinator: NSObject, WKUIDelegate {
        let parent: WebView
        init(_ parent: WebView) {
            self.parent = parent
        }
        func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) {
            decisionHandler(WKPermissionDecision.grant)
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView {
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.uiDelegate = context.coordinator
        uiView.load(URLRequest(url: self.url))
    }
}

WebView 配置

Azure 通信呼叫 Web SDK 需要启用 JavaScript。

allowsInlineMediaPlayback 也必须是 true

let prefs = WKWebpagePreferences()
prefs.allowsContentJavaScript = true
prefs.preferredContentMode = .recommended

let configuration = WKWebViewConfiguration()
configuration.defaultWebpagePreferences = prefs
configuration.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: CGRect(), configuration: configuration)

已知问题

当应用进入后台时麦克风静音

当用户锁定屏幕或者当 WkWebView 应用进入后台时,麦克风输入会被静音,直到应用返回到前台。 这是 iOS WkWebView 系统行为,Azure 通信服务呼叫 Web SDK 不会将麦克风静音。

应用进入后台后不久连接断开

这也是 iOS 应用行为。 当我们切换到其他音频/视频应用时,连接将在大约 30 秒后断开。 如果应用仅在后台停留很短时间,这不是问题。 当应用返回前台时,通话会恢复。 如果应用在后台停留的时间较长,服务器会认为用户不在,就会将用户从参与者列表中移除。 在这种情况下,当用户将 WkWebView 应用切换回前台时,通话会中断,不会恢复。

后续步骤

有关详细信息,请参阅以下文章: