美文网首页
react native实现地图展示和周边POI数据以及关键字搜

react native实现地图展示和周边POI数据以及关键字搜

作者: 凹凸怪cq | 来源:发表于2018-04-23 22:38 被阅读1350次

最近做了一个基于高德地图demo,主要功能是定位和地图的展示,周边POI的数据获取以及搜索关键字给出相应地址提示的功能。下面是效果图:

安卓

DDDE29DA2E2D28E900285E3077DEC2EB.jpg

IOS

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替换成(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啊

相关文章

网友评论

      本文标题:react native实现地图展示和周边POI数据以及关键字搜

      本文链接:https://www.haomeiwen.com/subject/ukjrlftx.html