Android Studio に入れておくとよい ライブラリバージョン検索 プラグイン「OK, Gradle!」

ライブラリの最新版を探すのに役に立ちそうな。

OK, Gradle! - Plugins | JetBrains

scana/ok-gradle: IntelliJ/Android Studio plugin for searching artifacts ids of popular Java libraries.

使ってみたけど、役に立つと思う。



動画のように、いろいろあるけど、

いちいち参照先探すのも面倒だから。


AndroidManifest.xml に Admob application ID の記述が必須になったとさ

こんなエラーメッセージ。


E/AndroidRuntime: FATAL EXCEPTION: main
    Process: ru.balumates.balu, PID: 4409
    java.lang.RuntimeException: Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider: java.lang.IllegalStateException:

    ******************************************************************************
    * The Google Mobile Ads SDK was initialized incorrectly. AdMob publishers    *
    * should follow the instructions here: https://goo.gl/fQ2neu to add a valid  *
    * App ID inside the AndroidManifest. Google Ad Manager publishers should     *
    * follow instructions here: https://goo.gl/h17b6x.                           *
    ******************************************************************************


        at android.app.ActivityThread.installProvider(ActivityThread.java:6242)
        at android.app.ActivityThread.installContentProviders(ActivityThread.java:5805)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5722)
        at android.app.ActivityThread.-wrap1(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.IllegalStateException:

    ******************************************************************************
    * The Google Mobile Ads SDK was initialized incorrectly. AdMob publishers    *
    * should follow the instructions here: https://goo.gl/fQ2neu to add a valid  *
    * App ID inside the AndroidManifest. Google Ad Manager publishers should     *
    * follow instructions here: https://goo.gl/h17b6x.                           *
    ******************************************************************************


        at com.google.android.gms.internal.ads.zzmn.attachInfo(Unknown Source:17)
        at com.google.android.gms.ads.MobileAdsInitProvider.attachInfo(Unknown Source:3)
        at android.app.ActivityThread.installProvider(ActivityThread.java:6239)
        	... 10 more
Disconnected from the target VM, address: 'localhost:8600', transport: 'socket'

Google Mobile Ads SDK v17.0.0 以降で必須だと。

Google Ads Developer Blog: Announcing v17.0.0 of the Android Google Mobile Ads SDK

このことは、


implementation "com.google.firebase:firebase-ads:17.0.0"

も同じ。

以下、AndroidManifest.xml の必須記述。


<manifest>
  <application>
    <meta-data
        android:name="com.google.android.gms.ads.APPLICATION_ID"
        android:value="ca-app-pub-################~##########"/>

  </application>
</manifest>

Ad Manager や NativeAppInstallAd / NativeContentAd も注意が必要な模様。


11月1日に迫った「targetSdkVersion は 26以上」に向けての対応の目処

メール来てますよね。

Hello Google Play Developer,

This is a reminder that starting November 1, 2018, updates to apps and games on Google Play will be required to target Android Oreo (API level 26) or higher. After this date, the Play Console will prevent you from submitting new APKs with a targetSdkVersion less than 26.

Configuring your app to target a recent API level ensures that users benefit from significant security and performance improvements, while still allowing your app to run on older Android versions (down to the minSdkVersion).

Action required

Please ensure that your apps are configured to target at least Android 8.0 (API level 26) by November 1, 2018. For technical advice on how to change your app's target API level to meet these requirements, refer to the migration guide.

Affected apps

The apps included below have one or more APKs—in production or testing tracks—that aren't currently targeting API level 26 or higher. Apps are listed with the maximum version code and corresponding targetSdkVersion. If you have more than 20 apps that could be affected in your account, please check the Play Console for a full list.

動くとはいうものの、GoogleサービスAPIの仕様や各サービス/プラットフォームのポリシーの変更が頻繁なことを考えると、放置しているアプリは一掃されていくと思われます。

メールには、以下が「マイグレーションガイド」として案内されています。

Meet Google Play's target API level requirement  |  Android Developers

おおまかに、影響しそうなキーワードを拾っておきます。

API 23 (6.0) 未満

「Runtime Permission」
実行時のパーミッション リクエスト  |  Android Developers

API 24 (7.0) 未満

「Doze」
Doze と App Standby 用に最適化する  |  Android Developers

「Firebase Cloud Messaging (FCM)」
Firebase Cloud Messaging  |  Firebase

「file://」
Setting up file sharing  |  Android Developers

API 26 (8.0) 未満

「startService()」
「startForeground()」
「startForegroundService()」
「Firebase Cloud Messaging (FCM)」
「Google Play services SDK」
「JobScheduler」

バックグラウンド実行制限  |  Android Developers

「Notification」
Create and Manage Notification Channels  |  Android Developers

「ANDROID_ID」
Settings.Secure  |  Android Developers

「multiple window/display」
マルチ ウィンドウのサポート  |  Android Developers
Android 8.0 の機能と API  |  Android Developers

「Camera API」
android.hardware.camera2  |  Android Developers

まとめ

Gradle周りやライブラリ同士の依存関係などもあって簡単には終われないですよね。

保守的に古いSDKにスティックしていた開発陣はモヤモヤ一掃のチャンスと思うべし。

あと、オプトインしといたほうがいいよ、と以下リンクがありました。

http://g.co/play/monthlynews


Admob firebase-ads:15.0.1 でメモリーリークする

なんか以前からよくリークしてましたよね、Admob。

今回は, 以下バージョン。


implementation "com.google.firebase:firebase-core:15.0.2"
implementation "com.google.firebase:firebase-ads:15.0.1"

Activity#finish()後、

百発百中でLeakCanaryが鳴く。

情報はないか、と探すが古いものばかり。

最新の公式サンプルを見る。

BannerExamples

advanced-APIDemo

BannerRecyclerViewExample

AndroidManifest.xmlの「INTERNET」関連の2行はもう不要だったり。

サンプル通りライフサイクル周り記述しても消えやしない。

百発百中でアウトでござる。


// Called when leaving the activity
public override fun onPause() {
    ad_view.pause()
    super.onPause()
}

// Called when returning to the activity
public override fun onResume() {
    super.onResume()
    ad_view.resume()
}

// Called before the activity is destroyed
public override fun onDestroy() {
    ad_view.destroy()
    super.onDestroy()
}

公式サンプルの中に以下を見つけた。


if (adView.getParent() != null) {
  ((ViewGroup) adView.getParent()).removeView(adView);
}

RecyclerViewAdapter.java#L146-L148

ぶら下がったままだった模様。

以下で完。


inline fun AdView.remove() {
  if (parent != null) {
    (parent as ViewGroup).removeView(this)
  }
}

最初のライフサイクル周りは、

公式マニュアル通り不要だったりしたが。


Google I/O 2018 にみる Android KTX その1

Android KTX は、次期 androidx のパッケージとも深い関わりをもっているようです。

androidx: Hello World!
You may notice that Android KTX uses package names that begin with androidx. This is a new package name prefix that we will be using in future versions of Android Support Library. We hope the division between android.* and androidx.* makes it more obvious which APIs are bundled with the platform, and which are static libraries for app developers that work across different versions of Android.

Android Developers Blog: Introducing Android KTX: Even Sweeter Kotlin Development for Android

また、パッケージ名に関してのマッピングも公式からアナウンスされ始めています。

AndroidX refactoring  |  Android Developers

そんな Android KTX に関係するいくつかの動画がアップされています。

Android Jetpack: sweetening Kotlin development with Android KTX (Google I/O 2018) - YouTube

Google I/O 2018: Stage 2 - YouTube

前回は、よく分からんオネーチャンが喋ってましたが、 今回は、Jake Wharton さんが遂に表に登場しました。

彼のトークやスライドは開発に有効に利用できることばかりです。

Kotlin の Extension Function の勉強にもなりますので、登場したコードを書き出しておきます。

並び順は、

「よくあるコード」(before)
「Android KTX のコード(拡張関数)」(KTX)
「KTXを利用したコード」(after)

です。

 

ViewGroupの再帰処理


// before
val userLayout: ViewGroup = findViewById(R.id.users)
for (index in 0 until userLayout.childCount) {
  val view = userLayout.getChildAt(index)
  // Do something with index and view...
}


// KTX
fun ViewGroup.forEachIndexed(action: (Int, View) -> Unit) {
  for (index in 0 until childCount) {
    action(index, getChildAt(index))
  }
}


// after
val userLayout: ViewGroup = findViewById(R.id.users)
userLayout.forEachIndexed { index, view ->
  // Do something with index and view...
}

 

getSystemService()


// before

// In an Activity, on API 23+...
val notifications = getSystemService(NotificationManager::class.java)

// or all API levels...
val notifications = ContextCompat.getSystemService(this,
  NotificationManager::class.java)


// KTX
inline fun <reified T> Context.systemService() =
  ContextCompat.getSystemService(this, T::class.java)


// after
val notifications = systemService<NotificationManager>()

 

Viewのパディング


// before
avatarView.setPadding(
  10, avatarView.paddingTop, 10, avatarView.paddingBottom)


// KTX
inline fun View.updatePadding(
  left: Int = paddingLeft,
  top: Int = paddingTop,
  right: Int = paddingRight,
  bottom: Int = paddingBottom
) {
  setPaddinng(left, top, right, bottom)
}


// after
avatarView.updatePadding(left = 10, right = 10)

 

デストラクチャ


// before
val rect = avaterView.clipBounds
val left = rect.left
val top = rect.top
val right = rect.right
val bottom = rect.bottom
// Use left, top, right, bottom...


// KTX
inline operator fun Rect.component1() = left
inline operator fun Rect.component2() = top
inline operator fun Rect.component3() = right
inline operator fun Rect.component3() = bottom


// after
val (left, top, right, bottom) = avatarView.clipBounds
// Use left, top, right, bottom...

val (left, top, right) = avatarView.clipBounds
// Use left, top, right...

val (left, _, right) = avatarView.clipBounds
// Use left, right...

 

すべての値のチェック


// before
val onlyDigits = true
for (c in phoneNumber) {
  if (!c.isDigit()) {
    onlyDigits = false
    break
  }
}


// before
val onlyDigits = phoneNumber.all { it.isDigit() }


// before
val onlyDigits = TextUtils.isDigitsOnly(phoneNumber)


// KTX
inline fun CharSequence.isDigitsOnly() = TextUtils.isDigitsOnly(this)


// after
val onlyDigits = phoneNumber.isDigitsOnly()

とりあえずは、前半のコードを書き出しておいて、次回へ

(つづく...)