Flutter插件flutter_alice的安装与使用指南

Flutter插件flutter_alice的安装与使用指南

Alice 是一个用于 Flutter 的 HTTP 检查工具,帮助调试 HTTP 请求。它捕获并存储 HTTP 请求和响应,可以通过简单的 UI 查看。

安装

1. 添加依赖到 pubspec.yaml

dependencies:
  flutter_alice: ^1.0.1

2. 安装依赖

$ flutter pub get

3. 导入包

import 'package:flutter_alice/alice.dart';

使用方法

Alice 配置

创建 Alice 实例

Alice alice = Alice();

添加导航键到应用

MaterialApp(
  navigatorKey: alice.getNavigatorKey(),
  home: ...
)

你也可以使用自己的导航键:

Alice alice = Alice(navigatorKey: yourNavigatorKeyHere);

如果需要延迟传递导航键,可以使用:

alice.setNavigatorKey(yourNavigatorKeyHere);

其他设置

如果你想使用深色模式,只需添加 darkTheme 标志:

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

HTTP 客户端配置

根据使用的 HTTP 客户端类型进行配置:

使用 Dio

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

使用 HttpClient (来自 dart:io 包)

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(),
);

使用其他 HTTP 客户端

你可以使用通用的 HTTP 调用接口:

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

扩展

你可以使用扩展来缩短你的 HTTP 和 HTTP 客户端代码,这将使代码更加简洁。

导入扩展

import 'package:flutter_alice/core/alice_http_client_extensions.dart';
import 'package:flutter_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());

示例 Demo

以下是一个完整的示例项目,展示了如何在 Flutter 应用中集成 flutter_alice 插件。

lib/main.dart

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

import 'package:alice_example/posts_service.dart';
import 'package:chopper/chopper.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_alice/alice.dart';
import 'package:flutter_alice/core/alice_http_client_extensions.dart';
import 'package:flutter_alice/core/alice_http_extensions.dart';
import 'package:http/http.dart' as http;
import 'package:overlay_support/overlay_support.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;

  [@override](/user/override)
  void initState() {
    _alice = Alice(
      showNotification: true,
      showInspectorOnShake: true,
      darkTheme: false,
    );
    _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) {
    return OverlaySupport(
      child: MaterialApp(
        theme: ThemeData(primarySwatch: Colors.blue),
        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(
                    "Welcome to example of Alice Http Inspector. Click buttons below to generate sample data."),
                ElevatedButton(
                  child: Text("Run Dio HTTP Requests"),
                  onPressed: _runDioRequests,
                ),
                ElevatedButton(
                  child: Text("Run http/http HTTP Requests"),
                  onPressed: _runHttpHttpRequests,
                ),
                ElevatedButton(
                  child: Text("Run HttpClient Requests"),
                  onPressed: _runHttpHttpClientRequests,
                ),
                ElevatedButton(
                  child: Text("Run Chopper HTTP Requests"),
                  onPressed: _runChopperHttpRequests,
                ),
                const SizedBox(height: 24),
                _getTextWidget(
                    "After clicking on buttons above, you should receive notification."
                    " Click on it to show inspector. You can also shake your device or click button below."),
                ElevatedButton(
                  child: Text("Run HTTP Insepctor"),
                  onPressed: _runHttpInspector,
                ),
                ElevatedButton(
                  child: Text("test"),
                  onPressed: () {
                    _dio.interceptors.add(_alice.getDioInterceptor());
                  },
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

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

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

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

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

    _dio.get("http://dummy.restapiexample.com/api/v1/employees");
  }

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

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

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

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

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

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

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

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

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

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

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

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

  void _runHttpHttpClientRequests() {
    Map<String, dynamic> body = {"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: Map());

    _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插件flutter_alice的安装与使用指南的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件flutter_alice的安装与使用指南的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,针对您提到的Flutter功能未定义插件 flutter_alice 的问题,我们可以提供一个基本的集成和使用示例。假设 flutter_alice 是一个用于日志记录或调试的插件(请注意,这个假设基于插件名称的猜测,实际功能可能有所不同),以下是如何在Flutter项目中集成和使用该插件的示例代码。

首先,确保您已经在 pubspec.yaml 文件中添加了 flutter_alice 依赖项(请注意,您需要替换为实际的插件版本号和描述):

dependencies:
  flutter:
    sdk: flutter
  flutter_alice: ^x.y.z  # 替换为实际版本号

然后,运行 flutter pub get 来获取依赖项。

接下来,在您的 Flutter 应用中初始化并使用 flutter_alice。以下是一个简单的示例,展示了如何配置和使用该插件进行日志记录:

import 'package:flutter/material.dart';
import 'package:flutter_alice/flutter_alice.dart';

void main() {
  // 初始化 AliceClient,配置日志级别和其他选项
  AliceClient.init(
    enable: true, // 是否启用日志记录
    level: AliceLevel.verbose, // 设置日志级别
    output: AliceOutput.console, // 设置输出目标,例如控制台
    // 可以添加更多配置,如文件输出、远程服务器等
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Alice Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    // 记录一个日志
    Alice.log('App started');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Alice Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '0',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 在按钮点击时记录一个日志
          Alice.verbose('Button pressed');
          // 这里可以添加其他逻辑,比如计数器增加
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. main 函数中初始化 AliceClient,并配置了日志级别和输出目标。
  2. MyHomePageinitState 方法中记录了一个启动日志。
  3. 在浮动按钮的 onPressed 回调中记录了一个按钮点击日志。

请注意,flutter_alice 是一个假设的插件名称,实际使用时您需要替换为真实存在的插件,并根据其文档进行配置和使用。如果 flutter_alice 插件不存在或功能不同,请参考该插件的实际文档进行调整。

回到顶部