技術研究所の(ホ)です。

 

既に本ブログで紹介済みですが、11月末にクレスコフェアが開催されました。

その入場受付や投票を行うAndroidアプリをKotlinで作ったのですが、インストールに失敗するとの報告を受けたので、その原因と対処について記載します。

Kotlin とは

IntelliJ などの高性能なIDEを開発しているJetBrains社が開発している静的型付けのオブジェクト指向プログラミング言語です。

一部ではAndroid開発に置いてJavaの次なる標準的なプログラミング言語になるのでは?とか、Android版のSwift(iOSアプリ開発用言語)と言われているとかいないとか。

現象まとめ

インストールできないという方々からは下記の情報が得られました。

  •  「アプリケーションのインストール中に不明なエラーコードが発生しました」というダイアログが表示された。
    •  エラーコードとして -11 が表示されていた
    •  2回目以降はエラーコードとして -24 が表示されていた
  •  失敗するのは Android のバージョンが 4.2 の端末のみ
    •  今回のminSdkVersionは 4.2 (API Level : 17) 
  • いざ、調査・分析

    当然ですが、エラーコードが何を示しているかを見ます。

    -11 : PackageManager.INSTALL_FAILED_DEXOPT

    これは、メソッド数が多すぎる場合などに発生します。

    Android はインストール時にメソッドの情報を固定サイズの領域に保持するのですが、そのサイズを超えてしまう場合はエラーになってしまいます。ただ、4.x 以降では8 or 16MB とのことで、4.2 のみで発生する理由とは考えにくい。

    -24 : PackageManager.INSTALL_FAILED_UID_CHANGED

    これは、同じパッケージ名だけど、別な鍵でビルドされたアプリが既にインストール済みの場合に発生します。

    恐らく INSTALL_FAILED_DEXOPT でインストールが失敗してゴミファイルが残ってしまっていることが原因と思われます。ちゃんとインストールさえできれば問題ないはず。

    エラーコードだけでは、原因がよく分かりませんでした。

    原因は?

    エラーコードとAndroid のバージョンを調べた限りでは特に原因が見つからなかったため、ひょっとしてKotlinが絡んでいるのではと思い、再度調べたところすぐに見つかりました。

    I have a very similar problem, but only on devices with API 17 and older ones. None of my Kotlin apps work on those devices, and all of them work perfectly on API 19 and newer ones. So is it that just the older APIs aren’t (yet) supported? I use Kotlin beta 1038.

    どうやら、Kotlinのライブラリ自体の問題のようです。1.0.0 (β)がリリースされた直後に喜び勇んで使ったあれです。

    もし、これが映画だったら「この選択が大きな問題を引き起こすとは、この時には知る由もなかった。。。」などと、例の低いトーンのナレーションがながれていたことでしょう。

    対処

    INSTALL_FAILED_DEXOPT(-11)

    Kotlin のバージョンを上げればおしまいなのですが、少しだけ手間取ったため、これもメモとして残しておきます。

    1. Kotlin のアップデート

    build.gradleに記載のKotlinのバージョンを下記のリンク先の適当なVersion に変更します。

    2. プロジェクトのClean

    Kotlinのアップデートだけではアップデート前に生成されたクラスファイルが残り続けるので、一度Cleanする必要があります。

    IntelliJの [Build] -> [Clean Project]ではKotlinが作成したClassファイルが消されないため、Gradleのcleanタスクを実行するとか、以下のディレクトリ下のKotlinが生成するクラスファイルを消してください。

    • your-project/your-module/build/tmp/kotlin-classes
    • your-project/your-module/build/intermediates/classes/

    INSTALL_FAILED_UID_CHANGED(-24)

    問題が修正されても、端末に以前のインストールで失敗した履歴が残ったままでは、このエラーが出続けます。

    そこで、この履歴を削除する必要があるのですが、多くの端末は再起動で消えるようです。

    ただ、再起動しても消えない端末もあるらしく(特定メーカ?)、それでも消す場合には端末の初期化やルート化などが必要らしいです。

    実はこっちのほうが大問題でした。

    まとめ

    Kotlin良いよ。という話はよく聞きますが、まだβが取れていないものです。まだまだ問題が残っている可能性があります。リリース前にはよくテストしましょう。(自戒と自責の念を込めて)

    P.S.

    Githubのサンプルはこの罠が残っているので注意してくださいね。