目前看了下很多高德定位的,基本都是監(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('沒有可用的地圖軟件!');
}
})