Android용 드라이버 SDK 시작하기

Driver SDK를 사용하여 이동 및 주문 진행률 애플리케이션에 향상된 탐색 및 추적 기능을 제공할 수 있습니다. Driver SDK는 주문형 차량 공유 솔루션 Fleet 엔진에 차량 위치 및 작업 업데이트를 제공합니다.

Driver SDK는 Fleet Engine 서비스와 커스텀 서비스가 차량의 위치와 상태를 인식하도록 유지합니다. 예를 들어 차량은 ONLINE 또는 OFFLINE일 수 있으며 이동이 진행됨에 따라 차량 위치가 변경됩니다.

최소 시스템 요구사항

휴대기기에서는 Android 6.0(API 수준 23) 이상을 실행해야 합니다.

빌드 및 종속 항목 구성

드라이버 SDK 버전 4.99 이상은 Google Maven 저장소에서 사용할 수 있습니다.

Gradle

build.gradle 파일에 다음을 추가합니다.

repositories {
    ...
    google()
}

Maven

pom.xml 파일에 다음을 추가합니다.

<project>
  ...
  <repositories>
    <repository>
      <id>google-maven-repository</id>
      <url>https://maven.google.com</url>
    </repository>
  </repositories>
  ...
</project>

프로젝트 구성

Driver SDK를 사용하려면 앱에서 minSdkVersion 23 이상을 타겟팅해야 합니다.

드라이버 SDK로 빌드된 앱을 실행하려면 Android 기기에 Google Play 서비스가 설치되어 있어야 합니다.

개발 프로젝트 설정하기

Google Cloud 콘솔에서 개발 프로젝트를 설정하고 프로젝트의 API 키를 가져오는 방법은 다음과 같습니다.

  1. Driver SDK와 함께 사용할 새 Google Cloud 콘솔 프로젝트를 만들거나 기존 프로젝트를 선택합니다. 새 프로젝트가 Google Cloud 콘솔에 표시될 때까지 몇 분 정도 기다립니다.

  2. 데모 앱을 실행하려면 프로젝트에서 Android용 Maps SDK에 액세스할 수 있어야 합니다. Google Cloud 콘솔에서 API 및 서비스 > 라이브러리를 선택한 다음 Android용 Maps SDK를 검색하여 사용 설정합니다.

  3. API 및 서비스 > 사용자 인증 정보 > 사용자 인증 정보 만들기 > API 키를 선택하여 프로젝트의 API 키를 가져옵니다. API 키를 가져오는 방법에 대한 자세한 내용은 API 키 가져오기를 참고하세요.

앱에 드라이버 SDK 추가

드라이버 SDK는 Google Maven 저장소에서 제공됩니다. 저장소에는 SDK의 프로젝트 객체 모델 (.pom) 파일과 Javadocs가 포함됩니다. 앱에 드라이버 SDK를 추가하려면 다음 단계를 따르세요.

  1. Gradle 또는 Maven 구성에 다음 종속 항목을 추가하여 원하는 버전의 드라이버 SDK를 VERSION_NUMBER 자리표시자로 대체합니다.

    Gradle

    build.gradle에 다음을 추가합니다.

    dependencies {
      ...
      implementation 'com.google.android.libraries.mapsplatform.transportation:transportation-driver:VERSION_NUMBER'
    }
    

    Maven

    pom.xml에 다음을 추가합니다.

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.mapsplatform.transportation</groupId>
        <artifactId>transportation-driver</artifactId>
        <version>VERSION_NUMBER</version>
      </dependency>
    </dependencies>
    
  2. 드라이버 SDK는 Navigation SDK에 종속됩니다. 이 종속 항목은 특정 버전의 Navigation SDK가 필요한 경우 다음과 같이 빌드 구성 파일에 명시적으로 정의되어야 하는 방식으로 구성됩니다. 언급된 코드 블록을 생략하면 프로젝트가 항상 메이저 출시 버전 내에서 Navigation SDK의 최신 버전을 다운로드할 수 있습니다. 최신 버전의 Driver SDK와 Navigation SDK의 결합된 동작은 출시 전에 엄격한 테스트를 거쳤습니다.

    이에 따라 개발 및 출시 환경의 종속 항목 구성을 정렬합니다.

    Gradle

    build.gradle에 다음을 추가합니다.

    dependencies {
      ...
      implementation 'com.google.android.libraries.navigation:navigation:5.0.0'
    }
    

    Maven

    pom.xml에 다음을 추가합니다.

    <dependencies>
      ...
      <dependency>
        <groupId>com.google.android.libraries.navigation</groupId>
        <artifactId>navigation</artifactId>
        <version>5.0.0</version>
      </dependency>
    </dependencies>
    

앱에 API 키 추가하기

드라이버 SDK를 앱에 추가한 후 앱에 API 키를 추가합니다. 개발 프로젝트를 설정할 때 가져온 프로젝트 API 키를 사용해야 합니다.

이 섹션에서는 앱에서 더 안전하게 참조할 수 있도록 API 키를 저장하는 방법을 설명합니다. 버전 제어 시스템에 API 키를 체크인하면 안 됩니다. 이 파일은 프로젝트의 루트 디렉터리에 있는 local.properties 파일에 저장해야 합니다. local.properties 파일에 관한 자세한 내용은 Gradle 속성 파일을 참고하세요.

이 작업을 간단히 진행하고 싶다면 Android용 Secrets Gradle Plugin을 사용하세요.

플러그인을 설치하여 API 키를 저장하는 방법은 다음과 같습니다.

  1. 루트 수준 build.gradle 파일을 열고 다음 코드를 buildscript 아래 dependencies 요소에 추가합니다.

    Groovy

    buildscript {
        dependencies {
            // ...
            classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0"
        }
    }
    

    Kotlin

    buildscript {
        dependencies {
            // ...
            classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.0")
        }
    }
    
  2. 앱 수준 build.gradle 파일을 열고 plugins 요소에 다음 코드를 추가합니다.

    Groovy

    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
    

    Kotlin

    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
    
  3. Android 스튜디오를 사용하는 경우 프로젝트를 Gradle과 동기화합니다.

  4. 프로젝트 수준 디렉터리에서 local.properties을 열고 다음 코드를 추가합니다. YOUR_API_KEY를 직접 생성한 API 키로 변경합니다.

    MAPS_API_KEY=YOUR_API_KEY
    
  5. AndroidManifest.xml 파일에서 com.google.android.geo.API_KEY로 이동한 후 android:value 속성을 다음과 같이 업데이트합니다.

    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="${MAPS_API_KEY}" />
    

다음 예는 샘플 앱의 전체 매니페스트를 보여줍니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.driverapidemo">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/_AppTheme">

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="${MAPS_API_KEY}" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

앱에 필수 저작자 표시를 포함합니다.

앱에서 Driver SDK를 사용하는 경우 앱의 법적 고지 섹션에 저작자 표시 텍스트와 오픈소스 라이선스를 포함해야 합니다. 저작자 표시는 독립적인 메뉴 항목 또는 정보 메뉴 항목의 일부로 포함하는 것이 가장 좋습니다.

라이선스 정보는 보관 취소된 AAR 파일의 'third_party_licenses.txt' 파일에서 확인할 수 있습니다.

오픈소스 알림을 포함하는 방법은 https://developers.google.com/android/guides/opensource를 참고하세요.

종속 항목

ProGuard를 사용하여 빌드를 최적화하는 경우 ProGuard 구성 파일에 다음 줄을 추가해야 할 수 있습니다.

-dontwarn com.google.**
-dontwarn okio.**

지원되는 최소 API 수준은 23입니다.

SDK 초기화

DriverContext 객체를 초기화하려면 제공업체 ID (일반적으로 Google Cloud 프로젝트 ID)가 필요합니다. Google Cloud 프로젝트 설정에 대한 자세한 내용은 인증 및 승인을 참조하세요.

Driver SDK를 사용하기 전에 먼저 Navigation SDK를 초기화해야 합니다. SDK를 초기화하려면 다음 안내를 따르세요.

  1. NavigationApi에서 Navigator 객체를 가져옵니다.

    Java

    NavigationApi.getNavigator(
        this, // Activity
        new NavigationApi.NavigatorListener() {
          @Override
          public void onNavigatorReady(Navigator navigator) {
            // Keep a reference to the Navigator (used to configure and start nav)
            this.navigator = navigator;
          }
        }
    );
    

    Kotlin

    NavigationApi.getNavigator(
      this, // Activity
      object : NavigatorListener() {
        override fun onNavigatorReady(navigator: Navigator) {
          // Keep a reference to the Navigator (used to configure and start nav)
          this@myActivity.navigator = navigator
        }
      },
    )
    
  2. DriverContext 객체를 만들고 필수 필드를 채웁니다.

    Java

    DriverContext driverContext = DriverContext.builder(application)
        .setProviderId(providerId)
        .setVehicleId(vehicleId)
        .setAuthTokenFactory(authTokenFactory)
        .setNavigator(navigator)
        .setRoadSnappedLocationProvider(
            NavigationApi.getRoadSnappedLocationProvider(application))
        .build();
    

    Kotlin

    val driverContext =
      DriverContext.builder(application)
        .setProviderId(providerId)
        .setVehicleId(vehicleId)
        .setAuthTokenFactory(authTokenFactory)
        .setNavigator(navigator)
        .setRoadSnappedLocationProvider(NavigationApi.getRoadSnappedLocationProvider(application))
        .build()
    
  3. DriverContext 객체를 사용하여 *DriverApi를 초기화합니다.

    Java

    RidesharingDriverApi ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext);
    

    Kotlin

    val ridesharingDriverApi = RidesharingDriverApi.createInstance(driverContext)
    
  4. API 객체에서 RidesharingVehicleReporter를 가져옵니다. (*VehicleReporterNavigationVehicleReporter를 확장합니다.)

    Java

    RidesharingVehicleReporter vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter();
    

    Kotlin

    val vehicleReporter = ridesharingDriverApi.getRidesharingVehicleReporter()
    

AuthTokenFactory로 인증

Driver SDK는 위치 업데이트를 생성할 때 이러한 업데이트를 Fleet Engine 서버로 전송해야 합니다. 이러한 요청을 인증하기 위해 드라이버 SDK는 호출자가 제공한 AuthTokenFactory 인스턴스를 호출합니다. 팩토리는 위치 업데이트 시 인증 토큰을 생성합니다.

토큰이 생성되는 정확한 방법은 각 개발자의 상황에 따라 다릅니다. 그러나 구현 시 다음을 해야 할 수 있습니다.

  • HTTPS 서버에서 JSON 형식의 인증 토큰 가져오기
  • 토큰 파싱 및 캐시
  • 토큰이 만료되면 토큰 새로고침

Fleet Engine 서버에서 예상하는 토큰에 대한 자세한 내용은 승인을 위한 JSON 웹 토큰 (JWT) 만들기를 참조하세요.

다음은 AuthTokenFactory의 스켈레톤 구현입니다.

Java

class JsonAuthTokenFactory implements AuthTokenFactory {
  private String token;  // initially null
  private long expiryTimeMs = 0;

  // This method is called on a thread whose only responsibility is to send
  // location updates. Blocking is OK, but just know that no location updates
  // can occur until this method returns.
  @Override
  public String getToken(AuthTokenContext authTokenContext) {
    if (System.currentTimeMillis() > expiryTimeMs) {
      // The token has expired, go get a new one.
      fetchNewToken(authTokenContext.getVehicleId());
    }
    return token;
  }

  private void fetchNewToken(String vehicleId) {
    String url =
        new Uri.Builder()
            .scheme("https")
            .authority("yourauthserver.example")
            .appendPath("token")
            .appendQueryParameter("vehicleId", vehicleId)
            .build()
            .toString();

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();
      token = obj.get("Token").getAsString();
      expiryTimeMs = obj.get("TokenExpiryMs").getAsLong();

      // The expiry time could be an hour from now, but just to try and avoid
      // passing expired tokens, we subtract 10 minutes from that time.
      expiryTimeMs -= 10 * 60 * 1000;
    } catch (IOException e) {
      // It's OK to throw exceptions here. The StatusListener you passed to
      // create the DriverContext class will be notified and passed along the failed
      // update warning.
      throw new RuntimeException("Could not get auth token", e);
    }
  }
}

Kotlin

class JsonAuthTokenFactory : AuthTokenFactory() {

  private var token: String = ""
  private var expiryTimeMs: Long = 0

  // This method is called on a thread whose only responsibility is to send
  // location updates. Blocking is OK, but just know that no location updates
  // can occur until this method returns.
  override fun getToken(context: AuthTokenContext): String {
    if (System.currentTimeMillis() > expiryTimeMs) {
      // The token has expired, go get a new one.
      fetchNewToken(authTokenContext.getVehicleId())
    }
     return token
  }

  fun fetchNewToken(vehicleId: String) {
    val url =
      Uri.Builder()
        .scheme("https")
        .authority("yourauthserver.example")
        .appendPath("token")
        .appendQueryParameter("vehicleId", vehicleId)
        .build()
        .toString()

    try {
      val reader = InputStreamReader(URL(url).openStream())

      reader.use {
        val obj = com.google.gson.JsonParser.parseReader(r).getAsJsonObject()

        token = obj.get("ServiceToken").getAsString()
        expiryTimeMs = obj.get("TokenExpiryMs").getAsLong()

        // The expiry time could be an hour from now, but just to try and avoid
        // passing expired tokens, we subtract 10 minutes from that time.
        expiryTimeMs -= 10 * 60 * 1000
      }
    } catch (e: IOException) {
      // It's OK to throw exceptions here. The StatusListener you passed to
      // create the DriverContext class will be notified and passed along the failed
      // update warning.
      throw RuntimeException("Could not get auth token", e)
    }
  }
}

이 구현에서는 기본 제공 자바 HTTP 클라이언트를 사용하여 개발자의 인증 서버에서 JSON 형식의 토큰을 가져옵니다. 토큰은 재사용을 위해 저장됩니다. 이전 토큰의 만료 시간이 10분 이내이면 토큰을 다시 가져옵니다.

구현에서는 백그라운드 스레드를 사용하여 토큰을 갱신하는 등 다른 작업을 실행할 수도 있습니다.

AuthTokenFactory의 예외는 반복적으로 발생하지 않는 한 일시적인 것으로 간주됩니다. 여러 번 시도한 후 드라이버 SDK는 오류가 영구적인 것으로 가정하고 업데이트 전송 시도를 중지합니다.

StatusListener를 사용한 상태 및 Error Reporting

Driver SDK는 백그라운드에서 작업을 실행하므로 오류, 경고, 디버그 메시지와 같은 특정 이벤트가 발생할 때 StatusListener를 사용하여 알림을 트리거합니다. 오류는 본질적으로 일시적이거나 (예: BACKEND_CONNECTIVITY_ERROR) 위치 업데이트가 영구적으로 중지될 수 있습니다 (예: 구성 오류를 나타내는 VEHICLE_NOT_FOUND).

다음과 같이 선택적으로 StatusListener 구현을 제공합니다.

Java

class MyStatusListener implements StatusListener {
  /** Called when background status is updated, during actions such as location reporting. */
  @Override
  public void updateStatus(
      StatusLevel statusLevel, StatusCode statusCode, String statusMsg) {
    // Status handling stuff goes here.
    // StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
    // StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
    // BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
  }
}

Kotlin

class MyStatusListener : StatusListener() {
  /** Called when background status is updated, during actions such as location reporting. */
  override fun updateStatus(statusLevel: StatusLevel, statusCode: StatusCode, statusMsg: String) {
    // Status handling stuff goes here.
    // StatusLevel may be DEBUG, INFO, WARNING, or ERROR.
    // StatusCode may be DEFAULT, UNKNOWN_ERROR, VEHICLE_NOT_FOUND,
    // BACKEND_CONNECTIVITY_ERROR, or PERMISSION_DENIED.
  }
}

SSL/TLS 관련 참고사항

내부적으로 드라이버 SDK 구현은 SSL/TLS를 사용하여 Fleet Engine 서버와 안전하게 통신합니다. 이전 버전의 Android (API 버전 19 이하)에서는 서버와 통신할 수 있도록 SecurityProvider 패치가 필요할 수도 있습니다. Android에서 SSL을 사용하는 방법에 대한 자세한 내용은 이 도움말을 참조하세요. 이 문서에는 보안 프로바이더에 패치를 적용하기 위한 코드 샘플도 포함되어 있습니다.

위치 업데이트 사용 설정

*VehicleReporter 인스턴스가 있으면 간단하게 위치 업데이트를 사용 설정할 수 있습니다.

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();

Kotlin

val reporter = ...

reporter.enableLocationTracking()

차량 상태가 ONLINE일 때 위치 업데이트가 일정한 간격으로 전송됩니다. reporter.enableLocationTracking()를 호출해도 차량 상태가 자동으로 ONLINE로 설정되지는 않습니다. 명시적으로 차량 상태를 설정해야 합니다.

보고 간격은 기본적으로 10초입니다. 보고 간격은 reporter.setLocationReportingInterval(long, TimeUnit)를 사용하여 변경할 수 있습니다. 지원되는 최소 업데이트 간격은 5초입니다. 더 자주 업데이트하면 요청 및 오류가 느려질 수 있습니다.

위치 업데이트 사용 중지

운전자의 시프트가 완료되면 DeliveryVehicleReporter.disableLocationTracking 또는 RidesharingVehicleReporter.disableLocationTracking를 호출하여 위치 업데이트를 중지하고 차량을 오프라인으로 표시할 수 있습니다.

이 호출을 통해 마지막 업데이트가 즉시 전송되도록 예약되어 차량이 오프라인 상태임을 나타냅니다. 이 업데이트에 사용자의 위치는 포함되지 않습니다.

차량 상태 설정

위치 업데이트가 사용 설정된 경우 차량 상태를 ONLINE로 설정하면 차량을 SearchVehicles 쿼리에 사용할 수 있습니다. 마찬가지로 차량을 OFFLINE로 표시하면 차량이 이용 불가로 표시됩니다.

서버 측 (차량 업데이트 참고)에서 또는 드라이버 SDK에서 직접 차량 상태를 설정할 수 있습니다.

Java

RidesharingVehicleReporter reporter = ...;

reporter.enableLocationTracking();
reporter.setVehicleState(VehicleState.ONLINE);

Kotlin

val reporter = ...

reporter.enableLocationTracking()
reporter.setVehicleState(VehicleState.ONLINE)

위치 업데이트가 사용 설정되면 setVehicleState 호출이 다음 위치 업데이트 시 전파됩니다.

위치 추적이 사용 설정되지 않은 상태에서 차량을 ONLINE로 표시하면 IllegalStateException이 발생합니다. 위치 추적을 아직 사용 설정하지 않았거나 명시적으로 사용 중지하지 않은 경우 차량을 OFFLINE로 표시할 수 있습니다. 그러면 즉시 업데이트됩니다. RidesharingVehicleReporter.disableLocationTracking()를 호출하면 차량 상태가 OFFLINE로 설정됩니다.

setVehicleState가 즉시 반환되며 위치 업데이트 스레드에서 업데이트가 실행됩니다. 위치 업데이트의 오류 처리와 마찬가지로 차량 상태를 업데이트하는 오류는 DriverContext에 설정된 선택사항으로 제공되는 StatusListener를 사용하여 전파됩니다.