之前做过android地图开发,在自己的APP里集成第三方的地图sdk(百度,高德,腾讯,搜狗等),来实现导航,基于LBS周边搜索,定位,路线规划等功能需求,这种方法比较麻烦。同时还增加了app的体积,还有如果这个第三方地图软件的sdk更新了,那你自己的app还的做相应的更新,在react-native这种方法估计也可以,但是没去尝试,因为需求简单,就是实现导航,所以就用了接下来介绍这种方法,直接用url跳转到第三放的地图软件来导航,但首先要检测这个第三方的app有没有安装,没安装当然就不显示。目前只检测市场主流的几款地图app(百度地图,高德地图,腾讯地图,ios的苹果地图)
相关的参数要求:
苹果地图:具体的地址
高德地图:具体的地址,经纬度
百度地图:具体的地址,
腾讯地图:具体的地址,经纬度
总结下来,要实现这种跳转导航,必须要把地址经纬度都传过去。
效果图:
1 ios集成方法
1)新建一个react-native项目,用xcode打开,同时添加白名单
2)项目目录下新建一个class,命名为UtilMap,如图
3)编写UtilMap.m
#import "UtilMap.h" #import <CoreLocation/CoreLocation.h> #import <MapKit/MapKit.h> @implementation UtilMap RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(addEvent:(NSString *)name url:(NSString *)url lon:(NSString *)lon lat:(NSString *) lat address:(NSString*) address) { RCTLogInfo(@"地图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",[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{ RCTLogInfo(@"地图app===经度:%@------纬度:%@------地址:%@",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; RCTLogInfo(@"Longitude = %f",endPlacemark.location.coordinate.longitude); RCTLogInfo(@"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
具体什么意思,请看react-native 的官网及相关的ios地图原生开发
2 android集成
1)将新建的项目用android studio打开,同时新建一个maputil的包名和UtilMap类,
2)UtilMap.java
package com.mapdemo.maputil; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.net.Uri; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; public class UtilMap extends ReactContextBaseJavaModule { public UtilMap(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "UtilMap"; } /* 检测手机是否安装了相应的地图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; } } }
3)UtilMapPackage.java
package com.mapdemo.maputil; 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.ArrayList; import java.util.Collections; import java.util.List; public class UtilMapPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new UtilMap(reactContext)); return modules; } }
4)在MainApplication中注册这个模块
3 react-native 调用原生
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */ import React,{ Component } from 'react'; import { ActionSheet,WingBlank,WhiteSpace,Button,Toast } from 'antd-mobile'; import { Platform,StyleSheet,Text,View,TouchableOpacity,NativeModules,Linking,Alert } from 'react-native'; let lon = '121.2477511168'; // ---经度 121.248078 let lat = '31.0913734181'; // ---纬度 31.091769 let name = '上海松江王家厍路55弄';// let UtilMapManager = NativeModules.UtilMap; export default class App extends Component { iosmap() { let array = []; UtilMapManager.findEvents(lon,(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地图导航内 UtilMapManager.addEvent(events[buttonIndex].title,events[buttonIndex].url,name);//lon是经度,,,log是维度 }); } else if (array.length == 2) { if (events.length == 2 && events[0].url == 'ios') { //只针对ios平台 UtilMapManager.addEvent(events[0].title,events[0].url,name); } else { ActionSheet.showActionSheetWithOptions({ options: array,(buttonIndex) => { //跳到原生方法对应的app地图导航内 UtilMapManager.addEvent(events[buttonIndex].title,name);//lon是经度,log是维度 }); } } else {//只适用于android平台 Alert.alert('没有可用的地图软件!'); } }) } render() { return ( <View style={styles.container}> <TouchableOpacity style={{ marginTop: 50 }} onPress={this.iosmap.bind(this)}> <Text>打开导航软件</Text> </TouchableOpacity> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#F5FCFF',welcome: { fontSize: 20,textAlign: 'center',margin: 10,instructions: { textAlign: 'center',color: '#333333',marginBottom: 5,});