###前言
前面介紹了Flutter中一些基本Widget的使用方法,下面我們來先下實戰中是如何構建生成Android包的,本文我們主要介紹純Flutter項目生成Android包的方法,以及遇到的問題
###正文
- 1、生成簽名文件
這個步驟對於一個Android開發來說應該是很簡單的,這裏我就不進行贅述,需要的小夥伴可以參考Android的簽名文件生成兩種方法
- 2、配置gradle文件
在/android/目錄下創建一個key.properties的文件,包含我們所需要一些內容,例如
storePassword="你簽名設置的密碼"
keyPassword="你簽名設置的密碼"
keyAlias="你簽名的別名"
storeFile="你的簽名文件存放的路徑"
在android/app/build.gradle文件中添加下面的信息
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()){
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android{
...
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
- 3、配置混淆
在/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.** { *; }
PS:之後需要混淆的庫都添加在這個文件中
然後在android/app/build.gradle文件中添加下面的信息
android {
...
buildTypes {
release {
signingConfig signingConfigs.release //使用正式release配置
minifyEnabled true //是否壓縮
useProguard true //打開混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //配置混淆文件
}
}
}
此時關於打包的前期配置就結束了,下面開始執行命令進行打包
- cd到工程目錄下
- flutter build apk
順利的話我們會看到如下內容
tianchibindeMacBook-Pro:flutter_build_apk tiancb$ flutter build apk
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
[!] Your app isn't using AndroidX.
To avoid potential build failures, you can quickly migrate your app by following the steps on https://goo.gl/CP92wY.
Removed unused resources: Binary resource data reduced from 44KB to 35KB: Removed 20%
Running Gradle task 'assembleRelease'...
Running Gradle task 'assembleRelease'... Done 47.0s
✓ Built build/app/outputs/apk/release/app-release.apk (15.3MB).
最後的build/app/outputs/apk/release/app-release.apk這是apk包的路徑。
上面我們說到,順利的話會直接生成apk包,現在我們來看下打包的過程中遇到的問題
Q1:ProcessException: Bad CPU type in executable
完整的日誌是
ProcessException: Bad CPU type in executable
Command: /Users/tiancb/Desktop/Android/flutter/bin/cache/artifacts/engine/android-arm-release/darwin-x64/gen_snapshot --causal_async_stacks --deterministic --snapshot_kind=app-aot-elf --elf=/Users/tiancb/Desktop/Flutter/flutter_build_apk/build/app/intermediates/flutter/release/android-arm/app.so --strip --no-sim-use-hardfp --no-use-integer-division /Users/tiancb/Desktop/Flutter/flutter_build_apk/build/app/intermediates/flutter/release/android-arm/app.dill
#0 runCommandAndStreamOutput (package:flutter_tools/src/base/process.dart:142:27)
<asynchronous suspension>
#1 GenSnapshot.run (package:flutter_tools/src/base/build.dart:75:12)
#2 AOTSnapshotter.build.<anonymous closure> (package:flutter_tools/src/base/build.dart:211:27)
#3 AOTSnapshotter._timedStep (package:flutter_tools/src/base/build.dart:344:33)
<asynchronous suspension>
#4 AOTSnapshotter.build (package:flutter_tools/src/base/build.dart:210:13)
<asynchronous suspension>
#5 BuildAotCommand.runCommand (package:flutter_tools/src/commands/build_aot.dart:149:56)
<asynchronous suspension>
#6 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:478:18)
<asynchronous suspension>
#7 FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:383:33)
<asynchronous suspension>
#8 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:29)
<asynchronous suspension>
#9 _rootRun (dart:async/zone.dart:1124:13)
#10 _CustomZone.run (dart:async/zone.dart:1021:19)
#11 _runZoned (dart:async/zone.dart:1516:10)
#12 runZoned (dart:async/zone.dart:1463:12)
#13 AppContext.run (package:flutter_tools/src/base/context.dart:152:18)
<asynchronous suspension>
#14 FlutterCommand.run (package:flutter_tools/src/runner/flutter_command.dart:375:20)
#15 CommandRunner.runCommand (package:args/command_runner.dart:197:27)
<asynchronous suspension>
#16 FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:396:21)
<asynchronous suspension>
#17 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:29)
<asynchronous suspension>
#18 _rootRun (dart:async/zone.dart:1124:13)
#19 _CustomZone.run (dart:async/zone.dart:1021:19)
#20 _runZoned (dart:async/zone.dart:1516:10)
#21 runZoned (dart:async/zone.dart:1463:12)
#22 AppContext.run (package:flutter_tools/src/base/context.dart:152:18)
<asynchronous suspension>
#23 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:356:19)
<asynchronous suspension>
#24 CommandRunner.run.<anonymous closure> (package:args/command_runner.dart:112:25)
#25 new Future.sync (dart:async/future.dart:224:31)
#26 CommandRunner.run (package:args/command_runner.dart:112:14)
#27 FlutterCommandRunner.run (package:flutter_tools/src/runner/flutter_command_runner.dart:242:18)
#28 run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:22)
<asynchronous suspension>
#29 _rootRun (dart:async/zone.dart:1124:13)
#30 _CustomZone.run (dart:async/zone.dart:1021:19)
#31 _runZoned (dart:async/zone.dart:1516:10)
#32 runZoned (dart:async/zone.dart:1500:12)
#33 run.<anonymous closure> (package:flutter_tools/runner.dart:60:18)
<asynchronous suspension>
#34 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:29)
<asynchronous suspension>
#35 _rootRun (dart:async/zone.dart:1124:13)
#36 _CustomZone.run (dart:async/zone.dart:1021:19)
#37 _runZoned (dart:async/zone.dart:1516:10)
#38 runZoned (dart:async/zone.dart:1463:12)
#39 AppContext.run (package:flutter_tools/src/base/context.dart:152:18)
<asynchronous suspension>
#40 runInContext (package:flutter_tools/src/context_runner.dart:56:24)
<asynchronous suspension>
#41 run (package:flutter_tools/runner.dart:51:10)
#42 main (package:flutter_tools/executable.dart:62:9)
<asynchronous suspension>
#43 main (file:///Users/tiancb/Desktop/Android/flutter/packages/flutter_tools/bin/flutter_tools.dart:8:3)
#44 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:299:32)
#45 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
FAILURE: Build failed with an exception.
* Where:
Script '/Users/tiancb/Desktop/Android/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 638
* What went wrong:
Execution failed for task ':app:compileflutterBuildReleaseArm'.
> Process 'command '/Users/tiancb/Desktop/Android/flutter/bin/flutter'' finished with non-zero exit value 1
* 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.
解決方法-執行下面的
flutter doctor --android-licenses
執行完之後會有一個
Accept? (y/N):
直接選擇y就行了
Q2 - Could not download …
完整的錯誤日誌是
Could not resolve all files for configuration ':app:releaseCompileClasspath'.
> Could not download armeabi_v7a_release.jar (io.flutter:armeabi_v7a_release:1.0.0-af04338413c3ed73316350f64248a152433073b6)
> Could not get resource 'http://download.flutter.io/io/flutter/armeabi_v7a_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/armeabi_v7a_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar'.
> Could not HEAD 'http://download.flutter.io/io/flutter/armeabi_v7a_release/1.0.0-af04338413c3ed73316350f64248a152433073b6/armeabi_v7a_release-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar'.
> Connect to download.flutter.io:80 [download.flutter.io/172.217.160.80, download.flutter.io/2404:6800:4012:0:0:0:0:2010] failed: No route to host (connect failed)
* 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.
* What went wrong:
Execution failed for task ':app:lintVitalRelease'.
> Could not resolve all artifacts for configuration ':app:profileRuntimeClasspath'.
> Could not download arm64_v8a_profile.jar (io.flutter:arm64_v8a_profile:1.0.0-af04338413c3ed73316350f64248a152433073b6)
> Could not get resource 'http://download.flutter.io/io/flutter/arm64_v8a_profile/1.0.0-af04338413c3ed73316350f64248a152433073b6/arm64_v8a_profile-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar'.
> Could not GET 'http://download.flutter.io/io/flutter/arm64_v8a_profile/1.0.0-af04338413c3ed73316350f64248a152433073b6/arm64_v8a_profile-1.0.0-af04338413c3ed73316350f64248a152433073b6.jar'.
> Read timed out
* 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.
解決方案
翻牆 - 你懂的
結語
截止到這裏,純Flutter項目的打包過程就講述完了。
以下是我的Flutter系列的鏈接,後續會持續更新,歡迎大家指正。
Flutter 系列文章
- Flutter 學習 - 開篇
- Flutter 學習 - 基礎框架
- Flutter 學習 - 網絡請求和數據解析
- Flutter 學習 - Widget 之 Text
- Flutter 學習 - Widget 之 RichText
- Flutter 學習 - Widget 之 Image和Icon
- Flutter 學習 - Widget 之 TextField
- Flutter 學習 - Widget 之 菜單按鈕
- Flutter 學習 - Widget 之 佈局 Widget
- Flutter 學習 - 容器類Widget
- Flutter 學習 - 可滾動的 Widget
- Flutter 學習 - 功能類Widget
更多關於技術相關的內容請關注博主公衆號–迷途程序猿