Fluter 应用调试

2020-9-9    seo达人

Flutter 构建模式

目前,Flutter一共提供了三种运行模式,分别是Debug、Release和Profile模式。其中,Debug模式主要用在软件编写过程中,Release模式主要用于应用发布过程中,而Profile模式则主要用于应用性能分析时,每个模式都有自己特殊的使用场景。下面简介介绍下这几种模式:


Debug模式

Debug模式又名调试模式,Debug模式可以同时在物理设备、仿真器或者模拟器上运行应用。默认情况下,使用flutter run命令运行应用程序时就是使用的Debug模式。在Debug模式下,所有的断言、服务扩展是开启的,并且在模式对快速开发和运行周期进行了编译优化,当使用调试工具进行代码调试时可以直接连接到应用的进程里。


Release模式

Release模式又名发布模式,此模式只能在物理设备上运行,不能在模拟器上运行。使用flutter run --release命令运行应用程序时就是使用的Release模式。在Release模式下,断点、调试信息和服务扩展是不可用的,并且Release模式针对快速启动、快速执行和安装包大小进行了优化。


Profile模式

Profile模式只能在物理设备上运行,不能在模拟器上运行。此模式主要用于应用性能分析,一些应用调试能力是被保留的,目的是分析应用存在的性能问题。Profile模式和Release模式大体相同,不同点体现在,Profile模式的某些服务扩展是启用的,某些进程调试手段也是开启的。


调试模式

在 Debug 模式下,app 可以被安装在物理设备、仿真器或者模拟器上进行调试。在Debug模式下,可以进行如下操作:


断点 是开启的。

服务扩展是开启的。

针对快速开发和运行周期进行了编译优化(但不是针对执行速度、二进制文件大小或者部署)。

调试开启,类似 开发者工具 等调试工具可以连接到进程里。

如果是在 Web 平台下的调试模式,可以进行如下操作:


本次构建 没有 最小化资源并且整个构建 没有 优化性能。

为了简化调试,这个 Web 应用使用了 dartdevc 编译器。

默认情况下,运行 flutter run 会使用 Debug 模式,同时 IDE 也支持这些模式。例如,Android Studio 提供了 Run > Debug… 菜单选项,而且在项目面板中还有一个三角形的绿色运行按钮图标 。


Release 模式

当你想要最大的优化以及最小的占用空间时,就使用 Release 模式来部署 app。 release 模式是不支持模拟器或者仿真器的,使用 Release 模式意味着。


断点是不可用的。

调试信息是不可见的。

调试是禁用的。

编译针对快速启动、快速执行和小的 package 的大小进行了优化。

服务扩展是禁用的。

对于Web开发来说,使用 Release 模式意味着。


这次构建资源已经被压缩,并且性能得以优化。

这个 Web 应用通过 dart2js 编译器构建,以确保更优秀的性能。

Profile 模式

在 Profile 模式下,一些调试能力是被保留的,足够分析你的 app 性能。Profile 模式在仿真器和模拟器上是不可用的,因为他们的行为不能代表真实的性能。和 release 相比, profile 模式有以下不同:


一些服务扩展是启用的。例如,支持 performance overlay。

Tracing 是启用的,一些调试工具,比如 开发者工具 可以连接到进程里。

在 Web 平台使用Profile 模式意味着:


资源文件没有被压缩,但是整体性能已经优化。

这个 Web 应用通过 dart2js 编译器构建。

调试工具

在Flutter应用开发中,有很多工具可以帮助调试 Flutter 应用程序,常见的如下所示。


开发者工具,是一套运行在浏览器的性能及分析工具。

Android Studio/IntelliJ 和 VS Code(借助 Flutter 和 Dart 插件)支持内置的源代码调试器,可以设置断点,单步调试,检查数值。

Flutter inspector,是开发者工具提供的 widget 检查器,也可直接在 Android Studio 和 IntelliJ 中使用(借助 Flutter 插件)。检查器可以可视化展现 widget 树,查看单个 widget 及其属性值,开启性能图层,等等。

开发者工具

要调试及分析应用,开发者工具可能是你的首选。开发者工具运行在浏览器,支持以下特性:


源代码调试器

Widget 检查器,展示可视化的 widget 树; “widget select” 模式,在应用中选择一个 widget,会在 widget 树直接定位到它的位置。

内存分析

时间线视图,支持跟踪,导入及导出跟踪信息

日志视图

如果你在Debug 模式 或Profile 模式 运行,那么可以在浏览器打开开发者工具连接到你的应用。开发者工具不能用在 Release 模式 编译的应用,因为调试和分析信息都被删除了。如果你要用开发者工具分析应用,需确保使用 Profile 模式运行应用。


在这里插入图片描述


断点调试

和其他语言一样,Flutter的断点调试支持在 IDE 或编辑器(比如 Android Studio/IntelliJ 和 VS Code)、或者通过编码两种方式。

其中,开发者工具调试器如下图所示。

在这里插入图片描述


如果需要,在源代码中设置断点,然后点击工具栏中的 【Debug】 按钮,或选择 【Run】 > 【Debug】即可开启调试功能。

在这里插入图片描述


开启调试后,可以在控制台看到如下一些信息。


底部的 Debugger 窗口会显示出堆栈和变量信息。

底部的 Console 窗口会显示详细的日志输出。

调试基于默认的启动配置,如果需要自定义,点击选择目标下拉按钮,选择 Edit configuration 进行配置。

在进行断点调试时,使用得最多的就是单步调试,三个单步调试按钮在暂停后会变为可用状态。


使用 Step in 来进入被调用的方法,在遇到方法内的第一行可执行代码时结束。

使用 Step over 直接执行某个方法调用而不进入内部;该按钮在当前方法内按行执行。

使用 Step out 来跳出当前方法,这种方式会直接执行完所有当前方法内的语句。

除此之外,我们还可以使用代码的方式进行断点调试,我们可以在源代码中使用 debugger()函数来开启断点,当代码运行到此处时就会刮起,如下所示。


import 'dart:developer';


void someFunction(double offset) {

 debugger(when: offset > 30.0);

 // ...

}

Dart 分析器

如果你使用的是 Android Studio或者VSCode,那么工具会自带的 Dart 分析器默认会检查代码,并发现可能的错误。如果你使用命令行,则可以使用 flutter analyze命令来检查代码。Dart 分析器非常依赖你在代码中添加的类型注解,以帮助跟踪问题。


另外,我们可以使用flutter analyze --flutter-repo命令将分析结果打印到控制台上,每次运行这个命名之前,请先运行flutter update-packages 升级的包,这样就可以获取的依赖包。如果你不这样做,你可能会从dart:ui得到一些错误消息,比如偏移量等。因为执行flutter analysis 命令时并不会主动去拉取依赖。


对于一次性的Dart分析,直接使用flutter analyze --flutter-repo即可,对于连续分析,则可以使用flutter analyze --flutter-repo --watch命令。如果你想知道多少个成员变量丢失了dartdocs,可以添加一个dartdocs参数。


Flutter inspector 工具

Flutter inspector 是分析Flutter组件状态树的利器,Flutter使用小部件来控制页面组件到布局的精准控制,Flutter inspector 可以帮助我们进行如下一些分析。


进行布局分析,理解布局层次

诊断布局问题

在这里插入图片描述


在调试模式下,我们点击Android Studio右边Flutter inspector按钮即可开启Flutter inspector分析,Flutter inspector提供了如下的可视化调试工具。

在这里插入图片描述


Select widget mode:启用此按钮后,选择组件树的代码会自动跳转到对应的源代码里面。

Refresh tree : 重新加载的组件信息。

Slow Animations:放慢动画速度,以便进行视觉上的查验。

Debug Paint: 边框、方向的可视化。

Paint Baselines: 每个渲染框在它的每个文本基线上画一条线。

Repaint Rainbow:查看重绘的严重程度,严重的会被爆红。

除了上面的功能外,我们还可以点击【Open DevTools】打开Flutter的调试页面,可以借助它进行很多性能分析,后面会具体介绍。

在这里插入图片描述


测量应用启动时间

要收集有关 Flutter 应用程序启动所需时间的详细信息,可以在运行 flutter run 命令时使用 trace-startup 和 profile 选项,如下所示。


flutter run --trace-startup --profile

跟踪输出被保存到 Flutter 工程目录在 build 目录下,一个名为 start_up_info.json 的 JSON 文件中,输出列出了从应用程序启动到这些跟踪事件(以微秒捕获)所用的时间,如下所示。


{

 "engineEnterTimestampMicros": 2346054348633,

 "timeToFrameworkInitMicros": 812748,

 "timeToFirstFrameRasterizedMicros": 1573154,

 "timeToFirstFrameMicros": 1221472,

 "timeAfterFrameworkInitMicros": 408724

}

对应的具体含义如下:


进入 Flutter 引擎时

展示应用第一帧时

初始化Flutter框架时

完成Flutter框架初始化时

使用Android Studio进行调试

Flutter官方推荐使用Android Studio或VSCode进行应用开发, 和其他语言的调试一样,Dart代码的调试流程也差不多。如果还没有Flutter项目,可以新建一个示例项目。通过单击首先,点击调试图标(Debug-run icon)同时打开调试面板并在控制台中运行应用,首次运行应用是最慢的,应用启动后,界面应该是下面这样的。

在这里插入图片描述


然后,我们在在 counter++ 这一行上添加断点。在应用里,点击 + 按钮(FloatingActionButton,或者简称 FAB)来增加数字,应用会暂停。

在这里插入图片描述


你可以 step in/out/over Dart 语句、热重载和恢复执行应用、以及像使用其他调试器一样来使用 Dart 调试器。


Flutter inspector

Flutter inspector 是一个用来可视化以及查看 Flutter widget 树的工具,提供如下功能:


了解现有布局

诊断布局问题

可以使用 Android Studio 窗口右侧的垂直按钮来打开Flutter inspector,如下图所示。


在这里插入图片描述


Flutter outline

Flutter Outline 是一个可视的显示页面构建方法的功能,注意在构建方法上可能与 widget 树不同,可以使用 Android Studio 窗口右侧的垂直按钮切换 outline 的显示。

在这里插入图片描述


Tip: 我们可以安装一个 Presentation Assistant 插件来辅助我们进行开发,Presentation Assistant 提供了很多的快捷功能。例如,当焦点在编辑面板中时,输入 command-Shift-A(Mac)或者 shift-control-A(Windows 和 Linux),该插件会同时显示「查找」面板并显示在所有三个平台上执行此操作的提示。

在这里插入图片描述


然后在输入框中输入attach关键字,显示如下图。


在这里插入图片描述


使用 Android Gradle 调试

为了调试原生代码,你需要一个包含 Android 原生代码的应用。在本节中,你将学会如何连接两个调试器到你的应用:

1)Dart 调试器。

2)Android Gradle 调试器。


创建一个基本的 Flutter 应用,然后替换 lib/main.dart 的代码为以下示例代码。


// Copyright 2017 The Chromium Authors. All rights reserved.

// Use of this source code is governed by a BSD-style license that can be

// found in the LICENSE file.


import 'dart:async';


import 'package:flutter/material.dart';

import 'package:url_launcher/url_launcher.dart';


void main() {

 runApp(MyApp());

}


class MyApp extends StatelessWidget {

 @override

 Widget build(BuildContext context) {

   return MaterialApp(

     title: 'URL Launcher',

     theme: ThemeData(

       primarySwatch: Colors.blue,

     ),

     home: MyHomePage(title: 'URL Launcher'),

   );

 }

}


class MyHomePage extends StatefulWidget {

 MyHomePage({Key key, this.title}) : super(key: key);

 final String title;


 @override

 _MyHomePageState createState() => _MyHomePageState();

}


class _MyHomePageState extends State<MyHomePage> {

 Future<void> _launched;


 Future<void> _launchInBrowser(String url) async {

   if (await canLaunch(url)) {

     await launch(url, forceSafariVC: false, forceWebView: false);

   } else {

     throw 'Could not launch $url';

   }

 }


 Future<void> _launchInWebViewOrVC(String url) async {

   if (await canLaunch(url)) {

     await launch(url, forceSafariVC: true, forceWebView: true);

   } else {

     throw 'Could not launch $url';

   }

 }


 Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {

   if (snapshot.hasError) {

     return Text('Error: ${snapshot.error}');

   } else {

     return Text('');

   }

 }


 @override

 Widget build(BuildContext context) {

   String toLaunch = 'https://flutter.dev';

   return Scaffold(

     appBar: AppBar(

       title: Text(widget.title),

     ),

     body: Center(

       child: Column(

         mainAxisAlignment: MainAxisAlignment.center,

         children: <Widget>[

           Padding(

             padding: EdgeInsets.all(16.0),

             child: Text(toLaunch),

           ),

           RaisedButton(

             onPressed: () => setState(() {

                   _launched = _launchInBrowser(toLaunch);

                 }),

             child: Text('Launch in browser'),

           ),

           Padding(padding: EdgeInsets.all(16.0)),

           RaisedButton(

             onPressed: () => setState(() {

                   _launched = _launchInWebViewOrVC(toLaunch);

                 }),

             child: Text('Launch in app'),

           ),

           Padding(padding: EdgeInsets.all(16.0)),

           FutureBuilder<void>(future: _launched, builder: _launchStatus),

         ],

       ),

     ),

   );

 }

}

然后,添加 url_launcher 依赖到 pubspec 文件,并执行 flutter pub get命令拉取依赖包。


name: flutter_app

description: A new Flutter application.

version: 1.0.0+1


dependencies:

 flutter:

   sdk: flutter


 url_launcher: ^3.0.3

 cupertino_icons: ^0.1.2


dev_dependencies:

 flutter_test:

   sdk: flutter

点击调试按钮(Debug-run icon)来同时打开调试面板并启动应用,如下图所示。

在这里插入图片描述


点击 【Attach debugger to Android process】 按钮,从进程对话框中,你应该可以看到每一个设备的入口。选择 show all processes 来显示每个设备可用的进程。

在这里插入图片描述


在调试面板中,你现在应该可以看到一个 Android Debugger 标签页,然后依次选择【app_name】 > 【android】 > 【app】 > 【src】 >【 main】 > 【java】 > 【io.flutter plugins】在项目面板,然后双击 GeneratedProjectRegistrant 在编辑面板中打开 Java 代码,此时Dart 和原生调试器都在与同一个进程交互。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

分享本文至:

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档