Google 多年来持续收紧 Maps Platform,而2026年5月的弃用浪潮是迄今影响最大的一次。Maps JavaScript API 将移除四项被广泛使用的功能:Heatmap Layer、Drawing Library、DirectionsService 和 DistanceMatrixService。如果你的应用依赖其中任何一项,在代码失效前只剩下几周时间完成迁移。
这不是那种旧接口会延续多年的「软弃用」。Google 设定了硬性移除日期,开发者控制台已经出现警告。本文详细说明变更内容、Google 的调整原因,以及如何通过可运行的代码示例完成各服务的迁移。如果需要即插即用的替代方案,我们也会展示 MapAtlas API 如何对应每个被弃用的 Google 服务。
弃用内容与时间表
受影响服务的完整时间表:
| 服务 | 弃用时间 | 移除日期 | 替代方案(Google) |
|---|---|---|---|
| Heatmap Layer (Maps JS API) | 2025年8月 | 2026年5月 | Maps Datasets API + deck.gl |
| Drawing Library (Maps JS API) | 2025年5月 | 2026年5月 | Extended Component Library |
| DirectionsService (Maps JS API) | 2026年2月25日 | 2026年5月 | Routes API (REST) |
| DistanceMatrixService (Maps JS API) | 2026年2月25日 | 2026年5月 | Routes API (REST) |
关键细节:Google 并非全面移除路由和距离计算功能,而是移除开发者使用了十余年的客户端 JavaScript 类,强制迁移至更新的 Routes API(服务端 REST 接口)。这不是简单的版本升级,而是将路由逻辑从浏览器迁移到后端的架构变更。
哪些代码会失效
如果代码库包含以下任意内容,在移除日期后将报错:
// All of these will stop working in May 2026
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();
移除后这些构造函数会抛出错误,没有任何回退机制,也不会优雅降级。地图能加载,但依赖这些类的所有功能会完全失效。
Google 为何强制推行这些变更
Google 的官方理由是性能提升和现代化改造。Routes API 作为 DirectionsService 和 DistanceMatrixService 的替代,支持旧版 JavaScript 类无法实现的新特性:环保路由、两轮车路由和过路费估算。
真正的驱动力是计费控制。将路由迁移到服务端 REST API 后,Google 可以实现更细粒度的计费和用量追踪。JavaScript 版 DirectionsService 允许客户端批量处理模式,Google 难以精确计量。Routes API 确保每个请求都经过可计量的接口。
对于 Heatmap Layer 和 Drawing Library,Google 正在推动开发者转向其 Extended Component Library 以及 deck.gl 等第三方可视化工具。这是一个更宏观趋势的体现:Google 将核心地图瓦片渲染保留在内部,其余功能外包给生态系统。
对开发者的实际影响:需要更多后端基础设施、管理更多 API 密钥,且新价格层的每请求成本在多数情况下更高。
迁移检查清单
编写任何迁移代码前,先完成以下检查清单:
1. 审查代码库
搜索代码库中对弃用类的引用:
# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|HeatmapLayer\|visualization.HeatmapLayer\|drawing.DrawingManager\|DrawingManager" \
--include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/
记录每个使用这些服务的文件和组件,注明调用发生在客户端(浏览器)还是服务端渲染上下文(如 Next.js API 路由)中。
2. 梳理使用模式
针对每个使用点,记录:
- 使用的出行方式(驾车、步行、骑行、公交)
- 途经点支持(简单 A 到 B,还是多站点路线)
- 消费的响应字段(距离、时长、折线、步骤、费用)
- 请求量(每日/每月请求数,用于成本估算)
- 延迟要求(面向用户的实时需求,还是批量处理)
3. 选择迁移目标
两个选项:
选项 A:继续使用 Google。 从弃用的 JavaScript 类迁移到新的 Google Routes API(REST)。需要后端改动、新的 API 密钥权限和账单更新。
选项 B:切换服务商。 迁移到第三方路由 API。由于集成代码无论如何都要重写,这是评估替代方案的好时机。
4. 搭建并行环境
绝对不要原地迁移。至少连续两周同时运行新旧实现,在切换前比较准确性和延迟表现。
5. 更新错误处理
弃用服务通过回调函数传递错误,REST API 替代方案返回 HTTP 状态码。错误处理逻辑需要相应调整。
逐 API 替换指南
DirectionsService 迁移至 MapAtlas Directions API
迁移前(Google,已弃用):
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin: { lat: 52.52, lng: 13.405 },
destination: { lat: 48.8566, lng: 2.3522 },
travelMode: google.maps.TravelMode.DRIVING,
waypoints: [
{ location: { lat: 50.9375, lng: 6.9603 }, stopover: true }
],
},
(result, status) => {
if (status === "OK") {
const route = result.routes[0];
console.log("Distance:", route.legs[0].distance.text);
console.log("Duration:", route.legs[0].duration.text);
}
}
);
迁移后(MapAtlas Directions API):
const response = await fetch(
"https://api.mapatlas.com/v1/directions?" +
new URLSearchParams({
origin: "52.52,13.405",
destination: "48.8566,2.3522",
waypoints: "50.9375,6.9603",
mode: "driving",
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
if (data.status === "OK") {
const leg = data.routes[0].legs[0];
console.log("Distance:", leg.distance.text);
console.log("Duration:", leg.duration.text);
// Polyline for map rendering
const polyline = data.routes[0].overview_polyline;
}
主要差异:
- 使用 REST 接口而非 JavaScript 类,调用来自后端而非浏览器。
- 认证更简单,只需在查询参数或请求头中传入一个 API 密钥。
- 响应结构相同,routes、legs、distance、duration 和 polyline 全部保留。
DistanceMatrixService 迁移至 MapAtlas Matrix API
迁移前(Google,已弃用):
const service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
travelMode: google.maps.TravelMode.DRIVING,
},
(response, status) => {
if (status === "OK") {
response.rows.forEach((row, i) => {
row.elements.forEach((element, j) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
}
}
);
迁移后(MapAtlas Matrix API):
const response = await fetch("https://api.mapatlas.com/v1/matrix", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.MAPATLAS_API_KEY}`,
},
body: JSON.stringify({
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
mode: "driving",
}),
});
const data = await response.json();
data.rows.forEach((row: any, i: number) => {
row.elements.forEach((element: any, j: number) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
响应结构几乎完全相同,主要变化是从基于回调的浏览器 API 切换为基于 Promise 的服务端 API。
Heatmap Layer 的替代方案
热力图可视化的迁移路径取决于具体需求:
方案一:MapLibre GL JS 热力图层(开源)
import maplibregl from "maplibre-gl";
const map = new maplibregl.Map({
container: "map",
style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
center: [13.405, 52.52],
zoom: 10,
});
map.on("load", () => {
map.addSource("heat-data", {
type: "geojson",
data: {
type: "FeatureCollection",
features: heatmapPoints.map((point) => ({
type: "Feature",
geometry: { type: "Point", coordinates: [point.lng, point.lat] },
properties: { weight: point.weight },
})),
},
});
map.addLayer({
id: "heatmap-layer",
type: "heatmap",
source: "heat-data",
paint: {
"heatmap-weight": ["get", "weight"],
"heatmap-intensity": 1,
"heatmap-radius": 20,
"heatmap-opacity": 0.7,
},
});
});
完全掌控热力图渲染,不依赖 Google 的瓦片服务器。
方案二:deck.gl HeatmapLayer(Google 官方推荐)
import { Deck } from "@deck.gl/core";
import { HeatmapLayer } from "@deck.gl/aggregation-layers";
const heatmapLayer = new HeatmapLayer({
data: heatmapPoints,
getPosition: (d) => [d.lng, d.lat],
getWeight: (d) => d.weight,
radiusPixels: 30,
});
两种方案均可行。MapLibre GL JS 与 MapAtlas 瓦片样式集成顺畅,deck.gl 则可叠加在任意底图上。
成本对比:Google Routes API vs MapAtlas
迁移至 Google 自己的 Routes API 不只是代码改动,还伴随新的价格体系:
| 服务 | Google(旧版,每1,000次) | Google Routes API(每1,000次) | MapAtlas(每1,000次) |
|---|---|---|---|
| Directions(基础) | $5.00 | $5.00 | $1.50 |
| Directions(高级,途经点/路况) | $10.00 | $10.00 | $2.50 |
| Distance Matrix(每元素) | $5.00 | $5.00 | $1.00 |
| Distance Matrix(高级) | $10.00 | $10.00 | $2.00 |
| Geocoding | $5.00 | $5.00 | $1.50 |
每月10万次路由请求的费用:
- Google Routes API: 约 $500-$1,000(取决于使用的功能)
- MapAtlas Directions API: 约 $150-$250
对于同时使用路由、地理编码和距离计算的应用,成本差距快速累积。每月处理50万个矩阵元素的物流平台,使用 Google 约需 $2,500,使用 MapAtlas 仅需 $500。
完整价格详情请参阅 MapAtlas 定价页面。
完整迁移示例:前后对比
以下是一个在地图上展示驾车路线的 React 组件完整迁移示例。
迁移前:React 中使用 Google Maps DirectionsService
import { useEffect, useRef } from "react";
function DirectionsMap({ origin, destination }: {
origin: google.maps.LatLngLiteral;
destination: google.maps.LatLngLiteral;
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new google.maps.Map(mapRef.current!, {
center: origin,
zoom: 7,
});
const directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin,
destination,
travelMode: google.maps.TravelMode.DRIVING,
},
(result, status) => {
if (status === "OK" && result) {
directionsRenderer.setDirections(result);
}
}
);
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
迁移后:MapAtlas Directions API + MapLibre GL JS
import { useEffect, useRef } from "react";
import maplibregl from "maplibre-gl";
function DirectionsMap({ origin, destination }: {
origin: { lat: number; lng: number };
destination: { lat: number; lng: number };
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new maplibregl.Map({
container: mapRef.current!,
style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
center: [origin.lng, origin.lat],
zoom: 7,
});
map.on("load", async () => {
// Fetch directions from your backend (or directly if CORS allows)
const res = await fetch(
`/api/directions?` +
new URLSearchParams({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
mode: "driving",
})
);
const data = await res.json();
if (data.routes?.[0]) {
const coordinates = data.routes[0].geometry.coordinates;
map.addSource("route", {
type: "geojson",
data: {
type: "Feature",
geometry: { type: "LineString", coordinates },
properties: {},
},
});
map.addLayer({
id: "route-line",
type: "line",
source: "route",
paint: {
"line-color": "#4A90D9",
"line-width": 5,
},
});
// Fit map to route bounds
const bounds = coordinates.reduce(
(b: maplibregl.LngLatBounds, coord: [number, number]) =>
b.extend(coord),
new maplibregl.LngLatBounds(coordinates[0], coordinates[0])
);
map.fitBounds(bounds, { padding: 50 });
}
});
return () => map.remove();
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
后端 API 路由(Next.js)
// app/api/directions/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const origin = searchParams.get("origin");
const destination = searchParams.get("destination");
const mode = searchParams.get("mode") || "driving";
const response = await fetch(
`https://api.mapatlas.com/v1/directions?` +
new URLSearchParams({
origin: origin!,
destination: destination!,
mode,
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
return NextResponse.json(data);
}
这种模式将 API 密钥保留在服务端,仅向客户端暴露路线几何数据。
截止日期前如何测试迁移
第一步:并行运行两套 API
切换前的两周内,对每个请求同时调用旧版 Google 服务和新替代服务,记录并比较两份响应:
async function getDirectionsWithComparison(
origin: string,
destination: string
) {
const [googleResult, mapatResult] = await Promise.all([
fetchGoogleDirections(origin, destination),
fetchMapAtlasDirections(origin, destination),
]);
// Compare key metrics
const distanceDelta = Math.abs(
googleResult.distance - mapatResult.distance
);
const durationDelta = Math.abs(
googleResult.duration - mapatResult.duration
);
console.log({
route: `${origin} -> ${destination}`,
googleDistance: googleResult.distance,
mapatDistance: mapatResult.distance,
distanceDeltaPercent: ((distanceDelta / googleResult.distance) * 100).toFixed(1),
googleDuration: googleResult.duration,
mapatDuration: mapatResult.duration,
durationDeltaPercent: ((durationDelta / googleResult.duration) * 100).toFixed(1),
});
// Use MapAtlas result in production, Google as validation
return mapatResult;
}
第二步:配置功能开关
使用功能开关控制应用调用哪套 API,便于出现问题时立即回滚:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
第三步:监控错误率
切换后重点关注:
- 新 API 的 HTTP 4xx/5xx 错误率
- 延迟增加(新服务商的响应时间可能不同)
- 响应中 缺失的字段(UI 依赖项)
- 边缘场景的路线准确性(轮渡路线、收费公路、限行区域)
第四步:上线前进行压力测试
如果应用存在流量峰值(例如物流平台的早高峰调度),以峰值流量的2倍对新 API 进行压力测试。MapAtlas 提供沙盒环境,可在不产生生产计费的情况下完成压力测试。
行动时间表:本周该做什么
如果尚未开始迁移,按以下优先顺序推进:
- 本周: 审查代码库,找出所有使用这四项弃用服务的位置。
- 第2周: 注册 MapAtlas 账户并获取 API 密钥。免费层包含10,000次测试请求。
- 第3周: 为最关键的服务(通常是 DirectionsService)实现替代方案。
- 第4周: 迁移其余服务并进行并行测试。
- 5月截止日期前: 完成切换,移除 Google API 依赖,更新账单配置。
迁移不是可选项。2026年5月后,弃用类将从 Maps JavaScript API 中移除,任何引用这些类的代码都会在运行时抛出错误。现在开始,有充足时间做好测试;等到最后一周,只能在压力下紧急修复生产环境。
需要迁移支持,MapAtlas 提供直接的开发者协助。通过联系页面联系我们,或从 API 文档开始,根据你的需求评估替代 API。
常见问题
Google Maps API 弃用具体何时生效?
Heatmap Layer 和 Drawing Library 分别于2025年8月和5月弃用,计划于2026年5月移除。DirectionsService 和 DistanceMatrixService 于2026年2月25日弃用,同样以2026年5月为移除目标。移除后,对这些服务的 API 调用将返回错误。
我现有的 Google Maps JavaScript API 密钥在2026年5月后还能用吗?
API 密钥对未被弃用的服务仍然有效。但凡通过 Maps JavaScript API 调用 DirectionsService、DistanceMatrixService、Heatmap Layer 或 Drawing Library 的代码都将失效。必须在截止日期前将这些调用迁移到替代 API。
Google Maps Directions API 最便宜的替代方案是什么?
MapAtlas 提供的 Directions API 费用约比 Google 同类产品低70%。免费层每月包含10,000次请求,足以完成迁移开发和测试。其他替代方案包括 Mapbox、HERE 和 OpenRouteService,但 MapAtlas 的请求/响应格式与 Google 最为接近,可有效降低迁移工作量。
可以分阶段迁移,还是必须一次性切换?
完全可以分阶段迁移。每个弃用服务相互独立,因此可先替换 DirectionsService,再替换 DistanceMatrixService,最后处理可视化库。这也是推荐的方式,因为每个替换都可以单独测试验证后再进行下一步。
MapAtlas 是否支持与 Google DirectionsService 相同的途经点和出行方式?
是的。MapAtlas Directions API 支持驾车、步行和骑行模式,以及中间途经点。请求格式略有不同(RESTful 接口 vs JavaScript 类),但核心功能——带出行方式选择的多站点路由——完全等价。

