最近做了一個基于高德地圖demo,主要功能是定位和地圖的展示,周邊POI的數(shù)據(jù)獲取以及搜索關(guān)鍵字給出相應(yīng)地址提示的功能。下面是效果圖:
安卓

IOS

用的是基于三方庫react-native-smart-amap,首先按照文檔,進(jìn)行一些配置。
執(zhí)行安裝命令
npm install react-native-smart-amap --save
iOS配置
將RCTAMap.xcodeproj作為Library拖進(jìn)你的Xcode里的project中.
將RCTAMap目錄里Frameworks目錄拖進(jìn)主project目錄下, 選擇copy items if needed, create groups, 另外add to target不要忘記選擇主project.
將RCTAMap目錄里Frameworks目錄里的AMap.bundle拖進(jìn)主project目錄下, 選擇copy items if needed, create groups, 另外add to target不要忘記選擇主project.
點擊你的主project, 選擇Build Phases -> Link Binary With Libraries, 將RCTAMap.xcodeproj里Product目錄下的libRCTAMap.a拖進(jìn)去.
同上位置, 選擇Add items, 添加一下系統(tǒng)庫
libstdc++.6.0.9.tbd
libc++.tb
libz.tbd
Security.framework
CoreTelephony.framework
SystemConfiguration.framework
JavaScriptCore.framework
CoreLocation.framework選擇Build Settings, 找到Header Search Paths, 確認(rèn)其中包含$(SRCROOT)/../../../react-native/React, 模式為recursive.
同上位置, 找到Framework Search Paths, 加入$(PROJECT_DIR)/Frameworks.
點擊在Libraries下已拖進(jìn)來的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屬性, 并設(shè)置值為YES(ios 10)
在AppDelegate.m中
#import <AMapFoundationKit/AMapFoundationKit.h> //引入高德地圖核心包
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[AMapServices sharedServices].apiKey = @"請?zhí)顚懩膋ey"; //設(shè)置高德地圖SDK服務(wù)key
...
}
安卓
使用高德地圖SDK, 申請應(yīng)用key等詳細(xì)信息請點擊這里
需要注意的是,需要獲取安全碼SHA1,分別發(fā)布和調(diào)試版
獲取發(fā)布版SHA1 :cd到你的keystore 所在的文件夾目錄
然后執(zhí)行cmd keytool -v -list -keystore (keystore) 回車 獲取發(fā)布版的SHA1值
獲取開發(fā)版的SHA1值:
終端輸入:cd .android 進(jìn)入到 .android下,輸入keytool -v -list -keystore debug.keystore命令,注意的是調(diào)試下的密碼默認(rèn)是: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中, 加入所需權(quán)限
<!--*************************高德地圖-定位所需要權(quán)限*************************-->
<!-- Normal Permissions 不需要運行時注冊 -->
<!--獲取運營商信息,用于支持提供運營商信息相關(guān)的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--用于訪問wifi網(wǎng)絡(luò)信息,wifi信息會用于進(jìn)行網(wǎng)絡(luò)定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--這個權(quán)限用于獲取wifi的獲取權(quán)限,wifi信息會用來進(jìn)行網(wǎng)絡(luò)定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<!-- 請求網(wǎng)絡(luò) -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 不是SDK需要的權(quán)限,是示例中的后臺喚醒定位需要的權(quán)限 -->
<!--<uses-permission android:name="android.permission.WAKE_LOCK" />-->
<!-- 需要運行時注冊的權(quán)限 -->
<!--用于進(jìn)行網(wǎng)絡(luò)定位-->
<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" />
<!--寫入擴展存儲,向擴展卡寫入數(shù)據(jù),用于寫入緩存定位數(shù)據(jù)-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--讀取緩存數(shù)據(jù)-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--用于讀取手機當(dāng)前的狀態(tài)-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 更改設(shè)置 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--*************************高德地圖-定位所需要權(quán)限*************************-->
- 在AndroidManifest.xml中, application標(biāo)簽內(nèi)加入
<!--高德地圖SDK key設(shè)置-->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="請?zhí)顚懩膋ey"/>
<!--高德地圖APS服務(wù)設(shè)置-->
<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: '商務(wù)住宅|學(xué)校',
dataArray: [],
searchArray: [],
isHidden: true
}
}
componentDidMount() {
//監(jiān)聽原生周邊POI數(shù)據(jù)回調(diào)
NativeAppEventEmitter.addListener('amap.onPOISearchDone', this._onPOISearchDone)
//監(jiān)聽輸入關(guān)鍵字回調(diào)周邊POI數(shù)據(jù)
NativeAppEventEmitter.addListener('amap.location.onLocationResult', this._onLocationResult),
//獲取當(dāng)前位置
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數(shù)據(jù)
_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='請輸入搜索內(nèi)容'
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(){
//這里可進(jìn)行一些數(shù)據(jù)更多加載的操作, 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
}
});
還有個需要另外做的是這個庫是沒有封裝原生的搜索功能,就是根據(jù)輸入來獲取周邊的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];
}
/* 提示搜索回調(diào) */
- (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);//限制在當(dāng)前城市
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數(shù)據(jù)以及根據(jù)輸入提示獲取周邊的相關(guān)功能就完成了。當(dāng)然這個只是一些基礎(chǔ)的簡單功能,如果需要更多更復(fù)雜的功能,就需要自己去集成iOS和安卓的原生API然后接入到自己的應(yīng)用里,需要親們自個兒去封裝啦。當(dāng)然如果有碰到的任何問題,歡迎各位咨詢我或者評論留言或者加入RN技術(shù)交流群:397885169。
如果遇到錯誤:
錯誤: 不兼容的類型: RCTAMapModule無法轉(zhuǎn)換為InputtipsListener
inputTips.setInputtipsListener(this);
改成:inputTips.setInputtipsListener((Inputtips.InputtipsListener) this);
項目地址,如果需要關(guān)鍵字搜索功能,記得需要手動修改node modules里的代碼,具體修改看文章或者demo。喜歡的同學(xué)可以給個star啊