之前一段时间尝试过使用 uniapp 来开发安卓/ios 的 APP,踩过很多坑,为了解决问题几乎翻遍了整个 dcloud 社区,最后成功上线了几款产品。因此对一些功能的实现来做一个总结,方便以后查看。
前提注明
注明:官方推荐长列表使用 nvue 做性能更好,问题在于 nvue 的限制极其离谱,如果长列表项目不是很多,建议不要用 nvue,如果列表项目很多,建议 flutter 或者原生开发。
设备相关
- 获取设备 ID 或唯一标识符:
- 获取平台:
自定义隐私政策
manifest.json
里配置
1 2 3 4 5
| "app-plus" : { "privacy" : { "prompt" : "custom" } }
|
在onLoad
中使用
1 2 3 4 5 6
| if (!plus.runtime.isAgreePrivacy()) { this.showCustomPrivacy = true; return; }
|
隐私政策弹窗的两个按钮需要两个方法:
1 2 3 4 5 6 7 8 9
| agreePrivacy() { plus.runtime.agreePrivacy(); this.showCustomPrivacy = false; }, disagreePrivacy() { plus.runtime.disagreePrivacy(); plus.runtime.quit(); },
|
文档 : Android 平台隐私与政策提示框配置方法
适配
状态栏适配(使用自定义导航栏)
非全屏 APP 下外部容器设置 padding-top: var(--status-bar-height);
--status-bar-height
是官方提供的 css 变量,表示状态栏高度
单独写一个元素做占位符,高度为var(--status-bar-height)
但这个 api 只能拿到状态栏高度,要想适配异性还需要进行其他配置。
状态栏样式
默认值:manifest.json
文件的 app-plus->statusbar->style 配置 支持 light 和 dark (根据文档设置了,然而没用)
在page.json
里设置 "navigationBarTextStyle ":"white"
,完美解决所有问题。
动态设置: plus.navigator.setStatusBarStyle(style); 需要在页面 onReady 和 onShow 里调用,这个 api 在 onLoad 里调用无效,切换页面导致颜色改变后返回不会触发 onReady,因此需要在 onShow 里再次调用,但是只在 onShow 里调用又会失效。
沉浸式状态栏 page.json 里配置:
1 2 3
| "app-plus": { "immersed": true }
|
导航栏
使用原生导航栏
page.json
相关页面中设置
1 2 3
| "style": { "navigationStyle": "default" }
|
自定义导航栏
1 2 3 4 5 6 7 8
| "style": { "navigationStyle": "custom", "navigationBarTextStyle": "black", "app-plus": { "titleNView": false, "scrollIndicator": "none" } }
|
ios 安全区
见第一个文档。
文档
uni-app 全面屏、刘海屏适配(iphoneX 适配)及安全区设置
Android 平台设置沉浸式状态栏显示效果
状态栏大全-状态栏透明(沉浸式)、变色及全屏的区别
iOS 平台设置系统状态栏(通知栏、顶部状态栏)样式背景颜色或透明
uni-app 导航栏开发指南
支付
manifest.json
中打开支付相关选项。微信支付需要填写与 APP 包名绑定的 appid
值,否则无法支付。
- 调用
uni.getProvider
(安卓) 或 plus.payment.getChannels
=> requestOrder
(IOS)获取支持的支付提供商 / 渠道。
- 传入参数至
uni.requestPayment
,不同支付渠道参数格式不同。
关于苹果内购的问题
苹果经常出现调用 api 后无法有弹窗的问题,参考文档:
苹果支付(内购项目)回调验证php 菜鸟技术天地-CSDN 博客苹果支付回调
苹果 ISO 内购支付,支付成功,但是回调不执行问题 - DCloud 问答
苹果内购 的经验分享 - DCloud 问答
支付接口问题, 终于搞定了! 特写这封感谢信! - DCloud 问答
分享苹果内购 requestPayment 没有任何返回 - DCloud 问答
详细见文档。
支付 - uni-app 官网
登录
云函数
这里使用 uniapp 的云函数实现短信发送和获取一键登录的手机号:
大致流程 : 右键项目文件夹 => 创建 uniCloud 云开发环境 => 创建一个并关联 => 右键 cloudfunctions 文件夹,新建云函数 => 完成后右键上传云函数。
一键登录
首先通过云函数获取手机号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 'use strict'; exports.main = async function (event) { const res = await uniCloud.getPhoneNumber({ appid: '__UNI__D2A5305', provider: 'univerify', apiKey: '', apiSecret: '', access_token: event.access_token, openid: event.openid, }); return { code: 0, message: 'success', data: res, }; };
|
客户端调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| uni.login({ provider: 'univerify', univerifyStyle: {...}, success(res){ let result = self.quickLogin(res.authResult); let phoneNum = result.result.data.phoneNumber; ... }, fail(res){} }) async quickLogin(data) { try { const res = await uniCloud.callFunction({ name: 'quickLogin', data: data }); return res; } catch (err) { return err; } }
|
成功或失败时都使用 uni.closeAuthView()
关闭一键登录弹窗
手机短信验证码登录
通过云函数发送验证码
1 2 3 4 5 6 7 8 9
| 'use strict'; exports.main = async (event, context) => { try { const res = await uniCloud.sendSms(event); return res; } catch (err) { return err; } };
|
uniCloud.sendSms()
的参数格式参考文档,这里为后端接口的返回值
1 2 3 4 5 6 7 8 9 10 11
| async sendSms(data) { try { const res = await uniCloud.callFunction({ name: 'sendSms', data: data }); return res; } catch (err) { return err; } }
|
第三方渠道登录
首先需要在进入页面时获取登录渠道
1 2 3 4 5 6 7 8 9 10
| uni.getProvider({ service: 'oauth', success: (res) => { console.log('oauth success:' + JSON.stringify(res)); res.provider.map((value) => { self.providerList.push(value); }); }, fail: (e) => {}, });
|
通过 providerList 中的值展示三方渠道登录按钮
调用 api 实现登录
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| uni.login({ provider: provider, success: (loginRes) => { uni.getUserInfo({ provider: provider, success: (res) => { }, fail: (e) => {}, }); }, fail: (e) => {}, });
|
其他问题
1 2 3 4 5 6 7 8 9 10 11 12 13
| uni.getSystemInfo({ success(res) { if (res.platform == 'ios') { self.canUseAppleLogin = parseInt(res.system) >= 13; plus.oauth.getServices(() => { try { self.isWXInstalled = plus.ios.import('WXApi').isWXAppInstalled(); } catch (e) {} }); } }, });
|
参考文档
uni 一键登录
短信发送
iOS 苹果授权登录(Sign in with Apple)/Apple 登录/苹果登录集成教程
安卓打包后,微信登录提示“认证失败,原因:用户取消”
QQ 登录鉴权报错
该怎么判断是否已安装微信和 QQ?
uni-app 如何判断是否安装腾讯 QQ 微信微博支付宝淘宝客户端
uni-app 怎么注销微信或者 qq 的授权登录?有 uni.logout 这个方法吗?
分享
文档:分享
参考代码(分享至微信朋友圈)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| shareWX() { uni.share({ provider: 'weixin', scene: 'WXSenceTimeline', type: 2, imageUrl: self.savetopimgurl, success: function(res) { uni.showToast({ title: '分享成功' }); }, fail: function(err) { uni.showToast({ title: err.errMsg.includes('未安装') ? '微信客户端未安装' : '分享失败,请检查您的网络', icon: 'none' }); } }); }
|
推送
获取客户端位移标识,用于定向推送,并在首次进入 APP 时上报
1 2
| var pinf = plus.push.getClientInfo(); var cid = pinf.clientid;
|
使用plus.push.createMessage()
方法创建本地推送消息。
使用plus.push.addEventListener('receive',()=>{})
接受推送信息并在回调中创建本地推送。
参考代码已经封装成 push.js,在 main.js 中 import 即可。
push.js 内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
(function () { function pushReady() { function jumpToPage(payload) { const url = payload.url + '?pushId=' + payload.id; if (payload.jump == '1') { uni.switchTab({ url: url, success(r) { }, fail(e) { }, }); } else { uni.navigateTo({ url: url, success(r) { plus.nativeUI.toast('navigate succ' + JSON.stringify(r)); }, fail(e) { plus.nativeUI.toast('navigate err' + JSON.stringify(e)); }, }); } }
function createPushOBj(msg, type) { return { title: msg.title, content: msg.content, id: msg.payload.id, jump: msg.payload.jump, url: msg.payload.url, }; }
plus.push.addEventListener('click', function (msg) { if (msg.payload.id == null) { jumpToPage(JSON.parse(msg.payload)); } else { jumpToPage(msg.payload); } });
plus.push.addEventListener('receive', function (msg) { plus.nativeUI.toast('receive:' + JSON.stringify(msg)); let payload = msg.payload; if (plus.os.name !== 'Android' && msg.type === 'receive') { let content = msg.content; let title = msg.title; let pl = { title: title, content: content, id: payload.id, jump: payload.jump, url: payload.url, }; plus.push.createMessage(content, JSON.stringify(pl), { title: title, }); } if (plus.os.name === 'Android' && msg.content.indexOf('{') === 0) { plus.nativeUI.toast('payload:' + payload); payload = JSON.parse(payload); let content = msg.content; let title = msg.title; let pl = createPushOBj(msg); plus.push.createMessage(content, JSON.stringify(pl), { title: title, }); }
if (plus.os.name === 'Android' && msg.content.indexOf('{') === -1) { let payload = JSON.parse(msg.payload);
let pl = { title: msg.title, content: msg.content, id: payload.id, jump: payload.jump, url: payload.url, }; plus.push.createMessage(msg.content, JSON.stringify(pl), { title: title, }); } }); }
pushReady(); })();
|
参考:
API Reference Push
UniPush 使用指南 - DCloud 问答
其他参考
iOS App 第一次安装启动后,会弹出是否允许联网的询问框,在用户点击同意前,调用联网 API 会失败。因此如果有信息需要在 create 或者 mount 方法中获取的话,就要做兼容处理,否则会导致用户首次进入 APP 时获取不到信息。
manifest.json 文档说明
使用 HTML5+ 注意事项 - uni-app 官网
H5 正常但 App 异常的可能性
iOS 云打包如何设置通用链接等 Capabilities 配置
iOS 平台微信 SDK 更新需要配置通用链接(Universal Links)
关于 IOS 缓存本地图片读取显示空白的问题解决办法
前万小心,安卓跟 IOS 获取本地文件的区别
Uploader(文件上传)问题汇总
uni-app 运行环境版本和编译器版本不一致的问题
5+API 错误代码
监听短信验证码并自动提交表单
Android 平台设置 UrlSchemes,实现被第三方应用调用
Android 平台云端打包权限配置 - DCloud 问答
push.js