Skip to content

Commit

Permalink
Expose versionCode and versionName from local.properties in FlutterEx…
Browse files Browse the repository at this point in the history
…tension (#141417)

This PR has no issue. I got this cool idea and decided to quickly try it out, and it works.

### Summary

This will allow Flutter Developers to have less code in their Android Gradle buildscripts.

```diff
 plugins {
     id "com.android.application"
     id "dev.flutter.flutter-gradle-plugin"
     id "kotlin-android"
 }

-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file("local.properties")
-if (localPropertiesFile.exists()) {
-    localPropertiesFile.withReader("UTF-8") { reader ->
-        localProperties.load(reader)
-    }
-}
-
-def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
-if (flutterVersionCode == null) {
-    flutterVersionCode = "1"
-}
-
-def flutterVersionName = localProperties.getProperty("flutter.versionName")
-if (flutterVersionName == null) {
-    flutterVersionName = "1.0"
-}
-
-def keystorePropertiesFile = rootProject.file("keystore.properties")
-def keystoreProperties = new Properties()
-
 keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

 android {
         applicationId "pl.baftek.discoverrudy"
         minSdk 21
         targetSdk 34
-        versionCode flutterVersionCode.toInteger()
-        versionName flutterVersionName
+        versionCode flutter.versionCode()
+        versionName flutter.versionName()
     }
```

The boilerplate that loads 'local.properties' can live in Flutter Gradle Plugin.

### Concerns

I was worried about lifecycle/ordering issues, so I tested it.

To Flutter Gradle Plugin, I added:

```diff
 class FlutterPlugin implements Plugin<Project> {
     //...

     @OverRide
     void apply(Project project) {
+        project.logger.quiet("Start applying FGP")
         // ...
     }
 }
```

and to my `android/app/build.gradle` I added:

```diff
 android {
+    logger.quiet("Start evaluating android block")
     namespace "pl.bartekpacia.awesomeapp"
     compileSdk 34
 
     defaultConfig {
         applicationId "pl.baftek.discoverrudy"
         minSdk 21
         targetSdk 34
         versionCode flutter.versionCode()
         versionName flutter.versionName()
     }
```

Gradle first applies the plugins (which sets versionCode and versionName on FlutterExtension), and then it executes the `android {}` extension block:

```
$ ./gradlew :app:assembleDebug

> Configure project :app
Start applying FGP
Start evaluating android block

BUILD SUCCESSFUL in 2s
383 actionable tasks: 10 executed, 373 up-to-date
```

So ordering is fine.
  • Loading branch information
bartekpacia authored Jan 12, 2024
1 parent d35ee11 commit fd827e3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 33 deletions.
22 changes: 2 additions & 20 deletions examples/hello_world/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@ plugins {
id "dev.flutter.flutter-gradle-plugin"
}

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}

android {
namespace "io.flutter.examples.hello_world"
compileSdk flutter.compileSdkVersion
Expand All @@ -38,8 +20,8 @@ android {
applicationId "io.flutter.examples.hello_world"
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
versionCode flutter.versionCode()
versionName flutter.versionName()
}

buildTypes {
Expand Down
14 changes: 2 additions & 12 deletions examples/layers/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,6 @@ if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

Expand All @@ -41,8 +31,8 @@ android {
applicationId "io.flutter.examples.layers"
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
versionCode flutter.versionCode()
versionName flutter.versionName()
}

buildTypes {
Expand Down
51 changes: 50 additions & 1 deletion packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ class FlutterExtension {

/** Allows to override the target file. Otherwise, the target is lib/main.dart. */
String target

/** The versionCode that was read from app's local.properties. */
String flutterVersionCode = null

/** The versionName that was read from app's local.properties. */
String flutterVersionName = null

/** Returns flutterVersionCode as an integer with error handling. */
Integer versionCode() {
if (flutterVersionCode == null) {
throw new GradleException("flutterVersionCode must not be null.")
}

if (!flutterVersionCode.isNumber()) {
throw new GradleException("flutterVersionCode must be an integer.")
}

return flutterVersionCode.toInteger()
}

/** Returns flutterVersionName with error handling. */
String versionName() {
if (flutterVersionName == null) {
throw new GradleException("flutterVersionName must not be null.")
}

return flutterVersionName
}
}

// This buildscript block supplies dependencies for this file's own import
Expand Down Expand Up @@ -226,7 +254,28 @@ class FlutterPlugin implements Plugin<Project> {
// Load shared gradle functions
project.apply from: Paths.get(flutterRoot.absolutePath, "packages", "flutter_tools", "gradle", "src", "main", "groovy", "native_plugin_loader.groovy")

project.extensions.create("flutter", FlutterExtension)
def extension = project.extensions.create("flutter", FlutterExtension)
def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader("UTF-8") { reader ->
localProperties.load(reader)
}
}

def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "1"
}
extension.flutterVersionCode = flutterVersionCode


def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0"
}
extension.flutterVersionName = flutterVersionName

this.addFlutterTasks(project)

// By default, assembling APKs generates fat APKs if multiple platforms are passed.
Expand Down

0 comments on commit fd827e3

Please sign in to comment.