flutter_inappwebview 本地 https 连接在 flutter 应用中被拒绝
flutter_inappwebview local https connection refused in flutter app
我正在尝试通过 https 提供资产中的本地内容,以便访问需要 ssl 的 webrtc 等功能。
由于 flutter_inappwebview 中提供了本地应用服务器
不处理 ssl 连接,我用 InAppLocalHostSecureServer 替换了 InAppLocalHostServer class,代码如下:
import 'dart:io';
import 'dart:async';
import 'package:flutter/services.dart' show rootBundle;
import 'package:mime/mime.dart';
class InAppLocalHostSecureServer {
HttpServer _server;
int _port = 8443;
InAppLocalHostSecureServer({int port = 8443}) {
this._port = port;
}
///Starts a server on http://localhost:[port]/.
///
///**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35)):
///```xml
///<key>NSAppTransportSecurity</key>
///<dict>
/// <key>NSAllowsLocalNetworking</key>
/// <true/>
///</dict>
///```
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
Future<void> start() async {
if (this._server != null) {
throw Exception('Server already started on https://localhost:$_port');
}
var completer = Completer();
runZoned(() async {
SecurityContext context = new SecurityContext();
var chain = await rootBundle.load('assets/certificates/cert.pem');
var key = await rootBundle.load('assets/certificates/key.pem');
context.useCertificateChainBytes(chain.buffer.asInt8List());
context.usePrivateKeyBytes(key.buffer.asInt8List(), password: 'dartdart');
HttpServer.bindSecure('127.0.0.1', _port, context).then((server) {
print('Server running on https://localhost:' + _port.toString());
this._server = server;
server.listen((HttpRequest request) async {
print(request);
var body = List<int>();
var path = request.requestedUri.path;
path = (path.startsWith('/')) ? path.substring(1) : path;
path += (path.endsWith('/')) ? 'index.html' : '';
try {
body = (await rootBundle.load(path)).buffer.asUint8List();
} catch (e) {
print(e.toString());
request.response.close();
return;
}
var contentType = ['text', 'html'];
if (!request.requestedUri.path.endsWith('/') &&
request.requestedUri.pathSegments.isNotEmpty) {
var mimeType =
lookupMimeType(request.requestedUri.path, headerBytes: body);
if (mimeType != null) {
contentType = mimeType.split('/');
}
}
request.response.headers.contentType =
ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.add(body);
request.response.close();
});
completer.complete();
});
}, onError: (e, stackTrace) {
print('Error: $e $stackTrace');
});
return completer.future;
}
///Closes the server.
Future<void> close() async {
if (this._server != null) {
await this._server.close(force: true);
print('Server running on http://localhost:$_port closed');
this._server = null;
}
}
}
大部分代码是原始代码的复制粘贴class。
我改变的是我调用 HttpServer.bindSecure 而不是 HttpServer.bind 并且我提供 openssl 证书和密钥。
服务器似乎启动时没有在控制台中记录错误,但我无法访问它。
这是尝试访问本地 url 的客户端代码:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'InAppLocalHostSecureServer.dart';
class WebAudioTest extends StatefulWidget {
@override
_WebAudioTestState createState() => _WebAudioTestState();
}
class _WebAudioTestState extends State<WebAudioTest> {
InAppWebViewController webView;
InAppLocalHostSecureServer localhostServer;
String url = "https://127.0.0.1:8443/assets/web/index.html";
@override
void initState() {
super.initState();
this.init();
}
void init() async {
this.localhostServer = new InAppLocalHostSecureServer();
await localhostServer.start();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Web Audio Test'),
),
body: InAppWebView(
initialUrl: url,
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)),
onWebViewCreated: (InAppWebViewController c) {
webView = c;
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE: " + consoleMessage.message);
},
),
);
}
}
console没有报错但是flutter页面报错如下:
网络::ERR_CONNECTION_REFUSED
欢迎任何帮助。
好的,回答我自己的问题:
我遇到的问题很简单,我过早地构建了 InAppWebView,在服务器完成启动之前。解决办法很简单,只要在服务器启动时设置一个标志为真,只有当标志为真时才创建 InAppWebView。
除此之外,WebRTC 在本地主机上无需 https 即可运行,我在 Android 和 iOS 上对其进行了测试。因此,此用例不需要本地 https。
但是无论如何,如果出于任何其他原因有人需要提供 https 本地内容,此 post 中的代码可以作为其基础。
我正在尝试通过 https 提供资产中的本地内容,以便访问需要 ssl 的 webrtc 等功能。
由于 flutter_inappwebview 中提供了本地应用服务器 不处理 ssl 连接,我用 InAppLocalHostSecureServer 替换了 InAppLocalHostServer class,代码如下:
import 'dart:io';
import 'dart:async';
import 'package:flutter/services.dart' show rootBundle;
import 'package:mime/mime.dart';
class InAppLocalHostSecureServer {
HttpServer _server;
int _port = 8443;
InAppLocalHostSecureServer({int port = 8443}) {
this._port = port;
}
///Starts a server on http://localhost:[port]/.
///
///**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35)):
///```xml
///<key>NSAppTransportSecurity</key>
///<dict>
/// <key>NSAllowsLocalNetworking</key>
/// <true/>
///</dict>
///```
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
Future<void> start() async {
if (this._server != null) {
throw Exception('Server already started on https://localhost:$_port');
}
var completer = Completer();
runZoned(() async {
SecurityContext context = new SecurityContext();
var chain = await rootBundle.load('assets/certificates/cert.pem');
var key = await rootBundle.load('assets/certificates/key.pem');
context.useCertificateChainBytes(chain.buffer.asInt8List());
context.usePrivateKeyBytes(key.buffer.asInt8List(), password: 'dartdart');
HttpServer.bindSecure('127.0.0.1', _port, context).then((server) {
print('Server running on https://localhost:' + _port.toString());
this._server = server;
server.listen((HttpRequest request) async {
print(request);
var body = List<int>();
var path = request.requestedUri.path;
path = (path.startsWith('/')) ? path.substring(1) : path;
path += (path.endsWith('/')) ? 'index.html' : '';
try {
body = (await rootBundle.load(path)).buffer.asUint8List();
} catch (e) {
print(e.toString());
request.response.close();
return;
}
var contentType = ['text', 'html'];
if (!request.requestedUri.path.endsWith('/') &&
request.requestedUri.pathSegments.isNotEmpty) {
var mimeType =
lookupMimeType(request.requestedUri.path, headerBytes: body);
if (mimeType != null) {
contentType = mimeType.split('/');
}
}
request.response.headers.contentType =
ContentType(contentType[0], contentType[1], charset: 'utf-8');
request.response.add(body);
request.response.close();
});
completer.complete();
});
}, onError: (e, stackTrace) {
print('Error: $e $stackTrace');
});
return completer.future;
}
///Closes the server.
Future<void> close() async {
if (this._server != null) {
await this._server.close(force: true);
print('Server running on http://localhost:$_port closed');
this._server = null;
}
}
}
大部分代码是原始代码的复制粘贴class。
我改变的是我调用 HttpServer.bindSecure 而不是 HttpServer.bind 并且我提供 openssl 证书和密钥。
服务器似乎启动时没有在控制台中记录错误,但我无法访问它。
这是尝试访问本地 url 的客户端代码:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'InAppLocalHostSecureServer.dart';
class WebAudioTest extends StatefulWidget {
@override
_WebAudioTestState createState() => _WebAudioTestState();
}
class _WebAudioTestState extends State<WebAudioTest> {
InAppWebViewController webView;
InAppLocalHostSecureServer localhostServer;
String url = "https://127.0.0.1:8443/assets/web/index.html";
@override
void initState() {
super.initState();
this.init();
}
void init() async {
this.localhostServer = new InAppLocalHostSecureServer();
await localhostServer.start();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Web Audio Test'),
),
body: InAppWebView(
initialUrl: url,
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)),
onWebViewCreated: (InAppWebViewController c) {
webView = c;
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE: " + consoleMessage.message);
},
),
);
}
}
console没有报错但是flutter页面报错如下:
网络::ERR_CONNECTION_REFUSED
欢迎任何帮助。
好的,回答我自己的问题:
我遇到的问题很简单,我过早地构建了 InAppWebView,在服务器完成启动之前。解决办法很简单,只要在服务器启动时设置一个标志为真,只有当标志为真时才创建 InAppWebView。
除此之外,WebRTC 在本地主机上无需 https 即可运行,我在 Android 和 iOS 上对其进行了测试。因此,此用例不需要本地 https。
但是无论如何,如果出于任何其他原因有人需要提供 https 本地内容,此 post 中的代码可以作为其基础。