惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

博客园 - H5开发技术

安卓手机系统WebView内核更新指南 C#强签名实战:恒盾混淆加密大师重签名教程 HTML打包APK自定义User Agent设置教程 HTML一键打包APK:实现安卓打印功能 HTML打包EXE退出密码配置详细教程 HTML打包APK实现拍照、录像、录音和文件选择 HTML打包APK:二维码扫码功能实现笔记 C#混淆选项选择指南:使用合适的加密方式保护C#代码 C#混淆随机种子详解与恒盾加密大师使用教程 在.NET项目集成混淆加密:自动化保护DLL和EXE 恒盾C#混淆加密大师1.5.0:EXE保护增强与.NET 10适配 EXE加密原生内核使用:解决系统环境兼容问题 EXE一机一码加密后无法运行?兼容模式使用指南 HTML打包EXE多实例共享进程:多开加速与状态共享 免费绿色JS混淆加密工具 - 离线版本分享 5分钟学会HTML打包AP本地文件加密 HTML打包EXE后桌面图标不更新?刷新缓存方法 HTML打包EXE 2.3.0更新详解(附最新版本下载地址-含免费内核) HTML打包EXE离线一机一码新增试用功能(附2026最新版下载地址) PDF加密转APK大师最新版本1.1.0更新, 附快速上手教程 极速图标设计大师 — 不会 PS 也能 3 秒做出专业 App 图标(附免费下载) HTML打包EXE导出配置文件教程:使用 .html2exe 文件备份、迁移和复用打包设置 BZ全景漫游可视化编辑器: 零代码制作360全景漫游H5作品 苹果手机快速开启开发者模式教程(iOS 16+) Windows平台生成苹果开发者测试证书教程 苹果签名安装助手 - 用 Apple ID 一键生成开发者测试证书教程 HTML打包EXE使用附件功能调用外部程序扩展你的EXE - 附实战演练实现录频功能 HTML打包EXE安装包配置教程 - 自定义安装目录和桌面快捷方式名 HTML打包/EXE加密的一机一码网络验证常见问题汇总 HTML打包EXE透明窗口教程 - 打造炫酷无边框透明桌面应用
HTML打包APK实现视频全屏播放方法
H5开发技术 · 2026-08-10 · via 博客园 - H5开发技术

HTML页面可以通过 video 标签播放网络和本地视频,结合浏览器全屏接口实现最大化播放,并在全屏时锁定横屏获得更好的观看体验。完成页面代码后,再通过HTML一键打包APK工具配置网络权限,即可生成支持视频播放和全屏播放的安卓APP。

工具官网:HTML一键打包APK工具官网

创建视频播放页面

在HTML项目入口目录中创建 index.html,页面包含视频播放区、最大化按钮和地址加载入口。

  • 视频播放:使用 video 标签加载网络或本地视频,并添加 playsinline 系列属性保证在APP内联播放。
  • 最大化按钮:调用浏览器全屏接口,将播放器切换到全屏状态,兼容打包后APP的WebView环境。
  • 横屏锁定:进入全屏时自动锁定为横屏,退出全屏时恢复竖屏。
  • 地址加载:支持输入视频直链地址,加载不同的视频进行测试。

视频标签需要添加 playsinlinewebkit-playsinlinex5-playsinline 属性,避免在部分WebView中点击播放时强制跳转系统播放器:

<video playsinline webkit-playsinline x5-playsinline src="video.mp4"></video>

最大化按钮通过全屏接口把播放器容器切换到全屏,并同时处理标准接口和 webkit 前缀接口,保证在打包后的WebView中正常工作:

if (shell.requestFullscreen) shell.requestFullscreen();
else if (shell.webkitRequestFullscreen) shell.webkitRequestFullscreen();

打包成APK

复制上述HTML代码, 保存到video-test.html文件中, 然后HTML一键打包APK工具中载入该文件, 然后点击打包生成APP即可

把html打包成apk

安装并测试功能

将生成的APK安装到安卓手机,依次测试页面中的各项功能:

  1. 打开APP,确认默认视频可以正常加载,点击“播放 / 暂停”按钮可以控制播放。
  2. 点击右上角的最大化按钮,确认播放器进入全屏状态,按钮图标切换为还原样式。
  3. 在全屏状态下旋转手机,确认画面锁定为横屏;退出全屏后确认恢复竖屏显示。
  4. 在地址栏中输入其他mp4直链地址并点击“加载”,确认可以切换播放不同的视频。
  5. 拖动进度条,确认视频可以从指定位置继续播放。

为了获得最好的兼容性,视频建议使用H.264视频编码和AAC音频编码的mp4文件。部分WebView版本对HEVC、VP9等编码的支持不一致,可能出现只有声音没有画面的情况。

如果点击最大化按钮没有进入全屏,请先确认APP系统设置中没有限制横屏,并检查手机是否开启了方向锁定;如果在线视频一直无法加载,请检查打包时是否勾选了网络权限,以及视频地址是否可以通过手机浏览器直接打开。网页中的自动播放在WebView里通常需要先有一次用户交互,因此建议像示例一样提供明确的播放按钮,而不是依赖页面打开后自动播放。

视频播放和最大化页面

一个完整的html示例代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>视频播放测试</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html, body {
    width: 100%; height: 100%;
    background: #000;
    font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
    overflow: hidden;
  }

  #player-wrap {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
  }

  /* 视频区域 */
  #video-box {
    position: relative;
    flex: 1;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
  }
  video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #000;
  }

  /* 最大化按钮(悬浮在视频右上角) */
  #btn-fullscreen {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 20;
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  #btn-fullscreen:active { background: rgba(255, 255, 255, 0.25); }
  #btn-fullscreen svg { width: 24px; height: 24px; }

  /* 底部控制栏 */
  #controls {
    position: relative;
    z-index: 10;
    background: #111;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  #btn-play {
    width: 100%;
    padding: 14px;
    font-size: 17px;
    color: #fff;
    background: #1f80ff;
    border: none;
    border-radius: 10px;
    -webkit-tap-highlight-color: transparent;
  }
  #btn-play:active { opacity: 0.8; }

  .url-row { display: flex; gap: 8px; }
  #url-input {
    flex: 1;
    min-width: 0;
    padding: 12px;
    font-size: 14px;
    color: #fff;
    background: #222;
    border: 1px solid #333;
    border-radius: 8px;
    outline: none;
  }
  #btn-load {
    padding: 0 16px;
    font-size: 14px;
    color: #fff;
    background: #333;
    border: none;
    border-radius: 8px;
    white-space: nowrap;
  }

  #status {
    font-size: 12px;
    color: #888;
    word-break: break-all;
  }

  /* 全屏时隐藏控制栏 */
  :fullscreen #controls { display: none; }
  :-webkit-full-screen #controls { display: none; }
</style>
</head>
<body>

<div id="player-wrap">
  <div id="video-box">
    <video id="video" playsinline webkit-playsinline x5-playsinline preload="metadata"
      src="./BigBuckBunny.mp4"></video>

    <!-- 最大化按钮 -->
    <button id="btn-fullscreen" aria-label="最大化">
      <svg id="icon-max" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M16 3h3a2 2 0 0 1 2 2v3"/>
        <path d="M8 21H5a2 2 0 0 1-2-2v-3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>
      </svg>
      <svg id="icon-min" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none">
        <path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/>
        <path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/>
      </svg>
    </button>
  </div>

  <div id="controls">
    <button id="btn-play">播放 / 暂停</button>
    <div class="url-row">
      <input id="url-input" type="url" placeholder="输入视频地址 (mp4/m3u8直链)">
      <button id="btn-load">加载</button>
    </div>
    <div id="status">就绪</div>
  </div>
</div>

<script>
(function () {
  var wrap = document.getElementById('player-wrap');
  var video = document.getElementById('video');
  var btnFs = document.getElementById('btn-fullscreen');
  var btnPlay = document.getElementById('btn-play');
  var btnLoad = document.getElementById('btn-load');
  var urlInput = document.getElementById('url-input');
  var status = document.getElementById('status');
  var iconMax = document.getElementById('icon-max');
  var iconMin = document.getElementById('icon-min');

  function setStatus(msg) { status.textContent = msg; }

  function isFullscreen() {
    return !!(document.fullscreenElement || document.webkitFullscreenElement ||
              document.webkitCurrentFullScreenElement);
  }

  function updateIcon() {
    var fs = isFullscreen();
    iconMax.style.display = fs ? 'none' : '';
    iconMin.style.display = fs ? '' : 'none';
  }

  // 最大化 / 退出全屏(兼容 iOS Safari 的 video 原生全屏)
  btnFs.addEventListener('click', function () {
    if (isFullscreen()) {
      if (document.exitFullscreen) document.exitFullscreen();
      else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
      else if (video.webkitExitFullscreen) video.webkitExitFullscreen();
      return;
    }
    if (wrap.requestFullscreen) {
      wrap.requestFullscreen();
    } else if (wrap.webkitRequestFullscreen) {
      wrap.webkitRequestFullscreen();
    } else if (video.webkitEnterFullscreen) {
      // iOS Safari: 只对 video 元素有效
      video.webkitEnterFullscreen();
    } else {
      setStatus('当前环境不支持全屏 API');
    }
  });

  ['fullscreenchange', 'webkitfullscreenchange'].forEach(function (ev) {
    document.addEventListener(ev, updateIcon);
  });
  video.addEventListener('webkitendfullscreen', updateIcon);

  // 播放 / 暂停
  btnPlay.addEventListener('click', function () {
    if (video.paused) video.play().catch(function (e) { setStatus('播放失败: ' + e.message); });
    else video.pause();
  });

  // 加载自定义地址
  btnLoad.addEventListener('click', function () {
    var url = urlInput.value.trim();
    if (!url) { setStatus('请输入视频地址'); return; }
    video.src = url;
    video.load();
    video.play().catch(function () {});
    setStatus('已加载: ' + url);
  });

  // 状态反馈
  video.addEventListener('playing', function () { setStatus('播放中 ' + video.videoWidth + 'x' + video.videoHeight); });
  video.addEventListener('pause', function () { setStatus('已暂停'); });
  video.addEventListener('error', function () {
    var err = video.error;
    setStatus('加载出错: ' + (err ? 'code ' + err.code : '未知错误'));
  });
  video.addEventListener('ended', function () { setStatus('播放结束'); });
})();
</script>
</body>
</html>