第一章 引言:H5 的边界到底在哪里
任何一个写过网页的开发者,迟早都会撞到同一堵墙:浏览器里跑得再溜的页面,一碰到手机原生能力就哑火。想调起摄像头扫个码?不行。想读写手机相册里的一张图?不行。想在应用被杀掉之后还能收到推送?更不行。
HTML5 标准本身把 Web 的能力边界画得很清楚——它只负责"渲染与交互",不负责"触碰硬件"。这堵墙在很长一段时间里把移动开发者劈成了两个阵营:
| 阵营 | 代表方案 | 优点 | 痛点 |
|---|---|---|---|
| 纯原生 | Android / iOS 双端开发 | 能力全、性能强 | 两套代码、成本翻倍 |
| 纯 Web | H5 网页 / 响应式站点 | 一套代码、随处可跑 | 调不动系统能力、体验打折 |
夹在中间的开发者一直想要第三个答案:能不能用 Web 技术写页面,却拿到原生的能力?
HTML5+(HTML5 Plus,下文简称 HTML5+ 或 H5+)就是冲着这个问题来的。它是由数字天堂(DCloud)推出的一套扩展规范,配合它自家的 5+ Runtime(运行时)与 HBuilderX 开发工具,让开发者用 HTML、CSS、JavaScript 写出的页面,能够通过 plus.* 这组 JS 接口,直接调用摄像头、相册、文件系统、定位、推送、支付、数据库等上百项原生能力。
一句话概括它的价值:前端的那套手艺不变,手机的能力门槛被抹平了。
本系列将分多章带你从零吃透 HTML5+:第一章打地基(是什么、怎么跑起来);后续章节逐个实战相机、文件、数据库、推送、支付等模块,并延伸到 uni-app 与 uni-app x 的生态对比。建议收藏,按章食用。
第二章 HTML5+ 是什么:拆开看三个关键词
要真正理解 HTML5+,把它拆成三个词就够了。
2.1 "HTML5":它不替代 Web 标准
HTML5+ 不是一门新语言,也不替代 HTML5 标准。它是在标准 HTML5 之上做加法——页面该用 HTML 写还是用 HTML 写,该用 CSS 画还是用 CSS 画,逻辑该用 JS 写还是用 JS 写。它只负责追加标准里没有的那部分原生能力接口。
2.2 "+":加的是 plus.* API
这是核心中的核心。运行时会在全局注入一个 plus 对象,下面挂着一大堆按业务划分的模块对象:
plus.device // 设备信息:型号、系统、UUID
plus.os // 操作系统信息
plus.camera // 摄像头拍照
plus.gallery // 相册选图、保存图片
plus.io // 文件系统读写
plus.storage // 本地键值存储
plus.sqlite // SQLite 数据库
plus.geolocation // 定位
plus.push // 消息推送
plus.pay // 支付
plus.share // 社交分享
plus.barcode // 二维码扫描
plus.nativeUI // 原生弹窗、toast
plus.webview // Webview 窗口管理
plus.runtime // 运行时控制
plus.key // 物理按键监听
每次调用 plus.xxx.xxx(),都是 JS 侧发起一次"原生能力调用请求",由运行时的桥接层转发给系统,再把结果异步回调回 JS。开发者感知到的,只是"一个函数 + 一个回调"。
2.3 "Runtime":承载这一切的运行时
光有 JS 接口定义没用,得有个容器真正去调系统 API。这个容器就是 5+ Runtime。它本质是一个定制过的 Webview(Android 上基于系统 WebView,可切换腾讯 X5 内核;iOS 端走 WKWebView 体系),在 Webview 之上挂载了原生能力桥。
开发者通过 HBuilderX 把 Web 工程打包成 App 时,最终产物就是"5+ Runtime 外壳 + 你的 HTML/CSS/JS 资源"。
2.4 它不是一个人在战斗:生态三件套
| 组件 | 作用 |
|---|---|
| HTML5+ 规范 | 定义了 plus.* 的接口标准,官网 www.html5plus.org 可查全部 API |
| HBuilderX | DCloud 的 IDE,负责创建项目、真机运行、云打包 |
| 5+ Runtime | 打包进 App 的运行时内核,承载规范落地 |
三件套配合起来,工作流是:HBuilderX 建工程 → 写 HTML/CSS/JS → 真机预览调试 → 一键云打包出 Android/iOS 安装包。
第三章 架构原理:一条从 JS 到原生的桥
知其然,还要知其所以然。看一个最简单的调用在底层经历了什么:
// 让手机震动一下
plus.device.vibrate(200);
这一行背后的完整链路:
你的 JS 代码
│ 调用 plus.device.vibrate()
▼
JS Bridge(桥接层,序列化参数)
│
▼
原生桥接模块(Android/iOS 双端各实现一份)
│ 调用系统震动服务
▼
系统硬件(马达震动)
│
▼
回调结果原路返回 JS(异步 success/fail 回调)
为什么要有桥? 因为 JS 跑在 Webview 的沙箱里,永远没有权限直接触碰系统硬件。桥的本质是"传话人":把 JS 的请求翻译成系统听得懂的原生调用,再把系统结果翻译回 JS 回调。
这种"Webview + 原生桥"的架构,业界统称 Hybrid(混合)开发。和它同类的还有 Apache Cordova(PhoneGap)、Ionic 等方案。HTML5+ 和它们的核心区别不在架构理念,而在于封装的 API 是否贴近中文开发者的真实业务——比如一键扫码、微信/支付宝支付、个推推送这类国内强需求,H5+ 都做了开箱即用的封装。
3.1 最重要的一个事件:plusready
因为桥的初始化需要时间(Runtime 要先启动原生部分、注入 plus 对象),所以在页面加载早期直接访问 plus 会拿到 undefined。规范提供了一个就绪事件:
document.addEventListener('plusready', function () {
// 从这里开始,plus.* 才保证可用
console.log('Runtime 已就绪,UUID: ' + plus.device.uuid);
}, false);
稳妥的写法是加一层兜底,避免在非 5+ 环境(比如浏览器里预览)直接报错:
function onReady(callback) {
if (window.plus) {
callback(); // 已经就绪,立即执行
} else {
document.addEventListener('plusready', function () {
callback();
}, false);
}
}
onReady(function () {
plus.nativeUI.toast('Runtime 就绪');
});
第四章 开发环境与工程结构:跑起第一个 H5+ 应用
4.1 环境准备
- 到 DCloud 官网下载 HBuilderX(Windows/macOS 均支持);
- 安装后无需额外配置,HBuilderX 自带 5+ App 项目的模板与打包通道。
4.2 新建一个 5+ App 项目
HBuilderX 菜单:文件 → 新建 → 项目 → 选择「5+App」,填好项目名即可生成。一个最小工程长这样:
my-h5plus-app/
├── manifest.json // 应用配置:包名、图标、权限、模块开关
├── index.html // 入口页面
├── css/
│ └── app.css
├── js/
│ └── app.js
└── images/ // 本地静态资源
4.3 manifest.json 是"应用身份证"
它声明了应用包名、显示名称、图标、启动图、用到的原生模块和权限。以拍照模块为例,必须先在 manifest 中开启对应权限,打包时才不会缺能力(HBuilderX 里 manifest 有可视化界面,这里给出 JSON 要点):
{
"name": "MyH5PlusApp",
"appid": "__UNI__XXXXXXX",
"versionName": "1.0.0",
"versionCode": "100",
"modules": {
"Camera": {},
"Gallery": {},
"Barcode": {},
"SQLite": {}
},
"permissions": {
"Camera": { "description": "使用摄像头拍照" },
"Storage": { "description": "读取相册与文件" }
}
}
4.4 第一个页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>我的第一个 H5+ 应用</title>
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<h1 id="title">正在初始化...</h1>
<button id="btn">点我震动</button>
<script src="js/app.js"></script>
</body>
</html>
// js/app.js
document.addEventListener('plusready', function () {
document.getElementById('title').innerHTML =
'设备型号:' + plus.device.model +
'|系统:' + plus.os.name + ' ' + plus.os.version;
document.getElementById('btn').addEventListener('click', function () {
plus.device.vibrate(200); // 原生震动
plus.nativeUI.toast('震动已触发');
});
}, false);
4.5 真机运行
HBuilderX 中点 运行 → 运行到手机或模拟器,手机开启 USB 调试连接电脑,HBuilderX 会自动安装 HBuilder 基座(一个内置 5+ Runtime 的调试壳),把页面实时跑起来。改代码可热刷新,这是日常开发的主循环。
基座分两种:标准基座(覆盖常用模块,免费调试用)和自定义基座(打包了全部你配置的模块,用于测试特殊能力,如支付、推送)。上线前务必用自定义基座回归一遍。
第五章 核心 API 体系:一张全景地图
plus.* 模块按用途可分五大类,先建坐标系再逐个击破:
| 类别 | 代表模块 | 典型场景 |
|---|---|---|
| 设备与系统 | device / os / screen / display / navigator / key | 获取机型、屏幕亮度、监听返回键 |
| 媒体能力 | camera / gallery / audio / video / barcode | 拍照、选图、扫码、录音 |
| 数据能力 | storage / sqlite / io / xmlhttprequest | 本地键值、数据库、文件读写 |
| 系统服务 | geolocation / push / pay / share / maps / messaging | 定位、推送、支付、分享 |
| UI 与窗口 | nativeUI / webview / runtime | 原生弹窗、多窗口、跳转与退出 |
后续章节(第二章起)将逐个模块实战,本章先给读者一张"地图感"。下面的第六章我们先从最高频的三个能力入手完整走一遍代码。
第六章 高频能力实战(代码向)
以下代码均为可在 5+ Runtime 中直接运行的最小示例。为节约篇幅,统一省略 plusready 包裹,实际项目中请按 3.1 节方式包一层。
6.1 拍照并保存到相册
拍照是 5+ 应用最高频能力,完整链路是:调起系统相机 → 得到临时文件路径 → 读取并展示 → 另存到系统相册。
var camera = plus.camera.getCamera();
// 1. 调起系统相机拍照
camera.captureImage(function (path) {
// path 形如 file:///storage/emulated/0/Android/data/xxx/cache/xxx.jpg
console.log('拍照成功: ' + path);
// 2. 展示到页面
var img = document.getElementById('preview');
img.src = path;
// 3. 保存到系统相册
plus.gallery.save(path, function () {
plus.nativeUI.toast('已保存到相册');
}, function (e) {
plus.nativeUI.toast('保存失败: ' + e.message);
}, { filename: '_doc/camera/' });
}, function (e) {
plus.nativeUI.toast('拍照取消或失败');
}, { filename: '_doc/camera/', format: 'jpg' });
6.2 从相册选择一张图
plus.gallery.pick(function (path) {
document.getElementById('preview').src = path;
}, function (e) {
console.log('取消选择: ' + e.message);
}, {
filter: 'image', // 只选图片
multiple: false, // 单选
system: false // 使用 H5+ 自带选择界面(false)或系统界面(true)
});
6.3 文件读写:把数据写成 txt 落盘
plus.io 是所有文件操作的入口。核心概念是 URL 与 Entry:先用 resolveLocalFileSystemURL 拿到文件/目录对象(Entry),再基于 Entry 做读写。_doc、_downloads、_www 是三个内置目录别名(分别对应应用文档目录、下载目录、应用资源目录)。
// 1. 解析应用文档目录
plus.io.resolveLocalFileSystemURL('_doc/', function (entry) {
// 2. 在文档目录下创建/打开一个文件
entry.getFile('mydata.txt', { create: true }, function (fileEntry) {
// 3. 创建写入器
fileEntry.createWriter(function (writer) {
writer.onwrite = function () {
plus.nativeUI.toast('写入成功: ' + fileEntry.fullPath);
};
writer.onerror = function (e) {
console.error('写入失败: ' + e.message);
};
// 4. 写入内容
writer.write('hello html5plus @ ' + new Date().toLocaleString());
}, function (e) {
console.error('创建写入器失败');
});
}, function (e) {
console.error('创建文件失败');
});
}, function (e) {
console.error('解析目录失败: ' + e.message);
});
6.4 本地键值存储:plus.storage
页面常用的 localStorage 在卸载/清理后可能丢失,业务数据建议用 plus.storage(持久化到应用私有目录):
// 写入
plus.storage.setItem('user_token', 'abc123xyz');
// 读取
var token = plus.storage.getItem('user_token');
// 删除
plus.storage.removeItem('user_token');
// 清空并查看条数
plus.storage.clear();
console.log('剩余条数: ' + plus.storage.getLength());
6.5 SQLite:结构化数据就交给数据库
数据量大、需要查询时,用 plus.sqlite。注意所有数据库操作都是异步的,成功后回调里才有数据:
var dbName = 'mydb';
var dbPath = '_doc/mydb.db';
// 1. 打开(不存在则创建)
plus.sqlite.openDatabase({
name: dbName,
path: dbPath,
success: function () {
console.log('数据库打开成功');
createTable();
},
fail: function (e) {
console.error('打开数据库失败: ' + e.message);
}
});
function createTable() {
plus.sqlite.executeSql({
name: dbName,
sql: 'CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
success: function () {
insertRow();
},
fail: function (e) {
console.error('建表失败: ' + e.message);
}
});
}
function insertRow() {
plus.sqlite.executeSql({
name: dbName,
sql: "INSERT INTO users(name, age) VALUES('Tom', 28)",
success: function () { queryRows(); },
fail: function (e) { console.error('插入失败: ' + e.message); }
});
}
// 3. 查询:返回二维数组,第一行是列名
function queryRows() {
plus.sqlite.selectSql({
name: dbName,
sql: 'SELECT * FROM users',
success: function (data) {
// data = [["id","name","age"], [1,"Tom",28]]
console.log(JSON.stringify(data));
plus.sqlite.closeDatabase({ name: dbName });
},
fail: function (e) {
console.error('查询失败: ' + e.message);
}
});
}
6.6 定位:拿到经纬度
plus.geolocation.getCurrentPosition(function (position) {
var coords = position.coords;
console.log('纬度: ' + coords.latitude + ', 经度: ' + coords.longitude);
}, function (e) {
console.error('定位失败: ' + e.message);
}, {
geocode: false,
coordsType: 'gcj02', // 国内地图坐标系
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
});
注意:国内上线的应用使用定位功能,需要在地图服务商(高德/百度)申请 Key 并在 manifest 中配置,否则坐标会偏移或失败。
6.7 拦截系统返回键
Android 物理返回键默认行为是退出应用。想在用户处于二级页面时"返回上一页"而非退出,需要监听并接管:
plus.key.addEventListener('backbutton', function () {
// 判断当前是否可返回
var pages = plus.webview.all();
if (pages.length > 1) {
plus.webview.current().close(); // 关掉当前页
} else {
plus.nativeUI.confirm('确定要退出应用吗?', function (e) {
if (e.index === 0) {
plus.runtime.quit();
}
}, '提示', ['退出', '取消']);
}
});
第七章 HTML5+、Cordova、uni-app:三张牌怎么选
很多新人会在这三者之间犯迷糊,这里给一张硬核对比表:
| 维度 | HTML5+(5+ App) | Cordova / PhoneGap | uni-app(Vue 版) |
|---|---|---|---|
| 页面技术 | 原生 HTML/CSS/JS | HTML/CSS/JS | Vue 语法 + 编译 |
| 是否可跑 H5 | 是 | 是 | 是(一套代码多端) |
| 原生能力 | plus.* 一套标准 | 插件系统(需自己写原生) | 封装好的 uni.* + 条件编译 |
| 学习曲线 | 低(会前端即可) | 中(插件要懂原生) | 中(要学 Vue/uni 规范) |
| 打包 | HBuilderX 云打包 | CLI + Android Studio/Xcode | HBuilderX 云打包 |
| 生态现状 | 规范成熟、维护平稳 | 老牌、插件市场庞大 | DCloud 当前主推、社区最活跃 |
选型建议:如果是纯 Web 背景、想最快把现有 H5 包成 App → 选 HTML5+;如果公司已有 Cordova 插件资产 → 沿用 Cordova;如果从零起步且要覆盖小程序/App/H5 多端 → 直接上 uni-app(它的 App 端底层正是由 5+ 能力演进而来)。
务必留意:DCloud 在 2023 年发布了 uni-app x——这是一次彻底重写:不再依赖 Webview 渲染,改用自研 UVM 渲染引擎与 uts 语言(类 TS),性能向原生看齐。它面向未来,但 HTML5+ 规范与 5+ Runtime 至今仍在大量存量 App 中稳定服役,学会 plus.* 的心智模型,对理解 uni-app x 的底层也大有帮助。
第八章 打包与发布:从代码到安装包
8.1 云打包(推荐给无原生环境开发者)
HBuilderX 菜单:发行 → 原生App-云打包:
| 平台 | 需要准备 | 说明 |
|---|---|---|
| Android | 签名证书(可勾选"使用公共测试证书"快速体验) | 正式上架各应用市场需自有证书 |
| iOS | Apple 开发者证书 .p12 + 描述文件 .mobileprovision | 需 Apple 开发者账号;个人免费账号仅能真机调试 7 天 |
勾选"使用 DCloud 公共证书"可以快速出一个可安装的 Android 包验证逻辑,但上架应用市场必须换成自己的证书(公共证书的包名大家共用,会互相覆盖冲突)。
8.2 离线打包(需要原生工程时)
pastebin.com/ALNXMjJp
pastebin.com/NKSG9qx1
pastebin.com/UEwPwZrJ
pastebin.com/8KNkaHEx
pastebin.com/WBLzYw7e
pastebin.com/hi5YxSqC
pastebin.com/xnhwQJh5
pastebin.com/t0YGaB9d
pastebin.com/W8AK2Axe
pastebin.com/V2X9x4Pt
pastebin.com/zye3ysN5
pastebin.com/a1F1xzzE
pastebin.com/84TzCVed
pastebin.com/HGMX17r2
pastebin.com/UBNG1UMU
pastebin.com/MGmaAjNu
pastebin.com/gkXBNGq5
pastebin.com/aHiU5ZXD
pastebin.com/yH8QxZhx
pastebin.com/bR1pS2HZ
pastebin.com/cWisfgwf
pastebin.com/wqHaZSNA
pastebin.com/tCzHPHEi
pastebin.com/UszaC4sM
pastebin.com/rAMMzbE0
pastebin.com/d1TxkSw3
pastebin.com/KYJZeukk
pastebin.com/HzgFmSTB
pastebin.com/sNRA5iEZ
pastebin.com/U7NycXrC
pastebin.com/xQdh3N52
pastebin.com/kh9yHsp3
pastebin.com/V8Kgyz8D
pastebin.com/vNaYdDZ1
pastebin.com/ky8kpmbk
pastebin.com/RFm66W50
pastebin.com/EZef4kfX
pastebin.com/LfqzNfEH
pastebin.com/WSpSbjS5
pastebin.com/pY70hUCt
pastebin.com/i6Pmf4yT
pastebin.com/64r5aehH
pastebin.com/4iz1mAMH
pastebin.com/H8Xkeyq6
pastebin.com/EHRRMpXQ
从 DCloud 官网下载对应平台的 5+ SDK,把 Web 资源放入原生工程 assets,再调用 SDK 提供的入口 Activity/ViewController 启动。适合需要深度集成原生 SDK 或走企业签名的场景。
8.3 发布前检查清单
- [ ] manifest 中包名、版本号正确;
- [ ] 用到的模块权限全部勾选;
- [ ] 图片资源走
_doc/_downloads目录而非硬编码绝对路径; - [ ] 生产环境关闭调试日志(5+ 的 console 输出在正式包默认关闭,无需额外处理);
- [ ] Android 上 iOS 双端分别用真机回归一遍相机、存储等敏感权限的授权弹窗流程。
第九章 高频坑与调试技巧:老司机的避雷手册
plus is not defined:在浏览器里预览 H5 页面时没有 Runtime,必然报错。所有业务代码必须包在plusready之后(见 3.1 兜底写法)。- plusready 触发多次:页面被反复创建时监听器叠加。用具名函数并在
plusready回调外注册,或注册后立即removeEventListener。 - 文件路径别写死:Android 的绝对路径带随机目录,每次安装都可能变化。一律用
_doc/、_downloads/等内置别名,或通过plus.io.convertLocalFileSystemURL动态转换。 - IO/数据库全是异步:新手容易在回调外直接拿返回值,拿到 undefined 后一脸懵。记住:H5+ 的回调里才是数据的家。
- 返回键误触退出:见 6.7,接管
backbutton事件做分级处理。 - 白屏:大概率是入口页地址配错(manifest 的 launch 页面)、本地资源用了绝对网络路径、或 Webview 加载被安全策略拦截。先开 HBuilderX 的控制台看错误日志。
- iOS 相册权限崩溃:manifest 没勾选相册权限描述,或没有在 Info.plist 中配置用途说明文案(云打包时 HBuilderX 会引导填写)。
- 调试三板斧:真机运行 +
console.log输出到 HBuilderX 控制台;plus.nativeUI.toast快速吐提示;复杂问题用alert(JSON.stringify(e))看完整错误对象。
第十章 从 HTML5+ 到 uni-app x:演进与展望
回看 HTML5+ 走过的路,本质是 Web 技术不断向原生能力"越界"的过程:
pastebin.com/MnayQBA7
pastebin.com/L7ih8xXf
pastebin.com/8LEbfRjv
pastebin.com/djzpBAHx
pastebin.com/ta7mHuJA
pastebin.com/yr93gVJz
pastebin.com/SUqMAWSg
pastebin.com/Fy5mKEpM
pastebin.com/6JPU8gvF
pastebin.com/7yec3BqS
pastebin.com/zGfiu7zS
pastebin.com/DrbUL7nP
pastebin.com/Uep7sBpx
pastebin.com/V4fFgdBX
pastebin.com/pAxQj262
pastebin.com/3DttEUsj
pastebin.com/Q7KBg75S
pastebin.com/41XjfGZr
pastebin.com/0HkTxCm6
pastebin.com/j7QYaWzV
pastebin.com/QqaeuJeE
pastebin.com/fsLXkxR0
pastebin.com/K2wMDpFs
pastebin.com/UDnersdN
pastebin.com/GxJCtZXv
pastebin.com/Zs1StUeY
pastebin.com/g0zb81qa
pastebin.com/ghm4EJji
pastebin.com/sNtN2A3c
纯 H5(能力墙)
│ DCloud 提出 HTML5+ 规范 + 5+ Runtime
▼
Hybrid 混合开发(HTML5+ / Cordova)
│ DCloud 推出 uni-app:一套代码编译多端
▼
uni-app(Vue 版,App 端 Webview 渲染)
│ 2023 年 uni-app x:自研 UVM 引擎 + uts
▼
uni-app x(无 Webview,接近原生性能)
对今天才入门的开发者,我的建议是:把 HTML5+ 当"底料"学——它的 plus.* 心智模型(异步回调、内置目录、桥接思想)是理解 DCloud 整个生态的地基;把 uni-app x 当"方向"看——那是性能与多端融合的未来。存量 5+ App 的维护与改版需求,在市场上依然长期存在,会 HTML5+ 就等于多了一门能立刻变现的手艺。
本章小结
本章完成了 HTML5+ 的"全景认知 + 环境搭建 + 五个高频能力实战",重点回顾:
- HTML5+ = HTML5 标准 +
plus.*原生能力接口 + 5+ Runtime; - 一切能力调用都走"JS → 桥 → 原生 → 回调"的异步链路;
plusready是代码安全的起跑线,务必兜底;manifest.json是能力的开关,忘开模块 = 运行时没有该能力;- 拍照、相册、文件、storage、SQLite、定位、返回键拦截是日常最高频的七板斧。
0 个评论
要回复文章请先登录或注册