/* * 功能:应用外唤起地图并标注地点 * 特点: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 }
0条大神的评论