Upgrading my Flutter app to Android compileSdkVersion 33
In my project, two dependencies require compileSdkVersion 33. Let's fix my project configuration:
Warning: The plugin sqflite requires Android SDK version 33.
For more information about build configuration, see https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
One or more plugins require a higher Android SDK version.
Fix this issue by adding the following to /Users/anhtuan/git/trading_journal/android/app/build.gradle:
android {
  compileSdkVersion 33
  ...
}I open the build.grade and change the compileSdkVersion from 31 to 33, then build the project again.
BUILD FAILED in 5s
┌─ Flutter Fix ──────────────────────────────────────────────────────┐
│ [!] Your project requires a newer version of the Kotlin Gradle plugin.                     │
│ Find the latest version on https://kotlinlang.org/docs/releases.html#release-details, then │
│ update /Users/anhtuan/git/trading_journal/android/build.gradle:                            │
│ ext.kotlin_version = '<latest-version>'                                                    │
└────────────────────────────────────────────────────────────────┘
Exception: Gradle task assembleDebug failed with exit code 1The nice thing is Flutter now tells you how to fix it. So I click the kotlinlang.org link and see that the latest version is 1.8.22. So I fix my build.gradle accordingly:
buildscript {
    ext.kotlin_version = '1.8.22'
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
...However now the build fails with this incomprehensible error:
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring root project 'android'.
> Could not resolve all artifacts for configuration ':classpath'.
   > Could not resolve org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22.
     Required by:
         project :
      > Cannot choose between the following variants of org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22:
          - gradle70JavadocElements
          - gradle70RuntimeElements
          - gradle70SourcesElements
          - gradle71JavadocElements
          - gradle71RuntimeElements
          - gradle71SourcesElements
          - gradle74JavadocElements
          - gradle74RuntimeElements
          - gradle74SourcesElements
          - gradle75JavadocElements
          - gradle75RuntimeElements
          - gradle75SourcesElements
          - gradle76JavadocElements
          - gradle76RuntimeElements
          - gradle76SourcesElements
          - javadocElements
          - runtimeElementsWithFixedAttribute
          - sourcesElements
        All of them match the consumer attributes:
          - Variant 'gradle70JavadocElements' capability org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22:
              - Unmatched attributes:
                  - Found org.gradle.category 'documentation' but wasn't required.
                  - Found org.gradle.docstype 'javadoc' but wasn't required.
                  - Required org.gradle.jvm.version '11' but no value provided.
                  - Required org.gradle.libraryelements 'jar' but no value provided.
                  - Found org.gradle.plugin.api-version '7.0' but wasn't required.
                  - Found org.gradle.status 'release' but wasn't required.
              - Compatible attributes:
                  - Required org.gradle.dependency.bundling 'external' and found compatible value 'external'.
                  - Required org.gradle.usage 'java-runtime' and found compatible value 'java-runtime'.
          - Variant 'gradle70RuntimeElements' capability org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22:
[and the logs go on and on...]And I seem to remember that the Gradle version also depended on the Kotlin version. So I looked it up and found this:
| Kotlin version | Gradle min and max versions | Android Gradle plugin min and max versions | 
|---|---|---|
| 1.8.20 | 6.8.3 – 7.6.0 | 4.1.3 – 7.4.0 | 
| 1.8.0 | 6.8.3 – 7.3.3 | 4.1.3 – 7.2.1 | 
| 1.7.20 | 6.7.1 – 7.1.1 | 3.6.4 – 7.0.4 | 
Looking for a similar issue among my previous blog posts, I find this. Turns out the Gradle version is defined in android/gradle/wrapper/gradle-wrapper.properties:
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
I am using Grade 6.1.1, which is lower than the minimum supported version of 6.8.3. Let's try it with 7.6.0:
Exception in thread "main" java.io.FileNotFoundException: https://downloads.gradle.org/distributions/gradle-7.6.0-all.zip
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1920)I had blindly just changed the version number. Let's see from the Gradle documentation what the actual URL is. I found the page on Google:
So there is no distribution for version 7.6.0. I should use 7.6.1 instead. So I run the build again, and after spinning for a little while, gives me this error:
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/anhtuan/git/trading_journal/android/app/build.gradle' line: 25
* What went wrong:
A problem occurred evaluating project ':app'.
> Failed to apply plugin 'kotlin-android'.
   > Can't infer current AndroidGradlePluginVersion: Is the Android plugin applied?I think it comes back to the build.grade's buildscript: classpath 'com.android.tools.build:gradle:3.5.0'. Based on the table above, it should be between 4.1.3 and 7.4.0. I run it again, and finally it runs!
The last thing to fix was the target API, in order to publish to the Play Store:
[!] Google Api Error: Invalid request - Your app currently targets API level 30 and must target at least API level 31.So I went back to [project]/android/app/build.gradle and upgraded from targetSdkVersion 30 to targetSdkVersion 31. This time compilation failed with this error:
/Users/anhtuan/git/trading_journal/android/app/src/main/AndroidManifest.xml:15:9-43:20 Error:
        android:exported needs to be explicitly specified for element <activity#com.example.trading_journal.MainActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:processReleaseMainManifest'.
> Manifest merger failed : android:exported needs to be explicitly specified for element <activity#com.example.trading_journal.MainActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.Apparently this setting is to specify whether the activity can be launched by another app. I don't need this and the default used to be false anyway. So I'll set it to false:
    <application
        android:name="${applicationName}"
        android:label="Trading Journal"
        android:icon="@mipmap/launcher_icon">
        <activity
            android:exported="false"
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
...After installing it on my phone, I tried to run the app and it sait "The app is not installed". When trying on the Emulator, it fails with this error:
Launching lib/main.dart on sdk gphone64 arm64 in debug mode...
main.dart:1
✓  Built build/app/outputs/flutter-apk/app-debug.apk.
ProcessException: Process exited abnormally:
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x20000000 cmp=com.wafrat.elysium/.MainActivity (has extras) }
Exception occurred while executing 'start':
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30000000 cmp=com.wafrat.elysium/.MainActivity (has extras) } from null (pid=32763, uid=2000) not exported from uid 10165
	at com.android.server.wm.ActivityTaskSupervisor.checkStartAnyActivityPermission(ActivityTaskSupervisor.java:1108)It turns out, it should have been set to true.
To summarize, I had to do these 6 tasks:
- in [project]/android/app/build.gradleupgradecompileSdkVersionto 33.
- in [project]/android/app/build.gradle, upgradetargetSdkVersionto 31.
- in [project]/android/build.gradle, upgradekotlin_versionto'1.8.22'.
- in [project]/android/build.gradle, upgradecom.android.tools.build:gradleto 7.4.0.
- in [project]/android/gradle/wrapper/gradle-wrapper.properties, upgradedistributionUrlto7.6.1.
- in android/app/src/main/AndroidManifest.xml, addandroid:exported="true"to the main Activity.