2017年11月19日日曜日

【Android Studio 3.0】既存アプリをAndroid Studio 3.0に対応させる。

  • 公開日:2017年11月18日

記事概要

kotlinとJavaの混じったアプリを2.3.x系でビルドすると、制約がひどく、ビルドも遅いのでAndroid Studio 3.0に移行しました.
結構色々なエラーと修正が発生したので、今後移行する人の役に立つように作業メモを記載して残しておきます。

環境

  • Android Studio 2.3.1 → Android Studio 3.0

Android Studio 3.0に対応

ダイアログで表示されるgradleのversionにアップデートします。ダイアログでOKを押下します。
自動的にbuild.gradleと/gradle/wrapper/gradle-wrapper.propertiesが上書きされます。

{project_folder}/build.gradle

     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath 'com.google.gms:google-services:3.0.0'
     }

{project_folder}/gradle/wrapper/gradle-wrapper.properties

-#Fri Jul 28 22:16:36 JST 2017
+#Sat Nov 18 19:40:49 JST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

jackOptionsを無効化

gradleの変更だけだと、おそらくビルドに失敗します。jackOptionsが有効だと以下のエラーが出力されます。

Event Log

Warning:The Jack toolchain is deprecated and will not run. To enable support for Java 8 language features built into the plugin, remove 'jackOptions { ... }' from your build.gradle file, and add

android.compileOptions.sourceCompatibility 1.8
android.compileOptions.targetCompatibility 1.8

Future versions of the plugin will not support usage of 'jackOptions' in build.gradle.
To learn more, go to https://d.android.com/r/tools/java-8-support-message.html

エラーの内容は、jackOptionsはもうすぐサポート終わるから使わないでってことです。
なので、以下のように変更します。

{project_folder}/app/build.gradle

    defaultConfig {
         // something...
         vectorDrawables.useSupportLibrary = true
-        jackOptions {
-            enabled true
-        }
         multiDexEnabled true
         // something...
    }

jackOptionsを削除するだけです。sourceCompatibilityとtargetCompatibilityは残しておきます。

flavor dimensionsの設定

Android Studio 3.0からは、単一のflavor dimensionを使用する場合でも、すべてのflavorが名前付きflavor dimensionに属している必要があります。でないと、以下のようなエラーが発生します。

Event Log

All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html

つまり、dimensionを定義してね。ってことです。正直、ダメな仕様だと思います。大規模なプロジェクトには便利な機能ですが、必須である理由がわかりません。大抵のアプリは小さいアプリなはずです。いずれ元に戻ると思いたいですね。
ビルド周りは大きく変わっているので、面倒でもサンプルプロジェクトを作成して仕様を確認することをお勧めします。ドキュメントを読むだけだと、ピンと来ないと思います。

私の環境は分ける必要がないので、以下のように名前を一つ追加しただけです。

{project_folder}/app/build.gradle

+    flavorDimensions 'normal'
     productFlavors {
         dev {
+            dimension 'normal'
         }
         prod {
+            dimension 'normal'
         }
     }

kotlinのバージョンアップ

jackOptionsが不要になったので、kotlinのバージョン縛りがなくなりました。なので、このままだと以下のエラーが発生します。

Event Log

Unable to find method 'com.android.build.gradle.internal.variant.BaseVariantData.getOutputs()Ljava/util/List;'. Possible causes for this unexpected error include:
Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.) Re-download dependencies and sync project (requires network)
The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem. Stop Gradle build processes (requires restart)
Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.
In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.

エラーにkotlinの文字が出ないのは良くないですね。いずれは改善して欲しいですね。
kotlinのアップデートはgradleの記載を変更するだけです。

{project_folder}/app/build.gradle

 buildscript {
     ext {
-        kotlin_version = '1.1.1'
+        kotlin_version = '1.1.51'
     }

buildToolのバージョンアップ

buildToolも更新が必要です。buildToolのバージョンが古いと以下の警告メッセージが表示されます。

Event Log

Error:The specified Android SDK Build Tools version (26.0.1) is ignored, as it is below the minimum supported version (26.0.2) for Android Gradle Plugin 3.0.0.
Android SDK Build Tools 26.0.2 will be used.
To suppress this warning, remove "buildToolsVersion '26.0.1'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.

gradleを更新します。

{project_folder}/app/build.gradle

 android {
-    compileSdkVersion 26
+    compileSdkVersion 27
     buildToolsVersion rootProject.buildToolsVersion

{project_folder}/build.gradle

 allprojects {
     repositories {
+        google()
         mavenCentral()
-        maven { url 'https://maven.google.com' }
     }
 }

 ext {
-    buildToolsVersion = "26.0.1"
-    supportLibVersion = "26.1.0"
+    buildToolsVersion = "27.0.1"
+    supportLibVersion = "27.0.1"
     multidexVersion = "1.0.0"
-    constraintLayoutVersion = "1.0.2"
+    constraintLayoutVersion = "1.1.0-beta3"
     rxandroidVersion = "2.0.1"
     rxjavaVersion = "2.1.3"

maven { url 'https://maven.google.com' } を google() に書き換えできるようになりました。

また、Android Studio 3.0だと、constraintLayoutが安定してIDEで表示されるようになりました。ConstraintLayoutを使うとviewの入れ子を少なくできて、描写が高速になるので、積極的に利用していきましょう。beta版が嫌な人は1.0.2でも良いと思います。サポートライブラリArchitecture Componentsの更新も忘れずに。

コード修正

最後にkotlinのアップデートとsdk27のアップデートのコード対応を行います。
私の環境で発生したエラーと修正方法を記載しておきます。

Error: style attribute '@android:attr/windowEnterAnimation' not found.

@が不要になりました。

{project_folder}/app/src/main/res/values/styles.xml

     <style name="Animations.GrowFromBottom">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_bottom</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_top</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_bottom</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_top</item>
     </style>
 
     <style name="Animations.GrowFromTop">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_top</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_bottom</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_top</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_bottom</item>
     </style>
 
     <style name="Animations.PopDownMenu">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
     </style>

Android3.0からは、デフォルトでAAPT2が有効になったことの影響です。

Error: Smart cast to 'Bundle' is impossible, because 'arguments' is a mutable property that could have been changed by this time

getArguments()のSmart castができなくなりました。コードを見ると、sdk27(サポートライブラリ)では以下のように実装されています。

android.support.v4.app.Fragment

    /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     */
    @Nullable
    final public Bundle getArguments() {
        return mArguments;
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     */
    final public Bundle getArguments() {
        return mArguments;
    }

@Nullableが追加されています。ブロックの引数を指定する必要があります。

{project_folder}/MainActivity.java

-        arguments?.let {
+        arguments?.let { it ->


というかこれは既存コードに潜在的なバグが含まれていたっぽいです。。。letのブロック内の変数はなるべくitに置き換えるか、名称を変更するべきですね。

Error: Class 'XYZPagerAdapter' is not abstract and does not implement abstract base class member public abstract fun isViewFromObject(@NonNull p0: View, @NonNull p1: Any): Boolean defined in android.support.v4.view.PagerAdapter

PagerAdapterにも変更が入ったようです。コードを見ると、sdk27(サポートライブラリ)では以下のように実装されています。

android.support.v4.app.Fragment

    public abstract boolean isViewFromObject(@NonNull View view, @NonNull Object object);

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    public abstract boolean isViewFromObject(View view, Object object);

これも同じように@Nullableが追加されています。?を削除します。

{project_folder}/MainActivity.java

-        override fun isViewFromObject(view: View?, `object`: Any?): Boolean {
+        override fun isViewFromObject(view: View, obj: Any): Boolean {

isViewFromObjectの引数って@NonNullだったんですね。チェックしてコード書いてた時期があったような。

Error: Fragment

Fragmentも変更されてますね。これもsdk27で@Nullableのアノテーションが追加されたのではないでしょうか。

android.support.v4.app.Fragment

    @Nullable
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    @Nullable
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

LayoutInflaterが@NonNullになっています。これは良い修正ですね。以下のように修正します。

{project_folder}/MainActivity.java

-    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,

-        val view = inflater!!.inflate(R.layout.fragment_floating_action, container, false)
+        val view = inflater.inflate(R.layout.fragment_floating_action, container, false)

Error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type FragmentActivity?

FragmentActivityも変更されてますね。これも@Nullableのアノテーションが追加されたのではないでしょうか。

android.support.v4.app.Fragment

    final public FragmentActivity getActivity() {
        return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }

    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    @Nullable
    final public FragmentActivity getActivity() {
        return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }

    /**
     * Return the {@link Context} this fragment is currently associated with.
     */
    @Nullable
    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

Safe-call演算子を使って書き換えます。

色々

-            activity.supportFragmentManager.popBackStack()
+            activity?.supportFragmentManager?.popBackStack()

-            Toast.makeText(context, context.getString(R.string.sample), Toast.LENGTH_SHORT).show()
+            Toast.makeText(context, context?.getString(R.string.sample), Toast.LENGTH_SHORT).show()

gradle修正

gradleを変更します。

compileをimplementationに変更します。

implementationにするとビルドが早くなります。
なぜなら、implementationは、コンパイルする必要がある依存ライブラリだけをコンパイルします。

{project_folder}/build.gradle

-    compile 'com.android.support:multidex:' + rootProject.multidexVersion
-    compile 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion
-    compile 'com.android.support:design:' + rootProject.supportLibVersion
-    compile 'com.android.support:support-v4:' + rootProject.supportLibVersion
-    compile 'com.android.support.constraint:constraint-layout:' + rootProject.constraintLayoutVersion
-    compile 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion
-    compile 'com.android.support:cardview-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:multidex:' + rootProject.multidexVersion
+    implementation 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:design:' + rootProject.supportLibVersion
+    implementation 'com.android.support:support-v4:' + rootProject.supportLibVersion
+    implementation 'com.android.support.constraint:constraint-layout:' + rootProject.constraintLayoutVersion
+    implementation 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:cardview-v7:' + rootProject.supportLibVersion

以上で終了です。お疲れさまでした。
コンパイルが随分と高速化されました。

結論

kotlinのNull Safety機能は強力ですね。小さいアプリだとAndroid Architecture Componentsは不要ですね。導入すると無駄にコードも増えますし。

kotlinの導入とconstraintLayoutの導入は本当にお勧めです。8.1のリリースも近いので、そろそろ既存アプリのandroid studio3.0の対応は終了させておきたいですね。

PICK UP

運営サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...