iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
Mobile Development

Google Maps SDK for Android 與 GIS App 開發筆記系列 第 5

Day 5: Google Maps SDK for Android–環境建置

  • 分享至 

  • xImage
  •  

到了第五天,終於要來動動手了。

開發環境

https://ithelp.ithome.com.tw/upload/images/20230919/20160271xmNnOA4a84.png

本次練習都是使用 Android Studio 的最新版本 Giraffe。

文章中對於 Android Studio 的安裝流程就不多做介紹,細節可以參考 官方的安裝教學,或是 iThome 社群上諸多大神們的分享。

基本上照著安裝指示走,遇到不確定的設定稍微看一下文件或是 Google 一下,應該都可以解決。

如果你在安裝上有遇到問題,歡迎留言討論~

相依套件

如果你已經安裝完畢,也開啟了一個新的專案,請在以下檔案中加入這些相依設定。

1. settings.gradle.kts

檢查 setting.gradle.kts 內有無以下的設定值

pluginManagement {
    repositories {
        google() // 這個
        mavenCentral() // 這個
        gradlePluginPortal() // 這個
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

2. build.gradle (app)

要使用 Google Maps 的 SDK,compileSdk 必須大於 API 31,minSdk 必須大於 API 19。最後在 depedencies block 中加入以下的 implementation

implementation("com.google.android.gms:play-services-maps:18.1.0")

大概是會長這樣。

android {
    // 必須大於 31
    compileSdk = 33

    defaultConfig {
        // 必須大於 19
        minSdk = 26
        
        // 略...
    }

    // 略...
}


dependencies {

    // 略...
    
    // 加入 Google Maps SDK
    implementation("com.google.android.gms:play-services-maps:18.1.0")
}

以上設定調整完後,請根據 IDE 的提示將專案 Sync,確認套件相依都沒有問題,沒有出現 Build Errors。

偷吃步:透過 Android Studio 自動建立

https://ithelp.ithome.com.tw/upload/images/20230919/20160271eSLIhgI2aG.png

如果你是創立新的專案,而且 Google Maps 是要建立在一個新的 Activity,那可以使用 Android Studio 的新增功能,IDE 將會自動把缺少的套件設定補上。

當然你也可以透過這個方法做好套件設定後,在把用不到的 Google Maps View Activity 刪除,另外自己實作 Google Maps。

測試一下

到這一步,我們已經完成了基本的環境建置,現在就讓我們實際建立一個帶有 MapViewActivity,看看能不能成功的把地圖開起來。

建立帶有 MapViewActivity

如果是前面用偷吃步的方法建立,這個步驟可以直接省略,直接將 App build 起來看看有沒有看到地圖。

如果是跟我一樣只有設定好 implementation 的朋友,可以跟著我繼續做下去。

這裡用的方式,有別於官方範例是使用 SupportMapFragment,而是改用 MapView

至於為什麼我要用 MapView 建立呢?

因為 SupportMapFragment 已經有範例可看了,當然寫點不一樣的囉XD

因為在小弟的開發實務上,常遇到 MapView 的寫法,想說就用這個來當範例,跟還不知道的人分享~

首先建立一個 Empty Activity 並在對應的 layout XML 中加入一個 MapView

activity_map_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapsActivity">

    <com.google.android.gms.maps.MapView
        android:id="@+id/map_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

MapViewActivity

設定好 Layout,讓我們回到 MapViewActivity

使用 ViewBinding 取得 RootView,與其底下的 MapView

(如果你是使用 findViewById() 其實也是一樣,只要能拿到 XML 上的那個 MapView 就可以了。)

取得 MapView 後,在分別 override Activity 的生命週期方法,並在裡面呼叫 MapView 相同名稱的方法。

  1. onCreate()
  2. onStart()
  3. onResume()
  4. onPause()
  5. onStop()
  6. onDestroy()
  7. onSaveInstanceState()
  8. onLowMemory()

以上這幾個方法,都是實作 MapView 時必須在對應的生命週期中呼叫的方法。

那為什麼 SupportMapsFragment 不用?

這是因為在 SupportMapsFragment 中,其類別已經幫你做好 MapView 的生命週期控管,所以不用額外呼叫這些方法。SupportMapsFragment 是將 Google Maps 加入到 App 中,最簡單的方式。

以下是我寫的範例程式碼,給各位參考~

package tw.dh46.ithome23.sample

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import tw.dh46.ithome23.sample.databinding.ActivityMapsBinding

class MapsActivity : AppCompatActivity() {

    private val TAG: String = MapsActivity::class.java.simpleName

    private val binding: ActivityMapsBinding by lazy {
        ActivityMapsBinding.inflate(layoutInflater)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.mapView.onCreate(savedInstanceState)

        binding.mapView.getMapAsync {
            Log.d(TAG, "onCreate: ")
        }
    }

    override fun onStart() {
        super.onStart()
        binding.mapView.onStart()
    }

    override fun onResume() {
        super.onResume()
        binding.mapView.onResume()
    }

    override fun onPause() {
        super.onPause()
        binding.mapView.onPause()
    }

    override fun onStop() {
        super.onStop()
        binding.mapView.onStop()
    }
    
    override fun onDestroy() {
        super.onDestroy()
        binding.mapView.onDestroy()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        binding.mapView.onSaveInstanceState(outState)
    }

    override fun onLowMemory() {
        super.onLowMemory()
        binding.mapView.onLowMemory()
    }
}

Build 起來看看

好不容易寫完,那就來跑跑看吧!

這時候 Build 起來,你應該會跟我一樣,發現 App crash 了,並在 Logcat 看到一堆紅字錯誤。

但就如同前輩們常說的,Logcat 看得到紅字錯誤都還算是好事,至少有一個好除錯的起點。/images/emoticon/emoticon01.gif

FATAL EXCEPTION: main
Process: tw.dh46.ithome23.sample, PID: 7357
java.lang.RuntimeException: Unable to start activity
ComponentInfo{tw.dh46.ithome23.sample/tw.dh46.ithome23.sample.MapsActivity}: java.lang.RuntimeException: API key not found.  
Check that <meta-data 
android:name="com.google.android.geo.API_KEY" android:value="your APIkey"/> 
is in the <application> element of AndroidManifest.xml

仔細閱讀了一下錯誤訊息,發現它寫的很直白,就是 SDK 在 AndroidManifest.xml 中找不到他要的 API KEY。

補充說明: AndroidManifest.xml 中的 Google Play 服務版本號設定

根據文件的說法,在 AndroidManifest.xml 的宣告中,應該要再加入以下的 tag。

<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />

但根據我的測試,其實不加也沒有關係,因為在 Merged 的 Manifest 中,IDE 依然有把這個 tag 給加進來,所以應該是不影響~

https://ithelp.ithome.com.tw/upload/images/20230921/201602712rGREz5nZT.png

好的,以上這就是今天的內容。
雖然 SDK 的使用不用收費,但還是要申請 API Key,這部分我們就明天再繼續吧~

明天見!!/images/emoticon/emoticon08.gif


上一篇
Day 4: Google Maps SDK for Android – 基本功能與費用介紹
下一篇
Day 6: Google Maps SDK for Android–金鑰申請
系列文
Google Maps SDK for Android 與 GIS App 開發筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言