NAV Navbar

Map8 Navigation SDK for Android

Map8 Navigation SDK 提供一個完整的導航畫面:只要給目的地,就能在您的 App 裡開啟逐向導航,不需要自己處理路線規劃、GPS 貼路與畫面。

內建功能:

畫面版面是固定的,您可以調整配色、接收導航事件,並決定導航畫面要放在 App 的哪裡。

系統需求

版本相容性

Navigation SDK 搭配的 Map8 Maps SDK
1.1.1 1.0.4 以上

語言

導航畫面的文字與語音播報目前只提供繁體中文。語音使用手機內建的文字轉語音(TTS),請確認手機已安裝中文語音(大部分 Android 手機預設就有)。

安裝

加入 aar

Navigation SDK 由以下 aar 組成,請一併放進 app/libs/:

aar 說明
Map8AndroidSDK-release.aar、map8-android-accounts-0.2.0.aar Map8 地圖 SDK(安裝方式見 Maps SDK 安裝指南)
map8-navigation-1.1.1.aar 導航畫面與導航流程
m8turnLib-release.aar 導航引擎

下載 Navigation SDK:https://api.map8.zone/download/navigation_sdk/map8-navigation-sdk-android.zip?key=您的key

解壓縮後會取得 map8-navigation-1.1.1.aar 與 m8turnLib-release.aar,跟地圖 SDK 的兩個 aar 一樣放進 app/libs/。

設定 build.gradle

在 app/build.gradle 的 dependencies 加入 Navigation SDK 的兩個 aar(地圖 SDK 的部分照 Maps SDK 安裝指南,已經加過就不用重複):

dependencies {
    // Map8 Navigation SDK
    implementation files('libs/map8-navigation-1.1.1.aar')
    implementation files('libs/m8turnLib-release.aar')

    // Map8 Maps SDK 與它需要的套件(同 Maps SDK 安裝指南)
    implementation files('libs/Map8AndroidSDK-release.aar')
    implementation files('libs/map8-android-accounts-0.2.0.aar')
    implementation 'com.mapbox.mapboxsdk:mapbox-android-telemetry:4.5.1'
    implementation 'com.mapbox.mapboxsdk:mapbox-sdk-geojson:4.8.0'
    implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.5.1'
    implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:4.8.0'
    implementation 'com.squareup.okhttp3:okhttp:3.12.3'
    implementation 'com.facebook.soloader:soloader:0.12.1'

    implementation 'androidx.appcompat:appcompat:1.7.0'
}

gradle.properties 需要開啟 Jetifier(地圖 SDK 本來就需要,已經設定過就不用重複):

android.useAndroidX=true
android.enableJetifier=true

Java 專案

Navigation SDK 是用 Kotlin 寫的。Kotlin 專案不用另外設定;Java 專案請再加上 Kotlin 標準函式庫:

dependencies {
    implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.24'
}

權限

需要的權限 SDK 都已經宣告,會自動合併進您的 App,不用另外修改 AndroidManifest.xml:

權限 用途
INTERNET 地圖圖資、路線規劃
ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION 導航定位
FOREGROUND_SERVICE、FOREGROUND_SERVICE_LOCATION 背景導航
POST_NOTIFICATIONS 背景導航時的常駐通知(Android 13 以上)

開始導航時,如果還沒有定位權限,導航畫面會自己跳出系統的權限詢問(Android 13 以上會一併詢問通知權限),不用自己處理。

設定 Map8 Key

在 App 啟動時設定一次 Map8 Key(地圖與導航共用同一把 Key),建議放在 Application:

import android.app.Application
import com.mapbox.mapboxsdk.Map8

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Map8.getInstance(this, "您的 Map8 Key")
    }
}

記得在 AndroidManifest.xml 的 <application> 加上 android:name=".MyApplication"。

快速開始

導航畫面是一個 Fragment:Map8NavigationFragment。建議用一個獨立的全螢幕 Activity 放它:

import android.os.Bundle
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import zone.map8.navigation.Map8NavigationDestination
import zone.map8.navigation.Map8NavigationEndReason
import zone.map8.navigation.Map8NavigationError
import zone.map8.navigation.Map8NavigationFragment
import zone.map8.navigation.Map8NavigationListener

class NavigationActivity : AppCompatActivity(), Map8NavigationListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(FrameLayout(this).apply { id = CONTAINER_ID })

        // 轉向時 Activity 會重建:先找找看是不是已經有導航畫面了
        val existing = supportFragmentManager.findFragmentById(CONTAINER_ID) as? Map8NavigationFragment
        val navigation = existing ?: Map8NavigationFragment.newInstance(
            Map8NavigationDestination(25.102355, 121.548493, "國立故宮博物院", "台北市士林區至善路二段221號")
        ).also {
            supportFragmentManager.beginTransaction().replace(CONTAINER_ID, it).commitNow()
        }
        navigation.listener = this
        if (existing == null) navigation.startNavigation()
    }

    // 使用者按了結束導航(抵達時會先顯示抵達畫面,按「完成」後預設會關閉這個 Activity)
    override fun onNavigationEnded(fragment: Map8NavigationFragment, reason: Map8NavigationEndReason) {
        if (reason == Map8NavigationEndReason.CANCELLED) finish()
    }

    // 無法導航(沒有定位權限、路線規劃失敗):一定要處理,否則畫面會停在原地
    override fun onNavigationFailed(fragment: Map8NavigationFragment, error: Map8NavigationError) {
        finish()
    }

    companion object {
        private const val CONTAINER_ID = 0x4d38
    }
}

執行後的流程:

  1. 取得使用者目前位置,規劃到目的地的路線
  2. 顯示路線預覽:整條路線、總時間、距離、主要道路、路線列表
  3. 使用者按下「開始導航」,進入逐向導航
  4. 抵達目的地時顯示抵達畫面,使用者按「完成」後關閉導航畫面

轉向與 Activity 重建

手機轉向、切換深色模式時,Android 會重建 Activity。Navigation SDK 會自動保留導航進度與所有設定,導航不會中斷,但有兩件事要注意(上面的範例已經示範):

在 Java 中使用

public class NavigationActivity extends AppCompatActivity implements Map8NavigationListener {

    private static final int CONTAINER_ID = 0x4d38;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout container = new FrameLayout(this);
        container.setId(CONTAINER_ID);
        setContentView(container);

        Map8NavigationFragment navigation =
            (Map8NavigationFragment) getSupportFragmentManager().findFragmentById(CONTAINER_ID);
        boolean isNew = navigation == null;
        if (isNew) {
            navigation = Map8NavigationFragment.newInstance(
                new Map8NavigationDestination(25.102355, 121.548493, "國立故宮博物院"));
            getSupportFragmentManager().beginTransaction().replace(CONTAINER_ID, navigation).commitNow();
        }
        navigation.setListener(this);
        if (isNew) navigation.startNavigation();
    }

    @Override
    public void onNavigationEnded(@NonNull Map8NavigationFragment fragment, @NonNull Map8NavigationEndReason reason) {
        if (reason == Map8NavigationEndReason.CANCELLED) finish();
    }

    @Override
    public void onNavigationFailed(@NonNull Map8NavigationFragment fragment, @NonNull Map8NavigationError error) {
        finish();
    }
}

Map8NavigationListener 的方法都有預設實作,Java 也只要覆寫需要的方法即可。

範例 App

我們提供一個完整的範例 App(Kotlin),示範目的地搜尋、導航、模擬導航,以及路線偏好、日夜間、導航視角、路線預覽、自訂配色等設定。

下載範例 App:https://api.map8.zone/download/navigation_sdk/map8-navigation-sdk-android-sample.zip?key=您的key

壓縮檔內已附所需的 aar,解壓縮後:

  1. 用 Android Studio 開啟 Map8NavigationSample 資料夾
  2. 在專案根目錄的 local.properties 加上一行 map8.key=您的 Map8 Key
  3. 接上 Android 手機執行
檔案 內容
SampleApplication.kt 設定 Map8 Key
MainActivity.kt 首頁:目的地、開始導航、模擬導航、各項設定
NavigationOptions.kt 設定 Map8NavigationFragment 各項屬性的寫法
NavigationActivity.kt 放置導航畫面、處理導航事件、轉向重建
PlaceSearchActivity.kt 用 Map8 地點搜尋 API 找目的地

路線預覽

預設在規劃完成後先顯示路線預覽,使用者確認後才開始導航。

// 關掉預覽:規劃完成後直接開始導航
navigation.showsRoutePreview = false

如果您想自己設計預覽畫面,可以關掉內建預覽,從 onRoutePlanned 取得路線摘要,使用者確認後再呼叫 startGuidance():

override fun onRoutePlanned(fragment: Map8NavigationFragment, summary: Map8NavigationRouteSummary) {
    println("總距離 ${summary.distance} 公尺,約 ${summary.duration / 60} 分鐘")
    println("經 ${summary.mainRoads().joinToString("、")}")
    for (step in summary.steps) {
        println("${step.roadName} ${step.distance} 公尺")
    }
}

// 使用者在您的預覽畫面按下開始
navigation.startGuidance()

路線偏好

在 startNavigation() 之前設定,導航中偏離路線重新規劃時也會沿用:

navigation.routePreference = Map8NavigationRoutePreference.AVOID_HIGHWAYS
值 說明
FASTEST 最佳路徑(預設)
SHORTEST 最短距離
PREFER_FREEWAY_1 國道一號優先
PREFER_FREEWAY_3 國道三號優先
AVOID_HIGHWAYS 避走高速公路

導航畫面操作

鏡頭模式

模式 說明
跟隨 預設,鏡頭跟著車子移動
自由 使用者拖曳、縮放、旋轉地圖後進入;畫面出現「回到導航」按鈕,停止操作 10 秒後自動回到跟隨
全覽 使用者按下全覽按鈕後進入,顯示剩下的路線;按「回到導航」回到跟隨
// 自動回到導航的秒數,null = 不自動回來
navigation.autoRecenterDelaySeconds = 15.0

// 用程式碼切換
navigation.showRouteOverview()
navigation.recenter()

導航視角

導航中的鏡頭有兩種視角:

視角 說明
TILTED 立體 預設,鏡頭往前傾斜,看得到前方較遠的路
TOP_DOWN 平面 從正上方往下看,車頭朝上
navigation.cameraPerspective = Map8NavigationCameraPerspective.TOP_DOWN

// 在畫面上顯示切換按鈕(預設不顯示),讓使用者在導航中自己切換
navigation.showsPerspectiveButton = true

導航途中也可以修改 cameraPerspective,鏡頭會用動畫轉過去。路線預覽與全覽固定是平面,不受這個設定影響。

使用者按切換按鈕時會呼叫 listener,可以在這裡記住使用者的選擇,下次導航時設定回 cameraPerspective:

override fun onCameraPerspectiveChanged(fragment: Map8NavigationFragment, perspective: Map8NavigationCameraPerspective) {
    // 例如存到 SharedPreferences
}

語音

navigation.isVoiceMuted = true

畫面上的語音按鈕也可以切換靜音。

語音播報時會自動降低其他 App 的音樂音量、暫停 Podcast,播完再恢復。音量跟著手機的媒體音量。

結束導航

畫面左下角內建結束按鈕。如果您想自己提供結束方式,可以關掉內建按鈕:

navigation.showsEndButton = false

// 在您自己的按鈕裡
navigation.stopNavigation()

抵達

抵達目的地時預設顯示抵達畫面(已抵達目的地、名稱、地址、「完成」按鈕)。使用者按「完成」後會呼叫 onNavigationFinished,沒有覆寫時預設等同按下返回鍵:導航畫面是獨立的 Activity 就會關閉它;用 addToBackStack 加進來的 Fragment 則會從返回堆疊移除。

// 想自己處理抵達後的畫面
navigation.showsArrivalScreen = false

override fun onNavigationEnded(fragment: Map8NavigationFragment, reason: Map8NavigationEndReason) {
    if (reason == Map8NavigationEndReason.ARRIVED) {
        // 顯示您自己的抵達畫面
    }
}

背景導航

導航中按 Home 鍵、切換到其他 App 或鎖屏時,定位與語音會持續運作,不需要任何設定。

為了讓系統不要在背景限制定位、把 App 停掉,SDK 會在導航期間啟動前景服務,通知列會常駐一則「導航至(目的地)」的通知,顯示剩餘距離、時間與預計抵達時刻;點通知會回到導航畫面。導航結束、抵達或失敗時,通知會自動移除。

外觀

日間/夜間

預設依目的地的日出日落時間自動切換,夜間會改用深色地圖與較暗的面板。

navigation.appearance = Map8NavigationAppearance.AUTOMATIC  // 預設,依日出日落切換
navigation.appearance = Map8NavigationAppearance.LIGHT      // 一律日間
navigation.appearance = Map8NavigationAppearance.DARK       // 一律夜間

配色

可以把導航畫面調整成您的品牌色。日間與夜間各一組配色,隨時修改都會立即套用。顏色是 Android 的 ARGB 整數(例如 Color.parseColor("#3B82F6"))。

navigation.colorScheme = Map8NavigationColorScheme.DEFAULT.copy(
    routeLine = Color.parseColor("#34C759"),
    accent = Color.parseColor("#34C759"),
)

// 夜間另外設定,不設定則使用內建的夜間配色
navigation.nightColorScheme = Map8NavigationColorScheme.NIGHT
欄位 說明
panelBackground 主要面板底色:轉彎卡片、下方資訊列、測速警示
secondaryPanelBackground 次要面板底色:「接著」那一列、狀態提示
panelText 面板文字與轉彎圖示、車道箭頭
warning 接近測速照相、超速時閃爍的警示色
routeLine 尚未走過的路線(外框會自動調暗)
traveledRouteLine 已經走過的路線(外框會自動調暗)
accent 強調色:車標箭頭、浮動按鈕圖示
floatingButtonBackground 浮動按鈕底色

橫向畫面

導航畫面支援直向與橫向:橫向時資訊集中在左側,右側留給地圖。轉向時導航不會中斷(見「快速開始」的「轉向與 Activity 重建」)。只支援直向的 App 則維持直向顯示。

全螢幕與系統列

導航畫面會延伸到狀態列與導覽列底下,並自動避開它們(Android 15 以上預設就是這樣的全螢幕顯示)。放在全螢幕的 Activity 裡時,狀態列圖示的深淺會跟著日間/夜間自動調整,離開導航畫面後還原。

模擬導航

開發或測試時,可以不用實際移動,讓 SDK 沿著路線自動產生定位。模擬的定位與真實 GPS 走同一套流程。

navigation.simulation = Map8NavigationSimulation(
    originLatitude = 25.075828,
    originLongitude = 121.574365,
    speedKmh = 50.0,
    playbackRate = 4.0,   // 4 倍速
)
navigation.startNavigation()

導航事件

實作 Map8NavigationListener 接收導航事件。所有方法都有預設實作(Kotlin、Java 皆同),只覆寫需要的即可。所有方法都在主執行緒呼叫,可以直接更新 UI。

class NavigationActivity : AppCompatActivity(), Map8NavigationListener {

    override fun onRoutePlanned(fragment: Map8NavigationFragment, summary: Map8NavigationRouteSummary) {
        // 路線規劃完成
    }

    override fun onNavigationStarted(fragment: Map8NavigationFragment) {
        // 使用者按下開始導航
    }

    override fun onProgress(fragment: Map8NavigationFragment, progress: Map8NavigationProgress) {
        // 每收到一筆定位呼叫一次(通常約每秒一次):剩餘距離、剩餘時間、目前路名、車速
    }

    override fun onRerouted(fragment: Map8NavigationFragment) {
        // 偏離路線後已重新規劃
    }

    override fun onNavigationEnded(fragment: Map8NavigationFragment, reason: Map8NavigationEndReason) {
        // 抵達(ARRIVED)或使用者結束(CANCELLED)
    }

    override fun onNavigationFinished(fragment: Map8NavigationFragment) {
        // 使用者在抵達畫面按下「完成」(不覆寫時預設等同按返回鍵)
        finish()
    }

    override fun onNavigationFailed(fragment: Map8NavigationFragment, error: Map8NavigationError) {
        // 無法導航:沒有定位權限,或路線規劃失敗
        finish()
    }

    override fun onCameraModeChanged(fragment: Map8NavigationFragment, mode: Map8NavigationCameraMode) {
        // 鏡頭模式改變(跟隨/自由/全覽)
    }

    override fun onCameraPerspectiveChanged(fragment: Map8NavigationFragment, perspective: Map8NavigationCameraPerspective) {
        // 使用者按切換按鈕,改變了導航視角(立體/平面);用程式設定不會呼叫
    }
}

API 參考

套件名稱:zone.map8.navigation

Map8NavigationFragment

建立

介面 說明
Map8NavigationFragment.newInstance(destination) 以目的地建立導航畫面

屬性

屬性 型別 預設 說明
listener Map8NavigationListener? null 導航事件;Activity 重建後要重新設定
destination Map8NavigationDestination — 目的地,下次 startNavigation() 生效
routePreference Map8NavigationRoutePreference FASTEST 路線偏好
showsRoutePreview Boolean true 規劃完先顯示路線預覽
showsArrivalScreen Boolean true 抵達時顯示抵達畫面
showsEndButton Boolean true 顯示內建的結束導航按鈕
cameraPerspective Map8NavigationCameraPerspective TILTED 導航視角
showsPerspectiveButton Boolean false 顯示立體/平面切換按鈕
isVoiceMuted Boolean false 語音靜音
autoRecenterDelaySeconds Double? 10.0 自由模式停止操作後自動回到導航的秒數
appearance Map8NavigationAppearance AUTOMATIC 日間/夜間外觀
colorScheme Map8NavigationColorScheme DEFAULT 日間配色
nightColorScheme Map8NavigationColorScheme NIGHT 夜間配色
styleUrl / nightStyleUrl String Map8 預設樣式 日間/夜間地圖樣式
simulation Map8NavigationSimulation? null 模擬導航(開發測試用)
routeSummary Map8NavigationRouteSummary? 唯讀 目前路線摘要
cameraMode Map8NavigationCameraMode 唯讀 目前鏡頭模式
isNavigating Boolean 唯讀 是否正在導航中(含規劃路線中)
isNightAppearance Boolean 唯讀 目前是否為夜間外觀

方法

方法 說明
startNavigation() 開始:規劃路線,依設定顯示預覽或直接導航;沒有定位權限時先詢問
startGuidance() 從路線預覽進入導航(自行設計預覽畫面時使用)
stopNavigation() 結束導航,通知 onNavigationEnded(CANCELLED)
recenter() 回到導航視角
showRouteOverview() 全覽剩下的路線

資料型別

Map8NavigationDestination

欄位 型別 說明
latitude、longitude Double 目的地座標
name String 名稱,選填(顯示在抵達畫面與通知,不影響選路)
address String 地址,選填(顯示在抵達畫面,不影響選路)

Map8NavigationRouteSummary

欄位 型別 說明
distance Int 總距離(公尺)
duration Long 預估總時間(秒)
steps List<Map8NavigationRouteStep> 每一個步驟
mainRoads(limit) List<String> 主要道路(距離最長的幾條路名),limit 預設 2

Map8NavigationRouteStep

欄位 型別 說明
roadName String 道路名稱
distance Int 這一段的長度(公尺)
maneuver Map8NavigationManeuver 這一段結束時的轉彎

Map8NavigationProgress

欄位 型別 說明
distanceRemaining Int 剩餘距離(公尺)
durationRemaining Long 剩餘時間(秒)
currentRoadName String 目前道路名稱
speedKmh Int 目前車速(km/h)

Map8NavigationSimulation

欄位 型別 預設 說明
originLatitude、originLongitude Double — 模擬起點
speedKmh Double 50.0 模擬車速
playbackRate Double 1.0 播放倍速

列舉與錯誤

型別 值
Map8NavigationEndReason ARRIVED 抵達、CANCELLED 使用者結束
Map8NavigationError LocationPermissionDenied 沒有定位權限、RouteFailed 路線規劃失敗(cause 是原因)
Map8NavigationCameraMode FOLLOWING 跟隨、FREE 自由、OVERVIEW 全覽
Map8NavigationCameraPerspective TILTED 立體、TOP_DOWN 平面
Map8NavigationAppearance AUTOMATIC 自動、LIGHT 日間、DARK 夜間
Map8NavigationManeuver TURN_LEFT、TURN_RIGHT、U_TURN_LEFT、U_TURN_RIGHT、KEEP_LEFT、KEEP_RIGHT、STRAIGHT

Map8Navigation

介面 說明
Map8Navigation.VERSION Navigation SDK 版本,例如 "1.1.1"

程式碼壓縮(R8)

Navigation SDK、導航引擎與地圖 SDK 的 aar 都自帶保留規則,App 開啟 minifyEnabled 也不用另外寫 ProGuard 設定。

網路與隱私

連線網域

Navigation SDK 會連線到以下網域,如果您的網路環境有白名單限制,請一併開放:

網域 用途
api.map8.zone 地圖圖資與樣式
nav8.pakka.ai 路線規劃、路口實景圖

收集的資料

為了規劃路線,SDK 會將以下資料傳送到路線規劃伺服器,僅用於導航功能本身,不做跨 App 追蹤:

資料 用途
精確位置 規劃路線的起點、偏離路線後重新規劃
目的地座標,以及目的地名稱、地址的前 5 個字 規劃路線的終點;名稱與地址僅供伺服器記錄,不影響選路
裝置識別碼(App 自己產生的隨機 ID,不是硬體識別碼) 取得路線規劃服務的存取權杖

填寫 Google Play 的「資料安全性」表單時,請將「精確位置」與「裝置或其他 ID」列入,用途為「應用程式功能」,資料會加密傳輸、不與第三方分享。

常見問題

進入隧道後車標還會動嗎?

會。導航中超過 2 秒收不到 GPS,SDK 會沿著路線依進隧道前的車速推算位置,車標、語音與區間測速倒數照常進行;GPS 恢復後立即改回真實位置。若隧道內減速或塞車,出隧道時車標可能會往回修正一下。

偏離路線時會怎麼樣?

偏離路線超過 35 公尺並持續 5 秒,SDK 會播報「重新規劃路線」並自動規劃新路線,同時沿用原本的路線偏好。

沒有定位權限會怎麼樣?

使用者拒絕定位權限時,導航會結束並呼叫 onNavigationFailed,error 是 Map8NavigationError.LocationPermissionDenied,您可以在這裡引導使用者到設定開啟權限。

沒有語音?

請確認手機的媒體音量沒有調到最小,以及手機已安裝中文的文字轉語音資料(設定 → 一般管理 → 文字轉語音,或系統設定中的「文字轉語音輸出」)。


台灣圖霸感謝您的支持與愛護!