2013年6月7日 星期五

如何在 Android 上開發使用 Google Map V2 的 App

寫於 2013/06/06 

因為想在 Android App 上玩玩看 Google Map 的應用,所以開始研究如何把 Google Map 嵌入自己的 AP裡,整理自己研究後的心得和步驟如下:

1. 開發環境安裝

除了標準的 IDE 環境外{Eclipse},你還需要以下兩個 extra packages才能在你的環境裡開發 Google Map V2 相關的App,這兩個 packages 都可以透過 Android SDK Manager 下載到你的開發環境裡
  • Android support library
  • Google Play Service
請開啟 Android SDK Manager,勾選紅色框起的兩個項目安裝


2. 開啟 Google Map API 服務及 Key 的申請和安裝

你需要到 Google Console 上作兩件事情
  • 開啟 Google Map API V2 服務
  • 用你的憑證所產生的SHA-1註冊你的 App,並得到 Google Map API V2 的 Key
用你的 google 帳號 login Google Console 之後,你檢視他的服務項目可以發現,已經不能再用 Google Map API V1 的服務了


接下來註冊你的 App 並取得 Key這個步驟比較麻煩,首先你必須要準備一個 SHA-1 Hash ,而這個 Hash 必須是從用來 Sign 你的 APK 的憑證所產生的,看了一堆文件都說要用 Java JDK 的 Keytool 來產生 SHA-1 Hash。但如果你是使用 Eclipse ,這邊有一個簡單的方式:

首先點選 "Window" -> "Preferences" 叫出 Preferences 對話視窗,在對話視窗左邊選擇 "Android" -> "Build"




Debug Keystore 是指你用來 sign APK 的 Key 存放位置
SHA-1 fingerprint 的內容即是你要拿去 Google Console 申請 Google Map API V2 的 Key 用的
請注意,debug key 是 debug 階段拿來用的,一般正式出貨上架時會用另一組正式的 Key 來 Sign APK。因此,相對應的 API Key 也用 release Key 所產生的 SHA-1去申請註冊。

3. 新增新的專案,並匯入Google Play Service

開啟 Eclipse 已準備新增一個 Android Application project,這時候你必須要了解 API Level 和 Google Map API 版本之間的關係。在 API Level 12 之後才支援 V2,所以你必須考慮好你所支援的 Android 版本,當你的 App 僅支援 API Level 12 之後,基本上只需要考慮一種狀況。如果你必須考慮運行於 API Level 11或更早之前的系統,仍然是可以的,只是必須多一些考量,這在第四點撰寫程式的時候會提到。

Okay,你的專案已經新增好了,接下來在寫程式前要做好下面兩件事:
  • Import Google Play Service
  • Add Google Play service library in your project build environment 

Press "File" -> "Import..." 開啟 Import 的對話視窗:


選取 import 的 type 是 "Existing Android Code into Workspace",按下 "Next" button 會跳出 import 視窗,按下 "Browse" button 選取你剛剛安裝的 Google Play Service library,其路徑是在你的 SDK 安裝目錄裡的 "\extras\google\google_play_services\libproject\google-play-services_lib"。


選完之後,即會出現如上圖紅色框框裡的 Google Play Service專案,勾選之後按下 "Next" button 及完成了 Google Play Service 的匯入。


Press "Project" -> "Properties" 開啟 Android project properties 如下圖,選擇 "Android"。
在視窗左下角按"Add" button 選擇要加入的 library


你會看到綠色勾勾,如果哪時候看到的是紅色叉叉就代表有問題。
記住 "Is Library" 那個 option 千萬不能勾選,那代表你的專案最後是要 build 成 library。
按下 OK button 之後,代表你的 project build 已經可以使用指定的 library了。

4. 撰寫程式碼

這邊只是談論如何初步的把 Google Map 嵌入到你的 App,其他進階的應用待以後有空的時候再摸索。
基本上分成兩部分:
  • 在 AndroidManifest.xml 中宣告需要的 permission 和 Google Map API Key
  • 在 Activity Layout file 中宣告 Google Map element 的位置

關於 AndroidManifest.xml,範例如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.Maptest"
    android:versionCode="1" android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="12"
        android:targetSdkVersion="17" />
    <permission
        android:name="com.test.Maptest.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>
    <uses-permission android:name="com.test.Maptest.permission.MAPS_RECEIVE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.test.Maptest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
             android:value="YOUR_API_KEY"/>

    </application>
</manifest>







Layout file:

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment"
xmlns:map="http://schemas.android.com/apk/res-auto"
map:cameraBearing="45"
map:cameraTargetLat="25.033611"
map:cameraTargetLng="121.565000"
map:cameraTilt="0"
map:cameraZoom="13"
map:mapType="normal"
map:uiCompass="true"
map:uiRotateGestures="true"
map:uiScrollGestures="true"
map:uiTiltGestures="true"
map:uiZoomControls="false"
map:uiZoomGestures="true"/>



Reference

Google Developer - Google Maps Android API v2
Showing current location in Google Maps using API V2 with SupportMapFragment

後 記

為了搞定 Google Map API V2,前前後後摸索了很久,大部分的時間都花在只為了搞定 "gms.maps.MapFragment" ClassNotFound exception 這個問題。看了非常多的論壇討論,發現所有該加的都加了,也做了檢查再檢查,還是無解。最後大絕招是重開一次專案把上面的 3 和 4 重做一次,發現 ClassNotFound 的問題解決了!!

我推測應該是在一開始摸索的時候東試試、西試試的,把某些系統的設定檔搞壞了,
導致 apk build 出來的時候相關 GMS Map class 的參考路徑是錯的...