Flutter原生网络请求适配插件native_dio_adapter的使用
Flutter原生网络请求适配插件native_dio_adapter的使用
Native Dio Adapter
注意: 此插件在macOS、iOS和Android上使用原生HTTP实现。其他平台仍然使用Dart HTTP栈。
native_dio_adapter
是Dio的一个客户端,它利用了cupertino_http和cronet_http,将HTTP请求委托给原生平台而不是dart:io
平台。
灵感来源于Dart 2.18发布博客。
动机
使用原生平台实现,而非基于套接字的dart:io HttpClient实现,有以下几个优点:
- 自动支持平台特性,如VPN和HTTP代理。
- 支持更多的配置选项,例如只允许通过WiFi访问和阻止Cookie。
- 支持更多HTTP特性,如HTTP/3和自定义重定向处理。
开始使用
安装
在您的pubspec.yaml
文件中添加native_dio_adapter
包到依赖项中。
dependencies:
native_dio_adapter: ^latest_version # 替换为最新版本号
示例代码
以下是一个完整的Flutter应用示例,展示了如何使用native_dio_adapter
进行GET和POST请求:
// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:native_dio_adapter/native_dio_adapter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _doGetRequest() async {
final dio = Dio();
dio.httpClientAdapter = NativeAdapter(
createCupertinoConfiguration: () =>
URLSessionConfiguration.ephemeralSessionConfiguration()
..allowsCellularAccess = false
..allowsConstrainedNetworkAccess = false
..allowsExpensiveNetworkAccess = false,
);
try {
final response = await dio.get<String>('https://flutter.dev');
await showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Response ${response.statusCode}'),
content: SingleChildScrollView(
child: Text(response.data ?? 'No response'),
),
actions: [
MaterialButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
)
],
);
},
);
} catch (e) {
print(e);
}
}
void _doPostRequest() async {
final dio = Dio();
dio.httpClientAdapter = NativeAdapter(
createCupertinoConfiguration: () =>
URLSessionConfiguration.ephemeralSessionConfiguration()
..allowsCellularAccess = false
..allowsConstrainedNetworkAccess = false
..allowsExpensiveNetworkAccess = false,
);
try {
final response = await dio.post<String>(
'https://httpbin.org/post',
queryParameters: {'foo': 'bar'},
data: jsonEncode({'foo': 'bar'}),
options: Options(headers: {'foo': 'bar'}),
);
await showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Response ${response.statusCode}'),
content: SingleChildScrollView(
child: Text(response.data ?? 'No response'),
),
actions: [
MaterialButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
)
],
);
},
);
} catch (e) {
print(e);
}
}
void _doHttpClientRequest() async {
final config = URLSessionConfiguration.ephemeralSessionConfiguration()
..allowsCellularAccess = false
..allowsConstrainedNetworkAccess = false
..allowsExpensiveNetworkAccess = false;
final client = CupertinoClient.fromSessionConfiguration(config);
try {
final response = await client.get(Uri.parse('https://flutter.dev/'));
await showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Response ${response.statusCode}'),
content: SingleChildScrollView(
child: Text(response.body),
),
actions: [
MaterialButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
)
],
);
},
);
} catch (e) {
print(e);
}
}
void _doHttpClientPostRequest() async {
final config = URLSessionConfiguration.ephemeralSessionConfiguration()
..allowsCellularAccess = false
..allowsConstrainedNetworkAccess = false
..allowsExpensiveNetworkAccess = false;
final client = CupertinoClient.fromSessionConfiguration(config);
try {
final response = await client.post(
Uri.parse('https://httpbin.org/post'),
body: jsonEncode({'foo': 'bar'}),
);
await showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Response ${response.statusCode}'),
content: SingleChildScrollView(
child: Text(response.body),
),
actions: [
MaterialButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
)
],
);
},
);
} catch (e) {
print(e);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
ElevatedButton(
onPressed: _doGetRequest,
child: const Text('make get request'),
),
ElevatedButton(
onPressed: _doPostRequest,
child: const Text('make post request'),
),
ElevatedButton(
onPressed: _doHttpClientRequest,
child: const Text('make client request'),
),
ElevatedButton(
onPressed: _doHttpClientPostRequest,
child: const Text('make client post request'),
),
],
),
);
}
}
这个示例展示了如何使用native_dio_adapter
执行基本的GET和POST请求,并显示响应结果。您可以通过点击按钮来触发这些请求,并在弹出的对话框中查看响应内容。
使用嵌入式Cronet
从cronet_http
v1.2.0开始,您可以使用嵌入式的Cronet实现,只需简单地配置dart-define
。详情请参阅cronet_http文档。
希望这个指南能帮助您更好地理解和使用native_dio_adapter
!如果您有任何问题或需要进一步的帮助,请随时提问。
更多关于Flutter原生网络请求适配插件native_dio_adapter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter原生网络请求适配插件native_dio_adapter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是关于如何在Flutter项目中使用native_dio_adapter
插件来进行原生网络请求适配的示例代码。native_dio_adapter
是一个允许Flutter应用通过原生代码(如Android的Java/Kotlin或iOS的Swift/Objective-C)执行网络请求的插件。这通常用于需要更高效的网络操作或处理一些Flutter本身难以处理的复杂网络需求。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加native_dio_adapter
依赖:
dependencies:
flutter:
sdk: flutter
dio: ^4.0.0 # 确保dio版本与native_dio_adapter兼容
native_dio_adapter: ^最新版本号 # 替换为实际最新版本号
然后运行flutter pub get
来获取依赖。
2. 配置原生代码
iOS
在iOS项目中,你通常不需要做额外的配置,除非你有特定的网络设置需要在原生代码中处理。
Android
在Android项目中,你可能需要在AndroidManifest.xml
中添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
3. 使用native_dio_adapter进行网络请求
接下来,我们来看如何在Flutter代码中使用native_dio_adapter
。
初始化Dio实例并配置native_dio_adapter
import 'package:dio/dio.dart';
import 'package:native_dio_adapter/native_dio_adapter.dart';
void main() {
// 创建Dio实例
final dio = Dio();
// 配置native_dio_adapter
dio.options.transformResponse = NativeDioAdapter.transformResponse;
dio.options.baseUrl = "https://api.example.com"; // 替换为你的API基础URL
// 示例:GET请求
dio.get("/endpoint")
.then((response) {
// 处理响应
print(response.data);
})
.catchError((error) {
// 处理错误
print(error.response?.data ?? error.message);
});
// 示例:POST请求
final postData = {"key": "value"};
dio.post("/endpoint", data: postData)
.then((response) {
// 处理响应
print(response.data);
})
.catchError((error) {
// 处理错误
print(error.response?.data ?? error.message);
});
runApp(MyApp());
}
自定义原生网络请求(高级用法)
如果你需要在原生代码中执行更复杂的网络请求,你可以在Android和iOS项目中分别创建自定义的网络请求逻辑,并通过MethodChannel与Flutter通信。以下是一个简单的示例,展示如何在原生代码中处理网络请求,并通过MethodChannel返回结果。
Android(Java/Kotlin)
// MainActivity.java 或 MainActivity.kt
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.native_network_channel";
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("fetchData")) {
fetchData(result);
} else {
result.notImplemented();
}
});
}
private void fetchData(MethodChannel.Result result) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/endpoint")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
result.error("NETWORK_ERROR", e.getMessage(), null);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
result.success(response.body().string());
} else {
result.error("HTTP_ERROR", response.message(), null);
}
}
});
}
}
iOS(Swift/Objective-C)
// AppDelegate.swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "com.example.native_network_channel", binaryMessenger: controller)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) in
if call.method == "fetchData" {
fetchData(result: result)
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
func fetchData(result: @escaping FlutterResult) {
let url = URL(string: "https://api.example.com/endpoint")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
result(FlutterError(code: "NETWORK_ERROR", message: error.localizedDescription, details: nil))
return
}
guard let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 else {
result(FlutterError(code: "HTTP_ERROR", message: (response as? HTTPURLResponse)?.localizedString ?? "Unknown error", details: nil))
return
}
if let jsonString = String(data: data, encoding: .utf8) {
result(jsonString)
} else {
result(FlutterError(code: "PARSING_ERROR", message: "Failed to parse response", details: nil))
}
}
task.resume()
}
Flutter端调用原生方法
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const platform = MethodChannel('com.example.native_network_channel');
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Native Network Request'),
),
body: Center(
child: ElevatedButton(
onPressed: _fetchData,
child: Text('Fetch Data'),
),
),
),
);
}
Future<void> _fetchData() async {
try {
final String result = await platform.invokeMethod('fetchData');
print(result);
} on PlatformException catch (e) {
print("Failed to fetch data: '${e.message}'.");
}
}
}
这个示例展示了如何通过native_dio_adapter
和自定义原生代码来实现网络请求的适配。请注意,native_dio_adapter
的具体用法可能会随着版本更新而变化,因此建议查阅最新的官方文档和示例代码。