Flutter学习系列(3)— 编译和运行

一 创建Flutter应用

 

如果使用Android Studio 或者Visual Studio Code 可以从IDE中创建一个新Flutter应用程序,以AS为例,这里可以创建四种类型的项目。

当然也可以使用Flutter命令从命令行创建,通过help命令可以看有那些参数, 一般按下面命令就可以创建一个新的flutter项目

flutter create --help

➜flutter create  --org com.cc.flutter.hello flutter_hello
Creating project flutter_hello...

Running "flutter packages get" in flutter_hello...                 10.9s
Wrote 67 files.

All done!

Run "flutter doctor" for information about installing additional components.

In order to run your application, type:

  cd flutter_hello flutter run

Your application code is in flutter_hello/lib/main.dart.

创建成功之后看一下目录结构

➜  flutter_hello ll
total 32
-rw-r--r--   1 chengchao  staff   542B  3 26 00:04 README.md
drwxr-xr-x  12 chengchao  staff   384B  3 26 00:05 android
-rw-r--r--   1 chengchao  staff   896B  3 26 00:04 flutter_hello.iml
drwxr-xr-x   6 chengchao  staff   192B  3 26 00:04 ios
drwxr-xr-x   3 chengchao  staff    96B  3 26 00:04 lib
-rw-r--r--   1 chengchao  staff   3.2K  3 26 00:05 pubspec.lock
-rw-r--r--   1 chengchao  staff   2.6K  3 26 00:04 pubspec.yaml
drwxr-xr-x   3 chengchao  staff    96B  3 26 00:04 test

很简单,只有lib、ios、android三个主要目录,我们用AS打开看下结构

  • lib目录下只有main.dart文件,这个就是我们实现flutter程序的地方
  • android目录下是一个标准的android 项目,ios也是一样的道理

这里已经分别给你创建好了ios和android的原生环境,并且集成了flutter。

具体创建和运行程序参加官网: https://flutter.dev/docs/get-started/test-drive?tab=androidstudio

 

 

 

二 运行Flutter程序

 

程序创建好之后,可以直接通过IDE运行程序,也可以通过命令。为了对运行了解更多一些,我们从命令行运行。从命令行创建程序时有提示使用 flutter run来运行程序

➜  flutter_hello flutter run
No connected devices.

必须要连接一个设备, 对于Android来说可以连接一个真实的设备,也可以使用模拟器。模拟器我们可以从AS中启动,也可以通过flutter emulator命令,下面列举了我之前创建的模拟器。

➜  flutter_hello flutter emulator
2 available emulators:

Pixel_2_XL_API_28 • pixel_2_xl • Google • Pixel 2 XL API 28
Pixel_2_XL_API_Q  • pixel_2_xl • Google • Pixel 2 XL API Q

To run an emulator, run 'flutter emulators --launch <emulator id>'.
To create a new emulator, run 'flutter emulators --create [--name xyz]'.

You can find more information on managing emulators at the links below:
  https://developer.android.com/studio/run/managing-avds
  https://developer.android.com/studio/command-line/avdmanager

创建并启动之后就可以运行flutter程序了

使用命令行的好处就是,有些输出信息在IDE可能直接被我们忽略了。简单看一下上面运行的输出信息

  1. 因为模拟器是x86平台,程序运行在x86 debug mode
  2. 编译过程是gradle进行构建
  3. 使用android的 assembleDebug 任务进行编译
  4. 生成的Android安装包在 build/app/outputs/apk/debug/app-debug.apk
  5. 程序运行后可以使用hot reload (也就是不重启程序来修改程序,修改好马上可以看到效果)
  6. 因为debug模式,所以可以通过一个页面来查看flutter应用的相关信息

整体看起来和编译一个Android应用程序没有什么区别。来看一下flutter run命令还有什么参数, 下面选取了一下重要的

➜  flutter_hello flutter run --help
Run your Flutter app on an attached device.

Usage: flutter run [arguments]
-h, --help                                   Print this usage information.
    --debug                                  Build a debug version of your app (default mode).
    --profile                                Build a version of your app specialized for performance profiling.
    --release                                Build a release version of your app.
    --target-platform                        Specify the target platform when building the app for an Android device.
                                             Ignored on iOS.
                                             [default (default), android-arm, android-arm64, android-x86, android-x64]

    -t, --target=                            The main entry-point file of the application, as run on the device.
                                             If the --target option is omitted, but a file name is provided on the command line, then that is used instead.
                                             (defaults to "lib/main.dart")

可以看到,flutter有3中运行模式,debug、profile和release。 Android上还能指定对应的运行平台。使用release 模式运行看看

➜  flutter_hello flutter run --release
Using hardware rendering with device Android SDK built for x86. If you get graphics artifacts, consider enabling software rendering with
"--enable-software-rendering".
Release mode is not supported for emulators.

发现模拟器不能运行release和profile模式,用真机试试 , 使用flutter device可以查看连接的设备

➜  flutter_hello flutter devices
1 connected device:

HTC U 1w • FA7311705281 • android-arm64 • Android 8.0.0 (API 26)

运行一下release mode

➜  flutter_hello flutter run --release
Initializing gradle...                                              0.9s
Resolving dependencies...                                           1.4s
Launching lib/main.dart on HTC U 1w in release mode...
Running Gradle task 'assembleRelease'...
Running Gradle task 'assembleRelease'... Done                      21.0s
Built build/app/outputs/apk/release/app-release.apk (5.1MB).
Installing build/app/outputs/apk/app.apk...                         3.7s

To quit, press "q".

整个过程和debug模式差不多,只是改用了Android 的assembleRelease 任务编译release包。如果以 profile 模式运行,执行的是assembleProfile 任务,这个是普通Android程序没有的, 而且和debug模式一样可以查看相关的运行信息。

 

 

 

三 编译Flutter程序

 

如果仅仅只是编译flutter程序,可以使用flutter build flutter clean命令

➜  apk flutter build --help
Flutter build commands.

Usage: flutter build <subcommand> [arguments]
-h, --help    Print this usage information.

Available subcommands:
  aot         Build an ahead-of-time compiled snapshot of your app's Dart code.
  apk         Build an Android APK file from your app.
  appbundle   Build an Android App Bundle file from your app.
  bundle      Build the Flutter assets directory from your app.
  flx         Deprecated
  ios         Build an iOS application bundle (Mac OS X host only).

Run "flutter help" to see global options.
  • aot:把flutter中的dart code编译成对应的aot-snapshot文件,这里编译出的主要产物在build/aot/目录下:isolate_snapshot_data、isolate_snapshot_instr、vm_snapshot_data、vm_snapshot_instr、app.dill。这里的dart code包括我们自己的mian.dart,同时也包括framework和其他dart库的代码。
  • apk:编译一个release版的APK,使用的是assembleRelease任务,和前面一样,位于build/app/outputs/apk/release/app-release.apk
  • appbundle:编译整个app生成一个Android Bundle文件,位于build/app/outputs/bundle/release/app.aab这个是google发布的新的格式,不过好像只能在Google Play使用,具体可以参见https://developer.android.com/platform/technology/app-bundle
  • bundle:这个会把flutter的资源打包到一起,放在build/flutter_assets 目录下。

这些命令都可以携带参数,具体命令可以使用类似 flutter apk –help查看

--debug             Build a debug version of your app.
--profile           Build a version of your app specialized for performance profiling.
--release           Build a release version of your app (default mode).

大致上都差不多,最主要的是都可以指定编译的模式, 和flutter run一样。简单说Debug模式下支持Dart的断言、调试和一些扩展功能,代码并不是最优化的。 Release则不支持这些,代码是最优化的,Profile模式和Release类似,只是支持profile performance。

官网有介绍3种编译模式的区别  https://flutter.dev/docs/testing/build-modes  后面打算专门看一下dart和flutter的编译模式,所以这里简单了解一下就行了。

 

 

 

四 安装包结构

 

目前已知Android上flutter程序编译有三种模式,生成的APK都存放在build/app/outputs/apk/ 目录下:

➜  apk tree
.
├── app.apk
├── app.apk.sha1
├── debug
│   ├── app-debug.apk
│   └── output.json
├── profile
│   ├── app-profile.apk
│   └── output.json
└── release
    ├── app-release.apk
    └── output.json

3 directories, 8 files

我们使用Android Studio查看一下包含Flutter程序的APK的结构:

debug

 

release

 

profile

 

从上面3张图可以发现,Release和Profile的文件结构完全一样, Debug则有些不同,而且Debug的包大非常多,有3个平台的so文件,因为debug可以在模拟器上运行。 整个安装包结构和普通Android程序完全一样,主要是多了一些flutter相关的文件:

  • libflutter.so :前面在介绍flutter SDK时候看到过这个文件,这个是flutter的engine,也就是flutter整个环境是作为一个so打包在应用程序中的。
  • assets目录: 这个目录可以把一些文件打包到APK中,并在运行时使用。上面列出来的文件全部都是flutter使用的。当Android程序运行后,首先启动Flutter Engine, 然后Engine会从这个目录下读取相关文件,然后运行flutter程序。Debug和Release结构有些不同,我们以Release版本简单介绍一下
    • flutter_assets: 这个目录主要是存放flutter的资源文件,里面包含了IOS和Android上使用的字体文件。
    • vm_snapshot_data和vm_snapshot_instr  是dart代码AOT编译后生产的snapshot文件,其中instr是机器码,类似.text段,而data是数据,类似.data段。 这2个文件是Engine用来初始化DartVM的,不包含业务逻辑。
    • isolate_snapshot_data和isolate_snapshot_instr 是相关的dart代码(应该是包含业务和Framework的dart代码)AOT编译后生成的snapshot文件。isolate是Dart中的一个概念,代码都运行在isolate中,一个应用程序可以有多个isolate运行,他们直接不能直接通信,只能通过Dart VM 进行通信。

 

 

 

五 总结

 

这一篇主要了解了一下Android上如何创建、编译和运行一个全新Flutter程序。执行编译命令让我们了解了flutter的几种编译模式。通过对安装包结构的简单分析,对flutter有了更进一步的了解。

  1. Flutter有三种编译模式
  2. Flutter Engine 是打包在APK中的,也就是说flutter 的功能完全可以自己定制
  3. Release模式下代码都是以AOT编译生成的机器码,所以是平台相关的,目前Android只支持arm-v7
  4. Flutter相关代码和资源都打包在assets目录下,运行时会被拷贝到固定的目录,这样就为实现按需下载和热更新提供了可能
  5. 因为release是AOT,所以无法实现Hot Reload,而Debug模式之所以能实现,是因为所有代码都放到了kernel_blob.bin文件中。 这个代码不是机器码,只是dart进行kernel编译后的中间语言snapshot文件,它是和平台无关,以JIT方式运行,这也是Debug模式可以Hot Reload的原因。

 

上面会涉及到一些编译的知识比如JIT、AOT,如果不太了解可以在网上搜索一下。还有和Dart相关的一些支持比如 kernel编译、snapshot文件,kernel snapshot等。可以参见dart的wiki,但是说实话不是很好懂,或者细想会发现有不少不理解的地方。之前看到一篇很好的Dart VM的文章,后面计划结合这些这些一起写一篇文章。

https://github.com/dart-lang/sdk/wiki/Snapshots

https://github.com/dart-lang/sdk/wiki/Kernel-Documentation

 


如果本文对您有帮助,可以扫描下方二维码打赏!您的支持是我的动力!
微信打赏 支付宝打赏

1 评论

  1. 使用flutter build apk(不管后面是否加上–release/–debug),都会卡在那里很久没有反应。但是进入到android子目录中,使用./gradlew assembleRelease或者./gradlew assembleDebug都可以正常生成apk,不知道为啥

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注