昨日使用 Android Studio 途中彈了 Android Studio 3 的更新通知,那時因為知道升級會有 breaking change,擔心升級要大改 Gradle 設定檔。所以延後了一天才更新。今日試了將現有的 project 更新,暫時未遇到問題,應該算是完成了。

Android Studio 3 的更新通知

Android Studio 升級完成後,開啟 project。Android Studio 會提示你升級 build tool 之類的東西,按照指示進行。Android Studio 會改動你的 Gradle wrapper,build tool 版本。但之後 Gradle project sync 時可能會有一大堆 error。這時可以試試以下的方法:

檢查 app/build.gradlebuildToolsVersion 是否太舊。在根目錄的 build.gradleext 內加入 compileSdkVersionbuildToolsVersion

ext {
    compileSdkVersion = 26
    buildToolsVersion = '26.0.2'
    // ...
}

之後將 app/build.gradlecompileSdkVersionbuildToolsVersion 換成 ext 的 property:

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    // ...
}

然後在根目錄的 build.gradle 加入以下的內容。用意是將 subproject 的 Android 或 Android library project 的 compileSdkVersionbuildToolsVersion 強行設定成 ext 所訂的版本。如果你的 project 是 React Native 的話,應該會加入不少 subproject,而每個 subproject 都會有自己的 compileSdkVersionbuildToolsVersion,如果版本不一致的話是不能 build 的。你可以手動逐個更新 build.gradle,但之後用 NPM update 過那些 React Native component 之後你又要再手動改一次,非常麻煩。所以都是用下面的方法比較好:

subprojects { subproject ->
    afterEvaluate {
        if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
            android {
                compileSdkVersion rootProject.ext.compileSdkVersion
                buildToolsVersion rootProject.ext.buildToolsVersion
            }
        }
    }
}

之後試試 build project,可能已經成功。如果不能的話,就要繼續改其他地方。例如我的 project 有自訂 buildTypes,現在需要補回 matchingFallbacks 確保其他 Android 或 Android library subproject 的 buildTypes 能配對到你的 buildTypes

android {
    // ...
    buildTypes {
        debug {
            debuggable true
            minifyEnabled false
            shrinkResources false
            applicationIdSuffix devAppIdSuffix
            versionNameSuffix devVersionNameSuffix
            signingConfig signingConfigs.debug
            manifestPlaceholders = [
                    // ...
            ]
            ext.alwaysUpdateBuildId = false
        }
        upload {
            minifyEnabled true
            shrinkResources true
            signingConfig signingConfigs.upload
            manifestPlaceholders = [
                    // ...
            ]
            matchingFallbacks = ['release']
        }
        // ...
    }
    // ...
}

每個 productFlavors 都要加 dimension,之前無做就要補回。

android {
    // ...
    flavorDimensions "api"
    productFlavors {
        development {
            dimension "api"
            buildConfigField "String", "ENVIRONMENT", "\"development\""
            buildConfigField "String", "API_ENDPOINT", "\"foo.com\""
        }
        production {
            dimension "api"
            buildConfigField "String", "ENVIRONMENT", "\"production\""
            buildConfigField "String", "API_ENDPOINT", "\"bar.com\""
        }
    }
    // ...
}

加入 Google Maven repository。現在 Google 會將以下最新版本的 library 經這個 repository 發布。

  • Android Support Library
  • Architecture Components Library
  • Constraint Layout Library
  • Android Test Support Library
  • Databinding Library
  • Android Instant App Library
  • Google Play services
  • Firebase

如果之前有加過 maven { url 'https://maven.google.com' } 的話,要將它刪走。

buildscript {
    repositories {
        google()
        jcenter()
        // ...
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        // ...
    }
}

我的 project 到了現在已經能夠 build 到,如果不能的話要再查看其他文檔。

之後可以再將 dependency 設定更新到 Gradle 3.4 的新設定方式。compile 已經在 Gradle 3.4 開始 deprecated,要改用 implementationapiprovided 要轉用 compileOnly。跟據文檔的講法,應該要盡量使用 implementation。因為它會限制這個 dependency 的使用範圍,所以可以加快因改動 module 後再 build 的速度。如果出現 build error 的話,可以試試將 implementation 換成 apiapi 的功能其實和之前的 compile 一樣。debugCompile 換成 debugImplementationtestCompile 換成 testImplementation……以下是一些轉用 implementation 例子:

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion"
    
    implementation project(':react-native-camera')
    
    implementation "com.android.support:appcompat-v7:$androidSupportLibVersion"
    implementation "com.google.dagger:dagger:$daggerVersion"
    kapt "com.google.dagger:dagger-compiler:$daggerVersion"
    
    debugImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
    debugLeakCanaryImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
    releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"

    androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude group: 'com.google.code.findbugs', module: 'jsr305'
    })
    testImplementation 'junit:junit:4.12'
    testImplementation "org.robolectric:robolectric:3.4.2"
}

註:kapt 是 Kotlin annotation processing tool,如果是 Java project 應該用 annotationProcessor

參考