WebView全屏API

WKPreferences.isElementFullscreenEnabled #

核心功能 #

isElementFullscreenEnabled 是 WKPreferences 的布尔属性,控制 WebView 中的 JavaScript 是否可以调用 HTML5 全屏 API。

技术规格 #

Swift 配置 #

let config = WKWebViewConfiguration()
config.preferences.isElementFullscreenEnabled = true

let webView = WKWebView(frame: view.bounds, configuration: config)

JavaScript 全屏 API #

启用后,网页可以使用以下 API:

// 请求全屏
element.webkitRequestFullscreen();

// 退出全屏
document.webkitExitFullscreen();

// 检查全屏状态
document.webkitFullscreenElement;

// 全屏变化事件
document.addEventListener('webkitfullscreenchange', function() {
    if (document.webkitFullscreenElement) {
        console.log('进入全屏');
    } else {
        console.log('退出全屏');
    }
});

完整 HTML 示例 #

以下是一个可以直接在启用了 isElementFullscreenEnabled 的 WebView 中运行的示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebView 全屏 API 演示</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, sans-serif;
            margin: 20px;
            background: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .demo-box {
            width: 300px;
            height: 200px;
            background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
            border-radius: 10px;
            margin: 20px auto;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            transition: transform 0.2s;
        }
        
        .demo-box:hover {
            transform: scale(1.05);
        }
        
        .demo-box:-webkit-full-screen {
            width: 100vw;
            height: 100vh;
            border-radius: 0;
            font-size: 48px;
            background: linear-gradient(45deg, #ff6b6b 0%, #feca57 50%, #48dbfb 100%);
        }
        
        .button {
            background: #007AFF;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 6px;
            font-size: 16px;
            cursor: pointer;
            margin: 10px;
            transition: background 0.2s;
        }
        
        .button:hover {
            background: #0051D0;
        }
        
        .button:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        
        .status {
            margin: 20px 0;
            padding: 15px;
            background: #f8f8f8;
            border-radius: 6px;
            border-left: 4px solid #007AFF;
        }
        
        .error {
            border-left-color: #FF3B30;
            background: #fff5f5;
        }
        
        video {
            width: 100%;
            max-width: 400px;
            height: auto;
            border-radius: 10px;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>WebView 全屏 API 演示</h1>
        
        <div class="status" id="status">
            状态: 等待操作
        </div>
        
        <h2>1. 元素全屏演示</h2>
        <div class="demo-box" id="demoBox" onclick="toggleFullscreen(this)">
            点击进入全屏
        </div>
        
        <button class="button" onclick="enterFullscreen()">进入全屏</button>
        <button class="button" onclick="exitFullscreen()">退出全屏</button>
        
        <h2>2. 视频全屏演示</h2>
        <video controls id="demoVideo">
            <source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
            您的浏览器不支持视频标签。
        </video>
        
        <button class="button" onclick="videoFullscreen()">视频全屏</button>
        
        <h2>3. API 支持检测</h2>
        <div id="apiSupport"></div>
        
        <h2>4. 实时状态</h2>
        <div id="realTimeStatus">
            <p>当前全屏元素: <span id="fullscreenElement">无</span></p>
            <p>全屏可用: <span id="fullscreenEnabled">检测中...</span></p>
        </div>
    </div>

    <script>
        // 状态显示
        function updateStatus(message, isError = false) {
            const status = document.getElementById('status');
            status.textContent = '状态: ' + message;
            status.className = 'status' + (isError ? ' error' : '');
        }
        
        // 检测全屏 API 支持
        function checkFullscreenSupport() {
            const support = document.getElementById('apiSupport');
            let html = '<ul>';
            
            if (document.documentElement.webkitRequestFullscreen) {
                html += '<li>✅ webkitRequestFullscreen 支持</li>';
            } else {
                html += '<li>❌ webkitRequestFullscreen 不支持</li>';
            }
            
            if (document.webkitExitFullscreen) {
                html += '<li>✅ webkitExitFullscreen 支持</li>';
            } else {
                html += '<li>❌ webkitExitFullscreen 不支持</li>';
            }
            
            if (document.webkitFullscreenEnabled !== undefined) {
                html += '<li>✅ webkitFullscreenEnabled: ' + document.webkitFullscreenEnabled + '</li>';
            } else {
                html += '<li>❌ webkitFullscreenEnabled 不支持</li>';
            }
            
            html += '</ul>';
            support.innerHTML = html;
        }
        
        // 更新实时状态
        function updateRealTimeStatus() {
            document.getElementById('fullscreenElement').textContent = 
                document.webkitFullscreenElement ? document.webkitFullscreenElement.tagName : '无';
            document.getElementById('fullscreenEnabled').textContent = 
                document.webkitFullscreenEnabled ? '是' : '否';
        }
        
        // 切换全屏
        function toggleFullscreen(element) {
            if (document.webkitFullscreenElement) {
                exitFullscreen();
            } else {
                enterFullscreenForElement(element);
            }
        }
        
        // 进入全屏
        function enterFullscreen() {
            enterFullscreenForElement(document.getElementById('demoBox'));
        }
        
        // 为特定元素进入全屏
        function enterFullscreenForElement(element) {
            if (element.webkitRequestFullscreen) {
                element.webkitRequestFullscreen();
                updateStatus('正在进入全屏...');
            } else {
                updateStatus('全屏 API 不受支持', true);
            }
        }
        
        // 退出全屏
        function exitFullscreen() {
            if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
                updateStatus('正在退出全屏...');
            } else {
                updateStatus('退出全屏 API 不受支持', true);
            }
        }
        
        // 视频全屏
        function videoFullscreen() {
            const video = document.getElementById('demoVideo');
            if (video.webkitRequestFullscreen) {
                video.webkitRequestFullscreen();
                updateStatus('视频进入全屏...');
            } else {
                updateStatus('视频全屏不支持', true);
            }
        }
        
        // 全屏状态变化监听
        document.addEventListener('webkitfullscreenchange', function() {
            updateRealTimeStatus();
            if (document.webkitFullscreenElement) {
                updateStatus('已进入全屏模式');
            } else {
                updateStatus('已退出全屏模式');
            }
        });
        
        // 全屏错误监听
        document.addEventListener('webkitfullscreenerror', function() {
            updateStatus('全屏操作失败', true);
        });
        
        // 键盘事件监听(ESC 退出全屏)
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape' && document.webkitFullscreenElement) {
                exitFullscreen();
            }
        });
        
        // 页面加载完成后检测支持
        document.addEventListener('DOMContentLoaded', function() {
            checkFullscreenSupport();
            updateRealTimeStatus();
            updateStatus('页面加载完成,可以开始测试');
        });
        
        // 定时更新状态
        setInterval(updateRealTimeStatus, 1000);
    </script>
</body>
</html>

重要注意事项 #

屏幕旋转问题 #

  • 在仅支持竖屏的iOS应用中,启用此选项会禁用视频全屏时的屏幕旋转
  • 如果需要视频旋转功能,考虑保持 false 并使用原生视频控件

安全限制 #

  • 必须由用户手势触发(点击、触摸等)
  • 不能通过定时器或自动脚本调用

macOS 差异 #

  • macOS 上此选项是视频全屏的必要条件
  • iOS 上视频全屏可以独立于此选项工作

最佳实践 #

// 根据应用场景选择
if needsAdvancedWebFeatures {
    config.preferences.isElementFullscreenEnabled = true
} else {
    // 保持默认 false,避免意外的旋转问题
    config.preferences.isElementFullscreenEnabled = false
}

错误处理 #

// 检测是否支持全屏
if (!document.documentElement.webkitRequestFullscreen) {
    console.log('设备不支持全屏 API');
    // 显示替代方案
}

// 监听全屏错误
document.addEventListener('webkitfullscreenerror', function(e) {
    console.error('全屏操作失败:', e);
    // 用户友好的错误提示
});

本文档基于 Apple 官方文档和实际测试编写,适用于 iOS 15.4+ 开发。