Flutter:webview_flutter插件使用
Posted 無_爲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter:webview_flutter插件使用相关的知识,希望对你有一定的参考价值。
一、添加权限:
1.android网络权限(工程/android/app/src/main/AndroidManifest.xml):
<manifest ...>
...
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
2.ios添加使用说明(工程/ios/Runner/Info.plist):
<dict>
...
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
</dict>
二、使用WebView显示网页:
1.添加webview_flutter插件依赖,在pubspec.yaml中:
dependencies:
webview_flutter: ^3.0.4 #WebView插件
2.使用WebView显示网页:
class WebViewPage extends StatefulWidget //网页显示界面
const WebViewPage(Key? key, required this.url) : super(key: key); //外部传入URL
final String url;
@override
State<WebViewPage> createState() => _PageState();
class _PageState extends State<WebViewPage>
late WebViewController _webControl; //WebView控制类
final CookieManager _cookieManager = CookieManager();
late double progress = 0.01; //H5加载进度值
final double VISIBLE = 1;
final double GONE = 0;
late double progressHeight = GONE; //H5加载进度条高度
//显示或隐藏进度条
void setProgressVisible(double isVisible)
setState(()
progressHeight = isVisible;
);
@override
void initState()
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView(); //android平台时使用SurfaceAndroidWebView
WebView _createWebView()
return WebView( //WebView组件
initialUrl: widget.url, //设置URL地址
javascriptMode: JavascriptMode.unrestricted, //启用JS
onWebViewCreated: (WebViewController webControl) //WebView创建时触发
_webControl = webControl;
,
javascriptChannels: <JavascriptChannel>getJSChannel1(context), getJSChannel2(context), //添加JS方法(可以多个),实现与H5交互数据
navigationDelegate: (NavigationRequest request) //控制页面是否进入下页
if (request.url.startsWith('http://www.yyh.com'))
return NavigationDecision.prevent; //禁止跳下页
return NavigationDecision.navigate; //放行跳下页
,
onPageStarted: (String url) //H5页面开始加载时触发
setProgressVisible(VISIBLE); //显示加载进度条
,
onProgress: (int progress) //加载H5页面时触发多次,progress值为0-100
this.progress = progress.toDouble() / 100.0; //计算成0.0-1.0之间的值
,
onPageFinished: (String url) //H5页面加载完成时触发
setProgressVisible(GONE); //隐藏加载进度条
,
gestureNavigationEnabled: true, //启用手势
);
//添加JS方法1,与H5交互数据
JavascriptChannel getJSChannel1(BuildContext context)
return JavascriptChannel(
name: 'jsMethodName1', //方法名,与H5中的名称一致。H5中调用方式:js方法名1.postMessage("字符串");
onMessageReceived: (JavascriptMessage message) //接收H5发过来的数据
String json = message.message;
print("H5发过来的数据1: $json");
);
//添加JS方法2,与H5交互数据
JavascriptChannel getJSChannel2(BuildContext context)
return JavascriptChannel(
name: 'jsMethodName2',
onMessageReceived: (JavascriptMessage message)
String json = message.message;
print("H5发过来的数据2: $json");
);
@override
Widget build(BuildContext context)
return WillPopScope(
onWillPop: () async //拦截页面返回事件
if (await _webControl.canGoBack())
_webControl.goBack(); //返回上个网页
return false;
return true; //退出当前页
,
child: Scaffold(
appBar: AppBar(title: const Text('WebView使用')),
body: Stack(
children: [
_createWebView(), //WebView
SizedBox( //进度条
height: progressHeight,
child: LinearProgressIndicator(
backgroundColor: Colors.white,
valueColor: AlwaysStoppedAnimation(Colors.yellow),
value: progress, //当前加载进度值
))
],
)));
三、WebView常用方法:
1.加载html的几种方式:
(1)加载Html字符串:
String htmlString = '''
<!DOCTYPE html><html>
<head><title>Navigation Delegate Example</title></head>
<body>
加载Html内容
</body>
</html>
''';
方式1:
Future<void> loadHtmlString1() async
String content = base64Encode(const Utf8Encoder().convert(htmlString));
await _webControl.loadUrl('data:text/html;base64,$content');
方式2:
Future<void> loadHtmlString2() async
await _webControl.loadHtmlString(htmlString);
(2)加载Html文件:
资源文件方式:
Future<void> loadHtmlFile1() async
await _webControl.loadFlutterAsset('assets/www/index.html');
File方式:
Future<void> loadHtmlFile2() async
String dir = (await getTemporaryDirectory()).path;
File file = File(<String>dir, 'www', 'index.html'.join(Platform.pathSeparator));
await file.create(recursive: true);
String filePath = file.path;
await file.writeAsString(htmlString); //将html字符串写入文件
await _webControl.loadFile(filePath); //加载html文件
(3)加载HTTP请求:
Future<void> loadHttpRequest(String url, String json) async
final WebViewRequest request = WebViewRequest(
uri: Uri.parse(url), //设置URL
method: WebViewRequestMethod.post, //设置请求方式,post或get请求
headers: <String, String>'Content-Type': 'application/json', //请求头字段
body: Uint8List.fromList(json.codeUnits), //请求参数
);
await _webControl.loadRequest(request); //加载HTTP请求
2.运行JS代码:
Future<void> runJSCode() async //运行JS代码,模拟H5与Flutter交互数据
await _webControl.runJavascript('jsMethodName1.postMessage("字符串");'); //此处模拟调用Flutter中定义的JS方法
3.Cookie添加/获取/清空:
//添加cookie
Future<void> addCookie() async
await _cookieManager.setCookie(const WebViewCookie(name: 'key1', value: 'value1', domain: 'url域名', path: '/路径'));
//获取cookie列表
Future<List<String>> getCookieList() async
String cookies = await _webControl.runJavascriptReturningResult('document.cookie');
if (cookies == null || cookies == '""') <String>[];
return cookies.split(';'); //获取cookie列表
//清空cookie
Future<void> clearCookies(BuildContext context) async
await _cookieManager.clearCookies();
4.缓存对象添加/获取/清空:
//添加缓存对象
Future<void> addCache() async //caches.open()创建缓存对象, 存在时不创建
await _webControl.runJavascript('caches.open("缓存对象名"); localStorage["key1"] = "value1";');
//获取缓存对象
Future<void> getCacheList() async
await _webControl.runJavascript('caches.keys()'
'.then((cacheKeys) => JSON.stringify("cacheKeys" : cacheKeys, "localStorage" : localStorage))'
'.then((caches) => jsMethodName1.postMessage(caches))'); //获取H5缓存对象,调用定义的JS方法发给Flutter
//清空缓存对象
Future<void> clearCache() async
await _webControl.clearCache();
Flutter关于webview_flutter设置cookie
源头
现在项目的开发过程中,我们经常会遇到app集成H5相关的东西,但是在H5那边又需要用户的token的,在链接后面拼上,这样有点不安全,这时我们会想到用种植cookie的方式,把token种植到cookie中去,很显然我们使用的webview_flutter不支持cookie的植入,所以产生了要自己改他源码的想法。
使用例子:
WebView(
initialUrl: 'https://flutter.dev',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
cookieList: [
// {'k': 'app_user_auth', 'v': 'll123123123123123123'},
],
);
由此我们可以看到我新加了一个cookieList数组,又来设置cookie值的
iOS 修改的地方
NSDictionary<NSString*, id>* settings = args[@"settings"];
NSArray *cookies = args[@"cookieList"];
NSString* initialUrl = args[@"initialUrl"];
if(![cookies isKindOfClass:[NSNull class]]){
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: initialUrl]];
NSDictionary *headFields = request.allHTTPHeaderFields;
[cookies enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *dic = obj;
NSString *cookieSource = [NSString stringWithFormat:@"document.cookie = '%@=%@;path=/';",dic[@"k"], dic[@"v"]];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];
NSString *cookie = headFields[dic[@"k"]];
if (cookie == nil) {
[request addValue:[NSString stringWithFormat:@"%@=%@",dic[@"k"] , dic[@"v"]] forHTTPHeaderField:@"Cookie"];
}
}];
}
关于安卓
安卓同事用的JS交互的方式解决此问题,所以就没有修改源码
以上是关于Flutter:webview_flutter插件使用的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 webview_flutter 包运行自定义 Javascript?
webview_flutter滑动存在卡顿问题的完美解决方法