CLLocationManager和中國地圖偏移(China Shift)

CLLocationManager類的作用是監聽GPS的位置消息,當用戶座標發生變化時,會調用下面的方法進行通知:

-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;

問題來了,當我們把newLocation中的座標映射到MKMapView控件上時,會發現這個點跟本不是我們所在的位置,而是離我們百米左右的某個地方。
至於原因,。

那麼,我們需要將原始的(真實的)位置座標,轉換爲有中國特色的座標。
對於這個問題,本文總結了兩個處理辦法:

1. 使用IOS的私有類MKLocationManager來計算。
  這個做法是有風險的,蘋果不允許私有模塊被直接調用。換句話說,你的軟件可能會被Deny。

  因爲是私有模塊,我們需要聲明這個類和我們要用到的函數,代碼如下


@interface MKLocationManager   
    + (id)sharedLocationManager;       // 創建並獲取MKLocationManager實例
    - (BOOL)chinaShiftEnabled;        // 判斷IOS系統是否支持計算偏移
    - (CLLocation*)_applyChinaLocationShift:(CLLocation*)arg;   // 傳入原始位置,計算偏移後的位置
@end


在CLLocationManager的位置監聽函數中,我們把newLocation(原始位置),轉換爲中國位置

-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if ([[MKLocationManager sharedLocationManager] chinaShiftEnabled]) {
        newLocation = [[MKLocationManager sharedLocationManager] _applyChinaLocationShift:newLocation];
        if (newLocation == nil) {  // 很重要,計算location好像是要聯網的,軟件剛啓動時前幾次計算會返回nil。
            return;
        }
    }
    ...
}

這樣,經轉換後的newLocation,已經是中國的位置了。現在在映射到MKMapView上時,會顯示正確的所在位置。

 

2. 打開MKMapView的showsUserLocation功能。

  初始化MKMapView時,將屬性showsUserLocation設置爲YES,MKMapView會啓動內置的位置監聽服務,當用戶位置變化時,調用delegate的回調函數:

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    // 這裏得到的userLocation,已經是偏移後的位置了
}

這個方法不會用到IOS的私有類和函數,不會有被絕的風險。缺點可能是不能像CLLocationManager那樣進行豐富的配置,至少目前我還沒找到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章