You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 10:15:33