使用原生的调试器

如果你只使用 Dart 语言开发 Flutter 应用,并且不使用特定于平台的的库或者功能,你可以使用 IDE 的调试器调试你的代码。只有这篇指南的第一部分「调试 Dart 代码」对你有用。

如果你正在开发特定于平台的的插件或者使用由 Swift,ObjectiveC,Java 或 Kotlin 语言编写的特定于平台的库,你可以使用 Xcode(用于 iOS)或者 Android Gradle(用于 Android)调试这部分代码。本指南介绍如何将用于 Dart 和用于原生代码的 两个 调试器连接到你的 Dart 应用。

调试 Dart 代码

你可以使用 IDE 进行一般的 Dart 调试。以下内容针对 Android Studio 进行说明,但你也可以使用你喜欢的安装并配置好 Flutter 和 Dart 插件的编辑器来进行调试。

小提示

推荐连接到真机进行调试,而不是使用不支持 profie 构建模式的仿真器或模拟器。更多信息参考 Flutter 的构建模式

Dart 调试器

  • 使用 Android Studio 打开你的项目。如果你还没有项目,根据 开发体验初探 中的说明创建一个。

  • 通过单击调试图标(Debug-run icon)同时打开调试面板并在控制台中运行应用。

首次运行应用是最慢的,你会发现窗口底部的调试面板看起来会像这样:

Debug pane

你可以设置调试面板的显示位置,甚至可以用调试面板右侧的齿轮将其拆分到独立的窗口。对于 Android Studio 中的任何检查器都是如此。

  • counter++ 这一行上添加断点。

  • 在应用里,点击 + 按钮(FloatingActionButton,或者简称 FAB)来增加数字。应用会暂停。

  • 以下截图显示:

    • 编辑面板中的断点。

    • 当在断点处暂停时,在调试面板中显示应用的状态。

    • this 变量展开并显示其值。

App status when hitting the set breakpoint

你可以 step in/out/over Dart 语句、热重载和恢复执行应用、以及像使用其他调试器一样来使用 Dart 调试器。5: Debug 按钮切换调试面板的显示。

Flutter inspector

Flutter 插件提供了另外两个可能给你提供帮助的功能。Flutter inspector 是一个用来可视化以及查看 Flutter widget 树的工具,并帮助你:

  • 了解现有布局

  • 诊断布局问题

你可以使用 Android Studio 窗口右侧的垂直按钮切换检查器的显示。

Flutter inspector

Flutter outline

Flutter Outline 以可视形式显示构建方法。注意在构建方法上可能与 widget 树不同。你可以使用 Android Studio 窗口右侧的垂直按钮切换 outline 的显示。

screenshot showing the Flutter inspector

这篇指南剩下的部分介绍了如何搭建原生代码的调试环境。你应该可以想象到,对于 iOS 和 Android 这个过程是不同的。

小提示

通过安装 Presentation Assistant 插件来成为 Android Studio 的专业用户。你可以打开 Preferences > Plugins > Browsing repositories… 并在搜索框中输入 Presen 来找到并安装这个插件。

当你安装并重启 Android Studio 之后,通过使用以下功能这个插件可以帮助你成为一个专业用户:

  • 显示你执行的任何操作的名字和 Windows/Linux/Mac 的快捷键。

  • 允许你搜索并找到可用的操作、设置、文档等等。

  • 允许你切换首选项,打开视图或者执行操作。

  • 允许你设置键盘快捷键。(无法在 Mac 上运行此功能?)

例如,尝试下这个:

  • 当焦点在编辑面板中时,输入 command-Shift-A(Mac)或者 shift-control-A(Windows 和 Linux)。该插件会同时显示「查找」面板并显示在所有三个平台上执行此操作的提示。

Find panel

Presentation assistant's Find panel

Presentation assistant 的「查找」面板

Find pane

Presentation assistant's action hint for opening its Find panel on Mac, Windows and Linux

Presentation assistant 的在 Mac、Windows 和 Linux 上打开「查找」面板的操作提示。

  • 输入 attach 显示以下内容:

Find panel

  • 更新之后,你可以输入 Flutter 或者 Dart 来查看是否有新的可用的操作。

使用 Escape 隐藏 Presentation Assistant 的「查找」面板。

使用 Android Gradle 调试(Android)

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

  • 创建一个基本的 Flutter 应用。

  • 替换 lib/main.dart 为来自 url_launcher 包的以下示例代码

  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. import 'dart:async';
  6.  
  7. import 'package:flutter/material.dart';
  8. import 'package:url_launcher/url_launcher.dart';
  9.  
  10. void main() {
  11. runApp(MyApp());
  12. }
  13.  
  14. class MyApp extends StatelessWidget {
  15. @override
  16. Widget build(BuildContext context) {
  17. return MaterialApp(
  18. title: 'URL Launcher',
  19. theme: ThemeData(
  20. primarySwatch: Colors.blue,
  21. ),
  22. home: MyHomePage(title: 'URL Launcher'),
  23. );
  24. }
  25. }
  26.  
  27. class MyHomePage extends StatefulWidget {
  28. MyHomePage({Key key, this.title}) : super(key: key);
  29. final String title;
  30.  
  31. @override
  32. _MyHomePageState createState() => _MyHomePageState();
  33. }
  34.  
  35. class _MyHomePageState extends State<MyHomePage> {
  36. Future<void> _launched;
  37.  
  38. Future<void> _launchInBrowser(String url) async {
  39. if (await canLaunch(url)) {
  40. await launch(url, forceSafariVC: false, forceWebView: false);
  41. } else {
  42. throw 'Could not launch $url';
  43. }
  44. }
  45.  
  46. Future<void> _launchInWebViewOrVC(String url) async {
  47. if (await canLaunch(url)) {
  48. await launch(url, forceSafariVC: true, forceWebView: true);
  49. } else {
  50. throw 'Could not launch $url';
  51. }
  52. }
  53.  
  54. Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
  55. if (snapshot.hasError) {
  56. return Text('Error: ${snapshot.error}');
  57. } else {
  58. return Text('');
  59. }
  60. }
  61.  
  62. @override
  63. Widget build(BuildContext context) {
  64. String toLaunch = 'https://flutter.dev';
  65. return Scaffold(
  66. appBar: AppBar(
  67. title: Text(widget.title),
  68. ),
  69. body: Center(
  70. child: Column(
  71. mainAxisAlignment: MainAxisAlignment.center,
  72. children: <Widget>[
  73. Padding(
  74. padding: EdgeInsets.all(16.0),
  75. child: Text(toLaunch),
  76. ),
  77. RaisedButton(
  78. onPressed: () => setState(() {
  79. _launched = _launchInBrowser(toLaunch);
  80. }),
  81. child: Text('Launch in browser'),
  82. ),
  83. Padding(padding: EdgeInsets.all(16.0)),
  84. RaisedButton(
  85. onPressed: () => setState(() {
  86. _launched = _launchInWebViewOrVC(toLaunch);
  87. }),
  88. child: Text('Launch in app'),
  89. ),
  90. Padding(padding: EdgeInsets.all(16.0)),
  91. FutureBuilder<void>(future: _launched, builder: _launchStatus),
  92. ],
  93. ),
  94. ),
  95. );
  96. }
  97. }
  • 添加 url_launcher 依赖到 pubspec 文件,并执行 flutter pub get
  1. name: flutter_app
  2. description: A new Flutter application.
  3. version: 1.0.0+1
  4.  
  5. dependencies:
  6. flutter:
  7. sdk: flutter
  8.  
  9. url_launcher: ^3.0.3
  10. cupertino_icons: ^0.1.2
  11.  
  12. dev_dependencies:
  13. flutter_test:
  14. sdk: flutter
  • 点击调试按钮(Debug-run icon)来同时打开调试面板并启动应用。等待应用在设备上启动并在调试面板中显示 Connected。(第一次可能需要一分钟,但是之后的启动会变快。)应用包含两个按钮:1)Launch in browser 在你的手机默认浏览器中打开 flutter.io 和 2)Launch in app 在你的应用中打开 flutter.io。

screenshot containing two buttons for opening flutter.dev

  • 点击 Attach debugger to Android process 按钮(looks like a rectangle superimposed with a tiny green bug

小提示

如果这个按钮没有显示在 Projects 菜单栏上,确定你正在使用的是 Flutter 项目而不是 Flutter 插件

  • 从进程对话框中,你应该可以看到每一个设备的入口。选择 show all processes 来显示每个设备可用的进程。

  • 选择你想附加到的进程。在这个例子中是 Motorola Moto G 的 com.google.clickcount(或 com.company.app_name)进程。

screenshot containing two buttons for opening flutter.dev

  • 在调试面板中,你现在应该可以看到一个 Android Debugger 标签页。

  • 在项目面板,展开 app_name > android > app > src > main > java > io.flutter plugins。双击 GeneratedProjectRegistrant 在编辑面板中打开 Java 代码。

Dart 和原生调试器都在与同一个进程交互。使用其中一个或者同时使用两个来设置断点、检查堆栈、恢复运行……换句话说,调试!

screenshot of Android Studio in the Dart debug pane.

The Dart debug pane with two breakpoints set in lib/main.dart

Dart 调试面板和 lib/main.dart 中的两个断点。

screenshot of Android Studio in the Android debug pane.

The Android debug pane with one breakpoint set in GeneratedPluginRegistrant.java. Toggle between the debuggers by clicking the appropriate debugger in the Debug pane's banner.

Android 调试面板和 GeneratedPluginRegistrant.java 中的一个断点。通过单击调试面板顶部的相应调试器,在调试器之间进行切换。

使用 Xcode 调试(iOS)

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

[PENDING]

资源

下面的资源包含更多关于 Flutter、iOS 和 Android 调试的信息。

Flutter

Android

你可以在 developer.android.com 找到下列的调试资源。

iOS

你可以在 developer.apple.com 找到下列的调试资源。