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

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
博客园 - 叶小钗
爱范儿
爱范儿
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
T
Tailwind CSS Blog
博客园 - 司徒正美
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
小众软件
小众软件
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - 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>