広告IDとgoogle play Services
はじめに
よくゲームアプリとか広告で、端末ユニークにする場合
どうやってるんだろうみたいなのが気になったので、ちょっと調べてみた
広告IDについて
- google play services 4.0.30から対応
- 最近の広告ライブラリは広告IDを内部で使っているので、その手のやつを使うとエラーになる*1
- google_play_services_froyo には入ってない
* よくあるサンプルコード
public void getAdId() { Thread adIdThread = new Thread(new Runnable() { @Override public void run() { Info adInfo = null; try { adInfo = AdvertisingIdClient .getAdvertisingIdInfo(getApplicationContext());//★ final String id = adInfo.getId();//★1 final boolean isLAT = adInfo.isLimitAdTrackingEnabled();//★2 Log.d("DEBUG", "AndroidAdID : " + id); Log.d("DEBUG", "OptoutFlag : " + String.valueOf(isLAT)); } catch (Exception e) { //◎ } } }); adIdThread.start(); }
- ★の引数は、getApplicationContext() じゃないと値が取れない
- ◎の書き方だとExceptionが拾えないみたいな話が実はあり*2
- ★2 は インタレストベース広告をオプトアウト のチェックボックスのフラグだが
- ★1 の値は常に取れてしまう *3
} catch (IllegalStateException e1) { Log.e(TAG,e1.getMessage(),e1); } catch (GooglePlayServicesRepairableException e2) { Log.e(TAG,e2.getMessage(),e2); } catch (IOException e3) { Log.e(TAG,e3.getMessage(),e3); } catch (GooglePlayServicesNotAvailableException e4) { Log.e(TAG,e4.getMessage(),e4); } catch (Exception e) { //◎ Log.e(TAG,e.getMessage(),e); }
Exceptionを羅列すると何故か拾える・・
OutOfMemoryError / RealmError 拾う時とおなじようなもんなんだろうか・・
}catch(OutOfMemoryError oe){
} catch (RealmError e) { //致命的なRealmのエラー } catch (RealmException e) { //通常のRealmのエラー
規約的な話
みたいな話がGoogleの広告関連のページにかいてあったりも。
でも 1-2/1-3 あたりってどうやって確認してるんでしょうね・・
某高◎先生みたいな人がチェックして通報された場合、G様としてはアプリの公開を停止する という意味なんでしょうか・・
広告が同梱されている場合は、特にバイナリチェックだとわかんないかと思うんですが・・
google play services for froyo あたりの話(2017/3/19追記)
一応 6.5.+ 相当らしいんですけど
- AndroidManifest.xml
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
の記載対応しちゃうと、marketの方でapkアップロード時に弾かれてしまう・・><
極限まで古い端末対応できればいいんだけど、Android 2.1も対応できるかな~?って思っても古いGoogle Play ServicesがAndroid 2.2までしか対応してないので、頑張ってもそこまでなぁ_(:3 」∠)_
— じぇーん = Jane (@kinijane) 2017年3月19日
@kimukou2628 Google Play Services 4.1.+ でGradleに書き込むとAndroid 2.2で動きます~。 ちなみに、IS03でもGoogle Play開発者サービスの設定アプリ内に広告IDの設定はありました。
— じぇーん = Jane (@kinijane) 2017年3月19日
@kimukou2628 おおー。そんな方法があるのですね~! まぁ、Android 2.x対応も今回のみなので、深入りはしない予定ですw
— じぇーん = Jane (@kinijane) 2017年3月19日
一応 4.+ にすればgradleベースでも可能なよう。
確かに重いですね。。split対応は6.X系からだった記憶がありますが・・Google Play Services全部入りでpro-guard動かしてみたけど、コレ…重くないっすか… 今まで一部しか入れてなかったから実感はなかったが…w
— じぇーん = Jane (@kinijane) 2017年3月19日
でもまあ、gcm.jarとかの対応も対応サーバーをG様の方が廃止したようで
通信エラー出まくりですしね。過去互換は難しいと思います・・
google play service自体に関して
dependencyコンフリクト問題
google play servicesのLibrary自体が、
- resが豊富
- com.android.support ライブラリに強依存
- support-v4 とか
- recyclerview-v7 とか
でビルドが通らなかったり、実行時に落ちたりする
まあだから、◎のバージョンを揃えろみたいなASのLintエラーが煩かったりするわけですが・・・
android { compileSdkVersion '24'//◎ buildToolsVersion "25.0.2" //<=これはASに最新強いられる? } compile 'com.android.support:support-v4:24.1.+.' //◎ compile 'com.android.support:recyclerview-v7:24.1.+' //◎
で、そのリソースがリリースされていた時期のgoogle play serviceを使いましょう
みたいな話になるのですが、対応表みたいな情報がないんですよね・・
で対策的な書き方
- app/build.gradle
compile ('com.google.android.gms:play-services:6.5.87'){ exclude group: 'com.android.support' } compile 'com.android.support:support-v4:24.1.+.' //★ compile 'com.android.support:recyclerview-v7:24.1.+' //★ compile 'com.android.support:design:24.1.+'//★
な書き方が必要。 特に★は後ろの方で宣言する必要があり
コンフリクトをこじらせると・・・
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) //〜中略〜 compile "net.vvakame:jsonpullparser-core:1.6.2" annotationProcessor "net.vvakame:jsonpullparser-apt:1.6.2" //★ }
★とかが書くとエラーになります。
ただこちらは内部のaptのライブラリが問題起こしているのはわかりますが
exclude指定がわからないので対処法がないんですよね・・*6
この状態だとaptのplugin指定でもエラーになるのでaptのライブラリを使っているライブラリを外すしかないという嫌な対処になります
- data-bindingとか
- org.androidannotations とか
google play servicesのバージョンにこだわる理由
- 現在地情報のLatlng を取るだけであれば、今だと
- LocationManager + requestLocationUpdates
- GoogleApiClient + FusedLocationProviderApi
のにパターンになるわけですが、細かい情報等を取得しようとすると、やはり細かいAPIには差分が有り、バージョン依存等が発生したりするわけです。
1-1に関して
- オフラインでも位置情報取得可能
- ただGPSだけ自体では、元から精度が大雑把なので信頼性的に厳しい面も有る
1-2に関して
とかあったりします
で 1-2の実装前提であえてオフライン対策をしようとすると
- 正常に位置情報が取得できた時にPrefrence等に保存しておく
- オフライン時はその値をつかって現在地情報を語る
Location loc = new Location(LocationManager.GPS_PROVIDER); Double latitude =<<プリファレンスから取得>>; Double longitude =<<プリファレンスから取得>>; if(latitude == null || longitude == null ){ //東京駅の座標 latitude = new Double(35.681298); longitude = new Double(139.766247); } loc.setLatitude(latitude); loc.setLongitude(longitude); //位置情報を受信する関数に投げる onLocationChanged(loc);
これをFuseAPIのMockLocationでしようとすると
Location mockLocation = new Location("network"); mockLocation.setLatitude(50.120089); mockLocation.setLongitude(18.993206); mockLocation.setAccuracy(4.0f); mockLocation.setTime(System.currentTimeMillis()); LocationServices.FusedLocationApi.setMockMode(mGoogleApiClient, true); LocationServices.FusedLocationApi.setMockLocation(mGoogleApiClient, mockLocation); mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient);
なコードになり、
- mGoogleApiClientがつながっていないからException発生
という本末転倒なコードになるので意味が無いという。。
というかMockModeのときぐらいAPI利用頻度チェックやめようや。。
とかいいたい*8
*1:取れないときに内部で乱数生成してみたいなことまで遣ってくれてるAdの方が少ないみたい。AdMob自体もしていませんし・・・
*2:デバッカーで動かしたときに確かに体感した。なぜだかすごい疑問。。
*3:★2のチェックがついている時は、アプリやLibrary側で保存処理するな みたいな規約ページがあったりも・・
*4:セキュリティが騒がれた時期に急遽用意されたものらしい
*6:AS 2.3.Xの最新版だとandroid apt pluginを使っていると、annotationProcesser記述使え! と WarningをLintで吐くようになったが、未だにDaggerとか対応していないので意味がない。。
*7:FusedLocationApiは高精度でしか動きません。端末のみ とか バッテリーセーブモード とか無かったことになってる<苦笑
*8:MockModeってDebugやtestコードぐらいでしか使わないのですし・・