2***@qq.com
2***@qq.com
  • 发布:2021-12-15 00:13
  • 更新:2021-12-15 00:13
  • 阅读:831

应用外唤起地图并标注地点

分类:uni-app

map.js

/*   
*   功能:应用外唤起地图并标注地点  
*   特点:uni.openLocation()的简易替代品,唤起指定地图的某个标点。  
*   优点:不依赖uniapi,无须集成sdk,无须声明位置权限,兼容多个地图。  
*   缺点:非应用内置地图,依赖文档等等等。  
*   日期:2021年12月15日  
*   支付宝:\u004e\u0054\u0041\u0079\u004d\u0054\u0067\u0077\u004e\u007a\u0051\u0035\u0051\u0048\u0046\u0078\u004c\u006d\u004e\u0076\u0062\u0051\u003d\u003d  
*/  
/*  
#   用法  
    import mapTool from 'xxx.js'  
    mapTool.navTo(point, map)  
#   提示  
    1.未加入Google Map,未使用WGS84坐标系,需要唤起后直接导航 或 地址逆解析,请自行解决。  
    2.(重要)使用腾讯地图scheme需要开发者Key,请自行注册。  
    3.(重要)使用查询地图是否安装的方法mapsExist(),iOS9以后需要添加白名单才可查询。即在manifest.json文件plus->distribute->apple->urlschemewhitelist节点下添加(如urlschemewhitelist:["xxx"]),名称请参考下方MapsInfo对象各属性的i_wlname。  
    4.Document:  
    <https://lbsyun.baidu.com/index.php?title=uri>  
    <https://lbs.amap.com/api/amap-mobile/summary>  
    <https://lbs.qq.com/webApi/uriV1/uriGuide/uriOverview>  
    <https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html>  
    <https://developers.google.com/maps/documentation/ios/urlscheme>  
*/  

// 腾讯地图开发者Key  
const QQMapKey = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"  

const Platform = plus.os.name // Android;iOS;...  
const MapsInfo = {  
    baidu: {  
        url: 'http://map.baidu.com',  
        CN: '百度地图',  
        EN: 'bdmap',  
        w_uri: 'http://api.map.baidu.com',  
        a_intent: 'baidumap://',  
        a_pname: 'com.baidu.BaiduMap', //package name  
        i_scheme: 'baidumap://', // action  
        i_wlname: 'baidumap' // white list name  
    },  
    gaode: {  
        url: 'https://m.amap.com',  
        CN: '高德地图',  
        EN: 'amap',  
        w_uri: 'https://uri.amap.com',  
        a_intent: 'androidamap://',  
        a_pname: 'com.autonavi.minimap', //package name  
        i_scheme: 'iosamap://', // action  
        i_wlname: 'iosamap' // white list name  
    },  
    tengxun: {  
        url: 'https://map.qq.com',  
        CN: '腾讯地图',  
        EN: 'qqmap',  
        w_uri: 'https://apis.map.qq.com',  
        a_intent: 'qqmap://',  
        a_pname: 'com.tencent.map', //package name  
        i_scheme: 'qqmap://', // action  
        i_wlname: 'qqmap' // white list name  
    },  
    pingguo: { // 白名单需要增加maps,才可检测到系统地图  
        url: 'http://maps.apple.com',  
        CN: '系统地图',  
        EN: 'maps',  
        w_uri: 'http://maps.apple.com',  
        a_intent: 'androidamap://', // 安卓高德地图,理论上用不到  
        a_pname: 'com.autonavi.minimap', // 安卓高德地图,理论上用不到  
        i_scheme: 'maps://', // action  
        i_wlname: 'maps' // white list name  
    }  
}  
const DefaultMap = MapsInfo.tengxun // 据自身业务采用【腾讯地图】作为默认地图,腾讯地图scheme需要开发者Key  
const DefaultPoint = { // 默认标注,【找不到所在位置】意为lat、lng缺失;【未知位置】意为lbl缺失;  
    lat: 22.517007, // gcj02  
    lng: 113.392532, // gcj02  
    lbl: '找不到所在位置', // label  
    dtl: '未知地址' // detail  
}  
const DefaultService = { // 来源信息(可设为包名),百度地图、高德地图必填,不可空  
    web: 'web.xxx.app',  
    ios: 'ios.xxx.app',  
    android: 'android.xxx.app'  
}  

// GCJ-02(腾讯、高德等火星坐标系) To BD-09(百度坐标系)  
const gcj2bd = function(lat, lng) {  
    var point = new Object();  
    var x_pi = 3.14159265358979324 * 3000.0 / 180.0;  
    var x = new Number(lng);  
    var y = new Number(lat);  
    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 bd_lng = z * Math.cos(theta) + 0.0065;  
    var bd_lat = z * Math.sin(theta) + 0.006;  
    point.lng = bd_lng;  
    point.lat = bd_lat;  
    return point;  
}  

// BD-09(百度坐标系) To GCJ-02(腾讯、高德等火星坐标系)  
const bd2gcj = function(lat, lng) {  
    var point = new Object();  
    var x_pi = 3.14159265358979324 * 3000.0 / 180.0;  
    var x = new Number(lng - 0.0065);  
    var y = new Number(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 gcj_lng = z * Math.cos(theta);  
    var gcj_lat = z * Math.sin(theta);  
    point.lng = gcj_lng;  
    point.lat = gcj_lat;  
    return point;  
}  

// URL参数 To JSON对象  
const query2json = function(query) {  
    let param = {}; // 存储最终JSON结果对象  
    query.replace(/([^?&]+)=([^?&]+)/g, function(s, v, k) {  
        param[v] = decodeURIComponent(k); //解析字符为中文(据业务处理)  
        return k + '=' + v;  
    });  
    return param;  
}  

// JSON对象 To URL参数  
const json2query = function(json) {  
    let param = []  
    Object.keys(json).forEach(e => {  
        param.push(e + '=' + encodeURIComponent(json[e]))  
    })  
    return param.join('&')  
}  

// 深拷贝  
function _isArray (arr) {  
    return Object.prototype.toString.call(arr) === '[object Array]';  
}  
function _deepClone(obj) {  
    // 对常见的“非”值,直接返回原来值  
    if([null, undefined, NaN, false].includes(obj)) return obj;  
    if(typeof obj !== "object" && typeof obj !== 'function') {  
        //原始类型直接返回  
        return obj;  
    }  
    var o = _isArray(obj) ? [] : {};  
    for(let i in obj) {  
        if(obj.hasOwnProperty(i)){  
            o[i] = typeof obj[i] === "object" ? _deepClone(obj[i]) : obj[i];  
        }  
    }  
    return o;  
}  

// 判断是否存在这四个应用(百度地图、高德地图、腾讯地图、苹果地图),返回对象数组  
const mapsExist = function() {  
    let res = []  
    if (plus.runtime.isApplicationExist({  
            pname: MapsInfo.baidu.a_pname,  
            action: MapsInfo.baidu.i_scheme  
        })) {  
        console.log("[已安装百度地图]");  
        res.push(MapsInfo.baidu)  
    }  
    if (plus.runtime.isApplicationExist({  
            pname: MapsInfo.gaode.a_pname,  
            action: MapsInfo.gaode.i_scheme  
        })) {  
        console.log("[已安装高德地图]");  
        res.push(MapsInfo.gaode)  
    }  
    if (plus.runtime.isApplicationExist({  
            pname: MapsInfo.tengxun.a_pname,  
            action: MapsInfo.tengxun.i_scheme  
        })) {  
        console.log("[已安装腾讯地图]");  
        res.push(MapsInfo.tengxun)  
    }  
    if (Platform == 'iOS' && plus.runtime.isApplicationExist({  
            pname: MapsInfo.pingguo.a_pname,  
            action: MapsInfo.pingguo.i_scheme  
        })) {  
        console.log("[已安装系统地图]");  
        res.push(MapsInfo.pingguo)  
    }  
    return res  
}  

// 仅仅是打开地图应用(不荐)  
const openApp = function(map) {  
    if (Platform == "Android") {  
        plus.runtime.launchApplication({  
            pname: map.a_pname,  
        }, function(e) {  
            alert("Open system default browser failed: " + e.message);  
        });  
    } else if (Platform == "iOS") {  
        plus.runtime.launchApplication({  
            action: map.i_scheme  
        }, function(e) {  
            alert("Open system default browser failed: " + e.message);  
        });  
    } else {  
        alert("Operating system is not supported");  
    }  
}  

// 坐标参数处理  
const argHandle = function(point) {  
    if (!point) {  
        return DefaultPoint  
    }  
    let pot = _deepClone(point)  
    if (!pot.lat || !pot.lng) {  
        pot = DefaultPoint  
    }  
    if (!pot.lbl) {  
        pot['lbl'] = '未知位置'  
    }  
    if (!pot.dtl) {  
        pot['dtl'] = '未知地址'  
    }  
    return pot  
}  

// 应用内唤起地图应用,并标注位置,失败则使用浏览器唤起       C2C     对应导航path请查阅api文档  
const openByApp = function(map, point) {  
    return new Promise((resolve) => {  
        let pot = argHandle(point)  
        let url = ''  
        if (map.EN == 'bdmap') {  
            // 腾讯坐标系转换为百度坐标  
            let p = gcj2bd(pot.lat, pot.lng)  
            pot = {  
                ...pot,  
                ...p  
            }  

            if (Platform == 'Android') {  
                url =  
                    `bdapp://map/marker?location=${pot.lat},${pot.lng}&title=${pot.lbl}&content=${pot.dtl}&src=${DefaultService.android}`  
            } else if (Platform == 'iOS') {  
                url =  
                    `baidumap://map/marker?location=${pot.lat},${pot.lng}&title=${pot.lbl}&content=${pot.dtl}&src=${DefaultService.ios}`  
            }  
        } else if (map.EN == 'amap') {  
            if (Platform == 'Android') {  
                url =  
                    `androidamap://viewMap?lat=${pot.lat}&lon=${pot.lng}&poiname=${pot.lbl}&sourceApplication=${DefaultService.android}&dev=0`  
            } else if (Platform == 'iOS') {  
                url =  
                    `iosamap://viewMap?lat=${pot.lat}&lon=${pot.lng}&poiname=${pot.lbl}&sourceApplication=${DefaultService.ios}&dev=0`  
            }  
        } else if (map.EN == 'qqmap') {  
            if (Platform == 'Android') {  
                url =  
                    `qqmap://map/marker?marker=coord:${pot.lat},${pot.lng};title:${pot.lbl};addr:${pot.dtl}&referer=${QQMapKey}`  
            } else if (Platform == 'iOS') {  
                url =  
                    `qqmap://map/marker?marker=coord:${pot.lat},${pot.lng};title:${pot.lbl};addr:${pot.dtl}&referer=${QQMapKey}`  
            }  
        } else if (map.EN == 'maps') {  
            if (Platform == 'Android') {  
                url =  
                    `androidamap://viewMap?lat=${pot.lat}&lon=${pot.lng}&poiname=${pot.lbl}&sourceApplication=${DefaultService.android}&dev=0`  
            } else if (Platform == 'iOS') {  
                // Unlike some schemes, map URLs do not start with a “maps” scheme identifier. Instead, map links are specified as regular http links and are opened either in Safari or the Maps app on the target platform.  
                url = `http://maps.apple.com?ll=${pot.lat},${pot.lng}&q=${pot.lbl}`  
            }  
        }  

        if (url != '') {  
            plus.runtime.openURL(encodeURI(url), async function(e) {  
                console.error(e)  
                let result = await openByBrowser(map, point)  
                resolve(result)  
            });  
            resolve(true)  
        } else {  
            console.error('应用内唤起失败')  
            resolve(false)  
        }  

    })  
}  

// 浏览器唤起地图应用,并标注位置      C2B2C   对应导航path请查阅api文档  
const openByBrowser = function(map, point) {  
    return new Promise((resolve) => {  
        let pot = argHandle(point)  
        let url = ''  
        if (map.EN == 'bdmap') {  
            // 腾讯坐标系转换为百度坐标  
            let p = gcj2bd(pot.lat, pot.lng)  
            pot = {  
                ...pot,  
                ...p  
            }  
            url =  
                `http://api.map.baidu.com/marker?location=${pot.lat},${pot.lng}&title=${pot.lbl}&content=${pot.dtl}&src=${DefaultService.web}&output=html`  
        } else if (map.EN == 'amap') {  
            url =  
                `https://uri.amap.com/marker?position=${pot.lng},${pot.lat}&name=${pot.lbl}&src=${DefaultService.web}&callnative=1`  
        } else if (map.EN == 'qqmap') {  
            url =  
                `https://apis.map.qq.com/uri/v1/marker?marker=coord:${pot.lat},${pot.lng};title:${pot.lbl};addr:${pot.dtl}&referer=${DefaultService.web}`  
        } else if (map.EN == 'maps') {  
            url = `http://maps.apple.com?ll=${pot.lat},${pot.lng}&q=${pot.lbl}`  
        }  

        if (url != '') {  
            plus.runtime.openURL(encodeURI(url), function(e) {  
                console.error(e)  
                resolve(false)  
            });  
            resolve(true)  
        } else {  
            console.error('浏览器唤起失败')  
            resolve(false)  
        }  

    })  
}  

// 地图标注,map指定唤起地图(string,['qqmap','amap','bdmap','maps']之一),point坐标对象(object,DefaultPoint)  
const navTo = async function(point, map) {  
    // test  
    // let result = openByBrowser(MapsInfo.pingguo, point)  
    // let result = await openByApp(MapsInfo.pingguo, point)  
    // console.log('打开结果', result)  
    // return false  

    let result = false  
    let res = mapsExist()  
    if (res.length > 0) { // 无地图应用  
        let index = res.findIndex(e => { // 参数有指定地图应用  
            return e.EN == map  
        })  
        if (index != -1) {  
            result = await openByApp(res[index], point)  
        } else if (res.findIndex(e => { // 如果有安装默认地图应用,优先使用默认地图Api  
                return e.EN == DefaultMap.EN  
            }) != -1) {  
            result = await openByApp(DefaultMap, point)  
        } else { // 默认用第一个地图导航  
            result = await openByApp(res[0], point)  
        }  
    } else { // 无地图应用,浏览器打开  
        let arr = Object.values(MapsInfo)  
        let index = Object.values(MapsInfo).findIndex(e => { // 参数有指定地图应用  
            return e.EN == map  
        })  
        if (index != -1) {  
            result = await openByBrowser(arr[index], point)  
        } else {  
            result = await openByBrowser(DefaultMap, point)  
        }  
    }  
    return result  
}  

module.exports = {  
    navTo  
}  
1 关注 分享
1***@qq.com

要回复文章请先登录注册