如何在Android应用运行时嵌入外部来源的Flutter应用?
在Android应用中动态加载远程Flutter应用的可行方案
首先明确:完全可行,但原生FlutterActivity本身不支持直接加载远程zip包,需要手动实现下载、解压、自定义引擎初始化的流程,核心是利用Flutter的动态化能力加载指定路径的Flutter资源。
核心思路
Flutter应用运行依赖flutter_assets资源目录和对应的Native库(libflutter.so等),只要把远程下载的Flutter包解压到本地,再通过FlutterEngine指定自定义资源路径,就能在宿主应用中加载运行。
推荐实现步骤
1. 提前打包Flutter模块为可动态加载的包
将你的Flutter应用打包成包含完整运行资源的zip包:
- 执行
flutter build aar生成AAR,或者直接打包build/flutter_assets目录+对应的Native库(build/app/intermediates/merged_native_libs/release/out/lib下的so文件); - 确保打包的Flutter SDK版本和宿主Android应用的Flutter版本完全一致,否则会出现引擎兼容性崩溃。
2. 下载远程Flutter包到本地
用Android原生网络框架下载CDN上的zip文件:
- 推荐用
OkHttp或DownloadManager,下载到宿主应用的内部存储(比如context.filesDir,避免权限问题); - 加入下载进度监听、失败重试、文件校验(比如MD5)逻辑,确保下载的包完整。
3. 解压zip到指定目录
将下载的zip解压到本地固定路径,比如context.filesDir/flutter_dynamic,确保解压后目录结构如下:
flutter_dynamic/ ├─ flutter_assets/ # Flutter资源目录,包含dart代码快照、资源文件等 └─ lib/ ├─ arm64-v8a/ │ └─ libflutter.so # 对应架构的Flutter引擎库 └─ ... # 其他架构的so库(可选,按需打包)
4. 初始化FlutterEngine并加载动态模块
不要直接用FlutterActivity,手动创建FlutterEngine并指定自定义资源路径:
// 初始化FlutterEngine val flutterEngine = FlutterEngine(context) // 配置自定义资源路径,指向解压后的flutter_assets目录 val assetPath = File(context.filesDir, "flutter_dynamic/flutter_assets").absolutePath val customAssetManager = FlutterAssetManager(context.assets, assetPath) // 执行Dart入口点 flutterEngine.dartExecutor.executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() .setAssetManager(customAssetManager) ) // 将Flutter内容嵌入宿主Activity,用FlutterFragment或FlutterView supportFragmentManager.beginTransaction() .replace(R.id.flutter_container, FlutterFragment.withEngine(flutterEngine).build()) .commit()
5. 关键注意事项
- 版本一致性:宿主应用的Flutter SDK版本必须和远程Flutter模块的版本完全匹配,包括minor版本(比如3.10.0和3.10.1也可能不兼容);
- 插件依赖:如果Flutter模块用到了Native插件,宿主应用需要提前集成这些插件的依赖,否则会出现找不到方法的崩溃;
- 异常处理:添加解压失败、文件损坏、引擎初始化失败的捕获逻辑,给用户友好提示;
- 性能优化:可以缓存已下载的Flutter包,避免重复下载,同时校验版本号,有更新时再重新下载。
替代方案
如果需要更完善的动态化支持,可以考虑基于Flutter的add-to-app扩展方案,配合动态加载框架,但核心逻辑和上述步骤一致——都是通过自定义FlutterEngine加载本地路径的Flutter资源。
内容的提问来源于stack exchange,提问作者Endi
相关产品推荐
相关产品推荐

