配置Flutter开发环境
参考 在macOS Catalina(10.15.5)上搭建Flutter开发环境
新建Android工程
手动集成
如果想要在不使用 Flutter 的 Android Studio 插件的情况下手动将 Flutter 模块与现有的 Android 应用集成,可以参考以下步骤:
创建 Flutter 模块
假设你在 ~/Source/MyApplication6
路径下已有一个 Android 应用,并且你希望 Flutter 项目作为同级项目:
1 2 3 |
$ cd ~/Source/MyApplication6 $ flutter create -t module --org com.example my_flutter |
完成后的工程目录如下:
如果编译的时候报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
FAILURE: Build failed with an exception. * Where: Build file '~/Source/MyApplication6/app/build.gradle' line: 2 * What went wrong: An exception occurred applying plugin request [id: 'com.android.application'] > Failed to apply plugin 'com.android.internal.application'. > Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8. You can try some of the following options: - changing the IDE settings. - changing the JAVA_HOME environment variable. - changing `org.gradle.java.home` in `gradle.properties`. * 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 |
原因为Java版本问题,可以执行如下操作调整Java版本。
接下来,配置原来项目的 settings.gradle 增加如下内容:
1 2 3 4 5 |
setBinding(new Binding([gradle: this])) // new evaluate(new File( // new settingsDir.absoluteFile, // new 'my_flutter/.android/include_flutter.groovy' // new )) |
修改后的结果如下图:
如果编译的时候报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
FAILURE: Build failed with an exception. * Where: Script '~/Android/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 159 * What went wrong: A problem occurred evaluating script. > Failed to apply plugin class 'FlutterPlugin'. > Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by plugin class 'FlutterPlugin' * 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 |
则删除或注释掉原来的 settings.gradle 中的内容:
1 2 3 4 5 6 7 8 |
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() jcenter() // Warning: this repository is going to shut down soon } } |
最后的结果如下图:
接下来在原来项目的 build.gradle 中增加配置
1 |
implementation project(':flutter') |
最后的结果如图:
如果编译的时候报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Failed to resolve: androidx.appcompat:appcompat:1.4.0 Add Google Maven repository and sync project Show in Project Structure dialog Affected Modules: app Failed to resolve: junit:junit:4.+ Show in Project Structure dialog Affected Modules: app Failed to resolve: com.google.android.material:material:1.4.0 Add Google Maven repository and sync project Show in Project Structure dialog Affected Modules: app Failed to resolve: androidx.test.ext:junit:1.1.3 Add Google Maven repository and sync project Show in Project Structure dialog Affected Modules: app Failed to resolve: androidx.test.espresso:espresso-core:3.4.0 Add Google Maven repository and sync project Show in Project Structure dialog Affected Modules: app Failed to resolve: androidx.constraintlayout:constraintlayout:2.1.2 Add Google Maven repository and sync project Show in Project Structure dialog Affected Modules: app |
则在项目的根 build.gradle 的尾部增加maven配置:
1 2 3 4 5 6 |
allprojects { repositories { google() mavenCentral() } } |
调整后的代码如下:
预热FlutterEngine
创建自定义Application
源代码如下:
配置AndroidManifest.xml,增加自定义的类的引用
预热Flutter引擎
在我们刚刚新建的MyApplication.java中增加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * 初始化 FlutterEngine * * @param context 上下文 * @param routes 路由名称列表 */ private void initFlutterEngine(@NonNull final Context context, @NonNull final List<String> routes) { for (String route : routes) { final FlutterEngine flutterEngine = new FlutterEngine(context, null, false); flutterEngine.getDartExecutor().executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ); // 使用路由名称作为 engineId FlutterEngineCache.getInstance().put(route, flutterEngine); } } |
添加的效果如下图:
具体的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.mobibrw.example.myapplication; import android.app.Application; import android.content.Context; import androidx.annotation.NonNull; import java.util.ArrayList; import java.util.List; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngineCache; import io.flutter.embedding.engine.dart.DartExecutor; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); final List<String> routes = new ArrayList<>(); routes.add("flutter_engine"); initFlutterEngine(this, routes); } /** * 初始化 FlutterEngine * * @param context 上下文 * @param routes 路由名称列表 */ private void initFlutterEngine(@NonNull final Context context, @NonNull final List<String> routes) { for (String route : routes) { final FlutterEngine flutterEngine = new FlutterEngine(context, null, false); flutterEngine.getDartExecutor().executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ); // 使用路由名称作为 engineId FlutterEngineCache.getInstance().put(route, flutterEngine); } } } |
代码混淆,符号分离
在实际开发过程中,我们打包出的代码需要进行混淆(obfuscate),同时为了缩小应用下载大小,需要进行符号分离(split-debug-info)。
在 gradle.properties 增加参数:
1 2 3 4 5 |
extra-gen-snapshot-options=--obfuscate,--save-obfuscation-map=maps.json split-debug-info=symbols dart-obfuscation=true |
效果如下图:
最后生成的文件在 my_flutter 目录下。
对于 iOS 来说,可以通过在 iOS 的 Release.xcconfig 里增加
1 2 |
DART_OBFUSCATION=true SPLIT_DEBUG_INFO=misc/mapping/1.0.0 |
来实现代码混淆,如下图:
上面的配置对于通过 Add Flutter to existing app 实现集成的项目意义较大,可以在原项目的构建流程中自动集成混淆功能。
也可以通过命令行实现代码混淆功能,如下:
1 |
$ flutter build ios --obfuscate --split-debug-info=debug-info |
更详细的参考 Obfuscating Dart Code。
注意,官方版本的引擎已经实现符号分离,因此再次被压缩的空间已经不大。
一般情况下我们使用的是官方版本的引擎,如果需要调试 libflutter.so里面的符号,可以在flutter_infra页面直接下载带有符号表的SO文件,根据打包时使用的Flutter工具版本下载对应的文件即可。
比如2.8.1版本:
1 2 3 4 5 6 7 8 |
$ flutter --version # version命令可以看到Engine对应的版本 06afdfe54e Flutter 2.8.1 • channel stable • https://github.com/flutter/flutter.git Framework • revision 77d935af4d (3 周前) • 2021-12-16 08:37:33 -0800 Engine • revision 890a5fca2e Tools • Dart 2.15.1 $ cat `dirname $(which flutter)`/internal/engine.version # flutter安装目录下的engine.version文件也可以看到完整的版本信息 890a5fca2e34db413be624fc83aeea8e61d42ce6 890a5fca2e34db413be624fc83aeea8e61d42ce6 |
拿到引擎版本号后在https://console.cloud.google.com/storage/browser/flutter_infra_release/flutter/890a5fca2e34db413be624fc83aeea8e61d42ce6/ 看到该版本对应的所有构建产物,下载android-arm-release、android-arm64-release和android-x86目录下的symbols.zip。
参考链接
- android studio - Execution failed for task ':app:checkDebugAarMetadata'
- 将 Flutter module 集成到 Android 项目
- Android基础之自定义Application
- 集成Flutter到现有项目,并实现使用单个FlutterEngine管理多个入口
- 控制加载顺序,优化性能与内存
- 多个 Flutter 页面或视图
- 在 Android 应用中添加 Flutter 页面
- Flutter 镜像安装帮助
- Flutter的原理及美团的实践(中)
- Crashes - flutter/flutter Wiki Symbolicating stack traces for engine crashes
- Symbolicating stack traces for engine crashes
- 从0到1,本地编译FlutterEngine
- Obfuscating Dart Code
- How to obfuscate Flutter apps?