모든 준비를 마쳤습니다!

개발을 시작하려면 개발자 문서로 이동하세요.

Google Maps Roads API 활성화

개발을 시작하기 위해 Google Developers Console에서 우선적으로 해야 할 일을 몇 가지 소개하겠습니다.

  1. 프로젝트 생성 또는 선택
  2. Google Maps Roads API 활성화
  3. 적합한 키 생성
계속

고급 개념

참고: 아래 예시에서는 Java Client for Google Maps Services에서 Google Maps Roads API를 사용합니다. 선택한 언어에 맞게 개념을 조절할 수 있습니다. Python Client, Go ClientNode.js Client도 GitHub에서 사용할 수 있습니다.

데이터 가져오기

수집된 위치 데이터를 가져오는 여러 가지 방법이 있습니다. 여기서는 Google Maps Roads APISnap to Roads 기능을 사용하여 데이터를 가져오는 두 가지 기법에 대해 설명합니다.

GPX

GPX는 GPS 기기에 의해 캡처된 경로, 트랙 및 경유지를 공유하기 위한 오픈 XML 기반 형식입니다. 이 예시에서는 Java 서버 및 모바일 환경에 사용 가능한 경량 XML 파서인 XmlPull 파서를 사용합니다.

/**
 * Parses the waypoint (wpt tags) data into native objects from a GPX stream.
 */
private List<LatLng> loadGpxData(XmlPullParser parser, InputStream gpxIn)
        throws XmlPullParserException, IOException {
    // We use a List<> as we need subList for paging later
    List<LatLng> latLngs = new ArrayList<>();
    parser.setInput(gpxIn, null);
    parser.nextTag();

    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            continue;
        }

        if (parser.getName().equals("wpt")) {
            // Save the discovered latitude/longitude attributes in each <wpt>.
            latLngs.add(new LatLng(
                    Double.valueOf(parser.getAttributeValue(null, "lat")),
                    Double.valueOf(parser.getAttributeValue(null, "lon"))));
        }
        // Otherwise, skip irrelevant data
    }

    return latLngs;
}

다음은 지도에 로드되는 몇 가지 원시 GPX 데이터입니다.

지도 위의 원시 GPX 데이터

Android 위치 서비스

Android 기기에서 GPS 데이터를 캡처하는 최선의 방법은 사용자의 사용 사례에 따라 다릅니다. 위치 업데이트 수신 또는 GitHub의 Google Play 위치 샘플에 대한 Android 교육 과정을 참조하세요.

긴 경로 처리

snap to roads 기능은 개별 지점이 아닌 전체 경로에 따라 위치를 추론하므로, 긴 경로(즉, 요청당 100지점 한도 이상인 경로)를 처리할 때 주의해야 합니다.

개별 요청을 하나의 긴 경로로 처리하려면, 이전 요청의 마지막 지점이 후속 요청의 첫 지점으로 포함되도록 약간의 겹치는 부분을 포함해야 합니다. 포함되는 지점 수는 데이터의 정확도에 따라 다릅니다. 정확도가 낮은 요청의 경우 더 많은 지점을 포함시켜야 합니다.

이 예시에서는 Java Client for Google Maps Services를 사용하여 페이징된 요청을 전송한 다음, 보간된 지점을 포함한 데이터를 반환된 목록에 다시 연결합니다.

/**
 * Snaps the points to their most likely position on roads using the Roads API.
 */
private List<SnappedPoint> snapToRoads(GeoApiContext context) throws Exception {
    List<SnappedPoint> snappedPoints = new ArrayList<>();

    int offset = 0;
    while (offset < mCapturedLocations.size()) {
        // Calculate which points to include in this request. We can't exceed the API's
        // maximum and we want to ensure some overlap so the API can infer a good location for
        // the first few points in each request.
        if (offset > 0) {
            offset -= PAGINATION_OVERLAP;   // Rewind to include some previous points.
        }
        int lowerBound = offset;
        int upperBound = Math.min(offset + PAGE_SIZE_LIMIT, mCapturedLocations.size());

        // Get the data we need for this page.
        LatLng[] page = mCapturedLocations
                .subList(lowerBound, upperBound)
                .toArray(new LatLng[upperBound - lowerBound]);

        // Perform the request. Because we have interpolate=true, we will get extra data points
        // between our originally requested path. To ensure we can concatenate these points, we
        // only start adding once we've hit the first new point (that is, skip the overlap).
        SnappedPoint[] points = RoadsApi.snapToRoads(context, true, page).await();
        boolean passedOverlap = false;
        for (SnappedPoint point : points) {
            if (offset == 0 || point.originalIndex >= PAGINATION_OVERLAP - 1) {
                passedOverlap = true;
            }
            if (passedOverlap) {
                snappedPoints.add(point);
            }
        }

        offset = upperBound;
    }

    return snappedPoints;
}

다음은 Snap to Roads 요청을 실행한 후의 데이터입니다. 빨간 줄은 원시 데이터이고 파란 줄은 스냅된 데이터입니다.

도로에 스냅된 데이터의 예

할당량의 효율적인 사용

snap to roads 요청에 대한 응답에는 여러분이 제공한 지점에 매핑되는 장소 ID 목록이 포함되며, interpolate=true를 설정한 경우에는 잠재적으로 추가적인 지점이 포함됩니다.

속도 제한 요청에 허용된 할당량을 효율적으로 사용하려면, 요청에서 고유한 장소 ID만을 쿼리해야 합니다. 이 예시에서는 Java Client for Google Maps Services를 사용하여 장소 ID 목록에서 속도 제한을 쿼리합니다.

/**
 * Retrieves speed limits for the previously-snapped points. This method is efficient in terms
 * of quota usage as it will only query for unique places.
 *
 * Note: Speed limit data is only available for requests using an API key enabled for a
 * Google Maps APIs Premium Plan license.
 */
private Map<String, SpeedLimit> getSpeedLimits(GeoApiContext context, List<SnappedPoint> points)
        throws Exception {
    Map<String, SpeedLimit> placeSpeeds = new HashMap<>();

    // Pro tip: Save on quota by filtering to unique place IDs.
    for (SnappedPoint point : points) {
        placeSpeeds.put(point.placeId, null);
    }

    String[] uniquePlaceIds =
            placeSpeeds.keySet().toArray(new String[placeSpeeds.keySet().size()]);

    // Loop through the places, one page (API request) at a time.
    for (int i = 0; i < uniquePlaceIds.length; i += PAGE_SIZE_LIMIT) {
        String[] page = Arrays.copyOfRange(uniquePlaceIds, i,
                Math.min(i + PAGE_SIZE_LIMIT, uniquePlaceIds.length));

        // Execute!
        SpeedLimit[] placeLimits = RoadsApi.speedLimits(context, page).await();
        for (SpeedLimit sl : placeLimits) {
            placeSpeeds.put(sl.placeId, sl);
        }
    }

    return placeSpeeds;
}

다음은 위에서 고유한 각 장소 ID에 속도 제한이 표시된 데이터입니다.

지도 위의 속도 제한 기호

다른 API와의 상호 작용

snap to roads 응답에 장소 ID가 반환될 경우 한 가지 이점은, 많은 Google Maps API에서 이 장소 ID를 사용할 수 있다는 점입니다. 이 예시에서는 Java Client for Google Maps Services를 사용하여 위의 snap to road 요청에서 반환된 장소를 지오코딩합니다.

/**
 * Geocodes a snapped point using the place ID.
 */
private GeocodingResult geocodeSnappedPoint(GeoApiContext context, SnappedPoint point) throws Exception {
    GeocodingResult[] results = GeocodingApi.newRequest(context)
            .place(point.placeId)
            .await();

    if (results.length > 0) {
        return results[0];
    }
    return null;
}

여기에서 속도 제한 마커는 Google Maps Geocoding API의 주소로 주석이 달려 있습니다.

마커에 나타난 지오코딩된 주소

샘플 코드

고려 사항

설명을 위해 이 글을 지원하는 코드가 단일 Android 앱으로 제공됩니다. 실제로는 제3자의 불법 액세스로부터 키를 보호할 수 없기 때문에 서버측 API 키를 Android 앱에 배포하면 안됩니다. 그 대신, 키를 보호하기 위해 API 페이싱 코드를 서버측 프록시로 배포하고, Android 앱이 이 프록시를 통해 요청을 전송하도록 함으로써 요청이 인증되도록 해야 합니다.

다운로드

GitHub에서 코드를 다운로드합니다.

다음에 대한 의견 보내기...

Google Maps Roads API
Google Maps Roads API
도움이 필요하시나요? 지원 페이지를 방문하세요.