速记:Flutter构建Android版 2019-8-12 20:03:53

详细的步骤及解释参见Flutter中文网 - 发布Android版APP

以下步骤为精简版,适合新项目快速打包看效果(本文所有路径均基于项目的根目录)

改App名

/android/app/src/main/AndroidManifest.xml文件的application标签的android:label属性

App签名

创建keystore(若创建过则跳过)

keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

引用

创建/android/key.properties文件,写入内容

storePassword=<password from previous step>
keyPassword=<password from previous step>
keyAlias=key
storeFile=<location of the key store file, e.g. /Users/<user name>/key.jks>

gradle中使用签名

编辑/android/app/build.gradle

android字段前,加上

def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

另外,将

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.debug
  }
}

替换成

signingConfigs {
  release {
    keyAlias keystoreProperties['keyAlias']
    keyPassword keystoreProperties['keyPassword']
    storeFile file(keystoreProperties['storeFile'])
    storePassword keystoreProperties['storePassword']
  }
}
buildTypes {
  release {
    signingConfig signingConfigs.release
  }
}

配置混淆

创建/android/app/proguard-rules.pro文件,写入内容

#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.**  { *; }
-keep class io.flutter.util.**  { *; }
-keep class io.flutter.view.**  { *; }
-keep class io.flutter.**  { *; }
-keep class io.flutter.plugins.**  { *; }

开启混淆

再次编辑/android/app/build.gradlebuildTyperelease字段追加三个属性

android {
  ...
  buildTypes {
    release {
      signingConfig signingConfigs.release

      minifyEnabled true
      useProguard true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

构建

flutter build apk

问题总结

如果按照以上配置,可能会抛出以下错误

You are building a fat APK that includes binaries for android-arm, android-arm64.
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
        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 --split-per-abi
        Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split
Initializing gradle...                                              0.8s
Resolving dependencies...                                           6.9s
Running Gradle task 'assembleRelease'...
Calling mockable JAR artifact transform to create file: /Users/felbry/.gradle/caches/transforms-1/files-1.1/android.jar/a6b225094d3119968dd2814a7b6bcc04/android.jar with input /Users/felbry/Library/Android/sdk/platforms/android-28/android.jar
Request to incrementing alive workforce from 0. Current workforce (dead or alive) 0
thread-pool size=4
ProGuard, version 6.0.3
Reading input...
Reading program jar [/Users/felbry/.gradle/caches/transforms-1/files-1.1/flutter.jar/2e0236f2735369a254884fe908b3e7fc/jetified-flutter.jar] (filtered)
Reading program jar [/Users/felbry/b/first/build/app/intermediates/flutter/release/libs.jar] (filtered)
Reading program directory [/Users/felbry/b/first/build/app/intermediates/javac/release/compileReleaseJavaWithJavac/classes] (filtered)
Reading program jar [/Users/felbry/b/first/build/app/intermediates/transforms/mergeJavaRes/release/0.jar] (filtered)
Reading library jar [/Users/felbry/Library/Android/sdk/platforms/android-28/android.jar]
Reading library jar [/Users/felbry/Library/Android/sdk/build-tools/28.0.3/core-lambda-stubs.jar]
Reading library jar [/Users/felbry/Library/Android/sdk/platforms/android-28/optional/org.apache.http.legacy.jar]
Reading library jar [/Users/felbry/Library/Android/sdk/platforms/android-28/optional/android.test.mock.jar]
Reading library jar [/Users/felbry/Library/Android/sdk/platforms/android-28/optional/android.test.base.jar]
Reading library jar [/Users/felbry/Library/Android/sdk/platforms/android-28/optional/android.test.runner.jar]
Initializing...
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'void setContentView(android.view.View)' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.view.Window getWindow()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'void addContentView(android.view.View,android.view.ViewGroup$LayoutParams)' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.res.Resources$Theme getTheme()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.res.Resources getResources()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'androidx.fragment.app.FragmentManager getSupportFragmentManager()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.Intent getIntent()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.Context getApplicationContext()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.pm.PackageManager getPackageManager()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.ComponentName getComponentName()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterActivity: can't find referenced method 'android.content.pm.ApplicationInfo getApplicationInfo()' in program class io.flutter.embedding.android.FlutterActivity
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'void setArguments(android.os.Bundle)' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'androidx.fragment.app.FragmentActivity getActivity()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'androidx.lifecycle.Lifecycle getLifecycle()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'android.os.Bundle getArguments()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'android.content.Context getContext()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment: can't find referenced method 'android.content.res.Resources getResources()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment$1: can't find referenced method 'androidx.fragment.app.FragmentActivity getActivity()' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.android.FlutterFragment$Builder: can't find referenced method 'void setArguments(android.os.Bundle)' in program class io.flutter.embedding.android.FlutterFragment
Warning: io.flutter.embedding.engine.FlutterEngineAndroidLifecycle: can't find referenced method 'void markState(androidx.lifecycle.Lifecycle$State)' in program class io.flutter.embedding.engine.FlutterEngineAndroidLifecycle
Note: io.flutter.view.AccessibilityViewEmbedder$ReflectionAccessors: can't find dynamically referenced class android.util.LongArray
Note: there were 1 unresolved dynamic references to classes or interfaces.
      You should check if you need to specify additional program jars.
      (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Warning: Exception while processing task java.io.IOException: Please correct the above warnings first.
Thread(Tasks limiter_1): destruction
Warning: there were 20 unresolved references to program class members.
         Your input classes appear to be inconsistent.
         You may need to recompile the code.
         (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
> Job failed, see logs for details

* Try:
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 2m 16s
Running Gradle task 'assembleRelease'...
Running Gradle task 'assembleRelease'... Done                     137.0s (!)
*******************************************************************************************
The Gradle failure may have been because of AndroidX incompatibilities in this Flutter app.
See https://goo.gl/CP92wY for more information on the problem and how to fix it.
*******************************************************************************************
Gradle task assembleRelease failed with exit code 1

解决方案就是再次编辑/android/app/build.gradlebuildTyperelease字段追加一个对象,最终如下效果

android {
  ...
  buildTypes {
    release {
      signingConfig signingConfigs.release

      minifyEnabled true
      useProguard true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

      dependencies {
        implementation 'com.android.support:support-fragment:28.0.0'
      }
    }
  }
}

相关解释:

The Flutter Android Java code contains references to the Android fragment support library. But the default template Flutter app does not use fragments, so the template build.gradle script does not link in the fragment support library in order to reduce APK binary size.

However, Proguard will scan all the classes in the app and will generate the errors seen above unless it can find the fragment support classes.

You may need to declare a different dependency if you app uses the AndroidX libraries instead of support-fragment.