0


微信小程序内嵌webView访问H5界面,在H5界面获取定位

以下为uniapp代码!!!

第一步:

微信小程序webview组件路径写花生壳映射的https://***域名。

webView页面

<template>
    <view>
        <web-view :src="wvUrl"></web-view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                wvUrl: `https://******/h5/index/#/pages/login/login?platformToken=123456`,
            }
        },
        methods: {}
    }
</script>

<style>
</style>

第二步:

花生壳配置映射,获取域名。
花生壳动态域名解析服务-贝锐官网|花生壳官网|DNS内网穿透|域名注册|向日葵远程控制|远程桌面|蒲公英路由器-贝锐官网https://www.oray.com/

第三步:

uniapp获取定位。(过程全前端实现无后端)

3.1 下载所需文件(npm install crypto-js为了SHA1加密,npm install weixin-js-sdk为了使用微信的api)
3.2 manifest.json配置

** 重要:uniapp H5端口不能使用默认80(自己踩的坑)**

manifest.json

/* 小程序特有相关 */
    "mp-weixin": {
        "appid": "",
        "setting": {
            "urlCheck": false
        },
        "usingComponents": true,
        "permission": {
            "scope.userLocation": {
                "desc": "您的位置信息将用于小程序位置接口的效果展示"
            }
        },
        // 微信小程序使用位置相关api需要在此处注册
        "requiredPrivateInfos": ["getLocation"]
    },

"h5": {
        "devServer": {
            "port": 8081,
            // 此处代理是为了前端获取access_token、jsapi_ticket,如果是后端获取就不必写了
            "disableHostCheck": true,
            "proxy": {
                "/api": {
                    "target": "https://api.weixin.qq.com",
                    "changeOrigin": true,
                    "pathRewrite": {
                        "^/api": "" 
                    }
                }
            }
        }
    }
3.3 获取access_token、jsapi_ticket、签名,配置。(配置一次即可,其他页面只需要调用定位)
App.vue

<script>
    import wx from 'weixin-js-sdk';
    import {
        appid,
        secret
    } from "@/request/secret_appid.js";
    import {
        apiGetAccessToken,
        apiGetJsapi_ticket,
        getSignature
    } from '@/request/locationApi.js';
    export default {
        onLaunch: function() {
            let {
                accessToken,
                dateTime
            } = uni.getStorageSync("access_token");
            let {
                jsapiTicket
            } = uni.getStorageSync("jsapi_ticket");
            let chaTime = new Date().getTime() - dateTime;
            let h_2 = 2 * 60 * 60 * 1000; // 2*60*60*1000    2小时毫秒值
            if (!uni.getStorageSync("access_token") || chaTime >= h_2) { // 超过2小时需要重新获取accessToken
                console.log("重新请求token");
                this.gettoken();
            } else {
                console.log("直接走配置");
                let result = getSignature(jsapiTicket); // 传入ticket获得timestamp,nonceStr,signature
                this.configWx(result); // 初始化配置
            }
        },
        onShow: function() {},
        onHide: function() {},
        methods: {
            // 获取token
            gettoken() {
                apiGetAccessToken(appid, secret).then(res => {
                    // 需要缓存token
                    if (!res.data.errcode) {
                        let access_token = {
                            accessToken: res.data.access_token,
                            dateTime: new Date().getTime(),
                        }
                        uni.setStorageSync("access_token", access_token);
                        this.getJsapi_ticket(res.data.access_token); // 获取jsapi_ticket
                    } else {
                        uni.showToast({
                            title: `获取accessToken失败,errcode:${res.data.errcode}`,
                            icon: "none"
                        })
                    }
                })
            },
            // 获取jsapi_ticket
            getJsapi_ticket(accessToken) {
                apiGetJsapi_ticket(accessToken).then(res => {
                    if (res.data.errcode == 0) {
                        let jsapi_ticket = {
                            jsapiTicket: res.data.ticket
                        }
                        uni.setStorageSync("jsapi_ticket", jsapi_ticket);
                        let result = getSignature(res.data.ticket); // 签名获取timestamp,nonceStr,signature
                        this.configWx(result); // 初始化配置
                    } else {
                        uni.showToast({
                            title: `获取jsapi_ticket失败,errcode:${res.data.errcode}`,
                            icon: "none"
                        })
                    }
                })
            },
            // 初始化配置
            configWx(result) {
                wx.config({
                    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                    appId: appid, // 必填,公众号的唯一标识
                    timestamp: result.timestamp, // 必填,生成签名的时间戳
                    nonceStr: result.noncestr, // 必填,生成签名的随机串
                    signature: result.signature, // 必填,签名
                    jsApiList: ["getLocation"] // 必填,需要使用的JS接口列表
                });
                wx.error((err) => {
                    uni.showToast({
                        title: "配置失败",
                        icon: "none"
                    })
                })
            },
        }
    }
</script>

<style>
</style>
3.4 获取定位方法
weixin-js-sdk_location.js

import wx from 'weixin-js-sdk';
// 坐标转化的方法
import {
    gcj02tobd09
} from '@/utils/coordinateTransform.js';

// 获取地理坐标
export function getByLocation() {
    return new Promise((resolve, reject) => {
        wx.ready(() => {
            wx.getLocation({
                type: 'gcj02', // 默认为wgs84(gcj02)的gps坐标
                success: function(res) {
                    let result = gcj02tobd09(res.longitude, res.latitude);
                    let lngLat = {
                        code: 200,
                        lng: result[0],
                        lat: result[1]
                    };
                    resolve(lngLat)
                },
                error: function(err) {
                    reject(err)
                },
            })
        })
    })
}
3.5 使用
<template>
    <view></view>
</template>

<script>
    import {
        getByLocation
    } from '@/utils/weixin-js-sdk_location.js';

    export default {
        data() {
            return {}
        },
        onShow() {
            // 通过公众号sdk获取位置
            getByLocation().then(res => {
                if (res.code == 200) {
                    alert(JSON.stringify(res))
                } else {
                    uni.showToast({
                        title: "获取经纬度失败",
                        icon: "none"
                    })
                }
            })
        },
        methods: {}
    }
</script>

<style>
</style>

第四步:所需文件

4.1 secret_appid.js:存储appid及secret
// 测试公众号
let appid = "";
let secret = "";
export {
    appid,
    secret
}
4.2 locationApi.js:获取accessToken、jsapi_ticket、签名等方法
import CryptoJS from "crypto-js";

/* 
请求函数
*/
function request({
    url,
    method,
    params
}) {
    uni.showLoading({
        title: "加载中..."
    });

    return new Promise((resolve, reject) => {
        uni.request({
            url: url,
            method: method || 'GET',
            data: params || {},
            success(res) {
                resolve(res);
            },
            fail(err) {
                reject(err);
            },
            complete() {
                uni.hideLoading();
            }
        });
    });
}

/* 第一步:获取accessToken
access_token的有效期目前为2个小时,需定时刷新
传参:
    appid:开发者ID(AppID)
    secret:开发者密码(AppSecret)
*/
// https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}
function apiGetAccessToken(appid, secret) {
    return request({
        url: `/api/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`,
    })
}

/* 第二步:获取jsapi_ticket
jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket)用于权限验证的签名
传参:
    access_token
*/
function apiGetJsapi_ticket(access_token) {
    return request({
        url: `/api/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`,
    })
}

// 第三步:获取signature
function getSignature(ticket) {
    let noncestr = getRandomString(); // 16位随机字符串
    let jsapi_ticket = ticket; // 此处必须得到有效的jsapi_ticket
    let timestamp = getTimestamp(); // 时间戳
    let url = getConfigUrl(); // URL

    let obj = {
        noncestr,
        jsapi_ticket,
        timestamp,
        url
    }
    let string1 = sort_ascii(obj);
    let signature = CryptoJS.SHA1(string1).toString();

    let result = {
        noncestr,
        timestamp,
        signature
    }
    return result;
}

/* 
签名算法所需参数:
    noncestr:随机字符串,
    jsapi_ticket:有效的,
    timestamp:时间戳,
    url:(当前网页的URL,不包含#及其后面部分)

对以上四个参数整理成对象并按ascii码从小到大排序,排完序在进行sh1加密    得到signature
let result = { noncestr, jsapi_ticket: ticket, timestamp, url: getConfigUrl() };
sort_ascii(result)
*/
// 生成一个随机的字符串
function getRandomString(len = 16) {
    let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
    let maxPos = chars.length;
    let character = '';

    if (len) {
        for (let i = 0; i < len; i++) {
            character += chars.charAt(Math.floor(Math.random() * maxPos))
        }
    } else {
        for (let i = 0; i < len; i++) {
            character += chars.charAt(Math.floor(Math.random() * maxPos))
        }
    }
    return character;
}
// 获取时间戳
function getTimestamp() {
    return new Date().getTime();
}
// 获取url
function getConfigUrl() {
    let u = window.navigator.userAgent;
    let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
    //安卓需要使用当前URL进行微信API注册(即当场调用location.href.split('#')[0])
    //iOS需要使用进入页面的初始URL进行注册,(即在任何pushstate发生前,调用location.href.split('#')[0])
    let url = '';
    if (isiOS) {
        url = `${window.localStorage.getItem('_iosWXConfig_') || window.location.href.split('#')[0]}`; //获取初始化的url相关参数
    } else {
        url = window.location.href.split('#')[0];
    }
    return url;
}
// 按ascii码从小到大排序
function sort_ascii(obj) {
    let arr = [];
    let num = 0;
    for (let i in obj) {
        arr[num] = i;
        num++;
    }
    let sortArr = arr.sort();
    let str = ''; //自定义排序字符串
    for (let i in sortArr) {
        str += sortArr[i] + '=' + obj[sortArr[i]] + '&';
    }
    //去除两侧字符串
    let char = '&';
    str = str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '');

    return str;
}

export {
    apiGetAccessToken,
    apiGetJsapi_ticket,
    getRandomString,
    getTimestamp,
    getConfigUrl,
    sort_ascii,
    getSignature
}
4.3 weixin-js-sdk_location.js:获取定位封装的方法
import wx from 'weixin-js-sdk';
import {
    gcj02tobd09
} from '@/utils/coordinateTransform.js';

// 获取地理坐标
export function getByLocation() {
    return new Promise((resolve, reject) => {
        wx.ready(() => {
            wx.getLocation({
                type: 'gcj02', // 默认为wgs84(gcj02)的gps坐标
                success: function(res) {
                    let result = gcj02tobd09(res.longitude, res.latitude);
                    let lngLat = {
                        code: 200,
                        lng: result[0],
                        lat: result[1]
                    };
                    resolve(lngLat)
                },
                error: function(err) {
                    reject(err)
                },
            })
        })
    })
}
4.4 coordinateTransform.js:坐标转换方法
// 地图坐标转换公共方法

//定义一些常量
const PI = 3.1415926535897932384626;
const a = 6378245.0;
const ee = 0.00669342162296594323;

export function transformlat(lng, lat) {
  var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
  ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
  ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
  return ret
}

export function transformlng(lng, lat) {
  var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
  ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
  ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
  return ret
}

/**
 * 判断是否在国内,不在国内则不做偏移
 * @param lng
 * @param lat
 * @returns {boolean}
 */
export function out_of_china(lng, lat) {
  return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
}

/**
 * WGS84转GCj02
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function wgs84togcj02 (lng, lat) {
  if (out_of_china(lng, lat)) {
    return [lng, lat]
  } else {
    var dlat = transformlat(lng - 105.0, lat - 35.0);
    var dlng = transformlng(lng - 105.0, lat - 35.0);
    var radlat = lat / 180.0 * PI;
    var magic = Math.sin(radlat);
    magic = 1 - ee * magic * magic;
    var sqrtmagic = Math.sqrt(magic);
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
    dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
    var mglat = lat + dlat;
    var mglng = lng + dlng;
    return [mglng, mglat]
  }
}

/**
 * GCJ02 转换为 WGS84
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function gcj02towgs84 (lng, lat) {
  if (out_of_china(lng, lat)) {
    return [lng, lat]
  } else {
    var dlat = transformlat(lng - 105.0, lat - 35.0);
    var dlng = transformlng(lng - 105.0, lat - 35.0);
    var radlat = lat / 180.0 * PI;
    var magic = Math.sin(radlat);
    magic = 1 - ee * magic * magic;
    var sqrtmagic = Math.sqrt(magic);
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
    dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
    let mglat = lat + dlat;
    let mglng = lng + dlng;
    return [lng * 2 - mglng, lat * 2 - mglat]
  }
}

/**
 * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
 * 即 百度 转 谷歌、高德
 * @param bd_lon
 * @param bd_lat
 * @returns {*[]}
 */
export function bd09togcj02 (bd_lon, bd_lat) {
  var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
  var x = bd_lon - 0.0065;
  var y = bd_lat - 0.006;
  var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
  var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
  var gg_lng = z * Math.cos(theta);
  var gg_lat = z * Math.sin(theta);
  return [gg_lng, gg_lat]
}

/**
 * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
 * 即谷歌、高德 转 百度
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function gcj02tobd09 (lng, lat) {
  var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
  var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
  var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
  var bd_lng = z * Math.cos(theta) + 0.0065;
  var bd_lat = z * Math.sin(theta) + 0.006;
  return [bd_lng, bd_lat]
}

/**
 * WGS84转BD09
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function WGS84ToBD09 (lng, lat) {
  let gcj02 = wgs84togcj02(lng, lat);
  return gcj02tobd09(gcj02[0], gcj02[1]);
}

/**
 * BD09转WGS84
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function BD09ToWGS84 (lng, lat) {
  let gcj02 = bd09togcj02(lng, lat);
  return gcj02towgs84(gcj02[0], gcj02[1]);
}

第五步:

测试公众号(开启获取位置的权限、js接口安全域名)

微信公众平台https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

第六步:

vebniew的src域名要和js接口安全域名一致 (不能一个写花生壳域名一个写本地ip)

标签: vue.js 前端 xss

本文转载自: https://blog.csdn.net/weixin_46029283/article/details/135956204
版权归原作者 一只大菜鸟J 所有, 如有侵权,请联系我们删除。

“微信小程序内嵌webView访问H5界面,在H5界面获取定位”的评论:

还没有评论