React-native 高德定位

目前看了下很多高德定位的,基本都是监听写的,每次调用会使用多次.
所以自己写了一个封装适合ios和安卓. 还有获取第三方地图的跳转功能
只调用一次定位,不会重复调用,有使用的朋友请自行获取.
至于高德地图的配置 还请自行去高德官网查看,我这里只放出源码
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";
}

//~~~~~~~~~~~~~~~~~~~~~~~以下为调用第三方地图方法~~~~~~~~~~~~~~~~~~~~~~~~
RCT_EXPORT_METHOD(addEvent:(NSString *)name url:(NSString *)url lon:(NSString *)lon lat:(NSString *) lat address:(NSString*) address)
{
  NSLog(@"地图app=== %@ url %@-----经度:%@------纬度:%@------地址:%@", 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",@"导航功能",@"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===经度:",maps);
  
  callback(@[maps]);
  
}

//苹果地图
//跳转到苹果自带地图
- (void)appleMap:(NSString*)lon andB:(NSString*)lat andC:(NSString*)address{
  NSLog(@"地图app===经度:%@------纬度:%@------地址:%@",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 使用场景: 1. 跳转原生地图 2.计算线路
  MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation];
  //地理编码器
  CLGeocoder *geocoder = [[CLGeocoder alloc] init];
  //我们假定一个终点坐标,测试地址: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);
    //创建一个地图的地标对象o
    MKPlacemark *endMKPlacemark = [[MKPlacemark alloc] initWithPlacemark:endPlacemark];
    //在地图上标注一个点(终点)
    MKMapItem *endMapItem = [[MKMapItem alloc] initWithPlacemark:endMKPlacemark];
    //MKLaunchOptionsDirectionsModeKey 指定导航模式
    //NSString * const MKLaunchOptionsDirectionsModeDriving; 驾车
    //NSString * const MKLaunchOptionsDirectionsModeWalking; 步行
    //NSString * const MKLaunchOptionsDirectionsModeTransit; 公交
    [MKMapItem openMapsWithItems:@[currentLocation, endMapItem]
                   launchOptions:@{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey: [NSNumber numberWithBool:YES]}];
    
  }];
}

@end

ios代码就这么多,很多同学可能也会碰到 跳转第三方地图进行导航的需求,这里也都包含了

下面是安卓的代码:
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: 返回定位错误信息
        }
    }



    @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;
    }





    /*
    检测手机是否安装了相应的地图app。返回的数据格式为:[{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检测
        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检测
        if (isAppInstalled(getReactApplicationContext(), "com.autonavi.minimap")) {
            WritableNativeMap ob = new WritableNativeMap();
            ob.putString("title", "高德地图");
            ob.putString("url", "androidamap://navi?sourceApplication=导航功能&backScheme=nav123456&lat=" + lat + "&lon=" + lon + "&dev=0&style=2");
            array.pushMap(ob);
        }



        //腾讯地图app检测
        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) {
        //打开对应的app
        if(!url.equals("")){
            Intent i1 = new Intent();
            i1.setData(Uri.parse(url));
            getReactApplicationContext().startActivity(i1);
        }

    }

    /**
     * 查看是否安装了这个导航软件
     * 高德地图 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 里添加注册进去

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

好了下面是js 代码的调用方式

//记得要导入navtive  var MyLocation = NativeModules.MyLocation
 MyLocation.addEventCrood('定位', (error, location) => {
      alert(location);
    })

下面是第三方地图导航的使用

let lon = '121.2477511168';  // ---经度 121.248078
let lat = '31.0913734181';   // ---纬度 31.091769
let name = '上海市人民广场';//
//这里的ActionSheet 是自定义的一个弹窗,大家可以自己去找  我只是自己封装了下,使用方法和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) => {
            //跳到原生方法对应的app地图导航内
            MyLocation.addEvent(events[buttonIndex].title, events[buttonIndex].url, lon, lat, name);//lat是经度,,,log是维度
          });
      } else if (array.length == 2) {
        if (events.length == 2 && events[0].url == 'ios') {
          //只针对ios平台
          MyLocation.addEvent(events[0].title, events[0].url, lon, lat, name);
        } else {
          ActionSheet.showActionSheetWithOptions({
            options: array,
            cancelButtonIndex: array.length - 1,
            maskClosable: true,
          },
            (buttonIndex) => {
              //跳到原生方法对应的app地图导航内
              MyLocation.addEvent(events[buttonIndex].title, events[buttonIndex].url, lon, lat, name);//lat是经度,log是维度
            });
        }
      } else {//只适用于android平台
        Alert.alert('没有可用的地图软件!');
      }
    })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,069评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,212评论 1 287
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,912评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,424评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,741评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,194评论 1 206
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,553评论 2 307
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,289评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,923评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,251评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,775评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,144评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,698评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,936评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,658评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,214评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,159评论 2 258