Android用GoogleマップAPIのバージョン2を使ったAPKを作るときに,いくつか面倒なことがあったため,Antを使ったときの話です.

Googleマップv2に関するAntのメモ

Android用GoogleマップAPIのバージョン2が登場して,私のアプリもぼちぼちバージョン1から移行し始めています.

これに関連して,APKを作るときにいくつか面倒なことがあり,AntでAPKを作ることにしました.

そのときの話を書きます.

0.Ant環境の準備

まず,AntでAndroidプロジェクトをビルドできるように準備します.

antは,以下からダウンロードできます.

今回は,apache-ant-1.9.1-bin.zip を使いました.(Windows版)

1.APIキーの自動書き換え

GoogleマップAPIのキーがdebugビルドとreleaseビルドで違っているのは,version 1のときからそうですが, version 1の場合はプログラム内で設定できたため,プログラムで自動的に切り替えるという実装が可能でした.

しかしversion 2では,どうもAndroidManifest.xmlに直接書かなければならないようです.

それで,Antで自動的に書き換えることにしました.

Antの定義

該当プロジェクトのbuild.xmlに直接書いてもいいのですが,追加した分をわかりやすくするため, 同じディレクトリに custom_rules.xml というファイルを新規作成して配置します. (build.xmlから,この名前のファイルがあれば読み込まれるようになっています)

custom_rules.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="my_custom">
<target name="-pre-build">
	<!--
		## for extension ##
	-->
	<path id="android.antlibs">
		<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
	</path>
	<taskdef resource="anttasks.properties" classpathref="android.antlibs" />
	<!--
		## for Gmap V2 (switch API key) ##
	-->
	<condition property="gmapkey.use_release" value="true">
		<contains string="${ant.project.invoked-targets}" substring="release" />
	</condition>
	<if condition="${gmapkey.use_release}">
	<then>
		<property name="gmapkey.active" value="${gmapkey.release}" />
	</then>
	<else>
		<property name="gmapkey.active" value="${gmapkey.debug}" />
	</else>
	</if>
	<replaceregexp file="AndroidManifest.xml" match="(${gmapkey.leader})&quot;.*&quot;"
		replace="\1&quot;${gmapkey.active}&quot;" />
</target>
</project>
そして,同じディレクトリの ant.properties に以下の内容を追加します.

ant.properties

gmapkey.leader=android:name="com.google.android.maps.v2.API_KEY" android:value=
gmapkey.debug=※APIキー(デバッグ用)
gmapkey.release=※APIキー(リリース用)
AndroidManifest.xmlには,こんな感じで記述しておきます.
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value=""/>
簡単に説明しますと,
  • カスタム用に用意されているターゲット「-pre-build」を使う
  • 起動時に指定されたターゲットに「release」が含まれているかどうかで,debug,releaseを判断する
  • AndroidManifest.xmlの中身のうち,gmapkey.leader の内容を含む箇所を,判断した結果のキーで書き換える

という感じです.

2.OpenGL ES 2.0を要求するuses-featureの書き換え

背景

Google Maps API v2は,OpenGL ES 2.0が必要です.これは実質的には,Android 2.2以上とほぼ同じ意味になるようです.

しかしうちのアプリは,Android 1.6以上に対応しているものがほとんどなので,対応していない人のことを考える必要があります.

Googleマップv1版とv2版を同梱して切り替え可能にするのは良いのですが,AndroidManifest.xmlをどうするかという問題があります.

v2を使うためには以下の記述を入れる必要があるのですが,

<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
これを入れると,OpenGL ES 2.0以上というフィルタがGoogle Playでかかってしまうはずで, それに対応していない人は,Google Playからインストールできなくなります.

v1版を同梱していても,インストールできないのでは意味がありません.

かといってフィルタを外すために

<uses-feature android:glEsVersion="0x00020000" android:required="false"/>
にすると,対応している端末でもv2のマップが表示されなくなります.真っ白画面になりました.

...結局,

  • OpenGL ES 2.0以上を要求するmainfest記述のAPK →v2マップを表示する
  • OpenGL ES 2.0以上を要求しないmainfest記述のAPK →v1マップを表示する

という構成の,マルチAPKにせざるを得ないという結論に至りました.

manifestの仕様

例えば,バージョン1.0のAPKを作るときの仕様は,このようにしました.
v1版のAPK
  • OpenGL ES 2.0のuses-featureは無し
  • android:versionCode="1000"
  • android:versionName="1.0n"
v2版のAPK
  • OpenGL ES 2.0のuses-featureあり
  • android:versionCode="1001"
  • android:versionName="1.0"

マップv2が使える端末ではv2版を優先するように,versionCodeを1つ大きくしています.

また,versionName末尾の「n」に深い意味はないのですが,アプリ側でv1,v2のどちらを出すかを制御するための情報として, versionNameに特定の目印を入れています.

Antの定義

custom_rules.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="my_custom">
<target name="-pre-build">
	<!--
		## for extension ##
	-->
	<path id="android.antlibs">
		<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
	</path>
	<taskdef resource="anttasks.properties" classpathref="android.antlibs" />
	<!--
		## for Gmap V2 (GLES2.0) ##
	-->
	<if condition="${gmap.on}">
	<then>
		<property name="ver.code" value="${ver.c}1" />
		<property name="ver.name" value="${ver.n}" />
		<property name="gmap.glesline" value="${gmap.gles.contents}" />
	</then>
	<else>
		<property name="ver.code" value="${ver.c}0" />
		<property name="ver.name" value="${ver.n}n" />
		<property name="gmap.glesline" value="" />
	</else>
	</if>
	<replaceregexp file="AndroidManifest.xml" match="(android:versionCode=)&quot;.*&quot;"
		replace="\1&quot;${ver.code}&quot;" />
	<replaceregexp file="AndroidManifest.xml" match="(android:versionName=)&quot;.*&quot;"
		replace="\1&quot;${ver.name}&quot;" />
	<replaceregexp file="AndroidManifest.xml" match="(${gmap.gles.tag}).*(${gmap.gles.tag})"
		replace="\1${gmap.glesline}\2" />
</target>
</project>

ant.properties

gmap.gles.tag=<!-- #GLES# -->
gmap.gles.contents=<uses-feature android:glEsVersion="0x00020000" android:required="true"/>

AndroidManifest.xml

<!-- #GLES# --><!-- #GLES# -->
この謎のコメントは,uses-featureをmanifest内のどこに入れるかを示すためのものです.

antの起動時に,いくつか引数を渡します.バージョンコード,バージョン名,v2を有効にするかどうかです.

▼v1版のAPK
ant clean release -Dver.c=100 -Dver.n=1.0 -Dgmap.on=false

▼v2版のAPK
ant clean release -Dver.c=100 -Dver.n=1.0 -Dgmap.on=true

※custom_rules.xmlの内容は,APIキーの自動書き換え編とターゲットが同じ(-pre-build)ですので,実際にはマージして下さい. 話を単純化するために,独立した書き方にしています.

またこれとは別に,OpenGL ES 2.0には対応しているが,Google Play開発者サービスのバージョンが古いためv2マップが表示されない, という場合もありえますが,それはビルドの話とは関係ないため今回は割愛します.

kamolandをフォローしましょう


© 2021 KMIソフトウェア