Flutter Engine 自定义三部曲

1,855 阅读4分钟

准备工作

本机环境: macos , Fluttr 2.5

代理配置

  • Git代理配置

Git代理配置一般需要两种,第一种是走http协议的代理,第二种是走ssh协议代理

http代理(注意最后的1087端口,根据你的梯子的端口去配置)
git config --global http.proxy http://127.0.0.1:1087
git config --global https.proxy http://127.0.0.1:1087

如果要取消http代理
git config --global --unset http.proxy
git config --global --unset https.proxy

加上http代理后,内网很可能无法访问,加上如下配置
export no_proxy="127.0.0.1,localhost,xxxx"(xxx是内网git域名)

ssh代理
open ~/.ssh/config
文件里增加
Host github.com
   HostName github.com
   User git
   # 注意这里的1080端口,如 Shadowsocks,v2ray,根据自己的梯子端口配置)
   ProxyCommand nc -v -x 127.0.0.1:1080 %h %p
  • 终端代理配置(这是临时配置)
export http_proxy=http://127.0.0.1:1087
export https_proxy=http://127.0.0.1:1087

depot_tools工具安装

windows或者Linux 参考官网

1. mac或者linux环境
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

配置环境变量
export PATH="$PATH:/path/to/depot_tools"

获取源码

官方参考文档

构建前的配置

创建目录
mkdir -p flutter_engine/engine_251
cd flutter_engine/engine_251
创建gclient配置文件
[参考地址](https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/HEAD/README.gclient.md)

在上一步创建的目录中执行 touch .gclient
把以下的内容复制粘贴到.gclient文件中
solutions = [
  {
    "managed": False,
    "name": "src/flutter",
    "url": "git@github.com:flutter/engine.git",
    "custom_deps": {},
    "deps_file": "DEPS",
    "safesync_url": "",
  },
]

接着执行gclient sync

如果需要拉取指定版本的源码,例如文章中是Flutter 2.5.1版本,commitId是b3af521a050e6ef076778bcaf16e27b2521df8f8,那就参考下面的配置

引擎版本在这个文件:your_flutter_path/flutter/bin/internal/engine_version

solutions = [
  {
    "managed": False,
    "name": "src/flutter",
    "url": "git@github.com:flutter/engine.git@b3af521a050e6ef076778bcaf16e27b2521df8f8",
    "custom_deps": {},
    "deps_file": "DEPS",
    "safesync_url": "",
  },
]

如果之前已经同步过了,需要先回退到之前的提交,然后执行同步

//b3af521a050e6ef076778bcaf16e27b2521df8f8 就是flutter 2.5.1的版本
git reset --hard b3af521a050e6ef076778bcaf16e27b2521df8f8
gclient sync --with_branch_heads --with_tags --verbose

编译可debug的引擎产物

官方参考文档

编译过程中如果出现类似的错误,TypeError: expected str, bytes or os.PathLike object, not NoneType 需要python3,本机环境是pyrhon 3.8.7

以Android arm64产物为例

cd your_local_engine_path/flutter_engine/engine_251/src
./flutter/tools/gn --android --android-cpu arm64 --unoptimized
ninja -C out/android_debug_unopt_arm64/ -j 8
./flutter/tools/gn --android-cpu arm64 --unoptimized
ninja -C out/host_debug_unopt_arm64/ -j 8

编译完成之后使用本地引擎的产物

flutter build apk --debug --target-platform=android-arm64

--local-engine-src-path=your_engine_path/engine/src 

--local-engine=android_debug_unopt_arm64

或者直接使用flutter的build方式

flutter build apk --local-engine=android_debug_unopt --local-engine-src-path=/engine/src

gn的其他命令参考如下

gn -h 参数如下
usage: gn [-h] [--unoptimized]
          [--runtime-mode {debug,profile,release,jit_release}] [--interpreter]
          [--dart-debug] [--full-dart-debug]
          [--target-os {android,ios,linux,fuchsia}] [--android]
          [--android-cpu {arm,x64,x86,arm64}] [--ios] [--ios-cpu {arm,arm64}]
          [--simulator] [--fuchsia] [--linux-cpu {x64,x86,arm64,arm}]
          [--fuchsia-cpu {x64,arm64}] [--arm-float-abi {hard,soft,softfp}]
          [--goma] [--no-goma] [--lto] [--no-lto] [--clang] [--no-clang]
          [--clang-static-analyzer] [--no-clang-static-analyzer]
          [--target-sysroot TARGET_SYSROOT]
          [--target-toolchain TARGET_TOOLCHAIN]
          [--target-triple TARGET_TRIPLE]
          [--operator-new-alignment OPERATOR_NEW_ALIGNMENT] [--enable-vulkan]
          [--enable-fontconfig] [--enable-skshaper]
          [--enable-vulkan-validation-layers] [--embedder-for-target]
          [--coverage] [--out-dir OUT_DIR] [--full-dart-sdk]
          [--no-full-dart-sdk] [--ide IDE] [--build-glfw-shell] [--bitcode]
          [--stripped]
我们使用到的构建参数主要有以下几种
--android 指定android平台
--ios 指定ios平台
--runtime-mode debug,profile,release
--unoptimized 默认是optimized优化过的
--android-cpu {arm,x64,x86,arm64} 默认是arm(对应arm-v7)
--ios --ios-cpu {arm,arm64}
构建其他Android可debug产物
Android的arm的debug优化版
cd src/
./flutter/tools/gn --android 
ninja -C out/android_debug -j 8
./flutter/tools/gn 
ninja -C out/host_debug -j 8
Android x64的profile非优化版
cd src/
./flutter/tools/gn --android --android-cpu x64 --unoptimized --runtime-mode=profile
ninja -C out/android_profile_unopt_x64 -j 8
./flutter/tools/gn --android-cpu x64 --unoptimized --runtime-mode=profile
ninja -C out/host_profile_unopt_x64 -j 8
构建IOS可debug产物
iOS arm64未优化debug版本
cd /engine/src/
./flutter/tools/gn --ios --unoptimized --runtime-mode=debug
ninja -C out/ios_debug_unopt -j 8
./flutter/tools/gn --unoptimized --runtime-mode=debug
ninja -C out/host_debug_unopt -j 8

构建正式产物,替换本地引擎

第一步

cd your_local_engine_path/flutter_engine/engine_251/src

下面的步骤都不包含x86 第二步 调用gn生成ninjia配置文件

./flutter/tools/gn --runtime-mode=debug --android-cpu=arm --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=profile --android-cpu=arm --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=release --android-cpu=arm --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=debug --android-cpu=arm64 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=profile --android-cpu=arm64 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=release --android-cpu=arm64 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=debug --android-cpu=x64 --android --no-goma --no-dart-version-git-info 
./flutter/tools/gn --runtime-mode=profile --android-cpu=x64 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=release --android-cpu=x64 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=debug --android-cpu=x86 --android --no-goma --no-dart-version-git-info
./flutter/tools/gn --runtime-mode=jit_release --android-cpu=x86 --android --no-goma --no-dart-version-git-info

第三步,执行前最好先clean

ninja -C out/android_debug -t clean
ninja -C out/android_profile -t clean
ninja -C out/android_release -t clean
ninja -C out/android_debug_arm64 -t clean
ninja -C out/android_profile_arm64 -t clean
ninja -C out/android_release_arm64 -t clean
ninja -C out/android_debug_x64 -t clean
ninja -C out/android_profile_x64 -t clean
ninja -C out/android_release_x64 -t clean
ninja -C out/android_debug_x86 -t clean
ninja -C out/android_jit_release_x86 -t clean

第4步,执行具体的构建,这部分非常耗时,平均每个类型占用1.5G到2.3G左右,总共在16个G左右,所以预先留好磁盘空间

ninja -C out/android_debug -j 8
ninja -C out/android_profile -j 8
ninja -C out/android_release -j 8
ninja -C out/android_debug_arm64 -j 8  
ninja -C out/android_profile_arm64 -j 8
ninja -C out/android_release_arm64 -j 8
ninja -C out/android_debug_x64 -j 8
ninja -C out/android_profile_x64 -j 8
ninja -C out/android_release_x64 -j 8
ninja -C out/android_debug_x86 -j 8
ninja -C out/android_jit_release_x86 -j 8

构建完后AOT产物截图如下

引擎AOT产物.png 遗留问题,mac编译x86问题:github.com/flutter/flu… 简单解释下,从xcode10开始就放弃了 i386 toolchain,本机环境没有相关工具,解决方式是用windows或者linux编译,不过对于端上来说,基本上用不到x86了

产物归档和说明 官方文档

我们要收集哪些产物? 从架构模式分类看:

  •   arm:arm,arm-profile,arm-release,arm64,arm64-profile,arm64-release(真机上跑必须的)
    
  •   x86:android-x86,android-x86-jit-release
    
  •   x64:android-x64,android-x64-profile,android-x64-release
    

其中arm是我们跑真机必须的,Android中armeabi-v7a对应的就是这里的arm,arm64-v8a对应的就是arm64,而debug、profile、release就是flutter编译对应的三种模式。 至于x86和x64主要是模拟器在使用,这个根据自己项目的情况选择

从具体的产物看,主要有以下几种:

  • flutter.jar: 这个编译后最终的产物,其中包含引擎java代码的class文件和libflutter.so
  • gen_snapshot: 宿主端产物,在mac上跑就要编译mac产物,在Linux上跑就要在Linux上编译产物,官方文档对其解释的是 将 Dart 代码转换为特定于架构的 AOT 指令的二进制文件称为 gen_snapshot,其实就是对应平台的二进制执行文件
  • 符号表产物:libflutter.so和libflutter.so.TOC,注意和第一步提到的libflutter.so不一样,这里的libflutter.so是包含符号表的,主要用于还原线上引擎堆栈
收集的AOT产物如下

收集的AOT产物.png

符号表

收集的AOT符号表.png

AOT产物归一,如果编译机不是mac,那么对应的darwin-x64需要换成linux-x64或者windows-x64
mkdir -p flutter-engine/artifacts/android-arm
mkdir -p flutter-engine/symbols/android-arm
cp flutter_engine/engine_251/src/out/android_debug/flutter.jar flutter-engine/artifacts/android-arm/flutter.jar
cp flutter_engine/engine_251/src/out/android_debug/libflutter.so flutter-engine/symbols/android-arm/libflutter.so
cp flutter_engine/engine_251/src/out/android_debug/libflutter.so.TOC flutter-engine/symbols/android-arm/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-arm-profile
mkdir -p flutter-engine/artifacts/android-arm-profile/darwin-x64
mkdir -p flutter-engine/symbols/android-arm-profile
cp flutter_engine/engine_251/src/out/android_profile/flutter.jar flutter-engine/artifacts/android-arm-profile/flutter.jar
cp flutter_engine/engine_251/src/out/android_profile/clang_x64/gen_snapshot flutter-engine/artifacts/android-arm-profile/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_profile/libflutter.so flutter-engine/symbols/android-arm-profile/libflutter.so
cp flutter_engine/engine_251/src/out/android_profile/libflutter.so.TOC flutter-engine/symbols/android-arm-profile/libflutter.so.TOC


mkdir -p flutter-engine/artifacts/android-arm-release
mkdir -p flutter-engine/artifacts/android-arm-release/darwin-x64
mkdir -p flutter-engine/symbols/android-arm-release
cp flutter_engine/engine_251/src/out/android_release/flutter.jar flutter-engine/artifacts/android-arm-release/flutter.jar
cp flutter_engine/engine_251/src/out/android_release/clang_x64/gen_snapshot flutter-engine/artifacts/android-arm-release/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_release/libflutter.so flutter-engine/symbols/android-arm-release/libflutter.so
cp flutter_engine/engine_251/src/out/android_release/libflutter.so.TOC flutter-engine/symbols/android-arm-release/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-arm64
mkdir -p flutter-engine/symbols/android-arm64
cp flutter_engine/engine_251/src/out/android_debug_arm64/flutter.jar flutter-engine/artifacts/android-arm64/flutter.jar
cp flutter_engine/engine_251/src/out/android_debug_arm64/libflutter.so flutter-engine/symbols/android-arm64/libflutter.so
cp flutter_engine/engine_251/src/out/android_debug_arm64/libflutter.so.TOC flutter-engine/symbols/android-arm64/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-arm64-profile
mkdir -p flutter-engine/artifacts/android-arm64-profile/darwin-x64
mkdir -p flutter-engine/symbols/android-arm64-profile
cp flutter_engine/engine_251/src/out/android_profile_arm64/flutter.jar flutter-engine/artifacts/android-arm64-profile/flutter.jar
cp flutter_engine/engine_251/src/out/android_profile_arm64/clang_x64/gen_snapshot flutter-engine/artifacts/android-arm64-profile/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_profile_arm64/libflutter.so flutter-engine/symbols/android-arm64-profile/libflutter.so
cp lutter_engine/engine_251/src/out/android_profile_arm64/libflutter.so.TOC flutter-engine/symbols/android-arm64-profile/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-arm64-release
mkdir -p flutter-engine/artifacts/android-arm64-release/darwin-x64
mkdir -p flutter-engine/symbols/android-arm64-release
cp flutter_engine/engine_251/src/out/android_release_arm64/flutter.jar flutter-engine/artifacts/android-arm64-release/flutter.jar
cp flutter_engine/engine_251/src/out/android_release_arm64/clang_x64/gen_snapshot flutter-engine/artifacts/android-arm64-release/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_release_arm64/libflutter.so flutter-engine/symbols/android-arm64-release/libflutter.so
cp flutter_engine/engine_251/src/out/android_release_arm64/libflutter.so.TOC flutter-engine/symbols/android-arm64-release/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-x86
mkdir -p flutter-engine/symbols/android-x86
cp flutter_engine/engine_251/src/out/android_debug_x86/flutter.jar flutter-engine/artifacts/android-x86/flutter.jar
cp flutter_engine/engine_251/src/out/android_debug_x86/lib.stripped/libflutter.so flutter-engine/artifacts/android-x86/libflutter.so
cp flutter_engine/engine_251/src/out/android_debug_x86/libflutter.so flutter-engine/symbols/android-x86/libflutter.so
cp lutter_engine/engine_251/src/out/android_debug_x86/libflutter.so.TOC flutter-engine/symbols/android-x86/libflutter.so.TOC

mkdir -p flutter-engine/artifacts/android-x64
mkdir -p flutter-engine/symbols/android-x64
cp flutter_engine/engine_251/src/out/android_debug_x64/flutter.jar flutter-engine/artifacts/android-x64/flutter.jar
cp flutter_engine/engine_251/src/out/android_debug_x64/lib.stripped/libflutter.so flutter-engine/artifacts/android-x64/libflutter.so
cp flutter_engine/engine_251/src/out/android_debug_x64/libflutter.so flutter-engine/symbols/android-x64/libflutter.so
cp flutter_engine/engine_251/src/out/android_debug_x64/libflutter.so.TOC flutter-engine/symbols/android-x64/libflutter.so.TOC


mkdir -p flutter-engine/artifacts/android-x64-profile
mkdir -p flutter-engine/artifacts/android-x64-profile/darwin-x64
mkdir -p flutter-engine/symbols/android-x64-profile
cp /Users/yulun/flutter_engine/engine_251/src/out/android_profile_x64/flutter.jar flutter-engine/artifacts/android-x64-profile/flutter.jar
cp flutter_engine/engine_251/src/out/android_profile_x64/clang_x64/gen_snapshot flutter-engine/artifacts/android-x64-profile/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_profile_x64/libflutter.so flutter-engine/symbols/android-x64-profile/libflutter.so
cp flutter_engine/engine_251/src/out/android_profile_x64/libflutter.so.TOC flutter-engine/symbols/android-x64-profile/libflutter.so.TOC


mkdir -p flutter-engine/artifacts/android-x64-release
mkdir -p flutter-engine/artifacts/android-x64-release/darwin-x64
mkdir -p flutter-engine/symbols/android-x64-release
cp flutter_engine/engine_251/src/out/android_release_x64/flutter.jar flutter-engine/artifacts/android-x64-release/flutter.jar
cp flutter_engine/engine_251/src/out/android_release_x64/clang_x64/gen_snapshot flutter-engine/artifacts/android-x64-release/darwin-x64/gen_snapshot
cp flutter_engine/engine_251/src/out/android_release_x64/libflutter.so flutter-engine/symbols/android-x64-release/libflutter.so
cp flutter_engine/engine_251/src/out/android_release_x64/libflutter.so.TOC flutter-engine/symbols/android-x64-release/libflutter.so.TOC

如何在正式环境使用自定义引擎的产物

大部分博客说的都是在本地使用debug产物,但如果要集成AOT产物需要改动源码。
真正要集成到环境中的其实就是flutter.jar和gen_snapshot,符号表文件可以单独存放。

在讨论如何集成时,我们要先看flutter是如何载入引擎产物的。 关键源码位置在yourflutterpath/flutter/packages/flutter_tools/gradle/flutter.gralde里 源码传送门

// 远程仓库依赖 flutter.jar
addApiDependencies(project, buildType.name,
        "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")

// Add the `libflutter.so` dependency. 远程依赖flutter.so
addApiDependencies(project, buildType.name,
        "io.flutter:${arch}_$flutterBuildMode:$engineVersion")
        
// 仓库地址
https://storage.googleapis.com/download.flutter.io

可以看到官方把jar和so是分开的,和我们之前分离的产物还有一点差别,回头再看下引擎生成的产物,发现有个flutter_embedding_{buildType}-sources.jar,这个就是io.flutter:flutter_embedding_flutterBuildMode:$engineVersion的具体产物了。 这块逻辑实在1.12版本修改的,在1.12之前产物都是本地依赖,引擎产物放在yourflutterpath/flutter/bin/cache/artifacts/engine里,具体修改逻辑可以看这个提交git@github.com:flutter/flutter.git@242a4225a1bfc726360e7d0f26325d5ac4d30891

所以,在集成AOT产物的方案上就有了两种思路:

  1. 修改flutter.gradle源码,使其支持本地依赖,笔者采用的是这种
  2. 仿照官方,在自己的nexus仓库上新建22个产物,其中flutter.jar需要11个,flutter.so需要11个,当然如果只考虑arm,放弃x86,那12个就够了

AOT产物覆盖.png

首先要确保产物已经覆盖到yourflutterpath/flutter/bin/cache/artifacts/engine,然后我们通过开关判断当前是引用官方的远程产物还是本地产物(如何覆盖产物可以自己通过脚本实现,这里指说明flutter.gradle的修改逻辑),下面贴出关键代码

// 可以通过-p参数注入,判断自定义引擎开关
private boolean isAndroidCustomEngine() {
    if (project.hasProperty("enableCustomEngine")) {
        return project.property("enableCustomEngine").toBoolean()
    }
    return true
}


/引入flutter.jar,这里要注意,不仅仅是主工程,plugin工程需要编译依赖
 private void apiFlutterJar(Project currentProject, boolean  compileOnly) {
        String basePlatformArch = getBasePlatform(project)
        // This is meant to include the compiled classes only, however it will include `libflutter.so` as well.
        Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
        File debugJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile()
        baseJar["debug"] = debugJar
        baseJar["profile"] = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile()
        baseJar["release"] = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile()
        // Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones
        // added after applying the Flutter plugin.
        currentProject.android.buildTypes.each {
            def buildMode = buildModeFor(it)
            if (compileOnly){
                addCompileOnlyDependency(currentProject, it.name, project.files {
                    baseJar[buildMode]
                })
            }
            else{
                addApiDependencies(currentProject, it.name, project.files {
                    baseJar[buildMode]
                })
            }

        }
        currentProject.android.buildTypes.whenObjectAdded {
            def buildMode = buildModeFor(it)
            if (compileOnly){
                addCompileOnlyDependency(currentProject, it.name, project.files {
                    baseJar[buildMode]
                })
            }
            else{
                addApiDependencies(currentProject, it.name, project.files {
                    baseJar[buildMode]
                })
            }
        }
    }
    
    // 依赖libflutter.so,对源码中的packFlutterAppAotTask做点修改
// 增加一项,从flutter.jar中抽离出libflutter.so
libFlutterPlatforms.each { targetArch ->

    if (!isAndroidCustomEngine()) {
        return
    }
    // This check prevents including `libflutter.so` twice, since it's included in the base platform jar.
    // Unfortunately, the `pickFirst` setting in `packagingOptions` does not work when the project `:flutter`
    // is included as an implementation dependency, which causes duplicated `libflutter.so`.
    if (getBasePlatform(project) == targetArch) {
        return
    }
    // Don't include `libflutter.so` for other architectures when a local engine is specified.
    if (useLocalEngine()) {
        return
    }
    def engineArtifactSubdir = getEngineArtifactDirName(variant.buildType, targetArch);
    // Include `libflutter.so`.
    // TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
    from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${engineArtifactSubdir}/flutter.jar")) {
        include 'lib/**'
    }
}

addFlutterDependencies也要修改

    /**
     * Adds the dependencies required by the Flutter project.
     * This includes:
     *    1. The embedding
     *    2. libflutter.so
     */
    void addFlutterDependencies(buildType) {
      //...省略其他代码
        if (!isFlutterAppProject() || getPluginList().size() == 0 || isAndroidCustomEngine()) {
            if (isAndroidCustomEngine()) {
            // plugin项目需要引用
                apiFlutterJar(project,false)
            } else {
                addApiDependencies(project, buildType.name,
                        "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")
            }
        }
        List<String> platforms = getTargetPlatforms().collect()
        // Debug mode includes x86 and x64, which are commonly used in emulators.
        if (flutterBuildMode == "debug" && !useLocalEngine()) {
            platforms.add("android-x86")
            platforms.add("android-x64")
        }
        // 不是自定义引擎是才引用官方仓库的libflutter.so
        if (!isAndroidCustomEngine()) {
            platforms.each { platform ->
                String arch = PLATFORM_ARCH_MAP[platform].replace("-", "_")
                // Add the `libflutter.so` dependency.
                addApiDependencies(project, buildType.name,
                        "io.flutter:${arch}_$flutterBuildMode:$engineVersion")
            }
        }
    }

configurePluginProject方法里的addEmbeddingDependencyToPlugin闭包适配

 Closure addEmbeddingDependencyToPlugin = { buildType ->
            String flutterBuildMode = buildModeFor(buildType)
            // In AGP 3.5, the embedding must be added as an API implementation,
            // so java8 features are desugared against the runtime classpath.
            // For more, see https://github.com/flutter/flutter/issues/40126

            if (!supportsBuildMode(flutterBuildMode)) {
                return
            }
            if (!pluginProject.hasProperty('android')) {
                return
            }
            // Copy build types from the app to the plugin.
            // This allows to build apps with plugins and custom build types or flavors.
            pluginProject.android.buildTypes {
                "${buildType.name}" {}
            }
            // The embedding is API dependency of the plugin, so the AGP is able to desugar
            // default method implementations when the interface is implemented by a plugin.
            //
            // See https://issuetracker.google.com/139821726, and
            // https://github.com/flutter/flutter/issues/72185 for more details.
            if (isAndroidCustomEngine()){
                // 为每个plugin project添加 flutter.jar依赖
                apiFlutterJar(pluginProject,true)
               // 每个插件项目添加编译依赖 compileOnlyPluginProject(pluginProject, buildType.name)
            }
            else{
                addApiDependencies(
                  pluginProject,
                  buildType.name,
                  "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion"
                )
            }
        }

以上这几步参考的是1.9的源码,修改完成后会发现还有坑点。 远程的flutter产物会默认依赖几个Androidx的aar,依赖关系如下

+--- io.flutter:flutter_embedding_debug:1.0.0-b3af521a050e6ef076778bcaf16e27b2521df8f8
|    +--- androidx.lifecycle:lifecycle-common:2.2.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-common-java8:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-runtime:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    +--- androidx.arch.core:core-common:2.1.0
|    |    |    \--- androidx.annotation:annotation:1.1.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.fragment:fragment:1.1.0
|    |    +--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.core:core:1.1.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.2.0 (*)
|    |    |    +--- androidx.versionedparcelable:versionedparcelable:1.1.0
|    |    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0
|    |    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.collection:collection:1.1.0 (*)
|    |    +--- androidx.viewpager:viewpager:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    \--- androidx.customview:customview:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |         \--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.loader:loader:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-livedata:2.0.0
|    |    |    |    +--- androidx.arch.core:core-runtime:2.0.0
|    |    |    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0
|    |    |    |    |    +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    |    |    |    +--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    |    \--- androidx.arch.core:core-runtime:2.0.0 (*)
|    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0
|    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.activity:activity:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.core:core:1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.1.0 -> 2.2.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-viewmodel:2.1.0 (*)
|    |    |    \--- androidx.savedstate:savedstate:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.1.0
|    |    |         +--- androidx.arch.core:core-common:2.0.1 -> 2.1.0 (*)
|    |    |         \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 (*)
|    \--- androidx.annotation:annotation:1.1.0
+--- io.flutter:armeabi_v7a_debug:1.0.0-b3af521a050e6ef076778bcaf16e27b2521df8f8
+--- io.flutter:arm64_v8a_debug:1.0.0-b3af521a050e6ef076778bcaf16e27b2521df8f8
+--- io.flutter:x86_64_debug:1.0.0-b3af521a050e6ef076778bcaf16e27b2521df8f8
\--- io.flutter:x86_debug:1.0.0-b3af521a050e6ef076778bcaf16e27b2521df8f8

主要是远程产物默认带了androidx.annotation:annotation,但自定义AOT产物只有jar,因此在针对pluign-project时要做点改动

    // 主要是为每个plugin-project工程添加compileOnly,避免编译失败,这部分代码挫后续要改进
    //androidx.annotation:annotation:1.1.0
    //只依赖jar的话,plugin-project不会依赖这几个aar,所以在本地依赖引擎产物的时候需要compileOnly这几个aar
    private boolean compileOnlyPluginProject(Project pluginProject,String buildTypeName){
        if (pluginProject == null){
            return
        }
        List<String> flutterJarAPi = ["androidx.annotation:annotation:1.1.0"]
        flutterJarAPi.each { jarAPi->
            String[] abi = jarAPi.split(":")
            def group = abi[0]
            def name = abi[1]
            def version = abi[2]
            // 只判断implementation, api,compileOnly
            pluginProject.configurations {
                if (containsDependency("compileOnly",it,name,group)){
                    return
                }else if (containsDependency("implementation",it,name,group)){
                    return
                }else if (containsDependency("api",it,name,group)){
                                    return
                }else if (containsDependency("compile",it,name,group)){
                    return
                }
                addCompileOnlyDependency(pluginProject, buildTypeName, jarAPi)
            }
        }

    }


    private boolean containsDependency(String configuration, ConfigurationContainer configurationContainer, String name, String group) {
        DependencySet setImplementation = configurationContainer.getByName(configuration).getAllDependencies()
        Dependency dep = setImplementation.find {
            it.name == name && it.group == group
        }
        return dep != null
    }

至此,本地依赖自定义引擎产物完成。

依赖AOT产物个人认为后续改成远程方式比较好,尽量向官方的方案靠近,虽然也要修改源代码,但代码的入侵性相比第一种方式是更低的。

其他坑点

Linux 二进制执行文件

本地编译机的是mac,编译出的gen_snapshot只支持mac,所以要在Linux上再编译一次。具体编译过程还是参考官网。这里只是简单说下,Linux需要依赖以下几个工具,curl,unzip,git,python3 ,只要解决国内被墙的问题,过程和mac上基本一样

补充Linux编译过程中碰到的一些问题
depot_tools找不到python3
https://blog.csdn.net/u010164190/article/details/115101194
 
 
linux 安装python3
https://blog.csdn.net/zhuzuwei/article/details/105423370
 
 
libc.so.6: version `GLIBC_2.18' not found问题
https://www.jianshu.com/p/513e01fbd3e0
 
 
ModuleNotFoundError: No module named '_ctypes'的解决方案
https://www.cnblogs.com/fanbi/p/12375023.html