Issue building Flutter android APK with MS AppCenter using flavors

1,289

I had the same issue while using AppCenter, and I came across this answer that show the problem is caused by some build steps in gradle and that it is recommended to have a lib/main.dart in your project.

So I solved the problem by using the lib/main.dart to build the production version. The only file to change is the appcenter-post-clone.sh

Here's a look at my appcenter-post-clone.sh:

#!/usr/bin/env bash
# place this script in project/android/app/
cd ..
# fail if any command fails
set -e
# debug log
set -x

cd ..
# choose a different release channel if you want - https://github.com/flutter/flutter/wiki/Flutter-build-release-channels
# stable - recommended for production

git clone -b stable https://github.com/flutter/flutter.git
export PATH=`pwd`/flutter/bin:$PATH

echo "Building with flavor $FLAVOR"

target="lib/main.dart"
if [ "$FLAVOR" == "qa" ]; then
    target="lib/main_qa.dart";
elif [ "$FLAVOR" == "prod" ]; then
    target="lib/main.dart";
fi

echo "using entrypoint: $target"

flutter channel stable
flutter doctor
flutter pub get
flutter pub run build_runner build
flutter build apk --release --dart-define=API_KEY=$API_KEY --dart-define=FLAVOR=$FLAVOR --flavor $FLAVOR -t $target

# change apk file name
mv build/app/outputs/flutter-apk/app-$FLAVOR-release.apk build/app/outputs/flutter-apk/wfm.apk

# copy the APK where AppCenter will find it
mkdir -p android/app/build/outputs/apk/; mv build/app/outputs/flutter-apk/wfm.apk $_
Share:
1,289
cmpbedes
Author by

cmpbedes

Updated on December 24, 2022

Comments

  • cmpbedes
    cmpbedes over 1 year

    I've been following a combination of articles to attempt to build Flutter apps on MS Appcenter using flavors to achieve app environments (i.e. dev/test/live).

    To achieve this, i'm using the separate main-<environment>.dart entry file approach as shown in this article and followed this article for configuring Appcenter.

    I'm having issues with the build of the android apk because the main.dart is missing. I thought that passing the -t parameter to the build command would handle this?

    I'll add the build scripts and logs below but the flutter command being executed is this: flutter build apk --flavor dev --release -t lib/main_dev_test.dart

    The flutter build apk command seems to complete fine, however the build fails at the gradle task step with this error message:

    Task :app:compileFlutterBuildDevRelease FAILED
    12 actionable tasks: 2 executed, 10 up-to-date
    Error: Error when reading 'lib/main.dart': No such file or directory
    package:hello_world/main.dart: Error: No 'main' method found.
    Try adding a method named 'main' to your program.
    
    
    FAILURE: Build failed with an exception.
    
    * Where:
    Script '/Users/runner/work/1/s/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 904
    
    * What went wrong:
    Execution failed for task ':app:compileFlutterBuildDevRelease'.
    > Process 'command '/Users/runner/work/1/s/flutter/bin/flutter'' finished with non-zero exit value 1
    

    output when running locally on windows:

    flutter build apk --flavor dev --release -t lib/main_dev_test.dart
    You are building a fat APK that includes binaries for android-arm, android-arm64, android-x64.
    If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
        To generate an app bundle, run:
            flutter build appbundle --target-platform android-arm,android-arm64,android-x64
            Learn more on: https://developer.android.com/guide/app-bundle
        To split the APKs per ABI, run:
            flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
            Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split
    Running Gradle task 'assembleDevRelease'...
    Note: Some input files use unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    Calling mockable JAR artifact transform to create file: C:\Users\_USERFOLDER_\.gradle\caches\transforms-2\files-2.1\5760bf626ba5c024071f2e9f16ccfcc3\android.jar with input C:\Users\_USERFOLDER_\AppData\Local\Android\Sdk\platforms\android-28\android.jar
    Calling mockable JAR artifact transform to create file: C:\Users\_USERFOLDER_\.gradle\caches\transforms-2\files-2.1\08efdfe0d8cf00cccc6a03622959e0ad\android.jar with input C:\Users\_USERFOLDER_\AppData\Local\Android\Sdk\platforms\android-28\android.jar
    Calling mockable JAR artifact transform to create file: C:\Users\_USERFOLDER_\.gradle\caches\transforms-2\files-2.1\1a859f032ea56da6fdcf4706b3d23efa\android.jar with input C:\Users\_USERFOLDER_\AppData\Local\Android\Sdk\platforms\android-29\android.jar
    Removed unused resources: Binary resource data reduced from 759KB to 728KB: Removed 4%
    Running Gradle task 'assembleDevRelease'...
    Running Gradle task 'assembleDevRelease'... Done                  270.2s (!)
    √ Built build\app\outputs\flutter-apk\app-dev-release.apk (21.0MB).
    

    AppCenter Build Variant - devRelease (specified on the webUI)

    appcenter-post-clone.sh:

    #!/usr/bin/env bash
    # place this script in project/android/app/
    cd ..
    # fail if any command fails
    set -e
    # debug log
    set -x
    
    #print appcenter's output folder
    echo "!~! Appcenter output: $APPCENTER_OUTPUT_DIRECTORY"
    
    #print app flavour specified
    echo "Building app for $APP_ENV flavour"
    
    entrypoint="placeholder_to_replace.dart"
    
    #set target main<>.dart file
    if [ "$APP_ENV" == "dev" ]; then
        entrypoint="main_dev_test.dart";
    elif [ "$APP_ENV" == "beta" ]; then
        entrypoint="main_beta.dart";
    elif [ "$APP_ENV" == "prod" ]; then
        entrypoint="main_release.dart";
    fi
    
    echo "using entrypoint: $entrypoint"
    
    cd ..
    # choose a different release channel if you want - https://github.com/flutter/flutter/wiki/Flutter-build-release-channels
    # stable - recommended for production
    
    git clone -b stable https://github.com/flutter/flutter.git
    export PATH=`pwd`/flutter/bin:$PATH
    
    flutter channel beta
    flutter upgrade
    flutter doctor
    flutter build apk --release --flavor dev -t lib/$entrypoint
    
    # copy the APK where AppCenter will find it
    mkdir -p android/app/build/outputs/apk/; mv build/app/outputs/flutter-apk/app-$APP_ENV-release.apk $_
    

    android/app/build.gradle:

    def localProperties = new Properties()
    def localPropertiesFile = rootProject.file('local.properties')
    if (localPropertiesFile.exists()) {
        localPropertiesFile.withReader('UTF-8') { reader ->
            localProperties.load(reader)
        }
    }
    
    def flutterRoot = localProperties.getProperty('flutter.sdk')
    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 plugin: 'kotlin-android'
    apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
    
    android {
        compileSdkVersion 28
    
        sourceSets {
            main.java.srcDirs += 'src/main/kotlin'
        }
    
        lintOptions {
            disable 'InvalidPackage'
        }
    
        defaultConfig {
            // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
            applicationId "com.example.hello_world"
            minSdkVersion 21
            targetSdkVersion 28
            versionCode flutterVersionCode.toInteger()
            versionName flutterVersionName
        }
        signingConfigs {
            release {
                storeFile rootProject.file("app/android.keystore")
                storePassword System.getenv("APPCENTER_KEYSTORE_PASSWORD")
                keyAlias System.getenv("APPCENTER_KEY_ALIAS")
                keyPassword System.getenv("APPCENTER_KEY_PASSWORD")
            }
        }
        buildTypes {
            release {
                // TODO: Add your own signing config for the release build.
                // Signing with the debug keys for now, so `flutter run --release` works.
                signingConfig signingConfigs.release
            }
        }
        flavorDimensions "default"
        productFlavors {
            local {
                dimension "default"
                applicationIdSuffix ".dev"
            }
            dev {
                dimension "default"
                applicationIdSuffix ".dev"
            }
            beta {
                dimension "default"
                applicationIdSuffix ".beta"
            }
            prod {
                dimension "default"
            }
        }
    }
    
    flutter {
        source '../..'
    }
    
    dependencies {
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    }
    
    

    AppCenter build output:

    //---OMITTED TOOLING CLONING---
    
    Building flutter tool...
    Flutter is already up to date on channel beta
    Flutter 1.22.0-12.1.pre • channel beta • https://github.com/flutter/flutter.git
    Framework • revision 8b3760638a (8 days ago) • 2020-09-15 17:47:13 -0700
    Engine • revision 4654fc6cf6
    Tools • Dart 2.10.0 (build 2.10.0-110.3.beta)
    + flutter doctor
    Downloading Material fonts...                                       0.5s
    Downloading package sky_engine...                                   0.2s
    Downloading flutter_patched_sdk tools...                            0.7s
    Downloading flutter_patched_sdk_product tools...                    0.6s
    Downloading darwin-x64 tools...                                     1.6s
    Downloading libimobiledevice...                                     0.0s
    Downloading usbmuxd...                                              0.0s
    Downloading darwin-x64/font-subset tools...                         0.3s
    Downloading android-arm-profile/darwin-x64 tools...                 0.3s
    Downloading android-arm-release/darwin-x64 tools...                 0.2s
    Downloading android-arm64-profile/darwin-x64 tools...               0.3s
    Downloading android-arm64-release/darwin-x64 tools...               0.3s
    Downloading android-x64-profile/darwin-x64 tools...                 0.3s
    Downloading android-x64-release/darwin-x64 tools...                 0.3s
    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel beta, 1.22.0-12.1.pre, on Mac OS X 10.14.6 18G6020, locale en)
    [!] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
        ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
    [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
    [!] Android Studio (not installed)
    [!] Connected device
        ! No devices available
    
    ! Doctor found issues in 3 categories.
    + flutter build apk --flavor dev --release -t lib/main_dev_test.dart
    Running "flutter pub get" in s...                                   6.9s
    You are building a fat APK that includes binaries for android-arm, android-arm64, android-x64.
    If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
        To generate an app bundle, run:
            flutter build appbundle --target-platform android-arm,android-arm64,android-x64
            Learn more on: https://developer.android.com/guide/app-bundle
        To split the APKs per ABI, run:
            flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
            Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split
    Running Gradle task 'assembleDevRelease'...                     
    Gradle 5.6.2
    
    //---OMMITTED PACKAGE RESOLVE LINES---
    
    > Task :clean
    > Task :app:clean UP-TO-DATE
    > Task :barcode_scan:clean UP-TO-DATE
    > Task :camera:clean UP-TO-DATE
    > Task :device_info:clean UP-TO-DATE
    > Task :flutter_secure_storage:clean UP-TO-DATE
    > Task :package_info:clean UP-TO-DATE
    > Task :path_provider:clean UP-TO-DATE
    > Task :permission_handler:clean UP-TO-DATE
    > Task :shared_preferences:clean UP-TO-DATE
    > Task :sqflite:clean UP-TO-DATE
    
    > Task :app:compileFlutterBuildDevRelease FAILED
    Error: Error when reading 'lib/main.dart': No such file or directory
    package:hello_world/main.dart: Error: No 'main' method found.
    Try adding a method named 'main' to your program.
    
    
    FAILURE: Build failed with an exception.
    
    * Where:
    Script '/Users/runner/work/1/s/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 904
    
    * What went wrong:
    Execution failed for task ':app:compileFlutterBuildDevRelease'.
    > Process 'command '/Users/runner/work/1/s/flutter/bin/flutter'' finished with non-zero exit value 1
    
    * Try:
    12 actionable tasks: 2 executed, 10 up-to-date
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 6s
    Error: /Users/runner/work/1/s/android/gradlew failed with return code: 1
        at ChildProcess.<anonymous> (/Users/runner/work/_tasks/Gradle_8d8eebd8-2b94-4c97-85af-839254cc6da4/1.128.0/node_modules/vsts-task-lib/toolrunner.js:569:30)
        at emitTwo (events.js:106:13)
        at ChildProcess.emit (events.js:191:7)
        at maybeClose (internal/child_process.js:920:16)
        at Socket.<anonymous> (internal/child_process.js:351:11)
        at emitOne (events.js:96:13)
        at Socket.emit (events.js:188:7)
        at Pipe._handle.close [as _onclose] (net.js:509:12)
    ##[error]Error: /Users/runner/work/1/s/android/gradlew failed with return code: 1
    ##[section]Finishing: Gradle Task
    ##[section]Starting: Checkout YardAppFlutter@feature/switchable_build_configurations to s
    ==============================================================================
    Task         : Get sources
    Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
    Version      : 1.0.0
    Author       : Microsoft
    Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
    ==============================================================================
    Cleaning any cached credential from repository: YardAppFlutter (ExternalGit)
    ##[section]Finishing: Checkout YardAppFlutter@feature/switchable_build_configurations to s
    ##[section]Starting: Finalize Job
    Cleaning up task key
    Start cleaning up orphan processes.
    Terminate orphan process: pid (1609) (java)
    Terminate orphan process: pid (1550) (java)
    Terminate orphan process: pid (1428) (adb)
    ##[section]Finishing: Finalize Job
    ##[section]Finishing: Build
    
    • Phil Ives -Rain Everywhere
      Phil Ives -Rain Everywhere over 3 years
      I have the same issue. My script is quite similar. I'm looking for a way to set the entry point to the gradle build with no success.