Files
waf-platform/HttpDNSSDK/sdk/flutter/new_httpdns/example/lib/main.dart

390 lines
12 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'net/httpdns_http_client_adapter.dart';
import 'package:TrustAPP_httpdns/TrustAPP_httpdns.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'HTTP Request Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'HTTP Request Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
enum NetworkLibrary {
dio('Dio'),
httpClient('HttpClient'),
httpPackage('http');
const NetworkLibrary(this.displayName);
final String displayName;
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _urlController = TextEditingController();
String _responseText = 'Response will appear here...';
bool _isLoading = false;
late final Dio _dio;
late final HttpClient _httpClient;
late final http.Client _httpPackageClient;
NetworkLibrary _selectedLibrary = NetworkLibrary.dio;
bool _httpdnsReady = false;
bool _httpdnsIniting = false;
Future<void> _initHttpDnsOnce() async {
if (_httpdnsReady || _httpdnsIniting) return;
_httpdnsIniting = true;
try {
await TrustAPPHttpdns.init(
appId: 'app1f1ndpo9', // è¯·æ¿æ<C2BF>¢ä¸ºæ¨çš„应用 AppId
primaryServiceHost: 'httpdns-a.example.com', // è¯·æ¿æ<C2BF>¢ä¸ºä¸»æœ<C3A6>务域å<C5B8>? backupServiceHost: 'httpdns-b.example.com', // å<>¯é€‰ï¼šå¤‡æœ<C3A6>务域å<C5B8>? servicePort: 443,
secretKey: 'your_sign_secret_here', // å<>¯é€‰ï¼šä»…验签开å<E282AC>¯æ—¶éœ€è¦? );
await TrustAPPHttpdns.setHttpsRequestEnabled(true);
await TrustAPPHttpdns.setLogEnabled(true);
await TrustAPPHttpdns.setPersistentCacheIPEnabled(true);
await TrustAPPHttpdns.setReuseExpiredIPEnabled(true);
await TrustAPPHttpdns.build();
// å…ˆbuildå†<C3A5>执行解æž<C3A6>ç¸å…³åЍä½?
final preResolveHosts = 'www.TrustAPP.com';
await TrustAPPHttpdns.setPreResolveHosts([preResolveHosts], ipType: 'both');
debugPrint('[httpdns] pre-resolve scheduled for host=$preResolveHosts');
_httpdnsReady = true;
} catch (e) {
debugPrint('[httpdns] init failed: $e');
} finally {
_httpdnsIniting = false;
}
}
@override
void initState() {
super.initState();
// 设置默认的API URL用于演示
_urlController.text = 'https://www.TrustAPP.com';
// 仅馿¬¡è¿å…¥é¡µé<C2B5>¢æ—¶åˆ<C3A5>å§åŒ?HTTPDNS
_initHttpDnsOnce();
// å…ˆåˆ<C3A5>å§åŒHTTPDNSå†<C3A5>åˆ<C3A5>å§åŒDio
_dio = Dio();
_dio.httpClientAdapter = buildHttpdnsHttpClientAdapter();
_dio.options.headers['Connection'] = 'keep-alive';
_httpClient = buildHttpdnsNativeHttpClient();
_httpPackageClient = buildHttpdnsHttpPackageClient();
}
@override
void dispose() {
_urlController.dispose();
_httpClient.close();
_httpPackageClient.close();
super.dispose();
}
Future<void> _sendHttpRequest() async {
if (_urlController.text.isEmpty) {
setState(() {
_responseText = 'Error: Please enter a URL';
});
return;
}
setState(() {
_isLoading = true;
_responseText = 'Sending request...';
});
final uri = Uri.parse(_urlController.text);
try {
final String libraryName = _selectedLibrary.displayName;
debugPrint('[$libraryName] Sending request to ${uri.host}:${uri.port}');
int statusCode;
Map<String, String> headers;
String body;
switch (_selectedLibrary) {
case NetworkLibrary.dio:
final response = await _dio.getUri(
uri,
options: Options(
responseType: ResponseType.plain,
followRedirects: true,
validateStatus: (_) => true,
),
);
statusCode = response.statusCode ?? 0;
headers = {
for (final e in response.headers.map.entries)
e.key: e.value.join(','),
};
body = response.data is String
? response.data as String
: jsonEncode(response.data);
break;
case NetworkLibrary.httpClient:
final request = await _httpClient.getUrl(uri);
final response = await request.close();
statusCode = response.statusCode;
headers = {};
response.headers.forEach((name, values) {
headers[name] = values.join(',');
});
body = await response.transform(utf8.decoder).join();
break;
case NetworkLibrary.httpPackage:
final response = await _httpPackageClient.get(uri);
statusCode = response.statusCode;
headers = response.headers;
body = response.body;
break;
}
setState(() {
_isLoading = false;
final StringBuffer responseInfo = StringBuffer();
responseInfo.writeln('=== REQUEST ($libraryName) ===');
responseInfo.writeln('uri: ${uri.toString()}');
responseInfo.writeln();
responseInfo.writeln('=== STATUS ===');
responseInfo.writeln('statusCode: $statusCode');
responseInfo.writeln();
responseInfo.writeln('=== HEADERS ===');
headers.forEach((key, value) {
responseInfo.writeln('$key: $value');
});
responseInfo.writeln();
responseInfo.writeln('=== BODY ===');
if (statusCode >= 200 && statusCode < 300) {
try {
final jsonData = json.decode(body);
const encoder = JsonEncoder.withIndent(' ');
responseInfo.write(encoder.convert(jsonData));
} catch (_) {
responseInfo.write(body);
}
} else {
responseInfo.write(body);
}
_responseText = responseInfo.toString();
});
} catch (e) {
setState(() {
_isLoading = false;
_responseText = 'Network Error: $e';
});
}
}
// 使用 HTTPDNS è§£æž<C3A6>当å‰<C3A5> URL çš?host 并显示结æž?
Future<void> _testHttpDnsResolve() async {
final text = _urlController.text.trim();
if (text.isEmpty) {
setState(() {
_responseText = 'Error: Please enter a URL';
});
return;
}
final Uri uri;
try {
uri = Uri.parse(text);
} catch (_) {
setState(() {
_responseText = 'Error: Invalid URL';
});
return;
}
setState(() {
_isLoading = true;
_responseText = 'Resolving with HTTPDNS...';
});
try {
// ç¡®ä¿<C3A4>å<EFBFBD>ªåˆ<C3A5>å§åŒä¸€æ¬?
await _initHttpDnsOnce();
final res = await TrustAPPHttpdns.resolveHostSyncNonBlocking(
uri.host,
ipType: 'both',
);
setState(() {
_isLoading = false;
final buf = StringBuffer();
buf.writeln('=== HTTPDNS RESOLVE ===');
buf.writeln('host: ${uri.host}');
final ipv4 = (res['ipv4'] as List?)?.cast<String>() ?? const <String>[];
final ipv6 = (res['ipv6'] as List?)?.cast<String>() ?? const <String>[];
if (ipv4.isNotEmpty) buf.writeln('IPv4 list: ${ipv4.join(', ')}');
if (ipv6.isNotEmpty) buf.writeln('IPv6 list: ${ipv6.join(', ')}');
_responseText = buf.toString();
});
} catch (e) {
setState(() {
_isLoading = false;
_responseText = 'HTTPDNS Error: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// URL输入�
TextField(
controller: _urlController,
decoration: const InputDecoration(
labelText: 'Enter URL',
hintText: 'https://www.TrustAPP.com',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.link),
),
keyboardType: TextInputType.url,
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
flex: 3,
child: ElevatedButton.icon(
onPressed: _isLoading ? null : _sendHttpRequest,
icon: _isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.send),
label: Text(_isLoading ? 'Sending...' : 'Send Request'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: DropdownButton<NetworkLibrary>(
value: _selectedLibrary,
isExpanded: true,
underline: const SizedBox(),
icon: const Icon(Icons.arrow_drop_down),
items: NetworkLibrary.values.map((library) {
return DropdownMenuItem<NetworkLibrary>(
value: library,
child: Text(library.displayName),
);
}).toList(),
onChanged: _isLoading
? null
: (NetworkLibrary? newValue) {
if (newValue != null) {
setState(() {
_selectedLibrary = newValue;
});
}
},
),
),
),
],
),
const SizedBox(height: 16),
// HTTPDNS è§£æž<C3A6>按é®
ElevatedButton.icon(
onPressed: _isLoading ? null : _testHttpDnsResolve,
icon: const Icon(Icons.dns),
label: const Text('HTTPDNS Resolve'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
const SizedBox(height: 16),
// ä¿<C3A4>留空白分隔
const SizedBox(height: 16),
// å“<C3A5>åº”æ‡æœ¬æ˜¾ç¤ºåŒºåŸŸ
Expanded(
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
color: Colors.grey.shade50,
),
child: SingleChildScrollView(
child: Text(
_responseText,
style: const TextStyle(
fontFamily: 'monospace',
fontSize: 12,
),
),
),
),
),
],
),
),
);
}
}