混合App开发
概念:将写好的移动端页面,通过web view嵌套在App里面
注意:调用安卓方法传参是只能接受字符串,所以都需要通过JSON.stringify()转一下
获取安卓提供给H5的方法
- 在安卓通过web view打开移动端网页时,会在window里面挂载提供给H5的方法
- H5需要获取这些方法
export class bridge_javaToJs{
getUserInfo(){
return window.App && windwo.App.getUserInfo()
}
}
- 并将其挂载在Vue上
import Vue form 'vue';
import bridge_javaToJs from './bridge_javaToJs';
Vue.prototype.$app=new bridge_javaToJs();
- 为方便判断是否在安卓情况下打开的H5页面,在main.js里追加状态判定
import Vue form 'vue';
window.vm=new Vue({
data(){
return {
isApp:window.App,
}
}
})
隐藏DOM元素
安卓有可能只采用一半H5页面,也就是一半安卓,这样就需要对H5网页进行处理
- 隐藏DOM元素,这是一种比较简单的方法,看安卓需要那些部分,对于不需要的就进行隐藏操作
- 重写路由,为安卓重新配置路由,将需要的页面组合起来
- 优点是只加载需要DOM元素
- 缺点是涉及页面重构,还需要注意父子组件传值
路由拦截
- 在路由拦截之前我们需要分清楚那些是App用到的页面,哪些不是
- 因为对于H5页面跳往安卓原生页,需要调用安卓原生提供H5的方法
- 而H5跳往H5页面依旧依靠VueRouter
可以通过对路由meta里面添加信息来区分
const routes=[
{
path:'/home',
name:'Home',
component:Home,
meta:{
isAppPage:true,
}
},
{
path:'/home',
name:'Home',
component:Home,
meta:{
isAppPage:false,
}
}
]
- 安卓对于返回执行的方法是不一样的,通过重写VueRouter的方法和定义router.options里面选项来判断是前进还是后退
import Vue form 'vue';
import VueRouter from 'vue-router';
// 获取原型对象上push方法
const originalPush=VueRouter.prototype.push;
// 修改对象中push方法
VueRouter.prototype.push=function push(location){
// push是路由前进
router.options.isForward=true;
return originalPush.call(this,location).catch(err=>err)
}
// 获取原型对象上replace方法
const originalReplace=VueRouter.prototype.replace;
// 修改对象中push方法
VueRouter.prototype.replace=function replace(location){
// replace是路由前进
router.options.isForward=true;
return originalReplace.call(this,location).catch(err=>err)
}
// 获取原型对象上go方法
const originalGo=VueRouter.prototype.go;
// 修改对象中go方法
VueRouter.prototype.replace=function replace(index){
if(index>0){
router.options.isForward=true;
}else{
router.options.isForward=false;
}
return originalGo.call(this,index)
}
Vue.use(VueRouter);
const routes=[
{
path:'/home',
name:'Home',
component:Home,
meta:{
isAppPage:true,
}
},
{
path:'/home',
name:'Home',
component:Home,
meta:{
isAppPage:false,
}
}
]
const router=new VueRouter({
mode:'history',
routes,
isForward:false,
})
export default router;
- 在路由前置守卫中,通过Vue.$router.options.isForward和meta.isAppPage条件执行不同跳转操作
export const routerBefore=(to,from,next)=>{
const isApp=window.App;
// 是在安卓环境下并且是去往App页面或者去的信息里面表明是要去App页面(主要是为了一些是H5的页面但是要求用App的方法打开)
if(isApp && (to.meta.isAppPage||to.query.isAppPage)){
// 判断vue是否加载好了或者是否是前进
if(!vm || vm.$router.options.isForward){
const url='xxxx';
// 调用安卓方法跳转
vm?vm.$app.adjustRouter(url):window.App.adjustRouter(url)
}else{
// 调用安卓方法回退
vm.$app.nativeFallBack();
}
return;
}else{
// VueRouter操作
next();
}
}
- 对于第一次进入就有掉安卓回退方法的页面需要进行特殊操作,否则回退将失效。原因在于history里面只有一条历史记录,在浏览器里只有一条历史记录调用go回退时回回退到浏览器主页,web view并没有主页,回退不会生效,VueRouter里面的前置路由守卫也不会被触发,页面也就不会跳转
- 解决方案,先在VueRouter里进行配置count参数,重写Router方法以此来记录路由次数
import Vue from "vue";
import VueRouter from "vue-router";
//获取原型对象上的push函数
const originalPush = VueRouter.prototype.push;
//修改原型对象中的push方法
VueRouter.prototype.push = function push(location) {
router.options.isForward=true;
router.options.count++;
return originalPush.call(this, location).catch(err => err)
};
//获取原型对象上的replace函数
const originalReplace = VueRouter.prototype.replace;
//修改原型对象中的replace方法
VueRouter.prototype.replace = function replace(location) {
router.options.isForward=true;
router.options.count++;
return originalReplace.call(this, location).catch(err => err)
};
//获取原型对象上的go函数
const originGo=VueRouter.prototype.go;
VueRouter.prototype.go=function(index){
if(index>=0){
router.options.count++;
router.options.isForward=true;
}else{
router.options.count--;
router.options.isForward=false;
}
return originGo.call(this,index);
}
Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
// base: process.env.BASE_URL,
routes,
isForward:false,
count:0,
});
- 在需要后退的页面在后退前进行判断,如果是第一个页面,那么就不调用VueRouter方法,改为调用安卓原生提供的方法进行回退操作
<template>
<button @click="goBack">返回</button>
</template>
<script>
export default {
methods: {
goBack(){
if(this.$root.isNewApp && (window.history.length===1||this.$router.options.count===0)){
this.$app.nativeFallBack()
return;
}
this.$router.back()
}
}
}
</script>