IOS info.plist文件也按照官方说明配置了,但是我运行了课程代码,发现是可以,也没有报空安全错误,对比了下代码,只是增加了StreamSubscription变量的初始化,加了问号,断点调试,发现widget.url是有值,就算我替换成百度的链接,也是打不开,在pub上的issues查了也没相关问题,纠结啊
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
const CATCH_URLS = ['m.ctrip.com/', 'm.ctrip.com/html5/', 'm.ctrip.com/html5'];
class WebView extends StatefulWidget {
String url;
final String statusBarColor;
final String title;
final bool hideAppBar;
final bool backForbid;
WebView(
{required this.url,
required this.statusBarColor,
required this.title,
required this.hideAppBar,
this.backForbid = false}) {
if (url != null && url.contains('ctrip.com')) {
//fix 携程H5 http://无法打开问题
url = url.replaceAll("http://", 'https://');
}
}
@override
_WebViewState createState() => _WebViewState();
}
class _WebViewState extends State<WebView> {
final webviewReference = FlutterWebviewPlugin();
StreamSubscription<String>? _onUrlChanged;
StreamSubscription<WebViewStateChanged>? _onStateChanged;
StreamSubscription<WebViewHttpError>? _onHttpError;
bool exiting = false; //是否返回的标志位
_isToMain(String url) {
bool contain = false;
for (final value in CATCH_URLS) {
if (url.endsWith(value)) {
contain = true;
break;
}
}
return contain;
}
@override
void initState() {
super.initState();
webviewReference.close();
_onUrlChanged = webviewReference.onUrlChanged.listen((event) {});
_onStateChanged =
webviewReference.onStateChanged.listen((WebViewStateChanged state) {
switch (state.type) {
case WebViewState.startLoad:
///防止返回首页
if (_isToMain(widget.url) && !exiting) {
if (widget.backForbid) {
webviewReference.launch(widget.url);
} else {
Navigator.pop(context);
exiting = true;
}
}
break;
default:
break;
}
});
_onHttpError =
webviewReference.onHttpError.listen((WebViewHttpError error) {
print(error);
});
}
@override
void dispose() {
super.dispose();
_onUrlChanged?.cancel();
webviewReference.dispose();
_onStateChanged?.cancel();
_onHttpError?.cancel();
}
@override
Widget build(BuildContext context) {
String statusBarColorStr =
widget.statusBarColor.isEmpty ? 'ffffff' : widget.statusBarColor;
Color backButtonColor;
if (statusBarColorStr == 'ffffff') {
backButtonColor = Colors.black;
} else {
backButtonColor = Colors.white;
}
return Scaffold(
body: Column(
children: [
_appBar(
Color(int.parse('0xff' + statusBarColorStr)), backButtonColor),
///使用expanded撑满屏幕
Expanded(
child: WebviewScaffold(
url: widget.url,
userAgent: 'null', //防止携程H5页面重定向到打开携程APP ctrip://wireless/xxx的网址
///缩放
withZoom: true,
///页面缓存
withLocalStorage: true,
hidden: true,
initialChild: Container(
color: Colors.white,
child: Center(
child: Text('Waiting....'),
),
),
),
)
],
),
);
}
_appBar(Color backGroundColor, Color backButtonColor) {
if (widget.hideAppBar) {
return Container(
height: 30,
color: backGroundColor,
);
}
return Container(
color: backGroundColor,
padding: EdgeInsets.fromLTRB(0, 40, 0, 10),
child: FractionallySizedBox(
widthFactor: 1,
child: Stack(
children: [
///返回按钮
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Container(
margin: EdgeInsets.only(left: 10),
child: Icon(
Icons.close,
color: backButtonColor,
size: 26,
),
),
),
///标题
Positioned(
left: 0,
right: 0,
child: Center(
child: Text(
widget.title,
style: TextStyle(fontSize: 20, color: backButtonColor),
),
))
],
),
),
);
}
}
解锁Flutter开发新姿势,,系统掌握Flutter开发核心技术。
了解课程