React-native 高德定位

目前看了下很多高德定位的,基本都是監(jiān)聽寫的,每次調(diào)用會(huì)使用多次.
所以自己寫了一個(gè)封裝適合ios和安卓. 還有獲取第三方地圖的跳轉(zhuǎn)功能
只調(diào)用一次定位,不會(huì)重復(fù)調(diào)用,有使用的朋友請(qǐng)自行獲取.
至于高德地圖的配置 還請(qǐng)自行去高德官網(wǎng)查看,我這里只放出源碼
ios:
.h文件里

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <AMapLocationKit/AMapLocationKit.h>
#import <AMapLocationKit/AMapLocationManager.h>
#import <React/RCTEventEmitter.h>
NS_ASSUME_NONNULL_BEGIN

@interface LocationModule : NSObject<RCTBridgeModule,AMapLocationManagerDelegate>

@end

NS_ASSUME_NONNULL_END

.M文件里

//
//  LocationModule.m
//
//  Created by jonson liu on 2019/4/12.
//  Copyright ? 2019 Facebook. All rights reserved.
//

#import "LocationModule.h"
#import <React/RCTEventEmitter.h>
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <AMapLocationKit/AMapLocationKit.h>
#import <AMapLocationKit/AMapLocationManager.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface LocationModule ()
  @property(nonatomic, strong) id jsonStr;
@property(nonatomic, copy)RCTResponseSenderBlock callBack;
@end

@implementation LocationModule{
     AMapLocationManager *_manager;
}
RCT_EXPORT_MODULE(MyLocation)

RCT_EXPORT_METHOD(setOptions:(NSDictionary *)options) {
  if (options[@"distanceFilter"]) {
    _manager.distanceFilter = [options[@"distanceFilter"] doubleValue];
  }
  if (options[@"reGeocode"]) {
    _manager.locatingWithReGeocode = [options[@"reGeocode"] boolValue];
  }
  if (options[@"background"]) {
    _manager.allowsBackgroundLocationUpdates = [options[@"background"] boolValue];
  }
}

RCT_REMAP_METHOD(init, key:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
  [AMapServices sharedServices].apiKey = key;
  if (!_manager) {
    _manager = [AMapLocationManager new];
    _manager.delegate = self;
    resolve(nil);
  } else {
    resolve(nil);
  }
}


- (void)amapLocationManager:(AMapLocationManager *)manager
          didUpdateLocation:(CLLocation *)location
                  reGeocode:(AMapLocationReGeocode *)reGeocode {
  id json = [self json:location reGeocode:reGeocode];
  self.jsonStr = json;
  [_manager stopUpdatingLocation];
  [NSUserDefaults.standardUserDefaults setObject:json forKey:LocationModule.storeKey];
  NSString *callbackData = [NSString stringWithFormat:@"%@", self.jsonStr];
  self.callBack(@[[NSNull null],json]);
}

RCT_EXPORT_METHOD(addEventCrood:(NSString *)name callback:(RCTResponseSenderBlock)callback){
  //  接收RN傳過來了name
  [_manager startUpdatingLocation];
  self.callBack = callback;
  NSLog(@"~~~~~~~~~~%@",self.jsonStr);
  
  //回掉給JS
//  callback(@[[NSNull null],callbackData]);
  
}

- (id)json:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode {
  if (reGeocode && reGeocode.formattedAddress.length) {
    return @{
             @"accuracy": @(location.horizontalAccuracy),
             @"latitude": @(location.coordinate.latitude),
             @"longitude": @(location.coordinate.longitude),
             @"altitude": @(location.altitude),
             @"speed": @(location.speed),
             @"direction": @(location.course),
             @"timestamp": @(location.timestamp.timeIntervalSince1970 * 1000),
             @"address": reGeocode.formattedAddress,
             @"poiName": reGeocode.POIName,
             @"country": reGeocode.country,
             @"province": reGeocode.province,
             @"city": reGeocode.city,
             @"cityCode": reGeocode.citycode,
             @"district": reGeocode.district,
             @"street": reGeocode.street,
             @"streetNumber": reGeocode.number,
             @"adCode": reGeocode.adcode,
             };
  } else {
    return @{
             @"accuracy": @(location.horizontalAccuracy),
             @"latitude": @(location.coordinate.latitude),
             @"longitude": @(location.coordinate.longitude),
             @"altitude": @(location.altitude),
             @"speed": @(location.speed),
             @"direction": @(location.course),
             @"timestamp": @(location.timestamp.timeIntervalSince1970 * 1000),
             };
  }
}

+ (NSString *)storeKey {
  return @"AMapGeolocation";
}

//~~~~~~~~~~~~~~~~~~~~~~~以下為調(diào)用第三方地圖方法~~~~~~~~~~~~~~~~~~~~~~~~
RCT_EXPORT_METHOD(addEvent:(NSString *)name url:(NSString *)url lon:(NSString *)lon lat:(NSString *) lat address:(NSString*) address)
{
  NSLog(@"地圖app=== %@ url %@-----經(jīng)度:%@------緯度:%@------地址:%@", name, url,lon,lat,address);
  
  if ([url isEqualToString : @"ios"]) {
    [self appleMap:lon andB:lat andC:address];
  }else{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
  }
  
}

RCT_EXPORT_METHOD(findEvents:(NSString *)lon lat:(NSString *)lat address:(NSString*)address resolver:(RCTResponseSenderBlock)callback)
{
  NSMutableArray *maps = [NSMutableArray array];
  
  //蘋果地圖
  if ([[UIApplication sharedApplication]canOpenURL:[NSURL URLWithString:@"http://maps.apple.com/"]]) {
    NSMutableDictionary *iosMapDic = [NSMutableDictionary dictionary];
    iosMapDic[@"title"] = @"蘋果地圖";
    iosMapDic[@"url"] = @"ios";
    [maps addObject:iosMapDic];
  }
  //百度地圖
  if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"baidumap://"]]) {
    NSMutableDictionary *baiduMapDic = [NSMutableDictionary dictionary];
    baiduMapDic[@"title"] = @"百度地圖";
    NSString *urlString = [[NSString stringWithFormat:@"baidumap://map/direction?origin={{我的位置}}&destination=name=%@&mode=driving&coord_type=gcj02",address] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    baiduMapDic[@"url"] = urlString;
    [maps addObject:baiduMapDic];
  }
  //高德地圖
  if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"iosamap://"]]) {
    NSMutableDictionary *gaodeMapDic = [NSMutableDictionary dictionary];
    gaodeMapDic[@"title"] = @"高德地圖";
    NSString *urlString = [[NSString stringWithFormat:@"iosamap://navi?sourceApplication=%@&backScheme=%@&lat=%f&lon=%f&dev=0&style=2",@"導(dǎo)航功能",@"nav123456",[lat doubleValue],[lon doubleValue]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    gaodeMapDic[@"url"] = urlString;
    [maps addObject:gaodeMapDic];
  }
  //騰訊地圖
  if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"qqmap://"]]) {
    NSMutableDictionary *qqMapDic = [NSMutableDictionary dictionary];
    qqMapDic[@"title"] = @"騰訊地圖";
    NSString *urlString = [[NSString stringWithFormat:@"qqmap://map/routeplan?from=我的位置&type=drive&tocoord=%f,%f&to=%@&coord_type=1&policy=0",[lat doubleValue],[lon doubleValue],address] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    qqMapDic[@"url"] = urlString;
    [maps addObject:qqMapDic];
  }
  
  NSMutableDictionary *cancalMapDic = [NSMutableDictionary dictionary];
  cancalMapDic[@"title"] = @"取消";
  [maps addObject:cancalMapDic];
  
  //  RCTLogInfo(@"地圖app===經(jīng)度:",maps);
  
  callback(@[maps]);
  
}

//蘋果地圖
//跳轉(zhuǎn)到蘋果自帶地圖
- (void)appleMap:(NSString*)lon andB:(NSString*)lat andC:(NSString*)address{
  NSLog(@"地圖app===經(jīng)度:%@------緯度:%@------地址:%@",lon,lat,address);
  //  MKMapItem *currentLoc = [MKMapItem mapItemForCurrentLocation];
  //
  //  MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake([lat doubleValue], [lon doubleValue]) addressDictionary:nil]];
  //
  //  MKMapItem *aaa = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake([lat doubleValue], [lon doubleValue]) addressDictionary:nil]];
  //
  //  NSArray *items = @[currentLoc,toLocation];
  //  NSDictionary *dic = @{
  //                        MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
  //                        MKLaunchOptionsMapTypeKey : @(MKMapTypeStandard),
  //                        MKLaunchOptionsShowsTrafficKey : @(YES)
  //                        };
  //  [MKMapItem openMapsWithItems:items launchOptions:dic];
  //MKMapItem 使用場(chǎng)景: 1. 跳轉(zhuǎn)原生地圖 2.計(jì)算線路
  MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
  //地理編碼器
  CLGeocoder *geocoder = [[CLGeocoder alloc] init];
  //我們假定一個(gè)終點(diǎn)坐標(biāo),測(cè)試地址:121.226669,31.998277
  [geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    CLPlacemark *endPlacemark  = placemarks.lastObject;
    NSLog(@"Longitude = %f", endPlacemark.location.coordinate.longitude);
    NSLog(@"Latitude = %f", endPlacemark.location.coordinate.latitude);
    //創(chuàng)建一個(gè)地圖的地標(biāo)對(duì)象o
    MKPlacemark *endMKPlacemark = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
    //在地圖上標(biāo)注一個(gè)點(diǎn)(終點(diǎn))
    MKMapItem *endMapItem = [[MKMapItem alloc] initWithPlacemark:endMKPlacemark];
    //MKLaunchOptionsDirectionsModeKey 指定導(dǎo)航模式
    //NSString * const MKLaunchOptionsDirectionsModeDriving; 駕車
    //NSString * const MKLaunchOptionsDirectionsModeWalking; 步行
    //NSString * const MKLaunchOptionsDirectionsModeTransit; 公交
    [MKMapItem openMapsWithItems:@[currentLocation, endMapItem]
                   launchOptions:@{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey: [NSNumber numberWithBool:YES]}];
    
  }];
}

@end

ios代碼就這么多,很多同學(xué)可能也會(huì)碰到 跳轉(zhuǎn)第三方地圖進(jìn)行導(dǎo)航的需求,這里也都包含了

下面是安卓的代碼:
module代碼

package com.XXXXX; //自己包的位置

import android.util.Log;


import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import com.facebook.react.bridge.ReactApplicationContext;
import android.content.pm.PackageInfo;
import com.facebook.react.bridge.ReactContext;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

public class MyLocationModule extends ReactContextBaseJavaModule implements AMapLocationListener {
    private final ReactApplicationContext reactContext;
    private DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter;
    private static AMapLocationClient locationClient;
    private  static  Callback callback;

    MyLocationModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Override
    public String getName() {
        return "MyLocation";
    }

    @Override
    public void onLocationChanged(AMapLocation location) {
        if (location != null) {
            if (location.getErrorCode() == 0) {
                locationClient.stopLocation();
                callback.invoke(null, toReadableMap(location));
            }
            // TODO: 返回定位錯(cuò)誤信息
        }
    }



    @ReactMethod
    public void init(String key, Promise promise) {
        if (locationClient != null) {
            locationClient.onDestroy();
        }

        AMapLocationClient.setApiKey(key);
        locationClient = new AMapLocationClient(reactContext);
        locationClient.setLocationListener(this);
        eventEmitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
        promise.resolve(null);
    }

    @ReactMethod
    public void setOptions(ReadableMap options) {
        AMapLocationClientOption option = new AMapLocationClientOption();
        if (options.hasKey("interval")) {
            option.setInterval(options.getInt("interval"));
        }
        if (options.hasKey("reGeocode")) {
            option.setNeedAddress(options.getBoolean("reGeocode"));
        }
        locationClient.setLocationOption(option);
    }

    @ReactMethod
    public void start() {
        locationClient.startLocation();
    }

    @ReactMethod
    public void stop() {
        locationClient.stopLocation();
    }

    @ReactMethod
    public void addEventCrood(String name, Callback callback) {
        locationClient.startLocation();
        this.callback = callback;

    }

    @ReactMethod
    public void getLastLocation(Promise promise) {
        promise.resolve(toReadableMap(locationClient.getLastKnownLocation()));
    }

    private ReadableMap toReadableMap(AMapLocation location) {
        if (location != null) {
            WritableMap map = Arguments.createMap();
            map.putDouble("timestamp", location.getTime());
            map.putDouble("accuracy", location.getAccuracy());
            map.putDouble("latitude", location.getLatitude());
            map.putDouble("longitude", location.getLongitude());
            map.putDouble("altitude", location.getAltitude());
            map.putDouble("speed", location.getSpeed());
            if (!location.getAddress().isEmpty()) {
                map.putString("address", location.getAddress());
                map.putString("description", location.getDescription());
                map.putString("poiName", location.getPoiName());
                map.putString("country", location.getCountry());
                map.putString("province", location.getProvince());
                map.putString("city", location.getCity());
                map.putString("cityCode", location.getCityCode());
                map.putString("district", location.getDistrict());
                map.putString("street", location.getStreet());
                map.putString("streetNumber", location.getStreetNum());
                map.putString("adCode", location.getAdCode());
            }
            return map;
        }
        return null;
    }





    /*
    檢測(cè)手機(jī)是否安裝了相應(yīng)的地圖app。返回的數(shù)據(jù)格式為:[{title:'dadasda'url:app地圖URL},{title:'dadasda'url:app地圖URL},{title:'dadasda'url:app地圖URL}]
     */
    @ReactMethod
    public void findEvents(
            String lon,
            String lat,
            String address,
            Callback successCallback) throws Exception {

        WritableArray array = new WritableNativeArray();

        //百度地圖app檢測(cè)
        if (isAppInstalled(getReactApplicationContext(), "com.baidu.BaiduMap")) {
            WritableNativeMap ob = new WritableNativeMap();
            ob.putString("title", "百度地圖");
            ob.putString("url", "baidumap://map/direction?origin=我的位置&destination=name=" + address + "&mode=driving&coord_type=gcj02");
            array.pushMap(ob);
        }

        //高德地圖app檢測(cè)
        if (isAppInstalled(getReactApplicationContext(), "com.autonavi.minimap")) {
            WritableNativeMap ob = new WritableNativeMap();
            ob.putString("title", "高德地圖");
            ob.putString("url", "androidamap://navi?sourceApplication=導(dǎo)航功能&backScheme=nav123456&lat=" + lat + "&lon=" + lon + "&dev=0&style=2");
            array.pushMap(ob);
        }



        //騰訊地圖app檢測(cè)
        if (isAppInstalled(getReactApplicationContext(), "com.tencent.map")) {
            WritableNativeMap ob = new WritableNativeMap();
            ob.putString("title", "騰訊地圖");
            ob.putString("url", "qqmap://map/routeplan?from=我的位置&type=drive&tocoord=" + lat + "," + lon + "&to=" + address + "&coord_type=1&policy=0");
            array.pushMap(ob);
        }

        WritableNativeMap ob = new WritableNativeMap();
        ob.putString("title", "取消");
        ob.putString("url", "");
        array.pushMap(ob);

        successCallback.invoke(array);

    }

    @ReactMethod
    public void addEvent(String title,
                         String url,
                         String lon,
                         String lag,
                         String address) {
        //打開對(duì)應(yīng)的app
        if(!url.equals("")){
            Intent i1 = new Intent();
            i1.setData(Uri.parse(url));
            getReactApplicationContext().startActivity(i1);
        }

    }

    /**
     * 查看是否安裝了這個(gè)導(dǎo)航軟件
     * 高德地圖 com.autonavi.minimap
     * 百度地圖 com.baidu.BaiduMap
     * 騰訊地圖 com.tencent.map
     *
     * @param context
     * @param packagename
     * @return
     */
    public boolean isAppInstalled(Context context, String packagename) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(packagename, 0);
        } catch (Exception e) {
            packageInfo = null;
            e.printStackTrace();
        }

        if (packageInfo == null) {
            return false;
        } else {
            return true;
        }
    }
}

package 代碼

package com.XXXX;//自己包的位置

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;



public class MyLocationPackage implements ReactPackage {
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(new MyLocationModule(reactContext));
    }
}

最后不要忘記在mainapplication 里添加注冊(cè)進(jìn)去

 @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
       ...
        new MyLocationPackage()
       ...
      );
    }

好了下面是js 代碼的調(diào)用方式

//記得要導(dǎo)入navtive  var MyLocation = NativeModules.MyLocation
 MyLocation.addEventCrood('定位', (error, location) => {
      alert(location);
    })

下面是第三方地圖導(dǎo)航的使用

let lon = '121.2477511168';  // ---經(jīng)度 121.248078
let lat = '31.0913734181';   // ---緯度 31.091769
let name = '上海市人民廣場(chǎng)';//
//這里的ActionSheet 是自定義的一個(gè)彈窗,大家可以自己去找  我只是自己封裝了下,使用方法和Facebook的一樣

MyLocation.findEvents(lon, lat, name, (events) => {
      events.map((index, item) => {
        array.push(index.title);
      })
      if (array.length > 2) {
        ActionSheet.showActionSheetWithOptions({
          options: array,
          cancelButtonIndex: array.length - 1,
          maskClosable: true,
        },
          (buttonIndex) => {
            //跳到原生方法對(duì)應(yīng)的app地圖導(dǎo)航內(nèi)
            MyLocation.addEvent(events[buttonIndex].title, events[buttonIndex].url, lon, lat, name);//lat是經(jīng)度,,,log是維度
          });
      } else if (array.length == 2) {
        if (events.length == 2 && events[0].url == 'ios') {
          //只針對(duì)ios平臺(tái)
          MyLocation.addEvent(events[0].title, events[0].url, lon, lat, name);
        } else {
          ActionSheet.showActionSheetWithOptions({
            options: array,
            cancelButtonIndex: array.length - 1,
            maskClosable: true,
          },
            (buttonIndex) => {
              //跳到原生方法對(duì)應(yīng)的app地圖導(dǎo)航內(nèi)
              MyLocation.addEvent(events[buttonIndex].title, events[buttonIndex].url, lon, lat, name);//lat是經(jīng)度,log是維度
            });
        }
      } else {//只適用于android平臺(tái)
        Alert.alert('沒有可用的地圖軟件!');
      }
    })
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容