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

推荐订阅源

Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
M
MIT News - Artificial intelligence
D
Docker
量子位
T
Tailwind CSS Blog
人人都是产品经理
人人都是产品经理
月光博客
月光博客
有赞技术团队
有赞技术团队
J
Java Code Geeks
A
About on SuperTechFans
P
Proofpoint News Feed
Jina AI
Jina AI
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
V
V2EX
GbyAI
GbyAI
F
Fortinet All Blogs

博客园 - 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-07 · via 博客园 - H5开发技术

在HTML项目中,可以使用 html5-qrcode 调用手机摄像头并识别二维码。完成页面代码后,再通过HTML一键打包APK工具勾选相机权限,即可生成支持扫码的安卓APP。

如果你不了解HTML打包APK工具, 想要进一步了解, 可以查看官网:

HTML一键打包APK工具官网

创建扫码页面

在HTML项目入口目录中创建 index.html,写入以下代码。页面点击“开始扫码”后会申请摄像头权限,识别成功时停止摄像头并显示二维码内容。

<!doctype html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
        <title>二维码扫码</title>
        <script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js"></script>
        <style>
            * {
                box-sizing: border-box;
            }

            body {
                min-height: 100vh;
                margin: 0;
                padding: 20px;
                display: grid;
                place-items: center;
                font-family: 'Microsoft YaHei', sans-serif;
                background: #f4f7f5;
                color: #17221c;
            }

            main {
                width: min(100%, 440px);
            }

            h1 {
                margin: 0 0 8px;
                font-size: 30px;
            }

            p {
                margin: 0 0 18px;
                color: #526159;
            }

            #reader {
                width: 100%;
                min-height: 280px;
                overflow: hidden;
                border: 1px solid #cad4ce;
                border-radius: 8px;
                background: #101511;
            }

            #reader video {
                object-fit: cover;
            }

            .actions {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 10px;
                margin-top: 14px;
            }

            button {
                min-height: 48px;
                border: 0;
                border-radius: 6px;
                padding: 0 16px;
                font: inherit;
                font-weight: 700;
            }

            #startButton {
                background: #197447;
                color: white;
            }

            #stopButton {
                background: #dfe6e2;
                color: #26352d;
            }

            button:disabled {
                opacity: 0.5;
            }

            #status {
                min-height: 24px;
                margin-top: 12px;
                font-size: 14px;
                color: #526159;
            }
        </style>
    </head>
    <body>
        <main>
            <h1>二维码扫码</h1>
            <p>点击开始后,将摄像头对准二维码。</p>
            <div id="reader" aria-label="摄像头扫码区域"></div>
            <div class="actions">
                <button id="startButton" type="button">开始扫码</button>
                <button id="stopButton" type="button" disabled>停止扫码</button>
            </div>
            <div id="status" role="status">等待开始</div>
        </main>

        <script>
            const reader = new Html5Qrcode('reader');
            const startButton = document.getElementById('startButton');
            const stopButton = document.getElementById('stopButton');
            const status = document.getElementById('status');
            let isScanning = false;
            let resultHandled = false;

            async function stopScanning() {
                if (!isScanning) return;

                await reader.stop();
                isScanning = false;
                startButton.disabled = false;
                stopButton.disabled = true;
                status.textContent = '扫码已停止';
            }

            async function startScanning() {
                startButton.disabled = true;
                status.textContent = '正在请求摄像头权限...';
                resultHandled = false;

                try {
                    await reader.start(
                        { facingMode: 'environment' },
                        { fps: 10, qrbox: { width: 240, height: 240 } },
                        async decodedText => {
                            if (resultHandled) return;
                            resultHandled = true;
                            await stopScanning();
                            alert(decodedText);
                        },
                        () => {}
                    );

                    isScanning = true;
                    stopButton.disabled = false;
                    status.textContent = '正在扫描...';
                } catch (error) {
                    startButton.disabled = false;
                    status.textContent = '无法打开摄像头,请检查相机权限。';
                    console.error(error);
                }
            }

            startButton.addEventListener('click', startScanning);
            stopButton.addEventListener('click', () => {
                stopScanning().catch(console.error);
            });

            window.addEventListener('pagehide', () => {
                if (isScanning) reader.stop().catch(() => {});
            });
        </script>
    </body>
</html>

示例通过 CDN 加载 html5-qrcode。如果APP需要完全离线运行,请提前下载 html5-qrcode.min.js 放入项目目录,并将页面中的脚本地址改为本地相对路径。

打包APK并勾选相机权限

打开HTML一键打包APK工具,选择包含 index.html 的项目目录,填写应用名称、包名等打包信息。在权限设置中勾选“相机权限”,否则APP无法调用手机摄像头。

打包APK时勾选相机权限

确认配置后开始打包,等待工具生成APK文件。

安装并测试扫码

将生成的APK安装到安卓手机。首次点击“开始扫码”时,系统会弹出相机授权提示,选择允许后,将摄像头对准二维码。识别成功后,页面会停止扫描并弹出二维码中的文字或链接。

打包后的APP扫码运行效果

如果页面提示无法打开摄像头,请先在手机的应用权限设置中确认相机权限已经允许。扫码页面使用 CDN 脚本时,还需要确保手机能够正常访问网络;改用本地脚本后则不受此限制。