Flutter build ios产物分析

人总要爱着什么,活着才有意义。

前言

如果你是Android转iOS,或者是想开发Flutter插件,可以看看我的文章:iOS 入门开发踩坑实录。我就是一个Android开发,由于开发插件需要,学了部分的iOS开发的东西。

  • Flutter提供的官方接入方案:Add Flutter to existing apps,值得一提的是官方在Flutter 1.12上提供了Android Studio直接接入Flutter的方案。

踩坑的本机环境

注意对比下我的环境和你的环境是否一样,有些问题在Flutter的新版本中已经被修复了。

➜  app git:(master) ✗ flutter --version
Flutter 1.9.1+hotfix.6 • channel stable • https://github.com/flutter/flutter.git
Framework • revision cc949a8e8b (3 weeks ago) • 2019-09-27 15:04:59 -0700
Engine • revision b863200c37
Tools • Dart 2.5.0

Flutter doctor -v

➜  app git:(master) ✗ flutter doctor -v                  
[] Flutter (Channel stable, v1.9.1+hotfix.4, on Mac OS X 10.15 19A583, locale en-CN)
    • Flutter version 1.9.1+hotfix.4 at /Users/.../flutter
    • Framework revision cc949a8e8b (3 weeks ago), 2019-09-27 15:04:59 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0

 
[] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/notzuonotdied/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[] Xcode - develop for iOS and macOS (Xcode 11.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.1, Build version 11A1027
    • CocoaPods version 1.8.3

[] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 40.1.2
    • Dart plugin version 191.8423
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[!] IntelliJ IDEA Ultimate Edition (version 2019.2.3)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • For information about installing plugins, see
      https://flutter.dev/intellij-setup/#installing-the-plugins

[] VS Code (version 1.39.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.5.1

[] Connected device (1 available)
    • iPhone 11 Pro Max • 61AA9D21-B994-4FC5-9164-757EABF90190 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-1 (simulator)

! Doctor found issues in 1 category.

分析Flutter工程

本章节用于探讨Flutter编译产物以及其集成方式。

工程结构

首先,先看看混编Flutter的目录结构,主要包含了三个部分:

  • android:Android Native工程
  • iOS:iOS Native工程
  • flutter_module:Flutter Module工程

在这里插入图片描述

➜  temp tree -L 2
.
├── Android								# Android工程
├── flutter_module
│   ├── README.md
│   ├── flutter_module.iml
│   ├── flutter_module_android.iml
│   ├── lib								# Flutter源码目录
│   ├── pubspec.yaml					# Flutter依赖
│   └── test
└── iOS									# iOS工程
    ├── Podfile
    ├── Podfile.lock
    ├── Pods
    ├── iOS
    ├── iOS.xcodeproj
    └── iOS.xcworkspace

9 directories, 9 files

Flutter build ios

看看编译之后会生成什么产物?

先看看flutter_module目录的层级结构:

➜  flutter_module tree
.
├── README.md
├── flutter_module.iml
├── flutter_module_android.iml
├── lib									# Flutter源码
│   └── main.dart	
├── pubspec.lock
├── pubspec.yaml						# 依赖
└── test
    └── widget_test.dart

2 directories, 10 files

当我们执行Flutter build ios会发生什么?

➜  flutter_module flutter build ios
Building com.wtfexample.flutterModule for device (ios-release)...
Found saved certificate choice "Apple Development: [email protected] (xxxxxxxx)". To clear, use
"flutter config".
Signing iOS app for device deployment using developer identity: "Apple Development:
[email protected] (xxxxxxxx)"
Running Xcode build...

 ├─Building Dart code...                                    20.0s
 ├─Generating dSYM file...                                   0.3s
 ├─Stripping debug symbols...                                0.0s
 ├─Assembling Flutter resources...                           0.7s
 └─Compiling, linking and signing...                         3.9s
Xcode build done.                                           29.6s
Built /Users/.../flutter_module/build/ios/iphoneos/Runner.app.

让我们来看看目录结构:

➜  flutter_module tree -da -L 2
.
├── .android				# Android编译产物
│   ├── Flutter
│   ├── app
│   └── gradle
├── .idea
│   └── libraries
├── .ios					# iOS编译产物
│   ├── Config
│   ├── Flutter
│   ├── Frameworks
│   ├── Pods
│   ├── Runner
│   ├── Runner.xcodeproj
│   └── Runner.xcworkspace
├── build
│   ├── aot
│   ├── dSYMs.noindex
│   └── ios
├── lib
└── test

- 主要是多了以下的部分:

​```shell
.
├── .android				# Android编译产物
├── .ios					# iOS编译产物
├── build
│   ├── aot
│   ├── dSYMs.noindex
│   └── ios

这些也是我们要分析的内容啦,╮(╯▽╰)╭

.iOS/Config

➜  .ios tree Config
Config
├── Debug.xcconfig
├── Flutter.xcconfig
└── Release.xcconfig

0 directories, 3 files

➜  Config cat Debug.xcconfig
#include "Flutter.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
➜  Config cat Release.xcconfig
#include "Flutter.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
➜  Config cat Flutter.xcconfig
#include "../Flutter/Generated.xcconfig"
ENABLE_BITCODE=NO				# 目前Flutter不支持BitCode模式,默认关闭

Flutter.xcconfig

值得一提的是Flutter.xcconfig依赖了Flutter/Generated.xcconfig,这个文件详见下面章节的分析。Flutter/Generated.xcconfig配置了一些Flutter Module工程的关键环境变量。

.iOS/Flutter

➜  Flutter tree -da -L 2
.
├── .symlinks # 这是Flutter Module依赖的插件的路径,都是使用了Soft Link
│   ├── amap_location -> /Users/.../amap_location-0.2.0
│   ├── flutter_alipay -> /Users/.../flutter_alipay-0.1.2
│   ├── flutter_amap -> /Users/.../flutter_amap-0.0.1
│   ├── flutter_easy_nfc -> /Users/.../flutter_easy_nfc-0.0.1
│   ├── flutter_statusbar -> /Users/.../flutter_statusbar-0.0.1
│   ├── flutter_wechat_ble -> /Users/.../flutter_wechat_ble-0.1.4
│   ├── linker -> /Users/.../linker-0.0.2
│   └── mmkv_flutter -> /Users/.../mmkv_flutter-1.0.10
├── App.framework		# Flutter业务代码
│   └── flutter_assets 	# Flutter依赖的静态资源,如字体、图片等。
├── FlutterPluginRegistrant
│   └── Classes
└── engine # Flutter引擎,默认从$FlutterHome/bin/cache/artifacts复制一份。
    └── Flutter.framework

15 directories

Flutter/.symlinks

这是Flutter Module依赖的插件的路径,都是使用了Soft Link。

➜  .symlinks tree
.
├── amap_location -> /Users/.../amap_location-0.2.0
├── flutter_alipay -> /Users/.../flutter_alipay-0.1.2
├── flutter_amap -> /Users/.../flutter_amap-0.0.1
├── flutter_easy_nfc -> /Users/.../flutter_easy_nfc-0.0.1
├── flutter_statusbar -> /Users/.../flutter_statusbar-0.0.1
├── flutter_wechat_ble -> /Users/.../flutter_wechat_ble-0.1.4
├── linker -> /Users/.../linker-0.0.2
└── mmkv_flutter -> /Users/.../mmkv_flutter-1.0.10

8 directories, 0 files

Flutter/App.framework

Flutter业务层代码,以及一些静态资源文件。

我们可以看看flutter_assets到底有什么东西?

➜  App.framework git:(master) ✗ tree -a -L 2
.
├── App
├── Info.plist
└── flutter_assets
    ├── AssetManifest.json
    ├── FontManifest.json
    ├── LICENSE
    ├── animations		# 动画
    ├── assets							
    ├── fonts			# 字体
    ├── images			# 图片
    └── packages		# packages中的一些资源

6 directories, 5 files

Flutter/AppFrameworkInfo.plist

Flutter业务层代码编译产物App.framework的一些信息,诸如版本信息、BundleId、版本号等等。

Flutter/FlutterPluginRegistrant

Flutter注册制,自动注册各个依赖的Flutter插件。

  • GeneratedPluginRegistrant是编译的时候自动生成的。
➜  FlutterPluginRegistrant tree -a -L 2
.
├── Classes
│   ├── GeneratedPluginRegistrant.h
│   └── GeneratedPluginRegistrant.m
└── FlutterPluginRegistrant.podspec

1 directory, 3 files

如下所示:

➜  FlutterPluginRegistrant cat Classes/GeneratedPluginRegistrant.m
//
//  Generated file. Do not edit.
//

#import "GeneratedPluginRegistrant.h"
#import <amap_location/AmapLocationPlugin.h>
#import <flutter_alipay/FlutterAlipayPlugin.h>
#import <flutter_amap/FlutterAmapPlugin.h>
#import <flutter_easy_nfc/FlutterEasyNfcPlugin.h>
#import <flutter_statusbar/FlutterStatusbarPlugin.h>
#import <flutter_wechat_ble/FlutterWechatBlePlugin.h>
#import <linker/LinkerPlugin.h>
#import <mmkv_flutter/MmkvFlutterPlugin.h>

@implementation GeneratedPluginRegistrant

+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
  [AmapLocationPlugin registerWithRegistrar:[registry registrarForPlugin:@"AmapLocationPlugin"]];
  [FlutterAlipayPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterAlipayPlugin"]];
  [FlutterAmapPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterAmapPlugin"]];
  [FlutterEasyNfcPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterEasyNfcPlugin"]];
  [FlutterStatusbarPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterStatusbarPlugin"]];
  [FlutterWechatBlePlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterWechatBlePlugin"]];
  [LinkerPlugin registerWithRegistrar:[registry registrarForPlugin:@"LinkerPlugin"]];
  [MmkvFlutterPlugin registerWithRegistrar:[registry registrarForPlugin:@"MmkvFlutterPlugin"]];
}

@end

Flutter/Generated.xcconfig

这个是Flutter编译的时候自动生成的,定义了一些关键的配置。

➜  Flutter cat Generated.xcconfig
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/.../1.9.1+hotfix.6-stable
FLUTTER_APPLICATION_PATH=/Users/.../flutter_module
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
SYMROOT=${SOURCE_ROOT}/../build/ios
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1

Flutter/flutter_export_environment.sh

这个和Flutter/Generated.xcconfig一样是Flutter编译生成的,用于初始化一些必须的变量。

➜  Flutter cat flutter_export_environment.sh
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/.../1.9.1+hotfix.6-stable"
export "FLUTTER_APPLICATION_PATH=/Users/.../flutter_module"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"

具体用处可见下面章节Flutter/podhelper.rbinstall_flutter_application_pod函数实现。

Flutter/engine

这个是直接从Flutter的SDK安装目录复制过来的,路径在$FLUTTER_ROOT/bin/cache/artifacts

Flutter/podhelper.rb

这个是最核心的一部分,分析Flutter Module依赖的插件的依赖,install到Flutter的.ios工程中。

.ios/Podfile中,我们看到Podfile加载使用load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')加载了podhelper.rb这个脚本。

.ios git:(master) ✗ cat Podfile
platform :ios, '8.0'

# Flutter Module的目录
flutter_application_path = '../' 
# 这里的podhelper.rb就是.ios/Flutter/podhelper.rb
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

# install依赖
target 'Runner' do
  # 函数,定义在podhelper.rb
  install_flutter_engine_pod
  # 函数,定义在podhelper.rb
  install_flutter_plugin_pods flutter_application_path							
end

# 在pod install的最后一步,执行某些配置
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'NO'								# Flutter默认不支持BitCode
    end
  end
end

# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true

这个脚本其实就如下图所示的流程。

在这里插入图片描述

下面,我们来分析下Flutter/podhelper.rb

install_all_flutter_pods

这个是一个入口函数,包含了几个函数:

  • install_flutter_engine_pod
  • install_flutter_plugin_pods
  • install_flutter_application_pod
# Install pods needed to embed Flutter application, Flutter engine, and plugins
# from the host application Podfile.
#
# @example
#   target 'MyApp' do
#     install_all_flutter_pods 'my_flutter'
#   end
# @param [String] flutter_application_path Path of the root directory of the Flutter module.
#                                          Optional, defaults to two levels up from the directory of this script.
#                                          MyApp/my_flutter/.ios/Flutter/../..
def install_all_flutter_pods(flutter_application_path = nil)
  # 跳两级出去,即Flutter工程根目录
  flutter_application_path ||= File.join('..', '..')
  # 添加Flutter Engine依赖			
  install_flutter_engine_pod
  # 添加Flutter插件的依赖
  install_flutter_plugin_pods(flutter_application_path)
  # 添加Flutter业务代码的依赖
  install_flutter_application_pod(flutter_application_path)
end

install_flutter_engine_pod

# Install Flutter engine pod.
#
# @example
#   target 'MyApp' do
#     install_flutter_engine_pod
#   end
def install_flutter_engine_pod 
  # 核心工作,复制Flutter的引擎到工程目录下。
  engine_dir = File.join(__dir__, 'engine')
  if !File.exist?(engine_dir)
    # Copy the debug engine to have something to link against if the xcode backend script has not run yet.
    # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
    debug_framework_dir = File.join(flutter_root, 'bin', 'cache', 'artifacts', 'engine', 'ios')
    # 创建目录并拷贝引擎
    FileUtils.mkdir_p(engine_dir)
    FileUtils.cp_r(File.join(debug_framework_dir, 'Flutter.framework'), engine_dir)
    FileUtils.cp(File.join(debug_framework_dir, 'Flutter.podspec'), engine_dir)
  end

  # Keep pod path relative so it can be checked into Podfile.lock.
  # Process will be run from project directory.
  engine_pathname = Pathname.new engine_dir
  project_directory_pathname = Pathname.new Dir.pwd
  relative = engine_pathname.relative_path_from project_directory_pathname

  pod 'Flutter', :path => relative.to_s, :inhibit_warnings => true
end

debug_framework_dir = File.join(flutter_root, 'bin', 'cache', 'artifacts', 'engine', 'ios')指向的目录是Flutter引擎的目录,可以看看$FlutterRoot/bin/cache/artifacts/engine这个目录:

➜  1.9.1+hotfix.6-stable git:(stable) ✗ tree bin/cache/artifacts/engine -L 1 | grep ios
├── ios
│   ├── Flutter.framework
│   ├── Flutter.framework.zip
│   ├── Flutter.podspec
│   ├── LICENSE
│   ├── gen_snapshot_arm64
│   └── gen_snapshot_armv7
├── ios-profile
│   ├── Flutter.framework
│   ├── Flutter.framework.zip
│   ├── Flutter.podspec
│   ├── LICENSE
│   ├── gen_snapshot_arm64
│   └── gen_snapshot_armv7
└── ios-release
    ├── Flutter.framework
    ├── Flutter.framework.zip
    ├── Flutter.podspec
    ├── LICENSE
    ├── gen_snapshot_arm64
    └── gen_snapshot_armv7

install_flutter_plugin_pods

# Install Flutter plugin pods.
#
# @example
#   target 'MyApp' do
#     install_flutter_plugin_pods 'my_flutter'
#   end
# @param [String] flutter_application_path Path of the root directory of the Flutter module.
#                                          Optional, defaults to two levels up from the directory of this script.
#                                          MyApp/my_flutter/.ios/Flutter/../..
def install_flutter_plugin_pods(flutter_application_path)
  # 核心工作,增加Flutter插件注册FlutterPluginRegistrant库(自动生成并注册Flutter Channel)
  # 分析插件的依赖并创建插件的依赖的软链接到.symlinks目录下。
  flutter_application_path ||= File.join('..', '..')

  # Keep pod path relative so it can be checked into Podfile.lock.
  # Process will be run from project directory.
  current_directory_pathname = Pathname.new __dir__
  project_directory_pathname = Pathname.new Dir.pwd
  relative = current_directory_pathname.relative_path_from project_directory_pathname
  pod 'FlutterPluginRegistrant', :path => File.join(relative, 'FlutterPluginRegistrant'), :inhibit_warnings => true

  symlinks_dir = File.join(relative, '.symlinks')
  FileUtils.mkdir_p(symlinks_dir)
  plugin_pods = parse_KV_file(File.join(flutter_application_path, '.flutter-plugins'))
  plugin_pods.map do |r|
    symlink = File.join(symlinks_dir, r[:name])
    FileUtils.rm_f(symlink)
    File.symlink(r[:path], symlink)
    pod r[:name], :path => File.join(symlink, 'ios'), :inhibit_warnings => true
  end
end
➜  flutter_module cat .flutter-plugins
amap_location=/.../1.9.1+hotfix.6-stable/.pub-cache/.../amap_location-0.2.0/
flutter_alipay=/.../1.9.1+hotfix.6-stable/.pub-cache/.../flutter_alipay-0.1.2/
flutter_amap=/.../1.9.1+hotfix.6-stable/.pub-cache/.../flutter_amap-0.0.1/
flutter_easy_nfc=/.../1.9.1+hotfix.6-stable/.pub-cache/.../flutter_easy_nfc-0.0.1/
flutter_statusbar=/.../1.9.1+hotfix.6-stable/.pub-cache/.../flutter_statusbar-0.0.1/
flutter_wechat_ble=/.../1.9.1+hotfix.6-stable/.pub-cache/.../flutter_wechat_ble-0.1.4/
linker=/.../1.9.1+hotfix.6-stable/.pub-cache/.../linker-0.0.2/
mmkv_flutter=/.../1.9.1+hotfix.6-stable/.pub-cache/.../mmkv_flutter-1.0.10/

由此可见,这里保存了Flutter工程依赖的插件的本地缓存目录。

install_flutter_application_pod


# Install Flutter application pod.
#
# @example
#   target 'MyApp' do
#     install_flutter_application_pod '../flutter_settings_repository'
#   end
# @param [String] flutter_application_path Path of the root directory of the Flutter module.
#                                          Optional, defaults to two levels up from the directory of this script.
#                                          MyApp/my_flutter/.ios/Flutter/../..
def install_flutter_application_pod(flutter_application_path)
  # 编译Flutter的业务层代码并依赖到主工程。
  app_framework_dir = File.join(__dir__, 'App.framework')
  app_framework_dylib = File.join(app_framework_dir, 'App')
  if !File.exist?(app_framework_dylib)
    # Fake an App.framework to have something to link against if the xcode backend script has not run yet.
    # CocoaPods will not embed the framework on pod install (before any build phases can run) if the dylib does not exist.
    # Create a dummy dylib.
    FileUtils.mkdir_p(app_framework_dir)
    `echo "static const int Moo = 88;" | xcrun clang -x c -dynamiclib -o "#{app_framework_dylib}" -`
  end

  # Keep pod and script phase paths relative so they can be checked into source control.
  # Process will be run from project directory.
  current_directory_pathname = Pathname.new __dir__
  project_directory_pathname = Pathname.new Dir.pwd
  relative = current_directory_pathname.relative_path_from project_directory_pathname
  pod 'flutter_app', :path => relative.to_s, :inhibit_warnings => true

  # 读取flutter_export_environment.sh,并提供必要的环境变量
  flutter_export_environment_path = File.join('${SRCROOT}', relative, 'flutter_export_environment.sh');
  
  # 最关键的一步,涉及到了xcode_backend.sh。
  script_phase :name => 'Run Flutter Build Script',
    :script => "set -e\nset -u\nsource \"#{flutter_export_environment_path}\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build",
    :input_files => [
      File.join('${SRCROOT}', flutter_application_path, '.metadata'),
      File.join('${SRCROOT}', relative, 'App.framework', 'App'),
      File.join('${SRCROOT}', relative, 'engine', 'Flutter.framework', 'Flutter'),
      flutter_export_environment_path
    ],
    :execution_position => :before_compile
end


  • 这里,我们看到了一个很特别的脚本:

看看File.join('${SRCROOT}', flutter_application_path, '.metadata'),这里的'.metadata'

➜  flutter_module ✗ cat .metadata
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
  revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
  channel: stable

project_type: module

这里存放的是工程依赖的Flutter tool版本。

parse_KV_file

# 分析Generated.xcconfig等配置文件
def parse_KV_file(file, separator='=')
  file_abs_path = File.expand_path(file)
  if !File.exists? file_abs_path
    return [];
  end
  pods_array = []
  skip_line_start_symbols = ["#", "/"]
  File.foreach(file_abs_path) { |line|
    next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
    plugin = line.split(pattern=separator)
    if plugin.length == 2
      podname = plugin[0].strip()
      path = plugin[1].strip()
      podpath = File.expand_path("#{path}", file_abs_path)
      pods_array.push({:name => podname, :path => podpath});
     else
      puts "Invalid plugin specification: #{line}"
    end
  }
  return pods_array
end

flutter_root

# 分析Generated.xcconfig找到FLUTTER_ROOT地址
# FLUTTER_ROOT指的是Flutter SDK的路径
def flutter_root
  generated_xcode_build_settings = parse_KV_file(File.join(__dir__, 'Generated.xcconfig'))
  if generated_xcode_build_settings.empty?
    puts "Generated.xcconfig must exist. Make sure `flutter pub get` is executed in the Flutter module."
    exit
  end
  generated_xcode_build_settings.map { |p|
    if p[:name] == 'FLUTTER_ROOT'
      return p[:path]
    end
  }
end

小结

函数 作用
install_all_flutter_pods 入口函数,跳转到Flutter工程根目录,添加Flutter Engine依赖、Flutter插件依赖、Flutter业务层代码依赖。
install_flutter_engine_pod 复制Flutter Debug版本的引擎到工程目录下,位于.ios/Flutter
install_flutter_plugin_pods 生成Flutter插件的注册库并依赖,分析各个Flutter插件的依赖,并创建依赖库的软链接到.symlinks目录下,即注册插件、分析依赖并依赖到主工程。
install_flutter_application_pod 编译Flutter 业务层代码到App.framework,并依赖到主工程。
parse_KV_file 分析Generated.xcconfig等配置文件,用于插件依赖分析。
flutter_root 分析Generated.xcconfig找到FLUTTER_ROOT地址,FLUTTER_ROOT指的是Flutter SDK的路径。

.ios/Pods

这个目录存放的是Flutter插件依赖的库。

➜  .ios tree -L 1 Pods
Pods
├── AMap3DMap
├── AMapFoundation
├── AMapLocation
├── AliPay
├── Headers					# 头文件*.h
├── Local\ Podspecs			# Flutter插件的PodSpec
├── MMKV
├── Manifest.lock			# 即Podfile.lock,保存了依赖的版本和地址等信息
├── Pods.xcodeproj
└── Target\ Support\ Files 	# 存放Flutter插件依赖的库的一些配置文件

9 directories, 1 file

Pods/Headers

分为PrivatePublic分别存放依赖库的头文件。

➜  .ios tree -L 2 Pods/Headers
Pods/Headers
├── Private
│   ├── FlutterPluginRegistrant
│   ├── MMKV
│   ├── amap_location
│   ├── flutter_alipay
│   ├── flutter_amap
│   ├── flutter_easy_nfc
│   ├── flutter_statusbar
│   ├── flutter_wechat_ble
│   ├── linker
│   └── mmkv_flutter
└── Public
    ├── FlutterPluginRegistrant
    ├── MMKV
    ├── amap_location
    ├── flutter_alipay
    ├── flutter_amap
    ├── flutter_easy_nfc
    ├── flutter_statusbar
    ├── flutter_wechat_ble
    ├── linker
    └── mmkv_flutter

22 directories, 0 files

Pods/Local Podspecs

在Flutter工程中,直接在pubspec.yaml依赖了插件,在执行flutter build ios的时候,就会执行flutter pub getflutter package get,将Flutter插件下载到本地,最后Flutter插件的podspec会被自动转换为podspec.json,并存放在.ios/Pods/Local Podspecs中。

➜  .ios tree -L 1 Pods/Local\ Podspecs
Pods/Local\ Podspecs
├── Flutter.podspec.json
├── FlutterPluginRegistrant.podspec.json
├── amap_location.podspec.json
├── flutter_alipay.podspec.json
├── flutter_amap.podspec.json
├── flutter_easy_nfc.podspec.json
├── flutter_statusbar.podspec.json
├── flutter_wechat_ble.podspec.json
├── linker.podspec.json
└── mmkv_flutter.podspec.json

0 directories, 10 files

Pods/Target Support Files

存放Flutter插件依赖的库的一些配置文件。

➜  .ios tree -L 1 Pods/Target\ Support\ Files
Pods/Target\ Support\ Files
├── AMap3DMap
├── AMapFoundation
├── AMapLocation
├── AliPay
├── Flutter
├── FlutterPluginRegistrant
├── MMKV
├── Pods-Runner
├── amap_location
├── flutter_alipay
├── flutter_amap
├── flutter_easy_nfc
├── flutter_statusbar
├── flutter_wechat_ble
├── linker
└── mmkv_flutter

16 directories, 0 files

小结

flutter build ios --release后的一些关键编译产物为:

产物 介绍
App.framework Dart业务源码相关文件,在Debug模式下就是一个很小的空壳,在Release模式下包含全部业务逻辑。
flutter_assets Flutter依赖的静态资源,如字体、图片等。
在Flutter 1.9.1这种已经被合并进App.framework
FlutterPluginRegistrant Flutter插件注册制,自动注册Flutter插件。
Flutter.framework Flutter库和引擎。
.symlinks 指向Flutter插件依赖库的实际地址。

因此,实际上Native接入Flutter的需要的就是接入以上的产物,其中flutter build ios生成的产物Generated.xcconfig、flutter_export_environment.sh为编译提供了必要的参数。

附录

发布了181 篇原创文章 · 获赞 217 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/Notzuonotdied/article/details/103744872