Flutter命令行工具模拟插件flutter_curl的使用

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

Flutter命令行工具模拟插件flutter_curl的使用

libcurl for Flutter

GitHub Badge

Flutter 插件用于在 Flutter Android 和 iOS 应用中通过 libcurl 进行 HTTP 调用。Dart 内置的 HTTP 栈(作为 dart:io 的一部分)仅支持 HTTP 1.1。此插件旨在引入 libcurl 中可用的最新连接功能,如:

  • HTTP2 配合 Nghttp2
  • 使用 ALPN TLS 扩展从 HTTP 1.1 自动升级到 HTTP2
  • Brotli 压缩
  • 实验性 HTTP3 和 alt-svc 支持

快速开始

添加到项目

flutter pub add flutter_curl

示例用法

import 'package:flutter_curl/flutter_curl.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as paths;

void main() async {
  // 初始化客户端
  Client client = Client(
    verbose: true,
    interceptors: [
      // HTTPCaching(),
    ],
  );
  await client.init();

  // 发送请求
  final res = await client.send(Request(
    method: "GET",
    url: "https://ajinasokan.com/",
    headers: {
      "user-agent": "myapp-v1.0/android9"
    },
    // body
    // body: RequestBody.raw(utf8.encode("hello world")),
    // body: RequestBody.string("hello world"),
    // body: RequestBody.form({"age": "10", "hello": "world"}),
    // body: RequestBody.multipart([
    //   Multipart(name: "age", data: "24"),
    //   Multipart(name: "hello", data: "world"),
    //   Multipart.file(
    //     name: "fieldname",
    //     path: "/sdcard/todo.txt",
    //     filename: "filename.txt",
    //   ),
    // ]),
  ));

  // 读取响应
  print("Status: ${res.statusCode}");
  print("HTTP: ${res.httpVersion}");
  res.headers.forEach((key, value) {
    print("$key: $value");
  });
  print(res.text());
}

工作原理

此插件使用自定义构建的 libcurl 库,这些库通过 发布页面 分发。如果希望自行构建这些库,请遵循 cURL 项目的 说明。上述构建使用的配置包括:

  • Ngtcp2 用于 HTTP2
  • libbrotli
  • NDK min SDK: 21 (armv7a, arm64, x86_64),iOS min SDK: 8.0 (arm64, x86_64)
  • Android 二进制文件打包为 aar,iOS 二进制文件打包为 framework

这些二进制文件将在 Android 项目构建时或 iOS pod 安装时下载。在 Android 中,这些二进制文件是动态链接的,而在 iOS 中则是静态链接。

cURL API 通过 Dart 的 dart:ffi API(beta) 在不同的 isolate 中直接访问,以避免应用程序无响应,因为 cURL API 是阻塞的。

减小 APK 大小

Flutter 的 --target-platform 参数仅移除未指定架构的自身原生二进制文件。这不会向项目 gradle 添加 abiFilters,因此这不会从像 flutter_curl 这样的插件中移除未指定架构的二进制文件。

一个建议的解决方法是在项目的 gradle 配置中手动添加以下逻辑:

android {
    ...
    buildTypes {
        ...
        release {
            ...
            ndk {
                if (!project.hasProperty('target-platform')) {
                    abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
                } else {
                    def platforms = project.property('target-platform').split(',')
                    def platformMap = [
                        'android-arm': 'armeabi-v7a',
                        'android-arm64': 'arm64-v8a',
                        'android-x86': 'x86',
                        'android-x64': 'x86_64',
                    ]
                    abiFilters = platforms.stream().map({ e ->
                        platformMap.containsKey(e) ? platformMap[e] : e
                    }).toArray()
                }
            }
        }
    }
}

示例代码

以下是完整的示例代码,展示了如何在一个简单的 Flutter 应用中使用 flutter_curl 插件进行测试:

import 'package:flutter/material.dart';
import 'tests.dart';
import 'echo_server.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void runTests() async {
    await startTestServer();
    tests.forEach((t) {
      t.passed = null;
    });
    setState(() {});
    for (var t in tests) {
      await t.run();
      setState(() {});
    }
    await stopTestServer();
  }

  void runTest(Test t) async {
    await startTestServer();
    t.passed = null;
    setState(() {});
    await t.run();
    setState(() {});
    await stopTestServer();
  }

  String get title {
    int success = 0;
    int fail = 0;
    int stopped = 0;
    tests.forEach((e) {
      if (e.passed == true) success++;
      if (e.passed == false) fail++;
      if (e.passed == null) stopped++;
    });
    return "Success: $success, Fail: $fail, Stopped: $stopped";
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text(title)),
        body: ListView.builder(
          itemCount: tests.length,
          itemBuilder: (_, i) {
            return ListTile(
              onTap: () async {
                runTest(tests[i]);
              },
              leading: {
                null: Icon(Icons.more_horiz),
                true: Icon(
                  Icons.check_circle_outline,
                  color: Colors.green,
                ),
                false: Icon(
                  Icons.remove_circle,
                  color: Colors.red,
                )
              }[tests[i].passed],
              title: Text(tests[i].title),
            );
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => runTests(),
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

这个示例展示了如何设置一个包含多个测试用例的应用程序,并使用 flutter_curl 插件执行这些测试。每个测试的结果会在界面上实时更新。


更多关于Flutter命令行工具模拟插件flutter_curl的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter命令行工具模拟插件flutter_curl的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用命令行工具模拟插件 flutter_curl 的代码案例。这个插件允许你通过命令行接口(CLI)执行网络请求,类似于 curl 命令。

首先,你需要在你的 pubspec.yaml 文件中添加 flutter_curl 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_curl: ^x.y.z  # 请将 `x.y.z` 替换为最新版本号

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

接下来,我们编写一个简单的 Flutter 应用来展示如何使用 flutter_curl 插件。以下是一个完整的代码示例:

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

void main() {
  runApp(MyApp());
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  String _response = '';

  void _performCurlRequest() async {
    try {
      // 使用 FlutterCurl 发起 GET 请求
      String url = 'https://jsonplaceholder.typicode.com/posts/1';
      String command = 'GET $url';
      String result = await FlutterCurl.execute(command);

      // 更新 UI
      setState(() {
        _response = result;
      });
    } catch (e) {
      // 错误处理
      setState(() {
        _response = 'Error: ${e.toString()}';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Curl Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _performCurlRequest,
              child: Text('Perform CURL Request'),
            ),
            SizedBox(height: 20),
            Expanded(
              child: SingleChildScrollView(
                child: Text(
                  _response,
                  style: TextStyle(fontSize: 16),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

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

  1. pubspec.yaml 文件中添加了 flutter_curl 依赖。
  2. 创建了一个简单的 Flutter 应用,包含一个按钮和一个文本显示区。
  3. 当按钮被点击时,调用 _performCurlRequest 方法。
  4. _performCurlRequest 方法使用 FlutterCurl.execute 方法执行一个 GET 请求,并将响应结果存储在 _response 变量中。
  5. 更新 UI 以显示响应结果。

请注意,FlutterCurl.execute 方法接受一个字符串参数,该参数是你要执行的 curl 命令。在这个例子中,我们执行了一个简单的 GET 请求来获取一个 JSON 数据。

希望这个示例对你有帮助!如果你有任何其他问题,请随时询问。

回到顶部