看到群友在折騰地理定位卷要,簡單寫一下,不過是基于一段時間前的經(jīng)驗独榴,權(quán)做參考吧僧叉。
首先我們了解一下地理定位的基本知識:
手機定位方式
定位即獲取用戶當前經(jīng)緯度,手機定位方式常見有三種:
- GPS/北斗:根據(jù)系統(tǒng)GPS/北斗模塊通過與衛(wèi)星通信實時計算獲取經(jīng)緯度棺榔,精度10-100米左右,限制是容易受環(huán)境影響症歇,在室內(nèi)幾乎不起作用郎笆。
- 基站:根據(jù)運營商基站位置計算經(jīng)緯度谭梗,基站可能離手機百米甚至上千米遠,所以誤差較大宛蚓,精度100-3000米不等激捏,限制是定位較慢,精度差凄吏。
- WIFI:根據(jù)周圍WIFI路由器位置計算經(jīng)緯度远舅,在城市范圍,網(wǎng)絡(luò)節(jié)點比較密集痕钢,所以城市精度高點图柏,精度100-200米左右,限制是受周圍WIFI數(shù)量和分布影響任连,需要打開手機WIFI開關(guān)蚤吹。
混合式應(yīng)用地理定位的方案
混合式應(yīng)用有兩種定位方案:
- 原生定位;
- 網(wǎng)頁定位随抠;
原生定位使用GPS/北斗定位裁着,網(wǎng)頁定位僅支持基站定位和WIFI定位兩種方式,自然優(yōu)先選型原生定位暮刃,但是,為了在一些影響GPS信號接收的地方提高精度爆土,現(xiàn)在的第三方定位SDK大多又引入了后兩種方式作為輔助定位補充椭懊。高德和百度就是加入輔助定位的優(yōu)化過的定位方式,其中百度的會比高德的準確一點步势。
Cordova封裝第三方原生定位SDK
IOS平臺都是通過系統(tǒng)SDK接口獲取的氧猬,因此所有App獲取定位及精度的能力是相同的,即使Google Maps坏瘩、百度地圖盅抚、高德地圖這種專業(yè)地圖App也是如此;而Android平臺由于Google Service被閹割導(dǎo)致該系統(tǒng)SDK無法正常使用倔矾,國內(nèi)App通常是通過高德妄均、百度等第三方SDK接口獲取定位信息,各定位能力和精度上會有些差異哪自。所以丰包,如果搜索Github上的源碼,發(fā)現(xiàn)大多Cordova定位插件只封裝第三方SDK的Android版本壤巷。如果IOS需要定位功能邑彪,則大多會選用apache的通用Corodva定位插件cordova-plugin-geolocation。換句話說胧华,對于不少混合式應(yīng)用來說寄症,使用如下的組合方案:
Android上第三方定位SDK封裝的Cordova插件 + IOS上使用cordova-plugin-geolocation宙彪。
在個人看來,上述方案有巧,cordova-plugin-geolocation只是調(diào)用了系統(tǒng)的SDK释漆,并不會像國內(nèi)第三方SDK那樣添加了輔助定位的功能,總覺得有欠缺剪决,更傾向于也接入第三方定位SDK灵汪,有部分網(wǎng)友也有我這種想法,所以也封裝了第三方定位IOS版插件柑潦,如:cordova-plugin-baidumaplocation享言。
對于這些兼容Android和IOS的Cordova插件又是如何考量的?我個人傾向于三個特點:小渗鬼、易用览露、新:
- 如上述提到插件雖是較新的,但用的是百度地圖的庫譬胎,比較臃腫差牛,現(xiàn)在百度地圖把定位sdk獨立抽離了出來做成了百度定位sdk,所以如果它改成百度定位的庫我是比較樂意使用的堰乔。
- 百度和高德用誰好我也掙扎了一段時間偏化,最后選用高德,因為總體上镐侯,高德的文檔相對較好侦讨,API也比較清晰簡潔,對移動端的支持也更友好些(如提供有移動風格的城市列表選擇組件)苟翻。
- 現(xiàn)有的高德定位插件韵卤,大多不維護了,使用的第三方庫都是2年或以上崇猫,比較舊沈条,所以我造了個輪子:cordova-location-amap——但我也沒有維護了……
數(shù)據(jù)偏移之互聯(lián)網(wǎng)地圖坐標系
有時候通過定位獲取的經(jīng)緯度并不是適用所有地圖的,如高德定位獲取到的經(jīng)緯度是不能在百度地圖上正確打點的诅炉,因為地圖使用了不同的坐標系蜡歹,常見的互聯(lián)網(wǎng)地圖坐標系有下面三種:
WGS84(GPS)
國際標準,一般從國際標準的GPS設(shè)備獲取的坐標都是WGS84涕烧,以及國際地圖提供商使用的坐標系季稳。
GCJ02
中國標準,國測局02年發(fā)布的坐標系澈魄。又稱“火星坐標”景鼠。在中國,基于安全需要,必須至少使用“GCJ02”對地理位置進行加偏處理铛漓,把真實的坐標加密成虛假的坐標溯香。比如谷歌中國、高德浓恶、騰訊都在用這個坐標系玫坛。
BD09
百度標準。 除了火星坐標系統(tǒng)包晰,不同的地圖數(shù)據(jù)商也可能使用自己的坐標系統(tǒng)湿镀。百度就在“GCJ02”的基礎(chǔ)上進行二次加密。
所以跨地圖數(shù)據(jù)共享伐憾,一般有相應(yīng)的糾偏算法勉痴,如百度和高德的坐標轉(zhuǎn)換:
/**
* 高德坐標轉(zhuǎn)百度
* @param gg_lon 經(jīng)度
* @param gg_lat 緯度
*/
gaode2baidu(gg_lon, gg_lat): {
longitude: number,
latitude: number
} {
if(gg_lon || gg_lat){
return {
longitude: gg_lon,
latitude: gg_lat
}
}
var X_PI = Math.PI * 3000.0 / 180.0;
var x = gg_lon, y = gg_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_lon = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return {
longitude: parseFloat(bd_lon.toFixed(6)),
latitude: parseFloat(bd_lat.toFixed(6))
};
}
/**
* 百度坐標轉(zhuǎn)高德
* @param bd_lon 經(jīng)度
* @param bd_lat 緯度
*/
baidu2gaode(bd_lon, bd_lat): {
longitude: number,
latitude: number
} {
if(bd_lon || bd_lat){
return {
longitude: bd_lon,
latitude: bd_lat
}
}
var X_PI = Math.PI * 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_lon = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return {
longitude: parseFloat(gg_lon.toFixed(6)),
latitude: parseFloat(gg_lat.toFixed(6))
}
}
綜合上述知識,可以得出使用單一的定位功能树肃,也可以通過坐標轉(zhuǎn)換算法兼容各種地圖服務(wù)蒸矛,也就是說可以使用原生定位功能,結(jié)合網(wǎng)頁地圖實現(xiàn)地圖應(yīng)用胸嘴,如我就是下面的方式使用:
"cordova-location-amap": "^1.0.1",
"cordova-plugin-android-permissions": "^1.0.0",
加
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.4.3&key=3e1376d2e1aeff"></script>
<!-- UI組件庫 1.0 -->
<script src="http://webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
ionic中簡單示例操作:
- 去地圖服務(wù)商申請原生和Web版等key雏掠;
- 安裝基于對應(yīng)地圖服務(wù)商的Cordova插件,變量填入申請的key劣像;
- 在index.html中添加上述js文件乡话,然后在具體的某個頁面,如home.page.html中添加代碼(注意指定寬高耳奕,不然可能地圖出來了绑青,但是卻看不多,自己還找半天):
<div id="container" style="width:100%;height:100%">
</div>
- home.page.ts添加初始化地圖代碼:
declare let AMap: any;
declare let Zepto: any;
declare let AMapUI: any;
loadMap() {
if(typeof (AMapUI) == "undefined" || typeof (Zepto) == "undefined"){
return;
}
// 設(shè)置DomLibrary
AMapUI.setDomLibrary(Zepto);
if (typeof (AMap) != "undefined") {
const map = new AMap.Map('container', {
resizeEnable: true,
zoom: 10,
center: this.center
});
this.map = map;
// 加載BasicControl吮铭,loadUI的路徑參數(shù)為模塊名中 'ui/' 之后的部分
AMapUI.loadUI(['control/BasicControl'], (BasicControl)=> {
// 縮放控件
this.map.addControl(new BasicControl.Zoom({
position: 'lt', //left top时迫,左上角
showZoomNum: true // 顯示zoom值
}));
});
}
}
- 調(diào)用原生定位功能:
cordova.plugins.aMapLocation.getCurrentPosition(this.configNative,
(locate: {
city: string,
longitude: number,
latitude: number
}) => {
console.log(locate);
},
e => {
console.log(e);
}
);
基本調(diào)用就這樣子了颅停,省卻部分谓晌,僅提供主要代碼,如地圖key申請等請自行搜索癞揉。
定位方案不是唯一的纸肉,有的網(wǎng)頁定位的接口,會嘗試判斷是否安裝有自家的原生地圖應(yīng)用喊熟,有就借用其定位柏肪,沒有就使用網(wǎng)頁定位,有機會的也可以了解一下芥牌。