Flutter中使用WebViewController.runJavaScript存储登录凭证至WebView localStorage失败
解决webview_flutter中localStorage写入失败的问题
问题核心原因
你当前的代码存在两个关键问题导致登录凭证无法写入localStorage:
- 执行时机错误:在
initState中直接调用runJavaScript时,WebView页面还未加载完成,此时页面上下文不存在,JS代码无法生效。 - JS语法问题:注释中的代码直接将对象传入
localStorage.setItem,但localStorage仅支持存储字符串类型,必须用JSON.stringify转换对象。
控制台的Cannot read properties of null (reading 'd')错误,是网页代码尝试读取未写入成功的localStorage数据引发的空指针异常。
修复方案
1. 调整JS执行时机
将写入localStorage的代码移至NavigationDelegate的onPageFinished回调中,确保页面完全加载后再执行JS操作。
2. 修正JS语法
统一使用localStorage.setItem方法,确保所有存储内容为字符串类型(对象需转为JSON字符串)。
完整修复代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'dart:convert'; import 'model_response.dart'; class MyPageWidget extends StatefulWidget { MyPageWidget( {super.key, required this.data, required this.totalStep, required this.poster, required this.id}); List<Data> data; int totalStep; String poster; String id; @override State<MyPageWidget> createState() => _MyPageWidgetState(); } class _MyPageWidgetState extends State<MyPageWidget> { late WebViewController controller; @override void initState() { super.initState(); controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(const Color(0x00000000)) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) {}, onPageStarted: (String url) {}, // 页面加载完成后执行JS写入localStorage onPageFinished: (String url) async { await controller.runJavaScript(''' localStorage.setItem('token', ${jsonEncode(widget.id)}); localStorage.setItem('user', JSON.stringify({ "userData": { "_id": "63d8a45c8acb9efbdce5d8ec", "email": "test@gmail.com", "password": "123" }, "message": "User Login Successfully" })); '''); // 可选:验证写入结果 final token = await controller.runJavaScriptReturningResult('localStorage.getItem("token")'); print('已存储的token:$token'); }, onWebResourceError: (WebResourceError error) {}, onNavigationRequest: (NavigationRequest request) { if (request.url.startsWith('https://www.babylonjs.com/demos/gui/')) { return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ) ..loadRequest(Uri.parse('http://192.168.1.55:3000/model')); } @override void dispose() { super.dispose(); SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: WebViewWidget( controller: controller, ), ), ); } }
额外注意事项
- 如果
widget.id包含单引号、换行等特殊字符,使用jsonEncode()做转义处理,避免JS语法错误。 - 确保网页域名无跨域限制,本地调试通常无需额外配置,正式环境需检查CORS规则。
内容的提问来源于stack exchange,提问作者asaiTech
相关产品推荐
相关产品推荐

