React-Native-IOS使用高德地图

高德地图key值

  • http://lbs.amap.com/,注册帐号
  • 登录后,进入控制台,应用管理->我的应用,添加新key
    • Bundle ID值为 Xcode 切换到 General 标签,查看 Bundle Identifier的值

地图及定位

在github上找了好几个使用React Native封装基于ios的高德地图的依赖,但是大多数依赖无论手动连接还是自动连接都会有报错,个人感觉最大的可能就是不兼容现在的react-native^0.42.0,最后找到两个可以在IOS上显示的高德地图依赖和一个可以定位的依赖。

react-native-maps

可以显示高德地图,配置过程也非常简单,只需执行如下两个命令,运行时模拟器中地图显示的是英文,真机上地图显示的汉字,但是样式看上去有点奇怪,不知道是不是版本老的原因。

  • npm install react-native-maps --save
  • react-native link react-native-maps

虽然这个依赖显示了高德地图,但是经过这些安装高德地图的试验,我感觉这个依赖很奇怪。(1)没有看到高德地图相关的文件MAMapKit.framework、AMapFoundationKit.framework、AMapSearchKit.framework;(2)没有进行高德key值的配置,个人感觉在react-native-maps/ios/AirMaps/AIRMapManager.m文件中,31行应该是输入高德key值的地方。

react-native-smart-amap

在ios上,可以按照说明文档进行配置,也就是手动链接。我是先执行react-native link react-native-smart-amap进行自动链接,然后再按照说明文件进行配置,需要注意的地方有两点:

  • 拖进项目的RCTAMap.xcodeproj是在\node_modules\react-native-smart-amap\ios\RCTAMap路径下的,不是\node_modules\react-native-smart-amap\RCTAMap下的。
  • “点击在Libraries下已拖进来的RCTAMap.xcodeproj, 选择Build Settings, 找到Framework Search Paths, 将$(SRCROOT)/../../../ios/Frameworks替换成$(SRCROOT)/../../../../ios/Frameworks”这个步骤在每次重装依赖后都要重新执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { Component } from 'react';
import { StyleSheet, Dimensions, Platform, StatusBar } from 'react-native';
import AMap from 'react-native-smart-amap';
const WINDOW_WIDTH = Dimensions.get('window').width;
const WINDOW_HEIGHT = Dimensions.get('window').height;
const StatusBar_HEIGHT = StatusBar.currentHeight;
class SmartAmap extends Component {
constructor(props) {
super(props);
this.state = {
latitude: 39.889725,
longitude: 116.357357,
};
}
render() {
const options = {
frame: {
width: WINDOW_WIDTH,
height: Platform.OS === 'ios' ? WINDOW_HEIGHT - 55 : WINDOW_HEIGHT - StatusBar_HEIGHT - 55,
},
showsUserLocation: true,
userTrackingMode: Platform.OS === 'ios' ? AMap.constants.userTrackingMode.none : null,
centerCoordinate: {
latitude: this.props.centerCoordinate ? this.props.centerCoordinate.latitude : this.state.latitude,
longitude: this.props.centerCoordinate ? this.props.centerCoordinate.longitude : this.state.longitude,
},
zoomLevel: 18.1,
centerMarker: Platform.OS === 'ios' ? 'icon_location' : 'poi_marker',
};
return (
<AMap
ref={ component => this._amap = component }
style={{...StyleSheet.absoluteFillObject}}
options={options}
radius={100}
/>
);
}
}

这时的运行结果如下图所示,地图上并没有标注出坐标的位置,查了issuse列表看到别也提了这个问题,估计是依赖的问题,我就查了一下依赖的源码,试着找了一下,发现将react-native-smart-amap/ios/RCTAMap/RCTAMap/RCTAMapManager.m文件中422、423、424行的NO改为YES,地图上的位置标注就出来了,如下图所示。

以上都是在ios上的配置,在android端也有需要注意的地方。上一篇React-Native-Android使用高德地图已经讲了在android上使用高德地图,如果想在android端也使用react-native-smart-amap这个依赖来保持一致的话,需要先将android/setting.gradle、android/app/build.gradle、MainApplication.java中关于react-native-amap-android的配置去掉,然后再按照说明文档配置react-native-smart-amap,否则会报两个错误。

第一个错误如下图所示,解决办法是将gradle.properties文件中被注释的org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8放开。

第二个错误如下图所示,是由于包冲突,因为已经存在一个高德地图的依赖了,解决办法就是将android/setting.gradle、android/app/build.gradle、MainApplication.java中关于react-native-amap-android的配置去掉,只保留一个高德地图的配置。

而且android也是存在位置标注不显示的问题,需要将react-native-smart-amap/android/src/main/reactnativecomponent/amap/RCTAMapView.java文件的202行注释放开,地图上的位置标注就出来了,如下图所示。

react-native-smart-amap-location

在ios上,还是执行react-native link react-native-smart-amap-location进行自动链接,然后再按照说明文件进行配置,只有下面这一条需要注意:

  • “点击在Libraries下已拖进来的RCTAMapLocation.xcodeproj, 选择Build Settings, 找到Framework Search Paths, 将$(SRCROOT)/../../../ios/Frameworks替换成$(SRCROOT)/../../../../ios/Frameworks”这个步骤在每次重装依赖后都要重新执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import React, { Component } from 'react';
import { View, StyleSheet, Dimensions, Platform, StatusBar, NativeAppEventEmitter, Alert } from 'react-native';
import { Button } from 'antd-mobile';
import AMapLocation from 'react-native-smart-amap-location';
import AppEventListenerEnhance from 'react-native-smart-app-event-listener-enhance';
const WINDOW_WIDTH = Dimensions.get('window').width;
const WINDOW_HEIGHT = Dimensions.get('window').height;
const StatusBar_HEIGHT = StatusBar.currentHeight;
class SmartAmap extends Component {
constructor(props) {
super(props);
this.state = {
latitude: 39.889725,
longitude: 116.357357,
};
this.info = '';
this._onLocationResult = this._onLocationResult.bind(this);
}
componentDidMount() {
let viewAppearCallBack = (event) => {
AMapLocation.init(null); //使用默认定位配置
}
this.addAppEventListener(
this.props.navigator.navigationContext.addListener('didfocus', viewAppearCallBack),
NativeAppEventEmitter.addListener('amap.location.onLocationResult', this._onLocationResult)
);
}
componentWillUnmount () {
//停止并销毁定位服务
AMapLocation.cleanUp()
}
getLocation() {
AMapLocation.getLocation();
}
getReGeocode() {
AMapLocation.getReGeocode();
}
_onLocationResult(result) {
if(result.error) {
Alert.alert(`错误代码: ${result.error.code}, 错误信息: ${result.error.localizedDescription}`)
}
else {
if(result.formattedAddress) {
console.log("定位逆地理编码信息:", result)
Alert.alert(`格式化地址 = ${result.formattedAddress}`);
}
else {
console.log("定位地理编码信息:", result)
Alert.alert(`纬度 = ${result.coordinate.latitude}, 经度 = ${result.coordinate.longitude}`)
}
}
}
render() {
return (
<View>
<Button type="primary" onClick={this.getLocation}>
定位地理编码信息
</Button>
<Button type="primary" onClick={this.getReGeocode}>
定位逆地理编码信息
</Button>
</View>
);
}
}
export default AppEventListenerEnhance(SmartAmap);