Flutter功能未知插件fadlurahmanfdev_alice的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter功能未知插件fadlurahmanfdev_alice的使用

Alice

pub package pub package pub package

Alice 是一个用于调试 HTTP 请求的 Flutter 工具。它捕获并存储 HTTP 请求和响应,可以通过简单的用户界面查看。该工具受到 Chuck 和 Chucker 的启发。

支持的 Dart HTTP 客户端插件:

  • Dio
  • dart:io 包中的 HttpClient
  • http/http 包中的 Http
  • Chopper
  • 通用 HTTP 客户端

特性:

  • ✔️ 详细的 HTTP 调用日志(HTTP 请求,HTTP 响应)
  • ✔️ 检查器 UI 查看 HTTP 调用
  • ✔️ 保存 HTTP 调用到文件
  • ✔️ 统计信息
  • ✔️ HTTP 调用通知
  • ✔️ 支持常用的 Dart HTTP 客户端
  • ✔️ 错误处理
  • ✔️ 摇晃设备以打开检查器
  • ✔️ HTTP 调用搜索
  • ✔️ Flutter/Android 日志

安装

  1. 在你的 pubspec.yaml 文件中添加以下内容:
dependencies:
  fadlurahmanfdev_alice: ^0.4.2
  1. 运行安装命令:
$ flutter packages get
  1. 导入库:
import 'package:fadlurahmanfdev_alice/alice.dart';

使用

Alice 配置

  1. 创建 Alice 实例:
Alice alice = Alice();
  1. 将 navigator key 添加到你的应用中:
MaterialApp(
  navigatorKey: alice.getNavigatorKey(),
  home: ...
)

你需要添加这个 navigator key 才能显示检查器 UI。你也可以使用自己的 navigator key:

Alice alice = Alice(showNotification: true, navigatorKey: yourNavigatorKeyHere);

如果需要延迟传递 navigatorKey,可以使用:

alice.setNavigatorKey(yourNavigatorKeyHere);

这是运行 Alice 所需的最小配置。可以在 Alice 构造函数中设置可选参数,这些参数在下面列出。如果你不希望更改任何设置,可以直接跳转到 HTTP 客户端配置。

额外设置

你可以通过在 Alice 构造函数中设置 showNotification 来显示通知。点击此通知将打开检查器:

Alice alice = Alice(..., showNotification: true);

你还可以通过在 Alice 构造函数中设置 showInspectorOnShake 来通过摇晃设备来打开检查器(默认禁用):

Alice alice = Alice(..., showInspectorOnShake: true);

如果想传递其他通知图标,可以使用 notificationIcon 参数。默认值为 @mipmap/ic_launcher

Alice alice = Alice(..., notificationIcon: "myNotificationIconResourceName");

如果想限制内存中保存的 HTTP 调用的最大数量,可以使用 maxCallsCount 参数:

Alice alice = Alice(..., maxCallsCount: 1000));

如果你想改变 Alice 的方向性,可以使用 directionality 参数。如果该参数为 null,则使用应用程序的方向性:

Alice alice = Alice(..., directionality: TextDirection.ltr);

如果你想隐藏分享按钮,可以使用 showShareButton 参数:

Alice alice = Alice(..., showShareButton: false);

HTTP 客户端配置

如果你使用的是 Dio,只需添加拦截器:

Dio dio = Dio();
dio.interceptors.add(alice.getDioInterceptor());

如果你使用的是 dart:io 包中的 HttpClient:

httpClient
    .getUrl(Uri.parse("https://jsonplaceholder.typicode.com/posts"))
    .then((request) async {
        alice.onHttpClientRequest(request);
        var httpResponse = await request.close();
        var responseBody = await httpResponse.transform(utf8.decoder).join();
        alice.onHttpClientResponse(httpResponse, request, body: responseBody);
 });

如果你使用的是 http 包中的 http:

http.get('https://jsonplaceholder.typicode.com/posts').then((response) {
    alice.onHttpResponse(response);
});

如果你使用的是 Chopper,需要添加拦截器:

chopper = ChopperClient(
    interceptors: [alice.getChopperInterceptor()],
);

注意!Alice 会在请求中添加特殊的 “alice_token” 头以便计算正确的 HTTP 调用 ID。

如果你有其他 HTTP 客户端,可以使用通用 HTTP 调用接口:

AliceHttpCall aliceHttpCall = AliceHttpCall(id);
alice.addHttpCall(aliceHttpCall);

手动显示检查器

如果不想使用摇晃或通知:

alice.showInspector();

保存调用

Alice 支持将日志保存到移动设备存储。为了让保存功能工作,你需要在你的 Android 应用程序清单中添加以下权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Flutter 日志

如果想在 Alice 中记录 Flutter 日志,可以使用以下方法:

alice.addLog(log);

alice.addLogs(logList);

检查器状态

检查当前检查器是否打开(打开/关闭):

alice.isInspectorOpened();

扩展

你可以使用扩展来缩短 HTTP 和 HTTP 客户端代码。这虽然是可选项,但可能会改善你的代码库。

示例

导入:

import 'package:fadlurahmanfdev_alice/core/alice_http_client_extensions.dart';
import 'package:fadlurahmanfdev_alice/core/alice_http_extensions.dart';

使用扩展:

http
    .post('https://jsonplaceholder.typicode.com/posts', body: body)
    .interceptWithAlice(alice, body: body);

httpClient
    .postUrl(Uri.parse("https://jsonplaceholder.typicode.com/posts"))
    .interceptWithAlice(alice, body: body, headers: Map());

示例代码

以下是完整的示例代码:

import 'dart:convert';
import 'dart:io';

import 'package:fadlurahmanfdev_alice/alice.dart';
import 'package:fadlurahmanfdev_alice/core/alice_http_client_extensions.dart';
import 'package:fadlurahmanfdev_alice/core/alice_http_extensions.dart';
import 'package:chopper/chopper.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'posts_service.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Alice _alice;
  late Dio _dio;
  late HttpClient _httpClient;
  ChopperClient? _chopper;
  late PostsService _postsService;
  Color _primaryColor = Color(0xffff5e57);
  Color _accentColor = Color(0xffff3f34);
  Color _buttonColor = Color(0xff008000);
  TextStyle _buttonTextStyle = TextStyle(color: Colors.white);

  [@override](/user/override)
  void initState() {
    _alice = Alice(
      showNotification: true,
      showInspectorOnShake: true,
      maxCallsCount: 1000,
    );
    _dio = Dio(BaseOptions(
      followRedirects: false,
    ));
    _dio.interceptors.add(_alice.getDioInterceptor());
    _httpClient = HttpClient();
    _chopper = ChopperClient(
      interceptors: [_alice.getChopperInterceptor()],
    );
    _postsService = PostsService.create(_chopper);

    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    ButtonStyle _buttonStyle = ButtonStyle(
        backgroundColor: MaterialStateProperty.all<Color>(_buttonColor));
    return MaterialApp(
      theme: ThemeData(
        primaryColor: _primaryColor,
        colorScheme: ColorScheme.light(secondary: _accentColor),
      ),
      navigatorKey: _alice.getNavigatorKey(),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Alice HTTP Inspector - Example'),
        ),
        body: Container(
          padding: EdgeInsets.all(16),
          child: ListView(
            children: [
              const SizedBox(height: 8),
              _getTextWidget(
                  '欢迎来到 Alice Http Inspector 示例。请点击下面的按钮生成示例数据。'),
              ElevatedButton(
                child: Text(
                  '运行 Dio HTTP 请求',
                  style: _buttonTextStyle,
                ),
                onPressed: _runDioRequests,
                style: _buttonStyle,
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                child: Text(
                  '运行 http/http HTTP 请求',
                  style: _buttonTextStyle,
                ),
                onPressed: _runHttpHttpRequests,
                style: _buttonStyle,
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                child: Text(
                  '运行 HttpClient 请求',
                  style: _buttonTextStyle,
                ),
                onPressed: _runHttpHttpClientRequests,
                style: _buttonStyle,
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                child: Text(
                  '运行 Chopper HTTP 请求',
                  style: _buttonTextStyle,
                ),
                onPressed: _runChopperHttpRequests,
                style: _buttonStyle,
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                child: Text(
                  '日志示例数据',
                  style: _buttonTextStyle,
                ),
                onPressed: _logExampleData,
                style: _buttonStyle,
              ),
              const SizedBox(height: 24),
              _getTextWidget(
                  '点击上面的按钮后,你应该会收到通知。点击通知以显示检查器。你也可以摇晃你的设备或点击下面的按钮。'),
              ElevatedButton(
                child: Text(
                  '运行 HTTP 检查器',
                  style: _buttonTextStyle,
                ),
                onPressed: _runHttpInspector,
                style: _buttonStyle,
              )
            ],
          ),
        ),
      ),
    );
  }

  Widget _getTextWidget(String text) {
    return Text(
      text,
      style: TextStyle(fontSize: 14),
      textAlign: TextAlign.center,
    );
  }

  void _logExampleData() {
    final List<AliceLog> logs = [];
    logs.add(
      AliceLog(
        level: DiagnosticLevel.info,
        timestamp: DateTime.now(),
        message: 'Info log',
      ),
    );
    logs.add(
      AliceLog(
        level: DiagnosticLevel.debug,
        timestamp: DateTime.now(),
        message: 'Debug log',
      ),
    );
    logs.add(
      AliceLog(
        level: DiagnosticLevel.warning,
        timestamp: DateTime.now(),
        message: 'Warning log',
      ),
    );
    final notNumber = 'afs';
    try {
      int.parse(notNumber);
    } catch (e, stacktrace) {
      logs.add(
        AliceLog(
          level: DiagnosticLevel.error,
          timestamp: DateTime.now(),
          message: 'Error log',
          error: e,
          stackTrace: stacktrace,
        ),
      );
    }
    _alice.addLogs(logs);
  }

  void _runChopperHttpRequests() async {
    String body = jsonEncode(
        <String, dynamic>{'title': 'foo', 'body': 'bar', 'userId': '1'});
    _postsService.getPost('1');
    _postsService.postPost(body);
    _postsService.putPost('1', body);
    _postsService.putPost('1231923', body);
    _postsService.putPost('1', null);
    _postsService.postPost(null);
    _postsService.getPost('123456');
  }

  void _runDioRequests() async {
    Map<String, dynamic> body = <String, dynamic>{
      'title': 'foo',
      'body': 'bar',
      'userId': '1'
    };
    _dio.get<void>(
        'https://httpbin.org/redirect-to?url=https%3A%2F%2Fhttpbin.org');
    _dio.delete<void>('https://httpbin.org/status/500');
    _dio.delete<void>('https://httpbin.org/status/400');
    _dio.delete<void>('https://httpbin.org/status/300');
    _dio.delete<void>('https://httpbin.org/status/200');
    _dio.delete<void>('https://httpbin.org/status/100');
    _dio.post<void>('https://jsonplaceholder.typicode.com/posts', data: body);
    _dio.get<void>('https://jsonplaceholder.typicode.com/posts',
        queryParameters: <String, dynamic>{'test': 1});
    _dio.put<void>('https://jsonplaceholder.typicode.com/posts/1', data: body);
    _dio.put<void>('https://jsonplaceholder.typicode.com/posts/1', data: body);
    _dio.delete<void>('https://jsonplaceholder.typicode.com/posts/1');
    _dio.get<void>('http://jsonplaceholder.typicode.com/test/test');

    _dio.get<void>('https://jsonplaceholder.typicode.com/photos');
    _dio.get<void>(
        'https://icons.iconarchive.com/icons/paomedia/small-n-flat/256/sign-info-icon.png');
    _dio.get<void>(
        'https://images.unsplash.com/photo-1542736705-53f0131d1e98?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;w=1000&amp;q=80');
    _dio.get<void>(
        'https://findicons.com/files/icons/1322/world_of_aqua_5/128/bluetooth.png');
    _dio.get<void>(
        'https://upload.wikimedia.org/wikipedia/commons/4/4e/Pleiades_large.jpg');
    _dio.get<void>('http://techslides.com/demos/sample-videos/small.mp4');

    _dio.get<void>('https://www.cse.wustl.edu/~jain/cis677-97/ftp/e_3dlc2.pdf');

    final directory = await getApplicationDocumentsDirectory();
    File file = File('${directory.path}/test.txt');
    file.create();
    file.writeAsStringSync('123456789');

    String fileName = file.path.split('/').last;
    FormData formData = FormData.fromMap(<String, dynamic>{
      'file': await MultipartFile.fromFile(file.path, filename: fileName),
    });
    _dio.post<void>('https://jsonplaceholder.typicode.com/photos',
        data: formData);

    _dio.get<void>('http://dummy.restapiexample.com/api/v1/employees');
  }

  void _runHttpHttpRequests() async {
    Map<String, String> body = <String, String>{
      'title': 'foo',
      'body': 'bar',
      'userId': '1'
    };
    http
        .post(Uri.tryParse('https://jsonplaceholder.typicode.com/posts')!,
            body: body)
        .interceptWithAlice(_alice, body: body);

    http
        .get(Uri.tryParse('https://jsonplaceholder.typicode.com/posts')!)
        .interceptWithAlice(_alice);

    http
        .put(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!,
            body: body)
        .interceptWithAlice(_alice, body: body);

    http
        .patch(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!,
            body: body)
        .interceptWithAlice(_alice, body: body);

    http
        .delete(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!)
        .interceptWithAlice(_alice, body: body);

    http
        .get(Uri.tryParse('https://jsonplaceholder.typicode.com/test/test')!)
        .interceptWithAlice(_alice);

    http
        .post(Uri.tryParse('https://jsonplaceholder.typicode.com/posts')!,
            body: body)
        .then((response) {
      _alice.onHttpResponse(response, body: body);
    });

    http
        .get(Uri.tryParse('https://jsonplaceholder.typicode.com/posts')!)
        .then((response) {
      _alice.onHttpResponse(response);
    });

    http
        .put(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!,
            body: body)
        .then((response) {
      _alice.onHttpResponse(response, body: body);
    });

    http
        .patch(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!,
            body: body)
        .then((response) {
      _alice.onHttpResponse(response, body: body);
    });

    http
        .delete(Uri.tryParse('https://jsonplaceholder.typicode.com/posts/1')!)
        .then((response) {
      _alice.onHttpResponse(response);
    });

    http
        .get(Uri.tryParse('https://jsonplaceholder.typicode.com/test/test')!)
        .then((response) {
      _alice.onHttpResponse(response);
    });

    http
        .post(
            Uri.tryParse(
                'https://jsonplaceholder.typicode.com/posts?key1=value1')!,
            body: body)
        .interceptWithAlice(_alice, body: body);

    http
        .post(
            Uri.tryParse(
                'https://jsonplaceholder.typicode.com/posts?key1=value1&amp;key2=value2&amp;key3=value3')!,
            body: body)
        .interceptWithAlice(_alice, body: body);

    http
        .get(Uri.tryParse(
            'https://jsonplaceholder.typicode.com/test/test?key1=value1&amp;key2=value2&amp;key3=value3')!)
        .then((response) {
      _alice.onHttpResponse(response);
    });
  }

  void _runHttpHttpClientRequests() {
    Map<String, dynamic> body = <String, dynamic>{
      'title': 'foo',
      'body': 'bar',
      'userId': '1'
    };
    _httpClient
        .getUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts'))
        .interceptWithAlice(_alice);

    _httpClient
        .postUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts'))
        .interceptWithAlice(_alice, body: body, headers: <String, dynamic>{});

    _httpClient
        .putUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'))
        .interceptWithAlice(_alice, body: body);

    _httpClient
        .getUrl(Uri.parse('https://jsonplaceholder.typicode.com/test/test/'))
        .interceptWithAlice(_alice);

    _httpClient
        .postUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts'))
        .then((request) async {
      _alice.onHttpClientRequest(request, body: body);
      request.write(body);
      var httpResponse = await request.close();
      var responseBody = await utf8.decoder.bind(httpResponse).join();
      _alice.onHttpClientResponse(httpResponse, request, body: responseBody);
    });

    _httpClient
        .putUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'))
        .then((request) async {
      _alice.onHttpClientRequest(request, body: body);
      request.write(body);
      var httpResponse = await request.close();
      var responseBody = await utf8.decoder.bind(httpResponse).join();
      _alice.onHttpClientResponse(httpResponse, request, body: responseBody);
    });

    _httpClient
        .patchUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'))
        .then((request) async {
      _alice.onHttpClientRequest(request, body: body);
      request.write(body);
      var httpResponse = await request.close();
      var responseBody = await utf8.decoder.bind(httpResponse).join();
      _alice.onHttpClientResponse(httpResponse, request, body: responseBody);
    });

    _httpClient
        .deleteUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'))
        .then((request) async {
      _alice.onHttpClientRequest(request);
      var httpResponse = await request.close();
      var responseBody = await utf8.decoder.bind(httpResponse).join();
      _alice.onHttpClientResponse(httpResponse, request, body: responseBody);
    });

    _httpClient
        .getUrl(Uri.parse('https://jsonplaceholder.typicode.com/test/test/'))
        .then((request) async {
      _alice.onHttpClientRequest(request);
      var httpResponse = await request.close();
      var responseBody = await utf8.decoder.bind(httpResponse).join();
      _alice.onHttpClientResponse(httpResponse, request, body: responseBody);
    });
  }

  void _runHttpInspector() {
    _alice.showInspector();
  }
}

更多关于Flutter功能未知插件fadlurahmanfdev_alice的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter功能未知插件fadlurahmanfdev_alice的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


fadlurahmanfdev_alice 是一个 Flutter 插件,主要用于调试和监控网络请求。它类似于其他网络调试工具(如 ChuckerFlipper),通过展示应用中的 HTTP 请求和响应,帮助开发者调试和分析网络交互。

以下是关于 fadlurahmanfdev_alice 的详细使用方法和功能说明:


功能特点

  1. HTTP 请求监控:捕获应用中所有的 HTTP 请求和响应,包括 URL、请求方法、请求头、请求体、响应状态码、响应头和响应体。
  2. UI 展示:通过一个可交互的界面展示捕获的网络请求,方便查看详细信息。
  3. 调试模式:在调试阶段使用,帮助开发者快速定位问题。
  4. 支持多种请求库:可以与 Diohttp 等常见的 Flutter 网络请求库集成。

安装

pubspec.yaml 中添加依赖:

dependencies:
  fadlurahmanfdev_alice: ^1.0.0

运行 flutter pub get 安装插件。


基本用法

  1. 初始化 Alice

    import 'package:fadlurahmanfdev_alice/fadlurahmanfdev_alice.dart';
    
    final Alice alice = Alice();
    
  2. 集成到网络请求库

    • 集成 Dio

      import 'package:dio/dio.dart';
      import 'package:fadlurahmanfdev_alice/dio/alice_dio_interceptor.dart';
      
      final dio = Dio();
      dio.interceptors.add(AliceDioInterceptor(alice));
      
    • 集成 http

      import 'package:http/http.dart' as http;
      import 'package:fadlurahmanfdev_alice/http/alice_http_client.dart';
      
      final client = AliceHttpClient(alice, http.Client());
      
  3. 打开监控界面 在需要查看网络请求时,调用以下方法打开监控界面:

    alice.showInspector();
    
  4. 示例代码

    import 'package:flutter/material.dart';
    import 'package:dio/dio.dart';
    import 'package:fadlurahmanfdev_alice/fadlurahmanfdev_alice.dart';
    import 'package:fadlurahmanfdev_alice/dio/alice_dio_interceptor.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      final Alice alice = Alice();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Alice Example'),
            ),
            body: Center(
              child: ElevatedButton(
                onPressed: () async {
                  final dio = Dio();
                  dio.interceptors.add(AliceDioInterceptor(alice));
    
                  try {
                    final response = await dio.get('https://jsonplaceholder.typicode.com/posts');
                    print(response.data);
                  } catch (e) {
                    print(e);
                  }
                },
                child: Text('Send Request'),
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                alice.showInspector();
              },
              child: Icon(Icons.network_check),
            ),
          ),
        );
      }
    }
回到顶部