目前看了下很多高德定位的,基本都是监听写的,每次调用会使用多次.
所以自己写了一个封装适合ios和安卓. 还有获取第三方地图的跳转功能
只调用一次定位,不会重复调用,有使用的朋友请自行获取.
至于高德地图的配置 还请自行去高德官网查看,我这里只放出源码
ios:
.h文件里
#import
#import
#import
#import
#import
NS_ASSUME_NONNULL_BEGIN
@interface LocationModule : NSObject
@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
#import
#import
#import
#import
#import
@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 * _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 createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(new MyLocationModule(reactContext));
}
}
最后不要忘记在mainapplication 里添加注册进去
@Override
protected List getPackages() {
return Arrays.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('没有可用的地图软件!');
}
})