Google Maps Android API v2 gradle integration

之前提到 Google Maps API (v2) 在整合至 gradle 時會碰到一些問題, 這邊提供一種可能的解法.

首先來看是怎樣的狀況, Google Maps API 在使用時得請求一組 API key, 而這組 key 得對應到一個 package name. 我自己會申請兩組, 一組給 debug 版用, 另一組給 release 版用, 這是因為 debug 版使用不同的 package name (透過 packageNameSuffix) 在測試時才能於同一支手機安裝 debug & release 版. 這樣的組合透過簡單的 overlay 應用即可輕鬆達成: 獨立出 debug (or release) 使用的 resource folder, 把 API key 放在 strings.xml 即可.

但如果你的 app 有免費版與付費版呢 ? 套用我的設定就有 4 種 package name 配 4 組 key, 理論上分 4 個 resource overlay 就可以解決. 可以問題來了, gradle 只能讓你設定 flavor 或者 buildtype 的 sourceSets, 例如 free, paid, debug, release, 但並不提供 freedebug, freerelease, paiddebug, paidrelease 的設定方式, 因此就算你把 folder 區分為前述的樣子, 或者異想天開在 sourceSets 分兩層方式設定 flavor.buildtype 的 res.srcDirs, 都無法順利分開 API key 所使用的 strings.xml.

目前看到的解法是透過修改 AndroidManifest.xml 的方式, 在 variant.processManifest.doLast 時複製一份方便修改的版本到編譯中介目錄, 然後置入正確 API key 的設定.

我稍微研究 Android Tools Project Site 的文件, 試著找出另一種不用修改檔案的方式達到同樣的效果. 其中這一段吸引我的注意:

The following rules are used when dealing with all the sourcesets used to build a single APK:

  • All source code (src/*/java) are used together as multiple folders generating a single output.
  • Manifests are all merged together into a single manifest. This allows Product Flavors to have different components and/or permissions, similarly to Build Types.
  • All resources (Android res and assets) are used using overlay priority where the Build Type overrides the Product Flavor, which overrides the main sourceSet.
    - Each Build Variant generates its own R class (or other generated source code) from the resources. Nothing is shared between variants.

第三點提到 build type 的優先權最高, 如果我們在整合 resource 之前把 build type 的 folder 指定到我想要用的目錄呢 ? android gradle plugin 有提供 variant.mergeResources, 那麼試著在那之前把 build type 的 sourcesets 替換, 應該就行了吧 ? 花了點時間修改, 很幸運的跑起來沒有問題, 這邊提供給各位參考, 有使用 Google Maps API 且跟我有類似需求的朋友可以參考看看 :)

相關 code 可參考這 https://github.com/shakalaca/learning_gradle_android/blob/a7a37a7b94cc79fd5f6cac834935c178f50a4061/07_tricks/app/build.gradle

如果要定義額外的 resource file, 透過 project.ext.flavorname 定義, 其中 debugRes 為 debug 版的 resource, releaseRes 為 release 版的 resource, 沒有定義會自動使用 default.


comments powered by Disqus