6.1 原生 API 体系 本节导读:本章从版图开始。uni API 以 前缀把五大家族(设备、网络、位置、媒体、文件)收敛成统一入口,但"统一入口"不等于"全端一致"——本节给出能力分级的核对法与 promise 化的书写规范,用扫码与位置两个真实例子示范"查、调、降"三步。 能力分三级,核对三步走 把 uni API 全集摊开,按支持度分三级看:全端一致(showToast、showModal、getSystemInfo 等界面与系统信息类),标注差异(位置、支付、文件这类行为因端而异的),仅单端存在(App 端的 plus 体系、微信端的开放能力)。工程上的核对动作固化成三步:查文档的能力分级标注 → 在目标端真机各调一遍 → 差异处补降级分支。
本节导读:本章从版图开始。uni API 以
uni.前缀把五大家族(设备、网络、位置、媒体、文件)收敛成统一入口,但"统一入口"不等于"全端一致"——本节给出能力分级的核对法与 promise 化的书写规范,用扫码与位置两个真实例子示范"查、调、降"三步。
把 uni API 全集摊开,按支持度分三级看:全端一致(showToast、showModal、getSystemInfo 等界面与系统信息类),标注差异(位置、支付、文件这类行为因端而异的),仅单端存在(App 端的 plus 体系、微信端的开放能力)。工程上的核对动作固化成三步:查文档的能力分级标注 → 在目标端真机各调一遍 → 差异处补降级分支。跳过第二步是高发事故源——文档标注滞后于宿主更新,真机验证才是终审。
书写规范上,回调、promise、async 三种风格并存,公约建议统一 async/await(回调风格只在老代码迁移期保留):
// 界面类:全端一致,放心直调 async function confirmDelete(name) { const { confirm } = await uni.showModal({ title: '删除确认', content: `确定删除「${name}」吗?` }); return confirm; } // 系统信息类:同步版一次取全,别在循环里反复调 const sys = uni.getSystemInfoSync(); console.log(sys.platform, sys.windowWidth, sys.statusBarHeight);
设备族(电量、网络类型、屏幕参数)与网络族(getNetworkType、onNetworkStatusChange)大多全端一致,工程价值在两个习惯。其一,网络状态监听做全局单例:App.vue 的 onLaunch 里注册 onNetworkStatusChange,断网时把状态写进全局 store,页面按需响应,而不是每个页面自己注册一遍监听(泄漏源头)。其二,系统信息一次取全缓存:getSystemInfoSync 在启动时调一次存进全局,运行期反复调用既有开销,值也不会变。这两条做好,设备网络族基本不再产生问题。
位置族是"标注差异"级的代表,值得完整拆一遍。三端差异集中在授权模型:微信端首次调用 getLocation 触发授权弹窗,拒绝后再调不再弹窗(静默失败),要把用户引到设置页开开关;App 端要走系统的权限申请,iOS 还要求 manifest 里声明用途文案;H5 端依赖浏览器 Geolocation,http 环境直接不可用。标准写法把"查、调、降"三步走全:
function getLocation() { return new Promise((resolve, reject) => { uni.getLocation({ type: 'gcj02', // 国测局坐标系,国内地图组件通用 success: resolve, fail: async () => { // 拒绝授权后的降级链 const { confirm } = await uni.showModal({ title: '位置权限', content: '需要位置权限推荐附近门店,去设置开启?' }); // #ifdef MP-WEIXIN if (confirm) uni.openSetting({}); // #endif // #ifndef MP-WEIXIN if (confirm) uni.showToast({ title: '请在系统设置中开启定位', icon: 'none' }); // #endif reject(new Error('location denied')); } }); }); }
这段代码里藏着位置族的两个冷知识:坐标系必须显式选 gcj02(默认 wgs84 在国内地图上偏移几百米,"门店定位飘了"的工单多半源于此);微信端自 2022 年后 getLocation 还需要在后台声明用途类目,属于 6.4 节审核红线的预演。
媒体族覆盖图片相机(chooseImage、chooseMedia)、保存(saveImageToPhotosAlbum)、录音录像;文件族覆盖小程序端的 FileSystemManager 与 App 端的 plus 文件系统。商城的"保存分享图"功能串起三件事:
async function saveSharePoster(filePath) { // 选:海报已在本地临时路径,直接进授权环节 try { await uni.saveImageToPhotosAlbum({ filePath }); uni.showToast({ title: '已保存到相册', icon: 'success' }); } catch (e) { // 保存失败九成是相册授权被拒,引去设置 const { confirm } = await uni.showModal({ title: '需要相册权限', content: '去设置开启后重试?' }); // #ifdef MP-WEIXIN if (confirm) uni.openSetting({}); // #endif } }
两条易错点要背:临时路径有时效,chooseImage 返回的路径在本次启动内有效,要长期持有必须先保存或上传,"昨天还能显示的图今天没了"就是拿临时路径当了永久路径;写文件族 API 端差最大,公共代码里只走 uni 统一口径的子集(saveFile、getFileSystemManager 的基础操作),深度文件操作圈进条件编译按端实现。
通用版图摸完,下一节进入平台专属领地:用适配层把支付、分享、推送的端差异关进一层。