Android, iPhone等のスマートフォン向けアプリ開発などの話題を中心に、時事ネタなどを気の向くままに書いています。
Home
 

Androidアプリ開発のターゲットSDK変更時の落とし穴について





私どもの無料版Androidアプリには基本的に広告を付けています。(アプリ一覧はこちら)
幾つかの広告会社の広告を取り替えて利用しているのですが、その中でも以下の様な事を強要する横暴というか迷惑な広告会社も存在します。

  • 頻繁なAPI変更をして修正の手間を増やしてくれる(AdMob)
  • ターゲットSDKバージョンを(流行ってもいない)新しいものを要求する(AdMob)

最近は「頻繁なAPI変更をして修正の手間を増やしてくれる」事に関しては落ち着いてきたのですが、今回は「ターゲットSDKバージョンを(流行ってもいない)新しいものを要求する」問題が出て来ました。

「ターゲットSDKバージョンを変更するだけだよ! きちんとAndroidManifest.xmlのandroid:minSdkVersion属性を指定していれば問題なんか出ないよ! 簡単でしょ!」的な事を考えている様で安易にターゲットSDKバージョンを(流行ってもいない)3.2以上にする事を求めてきました。

大抵の場合、確かにターゲットSDKバージョンをAndroid 3.2にしても問題が出ませんが、私どものアプリでは問題が出ました。
そこで、備忘録、及び安易にターゲットSDKバージョンを上げるとどんな落とし穴があるのか注意喚起の為に記載したいと思います。

広告ライブラリを入れ替えるタイミングは、広告ライブラリの不具合が修正された場合か「広告ライブラリのバージョンxxはいつ以降使えなくなります。ビルドし直して下さい。」という場合かと思います。
しかも、その不具合がアプリを落としてくれるものだったり、使えなくなると言われたら新しいライブラリを使わざる終えなくなります。
大抵この様な強引な必要に迫られてライブラリを入れ替える事が多いです。

– 前提条件 –

私どものアプリのほとんどはAndroid 1.6以上で動作する様にしています。
そう、新しいOSバージョンの機能を取り入れつつ旧OSバージョンの端末でも動作させる為にReflectクラスを作ったりして裏では結構苦労して下位互換性を持たせているのです!(笑)

Reflectクラスに付いては以下のAndroid開発者サイトのブログを参照して下さい。
やり方がわからない場合は私ども SkyArtsではコンサルティングも行っていますので、よろしくお願いします!(笑)

Backward compatibility for Android applications
http://android-developers.blogspot.com/2009/04/backward-compatibility-for-android.html

– 広告ライブラリの要求内容 –

新しい広告ライブラリは、AndroidManifest.xmlファイルのactivityタグのandroid:configChanges属性にAndroid3.2で追加された属性値を指定する事を求めてきました。
もし設定しない場合は広告欄に configChangesを確認しろ!的なエラーメッセージが出ます。完全に嫌がらせですね(笑)

この位の設定は広告ライブラリで吸収して欲しいものですが、あくまでもアプリ開発者に苦労を強いるのがいつものやり方です。

– ターゲットSDKバージョンを上げてビルド&実行 –

流石に広告ではなくエラー表示しかされないのでは仕方ないのでAndroid3.2でビルドする事にしました。
Android 1.6でも動作させるようにとAndroidManifest.xmlには以下の指定をしています。

<uses-sdk android:minSdkVersion=”4″/>

Android3.2でビルドして2.2環境で走らせてみると、最初問題無さそうに見えたのですが、突然アプリが以下のエラーで落ちました。

java.lang.NoSuchMethodError: android.widget.AbsListView.setAdapter

勿論、1.6でビルドして 2.2環境で走らせてもこのエラーは出ません。
完全に3.2でビルドしたから発生したエラーです。

建前上、問題のライブラリは、Android 1.5以上で走るとされています。しかし、3.2を要求し、それに伴う問題は知りません、という事の様です(苦)

– エラーの詳細 –

該当のアプリでは訳あって ListViewではなく 抽象親クラスであるAdsListViewの変数を使用しているのですが、API仕様では以下の様な事になっています。

1.  ListView#setAdapter(ListAdapter) メソッドは、Android 1.0から存在している。
本来はこちらを呼んでいたつもり。

2.  Android 3.0から AdsListView#setAdapter(ListAdapter) が追加された。

Android 1.6でビルドしていた時には1.0からある ListView#setAdapter(ListAdapter)が呼び出されていたのですが、3.2でビルドしたため3.0で追加された AdsListView#setAdapter(ListAdapter) が呼び出されるようになり、2.2環境などで走らせた際に NoSuchMethodError が出た様です。

抽象親クラスで急に同じメソッドを追加しないで欲しいですね。
AndroidはDeprecatedなメソッドでも迷惑をかけ、新しく追加されたメソッドでも迷惑をかける様ですね(苦)
「Androidのdeprecatedメソッドの注意点」 については、以前まとめた エントリ を参照して下さい。

 

– エラーの回避方法 –

今回はListViewの抽象親クラスであるAdsListViewクラスに3.0で同じメソッドが追加された為にNoSuchMethodErrorが発生した事がわかったため、AdsListViewの変数で setAdapter(ListAdapter)を呼び出す時にListViewでキャストする事でNoSuchMethodErrorの発生を回避しました。

AdsListView adsListView;

((ListView)adsListView).setAdapter(adapter);

わかれば簡単なのですが、同じメソッドが追加されたバージョンなどを調べたりと結構手間がかかりました。

加えて、リリースビルド後に1.6環境で走らせてみた所、NoSuchMethodError ではなく VerifyErrorが発生しました。
最初は何かと思ったのですが、キャスト対策漏れが含まれていたために VerifyErrorが発生した様です。わかりづらいエラーですね。

– 今回わかった事 –

ビルドするSDKバージョンを上げても問題ない様に見えて、実は様々な細かい条件が絡んで問題が出る事がわかりました。
ただし、今回のエラーの様なケースは非常にまれだとは思います。しかし、他にも潜んでいる可能性はありますので、注意が必要です。 ビルド時にエラーが出ない分探すのも手間がかかりますので。

また、安易にターゲットSDKバージョンを上げてしまうと、新しいAPI使用時でもコンパイルエラーにならないため、ターゲットSDKバージョンよりも前の環境向けの開発がしづらくなるという結構大きな問題があります。
つまり、下位互換性を持たせる為の開発に手間がかかるようになってしまいます。

この様に様々な問題を出す可能性が高いため、特に共通で使用するライブラリが安易に新しい方のSDKバージョンでのビルドを要求してはいけないという事が良くわかりました。

今回の様な不具合が出ても改修するのはアプリ側ですし、もしこの事が原因でアプリが落ちたとしたらユーザーからすると前面に出ているアプリが責められる事になる可能性が高いと考えられます。
ましてや広告ライブラリのせいでアプリの評価が落ちるとしたら困りますよね。

今回は外部で開発された広告ライブラリが要求する新しい方のSDKバージョンでのビルドしたのですが、今後、自ら以前開発したアプリを新しい方のSDKバージョンでビルドする事があるかも知れません。
その時はこの様な落とし穴があるという事を覚えておくと良い事があるかも知れませんよ!(笑)

– SkyArts について –

私ども  SkyArts ではAndroid/iOSアプリなどのスマートフォン開発のコンサルティングなどを承っております。
加えて、私どもの既存アプリ のカスタマイズ開発なども承っております。「このアプリに自社業務向けにこの様な機能を入れたい!」といったご要望にお応えいたします。
ご連絡は メールTwitter などでお気軽にお問い合わせ下さい。

2011/12/07 This post was written by Categories: AndroidGoogle Tagged with:
No comments yet



コメントを残す

メールアドレスが公開されることはありません。

*

Top