Flutter多端(Android/iOS/Web)如何使用Google Places Autocomplete?
跨端兼容的Google Places Autocomplete解决方案
核心思路:通过后端代理规避Web端跨域限制
Google Places API直接在Web端调用会触发跨域问题,统一通过后端代理转发请求是最稳妥的跨端兼容方案——Android、iOS、Web端均调用自研后端接口,再由后端向Google Places API发起请求并返回结果,既解决跨域,又能保护API密钥不暴露。
具体实现步骤
1. 实现后端代理接口
用任意后端语言(示例以Node.js/Express为例)编写转发接口,接收前端搜索参数后请求Google Places API:
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const app = express(); // 配置CORS,允许前端域名(Web端需此配置) app.use(cors({ origin: '你的前端Web域名' })); const GOOGLE_API_KEY = '你的Google API密钥'; app.get('/api/places/autocomplete', async (req, res) => { const { input, radius, region, language, types, components } = req.query; try { const response = await axios.get('https://maps.googleapis.com/maps/api/place/autocomplete/json', { params: { input, radius, region, language, types, components, key: GOOGLE_API_KEY } }); res.json(response.data); } catch (error) { res.status(error.response?.status || 500).json({ error: error.message }); } }); app.listen(3000, () => console.log('代理服务启动在3000端口'));
2. 前端统一调用代理接口
替换原有直接调用Google API的逻辑,改为请求自研后端接口,实现跨端逻辑统一。以Flutter为例,自定义搜索组件:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class CrossPlatformPlacesAutocomplete extends StatefulWidget { final String hint; final String region; final String language; final String types; final String components; const CrossPlatformPlacesAutocomplete({ super.key, required this.hint, required this.region, required this.language, required this.types, required this.components, }); @override State<CrossPlatformPlacesAutocomplete> createState() => _CrossPlatformPlacesAutocompleteState(); } class _CrossPlatformPlacesAutocompleteState extends State<CrossPlatformPlacesAutocomplete> { final TextEditingController _controller = TextEditingController(); List<dynamic> _suggestions = []; Future<void> _loadSuggestions(String input) async { if (input.trim().isEmpty) { setState(() => _suggestions = []); return; } final url = Uri.parse('http://你的后端地址/api/places/autocomplete') .replace(queryParameters: { 'input': input, 'radius': '500000', 'region': widget.region, 'language': widget.language, 'types': widget.types, 'components': widget.components, }); final response = await http.get(url); if (response.statusCode == 200) { final data = jsonDecode(response.body); setState(() => _suggestions = data['predictions'] ?? []); } } @override Widget build(BuildContext context) { return AlertDialog( title: TextField( controller: _controller, decoration: InputDecoration(hintText: widget.hint), onChanged: _loadSuggestions, ), content: SizedBox( height: 220, child: ListView.builder( itemCount: _suggestions.length, itemBuilder: (context, index) { final item = _suggestions[index]; return ListTile( title: Text(item['description']), onTap: () => Navigator.pop(context, item), ); }, ), ), ); } } // 调用示例 // final result = await showDialog( // context: context, // builder: (context) => CrossPlatformPlacesAutocomplete( // hint: "Search City", // region: "in", // language: "en", // types: "(cities)", // components: "country:in", // ), // );
3. 关键注意事项
- 密钥安全:Google API密钥仅存储在后端,避免前端暴露导致滥用。
- 平台适配:Android/iOS端也可选择原生Google Places SDK,但用代理方案能彻底统一前端逻辑,减少平台差异化代码。
- 性能优化:后端可添加请求缓存,降低重复请求带来的延迟和API费用消耗。
内容的提问来源于stack exchange,提问作者Pavan Patil
相关产品推荐
相关产品推荐

