Flutter中如何获取Google Maps的OpeningHoursDetail及搜索功能结果
问题排查与解决方案
一、营业时间(OpeningHoursDetail)无法显示的问题
核心原因
- API未请求营业时间字段:
searchNearbyWithRadius接口默认不返回opening_hours数据,必须显式指定fields参数获取该字段。 - 时间类型转换错误:Google Places返回的时间是字符串格式(如
"0900"),代码中直接强制转换为TimeOfDay会导致隐性错误。 - 日期映射不匹配:Google Places的日期编码规则是
0=周日,1=周一…6=周六,而DateTime的枚举值是Monday=1,Sunday=7,直接匹配会导致日期显示错误。
修复步骤
- 修改
_getNearbyPlaces方法,添加fields参数:
Future<void> _getNearbyPlaces(LatLng userLocation) async { setState(() { isLoading = true; errorMessage = null; }); final location = Location(lat: userLocation.latitude, lng: userLocation.longitude); // 添加fields参数,明确请求营业时间等字段 final result = await _places.searchNearbyWithRadius( location, 5000, type: "restaurant", fields: ["name", "vicinity", "geometry", "opening_hours", "place_id"], ); setState(() { isLoading = false; if (result.status == "OK") { places = result.results; } else { errorMessage = result.errorMessage ?? "Unknown error"; } }); }
- 修复时间解析与日期映射方法:
// 新增解析时间字符串的方法 String _parseTimeString(String timeStr) { // 时间格式为HHMM,如"0900"转为"09:00" if (timeStr.length != 4) return timeStr; final hour = timeStr.substring(0, 2); final minute = timeStr.substring(2, 4); return "$hour:$minute"; } // 修改日期映射方法 String _getDayString(int day) { // Google Places的day编码:0=周日,1=周一...6=周六 switch (day) { case 1: return 'Monday'; case 2: return 'Tuesday'; case 3: return 'Wednesday'; case 4: return 'Thursday'; case 5: return 'Friday'; case 6: return 'Saturday'; case 0: return 'Sunday'; default: return ''; } }
- 更新
_showPlaceDetails中的时间显示逻辑:
for (var period in place.openingHours!.periods!) Text( '${_getDayString(period.open!.day)}: ${_parseTimeString(period.open!.time)} - ${_parseTimeString(period.close!.time)}', ),
二、搜索自动补全/无结果的问题
核心原因
- API密钥权限不足:未在Google Cloud控制台启用
Places API(包含Autocomplete和Details服务),或API密钥未正确配置应用限制(包名、SHA-1)。 - 错误处理缺失:未处理
PlacesAutocomplete和getDetailsByPlaceId的错误情况,无法定位问题。 - 包兼容性问题:
flutter_google_places与google_maps_webservice版本不兼容,导致请求失败。
修复步骤
验证API密钥配置:
- 登录Google Cloud控制台,确保启用了Maps SDK for Android和Places API。
- 检查API密钥的应用限制:添加你的Android应用包名和SHA-1指纹(在
API密钥->应用限制中配置)。
增强搜索方法的错误处理:
Future<void> _searchPlaces() async { try { Prediction? prediction = await PlacesAutocomplete.show( context: context, apiKey: kGoogleApiKey, mode: Mode.overlay, components: [ Component(Component.country, "MY"), Component(Component.country, "SG") ], // 添加自动补全的类型过滤(可选) types: ["establishment"], ); if (prediction != null) { PlacesDetailsResponse details = await _places.getDetailsByPlaceId( prediction.placeId!, // 请求必要字段 fields: ["geometry", "name", "vicinity"], ); if (details.status == "OK") { PlaceDetails placeDetails = details.result; LatLng location = LatLng( placeDetails.geometry!.location.lat, placeDetails.geometry!.location.lng, ); mapController.animateCamera(CameraUpdate.newLatLngZoom(location, 15)); _getNearbyPlaces(location); } else { setState(() { errorMessage = details.errorMessage ?? "Failed to get place details"; }); } } } catch (e) { setState(() { errorMessage = "Search error: ${e.toString()}"; }); } }
- 检查包版本兼容性:
在pubspec.yaml中确保使用兼容的版本,例如:
dependencies: flutter_google_places: ^0.3.0 google_maps_webservice: ^0.0.20 google_maps_flutter: ^2.5.0 location: ^5.0.3
三、额外注意事项
- 确保AndroidManifest.xml中已添加必要权限和元数据:
<!-- 权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <!-- Google Maps元数据 --> <meta-data android:name="com.google.android.geo.API_KEY" android:value="YOUR_API_KEY"/>
- 测试时使用真实设备,模拟器可能存在定位或API请求问题。
内容的提问来源于stack exchange,提问作者I Can Done
相关产品推荐
相关产品推荐

