前言
最近需要在原uniapp开发的app中嵌入h5页面,过程遇到了非常多的问题,很有必要记录一下
按需引入vant
因为技术栈使用的是vue3,所以使用unplugin-vue-components完成按需引入,配置如下
// vue.config.js
const { defineConfig } = require("@vue/cli-service");
const { VantResolver } = require("unplugin-vue-components/resolvers");
const Components = require("unplugin-vue-components/webpack");
module.exports = defineConfig({
configureWebpack: {
plugins: [
Components({
resolvers: [VantResolver()],
}),
],
},
});
- 在使用组件时直接使用即可无需引入
- 消息类
Toast、Dialog等组件unplugin-vue-components无法自动引入对应样式需手动引入
适配
适配采用postcss-px-to-viewport,设计稿基准是750,所以配置时需将viewportWidth设置为750,但vant组件的基准是375,所以适配需要对vant进行兼容(2022了再手动计算就不合适了),所以适配如下
module.exports = ({ file }) => {
const designWidth =
file.includes("node_modules") && file.includes("vant") ? 375 : 750;
return {
plugins: {
"postcss-px-to-viewport": {
viewportWidth: designWidth,
},
},
};
};
vue3
- 模板
vue3允许开发时模板不必被最外层元素包裹,但此种组件使用时无法添加class等属性
- 路由
匹配不到路由时配置更新为
{
path: "/:pathMatch(.*)*",
name: "NotFound",
component: () => import("@/views/notFound"),
}
base配置取消,通过createWebHistory传入
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
hooks
qjd-ui-hooks已无法直接在vue3项目中直接使用,原因是找不到@vue/composition-api,原项目使用的hooks并非完全适用于vue3
app跳转h5
旧报告跳转后调用接口是免登录接口,由于无安全考虑方案被废弃,新报告需要考虑登录态,目前做的较为简单,通过中转页面在h5设置cookie,成功后后续接口携带cookie即token信息访问即可存在登录态 & 登录时效
方案一:
- 前端
app调用后端接口获取shortKey webview页面嵌入服务端接口地址,shortKey传给服务端- 服务端拿到
shortKey后置换真正的token - 获取到
token后将其设置在h5部署域名下
结果:
- 本地可以完成跳转,测试地址浏览器可以看到
cookie - 后续真机测试时,
webview指向地址需为真实页面地址,此方案放弃
方案二:
webview页面嵌入h5页面地址- 跳转
webview前调用后端接口获取shortKey - 获取
shortKey后调用置换token接口,并在服务端设置cookie - 置换
token接口成功后跳转webview
结果:
cookie表现混乱,时有时无,怀疑和跨域有关,此方案放弃
方案三:
webview页面嵌入h5页面地址- 获取
shortKey后将跳转webview - 将
shortKey等参数带给h5页面 - 在
h5中转页面调用置换token接口,由服务端在此域名下设置cookie - 在
h5中转页面根据其他参数决定跳转哪个页面 - 在页面请求接口若
cookie已经失效,则跳转无权限页面 - 由于页面层级深一层层返回体验较差,在无权限页面提供返回按钮,直接会到
app
结果:
- 真机表现较为正常,偶现
cookie失效情况,需优化 app有接口轮询,会在cookie即将过期时更新cookie,则导致h5cookie过期时,回到app时app登录时效依然ok,表现不一,需优化- 后续微信消息跳转报告时此套逻辑不在适用,要走微信授权登录,需重新开发
h5向uni通信
由于需在无权限页提供一键返回按钮,需要h5向uniapp发送消息,uniapp文档不明朗,有误导倾向
- 误区一
文档中@meaasge的表述如下:
H5 暂不支持(可以直接使用 window.postMessage (opens new window))
此处H5指的是uniapp打包为H5,并非指在webview中嵌入的h5页面,所以在webview中嵌入的h5页面向uniapp发送消息时仍调用uni.postMessage而非window.postMessage
- 误区二
文档中关于demo部分调用了如下方法
document.addEventListener('UniAppJSBridgeReady', function() {})
此方法是监听uni是否已经注入,但此方法应是在初始化时调用,而对于更深层次的调用时无需使用该方法监听,可以直接使用uni或者初始化时调用该方法后注册一个全局变量,后续使用即可
综上,完成h5向uni通信如下:
- 引入
uni
<!-- 有条件可以将资源down下来放在本地 -->
<script type="text/javascript" src="https://unpkg.com/@dcloudio/uni-webview-js@0.0.3/index.js"></script>
- 调用
uni
// 返回
const backHandle = () => {
uni && uni.postMessage({
data: {
type: "back",
},
});
};
uni分享pdf
uniapp提供几种分享方式,大致两种
- 调用社区
sdk - 调用手机自带分享
uniapp集成的sdk目前支持微信、QQ、微博,这远不够目前要求的平台,如:钉钉、企业微信等平台需要自行实现,插件市场倒是可以找到插件,但是数量都只有一个,不但收费,而且质量、版本无保障,退而求其次,选择手机自带的分享功能
- 安卓
文档解释安卓高版本无法分享图片,若是携带图片,则默认为图片类型,此种效果不是我们想要的
- ios
强!!!
结论:
- 采用手机自带分享功能
- 分享时区分
ios和安卓,ios分享携带图片,安卓分享只有文案和链接
注: 分享出去的效果由机型确定,所以在测试华为分享微信时是真的丑
分享链接
原采用pc端pdf下载链接,但是由于content-type是错误的导致在钉钉上打开乱码,所以采用新的链接
新链接具备时效性,目前时效为1天,此链接具备一定安全性
ios安全区
对于新的ios手机如:iphone11、iphone12、iphonex等机型都有底部安全区,也就是底部白色区域,处理方案是添加viewport-fit=cover
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui,viewport-fit=cover" />
在h5上是没有什么问题的,基本可以解决问题,但是在uni中,表现不尽如人意,经过尝试去掉
body {
height: 100%;
}
后,凡是撑开body产生滚动条的页面不会产生底部白条,而其余页面偶现,暂无更好方案处理
样式变化后带来后续的滚动计算方式
ios齐刘海、底部黑条
完整样式如下,没有此样式,底部区域会被黑条覆盖
@supports ((height: constant(safe-area-inset-top)) or (height: env(safe-area-inset-top))) and (-webkit-overflow-scrolling: touch) {
body {
/* 适配齐刘海 */
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
/* 适配底部小黑条 */
padding-bottom: costant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
}
iphonex兼容
图片写了宽度后,高度会自适应,但是在iphonex机型下不写高度会出现图片拉长情况
特性环境测试问题
pc端服务端通过不同请求头拉取不同资源,移动端真机测试无法设置
uniapp真机模式提供了useragent配置,可以添加多余信息,配置如下
"app-plus" : {
"useragent": {
"value": "(#test#)",
"concatenate": true // 开启concatenate在原useragent上添加信息
},
"useragent_android": {
"value": "(#test#)",
"concatenate": true
},
"useragent_ios": {
"value": "(#test#)",
"concatenate": true
},
}
此种方式为静态配置,经测试服务端可以拿到配置的额外配置的(#test#)数据
可以后续改进方案通过setUserAgent动态设置useragent,如下
const userAgent = plus.navigator.getUserAgent();
plus.navigator.setUserAgent(userAgent + '(#test#)')
结语
移动端问题真心多