最近做了一个基于高德地图demo,主要功能是定位和地图的展示,周边POI的数据获取以及搜索关键字给出相应地址提示的功能。下面是效果图:
安卓
DDDE29DA2E2D28E900285E3077DEC2EB.jpgIOS
WechatIMG134.jpeg用的是基于三方库react-native-smart-amap,首先按照文档,进行一些配置。
执行安装命令
npm install react-native-smart-amap --save
iOS配置
-
将RCTAMap.xcodeproj作为Library拖进你的Xcode里的project中.
-
将RCTAMap目录里Frameworks目录拖进主project目录下, 选择copy items if needed, create groups, 另外add to target不要忘记选择主project.
-
将RCTAMap目录里Frameworks目录里的AMap.bundle拖进主project目录下, 选择copy items if needed, create groups, 另外add to target不要忘记选择主project.
-
点击你的主project, 选择Build Phases -> Link Binary With Libraries, 将RCTAMap.xcodeproj里Product目录下的libRCTAMap.a拖进去.
-
同上位置, 选择Add items, 添加一下系统库
libstdc++.6.0.9.tbd
libc++.tb
libz.tbd
Security.framework
CoreTelephony.framework
SystemConfiguration.framework
JavaScriptCore.framework
CoreLocation.framework -
选择Build Settings, 找到Header Search Paths, 确认其中包含$(SRCROOT)/../../../react-native/React, 模式为recursive.
-
同上位置, 找到Framework Search Paths, 加入$(PROJECT_DIR)/Frameworks.
-
点击在Libraries下已拖进来的RCTAMap.xcodeproj, 选择Build Settings, 找到Framework Search Paths, 将(SRCROOT)/../../../../ios/Frameworks.
-
在info.plist中加入Privacy - Location When In Use Usage Description属性(ios 10)
-
在info.plist中加入Allow Arbitrary Loads属性, 并设置值为YES(ios 10)
-
在AppDelegate.m中
#import <AMapFoundationKit/AMapFoundationKit.h> //引入高德地图核心包
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[AMapServices sharedServices].apiKey = @"请填写您的key"; //设置高德地图SDK服务key
...
}
安卓
使用高德地图SDK, 申请应用key等详细信息请点击这里
需要注意的是,需要获取安全码SHA1,分别发布和调试版
获取发布版SHA1 :cd到你的keystore 所在的文件夹目录
然后执行cmd keytool -v -list -keystore (keystore) 回车 获取发布版的SHA1值
获取开发版的SHA1值:
终端输入:cd .android 进入到 .android下,输入keytool -v -list -keystore debug.keystore命令,注意的是调试下的密码默认是:android
PackageName就是你的app的包名。
- 在android/settings.gradle中添加
include ':react-native-smart-amap'
project(':react-native-smart-amap').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-smart-amap/android')
- 在android/app/build.gradle中添加
dependencies {
...
// From node_modules
compile project(':react-native-smart-amap')
}
- 在MainApplication.java中添加
import com.reactnativecomponent.amaplocation.RCTAMapPackage; //import package
...
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RCTAMapPackage() //register Module
);
}
- 在AndroidManifest.xml中, 加入所需权限
<!--*************************高德地图-定位所需要权限*************************-->
<!-- Normal Permissions 不需要运行时注册 -->
<!--获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<!-- 请求网络 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 不是SDK需要的权限,是示例中的后台唤醒定位需要的权限 -->
<!--<uses-permission android:name="android.permission.WAKE_LOCK" />-->
<!-- 需要运行时注册的权限 -->
<!--用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--用于提高GPS定位速度-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取缓存数据-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 更改设置 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--*************************高德地图-定位所需要权限*************************-->
- 在AndroidManifest.xml中, application标签内加入
<!--高德地图SDK key设置-->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="请填写您的key"/>
<!--高德地图APS服务设置-->
<service android:name="com.amap.api.location.APSService" >
</service>
然后在js文件里 app.js
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
var Geolocation = require('Geolocation');
const {width: deviceWidth, height: deviceHeight} = Dimensions.get('window')
import AMap from 'react-native-smart-amap'
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props)
this.state = {
data: [],
longitude: '',
latitude: '',
loaded: false,
keywords: '商务住宅|学校',
dataArray: [],
searchArray: [],
isHidden: true
}
}
componentDidMount() {
//监听原生周边POI数据回调
NativeAppEventEmitter.addListener('amap.onPOISearchDone', this._onPOISearchDone)
//监听输入关键字回调周边POI数据
NativeAppEventEmitter.addListener('amap.location.onLocationResult', this._onLocationResult),
//获取当前位置
this.getCurrentPosition()
}
getCurrentPosition(){
Geolocation.getCurrentPosition(
(location) => {
console.log('---location----:',location)
this.setState({
longitude: location.coords.longitude,
latitude: location.coords.latitude,
loaded: true
},()=>{
setTimeout(()=>{
this.setState({
isHidden: false
})
},200)
})
},
(error) => {
alert("获取位置失败")
},
);
}
//获取周边POI数据
_onPOISearchDone=(data)=>{
console.log('----_onPOISearchDone----:',data)
this.setState({
dataArray: data.searchResultList,
})
}
_onLocationResult = (result) => {
console.log(`_onLocationResult...result`,result)
this.setState({
searchArray: result.searchResultList,
})
}
_onDidMoveByUser = (e) => {
// console.log('----_onDidMoveByUser--:',e.nativeEvent)
this.setState({
longitude: e.nativeEvent.data.centerCoordinate.longitude,
latitude: e.nativeEvent.data.centerCoordinate.latitude,
})
this._searchNearBy(e.nativeEvent.data.centerCoordinate.latitude,e.nativeEvent.data.centerCoordinate.longitude)
}
_searchNearBy(latitude,longitude) {
console.log('----_searchNearBy--:',latitude,longitude)
let obj={
page: 1,
coordinate: {
latitude: latitude,
longitude: longitude,
},
keywords: this.state.keywords,
}
this._amap.searchPoiByCenterCoordinate(obj)
}
render() {
if (!this.state.loaded){
return(
<View></View>
)
}
return (
<View style={styles.container}>
<View style={{width:deviceWidth,height: deviceHeight}}>
{
this.state.isHidden?(
null
):(
<AMap
ref={ component => this._amap = component }
style={{width:deviceWidth,height: deviceHeight/2,marginTop: 40}}
options={{
frame: {
width: deviceWidth,
height: deviceHeight/2
},
showsUserLocation: true,
userTrackingMode: Platform.OS == 'ios' ? AMap.constants.userTrackingMode.none : null,
centerCoordinate: {
latitude: this.state.latitude,
longitude: this.state.longitude,
},
zoomLevel: 18.1,
centerMarker: Platform.OS == 'ios' ? 'icon_location' : 'poi_marker',
}}
onLayout={this._onLayout}
onDidMoveByUser={this._onDidMoveByUser}
/>
)
}
<Image source={require('./redPin_lift.png')} style={styles.imageStyle}/>
<View style={styles.topView}>
<TextInput style={styles.searchTextInput}
value={this.state.searchValue}
onChangeText={(value) =>{
this._amap.searchLocation(value)
this.setState({searchValue: value});
}}
placeholder='请输入搜索内容'
placeholderTextColor="rgb(155,155,155)"
underlineColorAndroid="transparent"
autoCorrect={false}
autoCapitalize='none'
/>
<AnimatedFlatList
data={this.state.searchArray}
legacyImplementation={false}
ref={(flatList)=>this._flatList = flatList}
renderItem={this._renderSearchComponent}
keyExtractor={(item, index) => 'search_list_'+index}
/>
</View>
<AnimatedFlatList
data={this.state.dataArray}
legacyImplementation={false}
ref={(flatList)=>this._flatList = flatList}
renderItem={this._renderItemComponent}
onEndReached={()=>this._onEndReached()}
keyExtractor={(item, index) => 'dialog_list_'+index}
/>
</View>
</View>
);
}
_onEndReached(){
//这里可进行一些数据更多加载的操作, page+1即可
}
_renderItemComponent=({item,index})=>{
return(
<TouchableOpacity style={styles.itemStyle}>
<Text>{item.name}</Text>
<Text style={{color: '#676767'}}>{item.address}</Text>
</TouchableOpacity>
)
}
_renderSearchComponent=({item,index})=>{
let address=item.district+item.address+item.name
return(
<TouchableOpacity style={styles.itemSearchStyle} onPress={()=>{
alert(address)
}}>
<Text>{address}</Text>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#efefef',
},
itemStyle: {
width: '100%',
height: 50,
alignItems: 'center',
backgroundColor:'#ffffff',
justifyContent: 'center',
marginTop: 1
},
itemSearchStyle: {
width: '100%',
height: 50,
alignItems: 'center',
backgroundColor:'#ffffff',
justifyContent: 'center',
borderBottomColor: '#efefef',
borderBottomWidth: 1
},
imageStyle: {
position: 'absolute',
top: deviceHeight/2/2-36+50,
left: deviceWidth/2-22
},
searchTextInput: {
width: '100%',
marginTop: 20,
height: 40,
paddingLeft: 10,
backgroundColor: '#ffffff'
},
topView: {
position: 'absolute',
top: 0,
left: 0,
width: deviceWidth
}
});
还有个需要另外做的是这个库是没有封装原生的搜索功能,就是根据输入来获取周边的POI提示,这个需要分别在iOS和安卓库里封装原生
iOS
在react-native-smart-amap/AMap-ios.js里添加方法
searchLocation(value){
AMapManager.searchLocation(value)
}
接着在react-native-smart-amap/ios/RCTAMap/RCTAMap/的RCTAMapManager.m里添加方法:
RCT_EXPORT_METHOD(searchLocation:(NSString *)keywords)
{
AMapInputTipsSearchRequest *request=[[AMapInputTipsSearchRequest alloc] init];
request.keywords=keywords;
[self.search AMapInputTipsSearch:request];
}
/* 提示搜索回调 */
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response;
{
NSDictionary *result;
NSMutableArray *resultList;
resultList = [NSMutableArray arrayWithCapacity:response.tips.count];
if (response.tips.count > 0)
{
[response.tips enumerateObjectsUsingBlock:^(AMapTip *obj, NSUInteger idx, BOOL *stop) {
[resultList addObject:@{
@"uid": obj.uid,
@"name": obj.name,
@"adcode": obj.adcode,
@"district": obj.district,
@"latitude": @(obj.location.latitude),
@"longitude": @(obj.location.longitude),
@"address": obj.address,
}];
}];
}
result = @{
@"searchResultList": resultList
};
[self.bridge.eventDispatcher sendAppEventWithName:@"amap.location.onLocationResult"
body:result
];
}
Android
在react-native-smart-amap/AMap-android.js里添加方法
searchLocation(value){
AMapManager.searchLocation(value)
}
在react-native-smart-amap/android/src/main/java/com/reactnativecomponent/amap/RCTAMapModule.java里添加方法:
@ReactMethod
public void searchLocation(String value){
InputtipsQuery inputquery = new InputtipsQuery(value, "");
inputquery.setCityLimit(true);//限制在当前城市
Inputtips inputTips = new Inputtips(mContext, inputquery);
inputTips.setInputtipsListener(this);
inputTips.requestInputtipsAsyn();
}
@Override
public void onGetInputtips(final List<Tip> tipList, int rCode) {
WritableMap dataMap = Arguments.createMap();
WritableArray array = Arguments.createArray();
if (rCode == 1000) {
for (Tip tip : tipList) {
WritableMap data = Arguments.createMap();
data.putString("name", tip.getName());
data.putString("address", tip.getAddress());
data.putString("uid", tip.getPoiID());
data.putString("adCode", tip.getAdcode());
data.putString("district", tip.getDistrict());
data.putDouble("longitude", tip.getPoint().getLongitude());
data.putDouble("latitude", tip.getPoint().getLatitude());
array.pushMap(data);
}
dataMap.putArray("searchResultList", array);
}
else {
WritableMap error = Arguments.createMap();
error.putString("code", String.valueOf(rCode));
dataMap.putMap("error", error);
}
mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("amap.location.onLocationResult", dataMap);
}
至此iOS和安卓的地图展示和周边POI数据以及根据输入提示获取周边的相关功能就完成了。当然这个只是一些基础的简单功能,如果需要更多更复杂的功能,就需要自己去集成iOS和安卓的原生API然后接入到自己的应用里,需要亲们自个儿去封装啦。当然如果有碰到的任何问题,欢迎各位咨询我或者评论留言或者加入RN技术交流群:397885169。
如果遇到错误:
错误: 不兼容的类型: RCTAMapModule无法转换为InputtipsListener
inputTips.setInputtipsListener(this);
改成:inputTips.setInputtipsListener((Inputtips.InputtipsListener) this);
项目地址,如果需要关键字搜索功能,记得需要手动修改node modules里的代码,具体修改看文章或者demo。喜欢的同学可以给个star啊
网友评论