前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter引擎——下载、编译和调试

Flutter引擎——下载、编译和调试

作者头像
拉维
发布2022-03-28 09:07:19
1.9K0
发布2022-03-28 09:07:19
举报
文章被收录于专栏:iOS小生活iOS小生活

一、什么是Flutter引擎?

我们这里说的引擎,不单单指的是渲染引擎,它包含但不仅限于渲染引擎

我们打开一个Flutter工程,找到iOS文件夹,点开Runner.xcworkspace工程,找到products文件夹下面的Runner.app:

然后显示包内容,此时如果文件夹是空的,那么你就编译一下项目,之后该文件夹就有东西了,如下:

点进Frameworks文件夹:

其中,App.framework就是Dart代码;Flutter.framework就是Flutter引擎代码,我们今天这篇文章聊的就是Flutter的引擎,也就是说,我们今天要研究的就是Flutter.framework里面的内容。

看到这里你可能会有这么个疑问,研究这玩意儿干啥?就单纯为了装逼吗?实际上还真不是为了装逼。我们知道,苹果是不允许热更新的,很多流行的热更新框架都被苹果给封杀了,但这是不是意味着我们就百分百不能在iOS上面去做热更新呢?其实,我们是可以做到热更新的,但是这个前提是,你是用的这个热更新技术不要大面积使用,不要被苹果注意到、盯上,这样的话苹果的人工审核是审核不出来的。因此,如果你公司项目有该需求,并且你公司有足够的实力,那么就可以在自己公司内部组建一个专门的团队来研究热更新技术,而在Flutter中去研究热更新,就需要以Flutter引擎为基础做一些二次开发,因此研究Flutter引擎是非常有必要的

我们知道,FlutterSDK是有很多版本的,如下我现在使用的是2.8.1:

如果我们使用的FlutterSDK版本发生了变化,那么对应的Flutter引擎(即Flutter.framework)也会发生变化

我们使用的FlutterSDK是存放在本地的,当一个Flutter项目编译运行的时候,它是通过路径找到本地的FlutterSDK,然后将FlutterSDK中对应架构下面的引擎拷贝打包到该项目的可执行文件中的。

上图中,第二行2.8.1是FlutterSDK的版本,可以看到我这里使用的channel是stable,其实这里的channel就是git 分支,我们看一下有几个channel:

可以看到,flutter sdk有4个channel,我推荐使用stable,因为它是最稳定的版本。

如果我们要切换channel,那么就直接在flutter SDK路径下执行flutter channel master/stable即可:

第4行890a5fca2e是Flutter Engine的版本,其实它是一个commit ID 。

接下来我们来到Github的FlutterEngine仓库下:

可以看到,flutter的engine是由好多个分支以及版本的,默认情况下,从Github上面pull下来的都是主分支(main)的代码。上面也提到,890a5fca2e是Flutter Engine的版本,其实它是一个commit ID ,因此,我们是可以精确到某一个commit节点的,所以我们建议通过某一个commitID来精确下载某一个commit节点下的engine。如下:

二、Flutter引擎源代码的下载

参考文章:https://www.yuque.com/qingjiaowohank/etm87a/rz2kpa

1,准备部署工具depot_tools

在对应目录(我是在Flutter目录)下执行如下命令,克隆depot_tools项目:

代码语言:javascript
复制
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

2,gitHub配置SSH

当git clone的时候,可能会报SSH失效的错误:

代码语言:javascript
复制
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

这个是因为你GitHub的KEY过期了,长期不clone代码导致的。此时直接去百度一下该错误,按照搜索出来的方案一步步配置一下即可

3,配置工具的环境变量

代码语言:javascript
复制
vim ~/.bash_profile

4,安装最后一个工具ant

代码语言:javascript
复制
brew install ant

5,下载引擎

(1)

在对应位置下(我是在Flutter目录下)新建目录(注意,我们的路径不能有中文,否则后续Down下载的源码会有问题

代码语言:javascript
复制
mkdir engine

(2)创建gclien配置文件。(我们需要通过gclien下载源码)

代码语言:javascript
复制
touch .gclient

(3)配置.gclient文件。(尤其要确定CommitID 保持一致)

代码语言:javascript
复制
vim .gclient

将如下复制粘贴进来:

代码语言:javascript
复制
solutions = [
    {
        "managed": False,
        "name": "src/flutter",
        "url": "git@github.com:flutter/engine.git@6bc433c6b6b5b98dcf4cc11aff31cdee90849f32",
        "custom_deps": {},
        "deps_file": "DEPS",
        "safesync_url": "",
    },
]

这里的6bc433c6b6b5b98dcf4cc11aff31cdee90849f32是engine的commitID,需要找到你目前在使用的Flutter版本里面的engine的commitID,找到之后就在上面替换掉。那么如何找到这个engine的commitID呢?

这个engine的commitID存放在engine.version文件中,其路径如下:

然后我们cd到internal文件夹路径,通过cat命令查看engine.version文件

这里展示出来的890a5fca2e34db413be624fc83aeea8e61d42ce6就是当前FlutterSDK中的FlutterEngine版本的CommitID。

(4)执行gclient sync (这个操作将会fetch Flutter 所有的依赖。这里有10G文件,需要点时间,请保持网络!该操作需要访问国外网站)

代码语言:javascript
复制
gclient sync

需要注意的是,如果报SSH KEY的错误,那么就配置一下GITHUB的SSH KEY即可。

(5)关于升级

当我们升级了Flutter的SDK,我们想要升级引擎代码,直接更新 .gclient 文件。

首先找到对应的engine的commitID:

然后将这个修改到.gclient文件中

然后进入src/flutter目录(/Users/liwei/Flutter/engine/src/flutter),进行一次 git pull,然后git reset --hard commitID

代码语言:javascript
复制
git pull
git reset --hard commitID

这个命令就是告诉Git ,我下次下载就下载这个conmitID的

回到engine 目录(/Users/liwei/Flutter/engine),也就是.gclient文件所在的目录,执行如下命令:

代码语言:javascript
复制
gclient sync --with_branch_heads --with_tags --verbose

三、Flutter引擎源代码的编译

Flutter 引擎的源代码是需要通过Ninja来编译的,而GN是一个生成Ninja编译所需的构建文件的元构建系统

接下来来到GN所在的tools路径,在该路径下进行如下构建代码的执行:

代码语言:javascript
复制
#构建iOS设备使用的引擎
#真机debug版本
./gn --ios --unoptimized
#真机release版本(日常开发使用,如果我们要自定义引擎)
./gn --ios --unoptimized --runtime-mode=release
#模拟器版本
./gn --ios --simulator --unoptimized
#主机端(Mac)构建
./gn --unoptimized

构建完成会有四个Xcode工程

最后一步,就是使用ninja编译工程,这个操作是最耗时并且烧电脑的了。

首先配置一下环境变量:

代码语言:javascript
复制
vim ~/.bash_profile

保存退出之后:

代码语言:javascript
复制
source ~/.bash_profile

然后我们来到上面这个存储了4个Xcode工程的路径(/Users/liwei/Flutter/engine/src/out),执行如下命令:

代码语言:javascript
复制
ninja -C host_debug_unopt && ninja -C ios_debug_sim_unopt && ninja -C ios_debug_unopt && ninja -C ios_release_unopt

接下来就是漫长的等待了。

需要注意的是,由于一些配置的问题,不同的设备在编译的时候可能会遇到不同的问题,当遇到问题的时候就去解决问题好了。

四、将本地Flutter 引擎绑定到自己的Flutter项目中

上面介绍了Flutter引擎,以及引擎的下载和编译,接下来我们就在实际项目中去玩一下自己编译好的引擎。

首先创建一个Flutter工程,然后flutter run,之后打开flutter工程的ios目录下的Xcode工程。

首先看到有3个配置文件:

Debug是开发环境的配置文件;Release是发布环境的配置文件;Generated是通用配置文件,在这里面配置的东西会在Debug和Release里面同时生效

接下来我们再来看个东西:

这里的RunScript是在编译当前工程的时候会去执行的脚本,这里的脚本是FlutterSDK中的xcode_backend.sh脚本,其路径如下:

我们可以打开看一下:

可以看到,脚本里面会使用到很多的环境变量(比如FLUTTER_ROOT),这些环境变量是在哪里定义的呢?就是在Generated配置文件中定义的,如下:

所以,脚本中使用到的很多环境变量其实是在配置文件中定义的,当该脚本执行的时候,会从配置文件中去读取对应的环境变量。

接下来我在通用配置文件中增加两项配置,如下:

可以看到,我配置的LOCAL_ENGINE环境变量是ios_release_unopt,但是我是在Debug模式下编译的代码,此时会编译不通过。

好,下面我改一下LOCAL_ENGINE环境变量的配置,改成ios_debug_unopt,如下:

然后再在Debug模式下编译就编译成功了。

这也充分说明了,应用程序在编译的时候访问了如下路径下的Flutter本地引擎的代码:

然后后面我们在该路径下调整引擎代码,然后编译刚创建的Flutter工程就能看到对应的效果了。

接下来我们将工程跑起来,然后使用lldb指令添加一个touchesBegan事件的断点,如下:

然后点按手机屏幕,就能监听到如下事件:

可以看到,断点最后走到了FlutterViewController.mm文件的- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event方法中,那么这个FlutterViewController.mm文件时存放在哪里呢?

我们接下来来到本地Flutter引擎的代码:

双击打开flutter_engine.xcodeproj工程,Command+Shift+o搜索FlutterViewController.mm,然后找到第1000行代码,添加个注释,如下:

此时我们再打开Flutter工程的ios工程中断点到的地方:

可以看到,刚才在Flutter本地引擎工程中所做的调整,体现到了我在Flutter工程的iOS工程断点到的地方,这说明,该Flutter工程所用的引擎就是这个Flutter本地引擎!

只要将你自己创建的Flutter原工程配置上Flutter引擎,你就可以使用你自己的本地Flutter引擎代码,并且可以进行断点调试。

接下来我就稍微修改下本地引擎的代码,看看能不能其作用,如下,我在本地引擎代码中增加了一个NSLog:

需要注意哦,此时还不可以生效奥~

接下来使用ninja来编译本地Flutter引擎代码

然后再使用Xcode重新编译Flutter工程的ios工程,这样的话每一次点击屏幕都会打印了:

此时,我们修改的本地引擎中的代码才真正生效!!

五、总结

本文主要是介绍了如何在一个Flutter工程中去使用自己本地的Flutter引擎。这里的Flutter引擎是以一个以编译之后的二进制文件的形式存在于Flutter工程中的,那么如何去获取到一个编译之后的二进制形式的Flutter引擎呢?

第一步,通过配置.gclient文件下载Flutter引擎源代码。由于Flutter引擎源代码是在国外服务器上的,所以这里的下载操作需要访问国外网站,并且需要一定的时间。

第二步,通过GN来构建编译Flutter引擎所需的文件。构建的结果就是,在out文件夹下面生成了四个Xcode工程文件夹。

第三步,通过ninja编译上面👆第二步构建出来的4个Xcode工程。编译完成之后就能够生成对应的Flutter引擎二进制文件了,需要注意的是,初次编译的时候是很耗时间的。

现在我们已经获取到Flutter引擎的二进制可执行文件了,接下来就通过在Generated文件中配置对应环境变量,将我们自己的Flutter工程与本地的Flutter引擎关联起来,以使Flutter工程使用我们自己下载并且编译好的Flutter引擎。

以上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档