本节导读:通用层之外的能力,本节给出体系化的拿法:App 端 plus 运行时的边界、支付与分享的适配层实现、推送与角标的全链路,最后把适配层的组织规范定下来——条件编译只在适配函数体内出现,业务侧只见统一签名。
App 端有一套 uni API 覆盖不到的领地,入口是 plus 对象:原生窗口管理、推送、原生控件、系统级文件操作都在里面。使用规则有两条红线:plus 只在 App 端存在,其他端引用直接报错,所有 plus 调用必须圈在 #ifdef APP-PLUS 里;plus 对象在原生引擎初始化完成后才可用,过早调用(比如 main.js 顶层)拿到 undefined,正确的时机是 App.vue 的 onLaunch 之后。一个典型用法是 App 端的原生标题栏按钮:
// App.vue export default { onLaunch() { // #ifdef APP-PLUS const webview = plus.webview.currentWebview(); webview.setStyle({ titleNView: { buttons: [ { float: 'right', text: '···', fontSize: '18px', onclick: () => { uni.$emit('nav-more-tap'); } } ] } }); // #endif } };
支付是平台特有能力的教学样本:微信端走 requestPayment 加小程序支付参数,App 端同 API 但走渠道支付参数,H5 端干脆没有统一支付能力、要跳自建收银台。适配层的写法分两步:先定统一签名,再在函数体内分端实现:
// utils/pay.js —— 统一签名:pay({ orderId }),成功 resolve,失败 reject export function pay({ orderId }) { return new Promise((resolve, reject) => { // #ifdef MP-WEIXIN uni.requestPayment({ provider: 'wxpay', timeStamp: String(Math.floor(Date.now() / 1000)), nonceStr: makeNonce(), package: 'prepay_id=' + orderId, // 实际由下单接口返回 signType: 'RSA', paySign: '', // 服务端签名,示例略 success: resolve, fail: reject }); // #endif // #ifdef APP-PLUS uni.requestPayment({ provider: 'wxpay', // App 端需在 manifest 勾选支付模块并配置开放平台参数 orderInfo: { orderid: orderId }, success: resolve, fail: reject }); // #endif // #ifdef H5 uni.showToast({ title: '正在跳转收银台', icon: 'none' }); window.location.href = '/cashier?order=' + orderId; resolve({ redirected: true }); // #endif }); }
下单页面调用处只有一行 await pay({ orderId }),对三端差异零感知。这个模式的复利在变更时显现:某天微信支付参数升级,只改 utils/pay.js 的微信分支,全商城几十个支付入口一行不动。
分享在微信端有页面级钩子 onShareAppMessage(右上角菜单转发)与 button 的 open-type(主动触发),App 端走 plus 的原生分享或 uni.share,H5 端做复制链接加引导图。适配层照支付的样子收口成 share({ title, path, imageUrl }),业务页只调签名。推送的版图更偏 App:uni-app 用统一推送服务对接各厂商通道,manifest 里配置、云打包时生效,前端只面对 uni.onPushMessage 一个口子;小程序端与 H5 端没有系统级推送,用订阅消息(微信)与站内轮询补位。三类能力的适配层凑齐后,utils 目录会自然长出 pay.js、share.js、push.js——这个目录就是全项目"平台专属能力"的户口本,6.3 的插件与 6.4 的降级最终都汇到这里。

把模式固化成团队纪律,防止适配层随时间腐化。其一,条件编译只允许出现在 utils 适配层,页面与组件里出现 #ifdef 一律视为待整改(界面展示级的例外在 3.1 节讨论过,属于受控白名单)。其二,统一签名先行:先定参数与返回,再写各端实现,禁止"哪端先做哪端定接口"。其三,每端实现必配降级说明:能力缺失端的行为写进函数注释,评审时按注释核对。其四,适配层单测按端跑:至少在条件编译矩阵下各编译一轮,保证没有一端的分支语法错误被其他端的通过掩盖。
适配层怎么测才放心?给出最小可行方案。第一步,矩阵编译:四个端各构建一遍,保证每个分支都通过语法检查,这一步拦截的是"被裁掉分支里的低级错误"。第二步,签名测试:对每个适配函数写一份与平台无关的调用用例(给定输入,断言统一签名的返回形状),在能跑的端各执行一遍,保证业务侧看到的行为一致。第三步,真机抽查:支付成功、支付取消、支付失败三条路径在真实环境各走一次——支付这类动作模拟器验证不了回调,真机抽查不可省。三步下来大约半天工作量,换来的是适配层可以被放心复用一整年。
特有能力收进一层后,下一节处理连 API 都没有的领地:原生插件的开发与集成。