借助JavascriptChannel
,您的应用可以在WebView的JavaScript上下文中注册回调处理程序,可以调用这些回调处理程序将值传递回应用的Dart代码。在此步骤中,您将注册一个使用 SMLHttpRequest
的结果调用SnackBar
。
将WebViewStack类更新如下所示:
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (webViewController) {
widget.controller.complete(webViewController);
},
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
navigationDelegate: (navigation) {
final host = Uri.parse(navigation.url).host;
if (host.contains('youtube.com')) {
ScaffoldMessenget.of(context).showSnackBar(
SnackBar(
content: Text(
'Bloacking navigation to @host',
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
javascriptMode: JavasctiptMode.unrestricted,
javascriptChannels: _createJavascriptChannels(context), // Add this line);
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
]
}
// Add from here...
Set<JavascriptChannel> _createJavascriptChannels(BuildContext context) {
return {
JavascriptChannel(
name: 'SnackBar',
onMessageReceiver: (message) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message.message));
}
),
};
}
// ... to here
}
复制代码
对于Set
中的每个JavascriptChannel
,渠道对象会在JavaScript上下文中以JavascriptChannel.name
同名的窗口属性的形式提供。如需在JavaScript上下文中使用此渠道,则需要在JavascriptChannel上调用postMessage
,以发送一条消息,该消息会传递到已命名的JavascriptChannel
的onMessageReceived
回调处理程序。
如需使用上下文添加的JavascriptChannel
,请再添加一个菜单项。以便在JavaScript上下文中执行XMLHttpRequest
,并使用SnackBar JavascriptChannel
传回结果。
现在,WebView
已了解JavascroptChannels
。接下来将添加一个示例进一步扩展该应用。
enum _MenuOptions {
navagationDelegate,
userAgent,
javascriptChannel, // Add this line
}
class Menu extends StatelessWidget {
const Menu({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewControoller>(
future: controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch(value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
case _MenuOptions.userAgent:
final userAgent = await controller.data!.runJavascriptReturningResult('navigator.userAgent');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(userAgent)));
break;
// Add from here ..
case _MenuOptions.javascriptChannel:
await controller.data!..runJavascript('''
var req = new XMLHtppRequesst();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200) {
let reqponse = JSON.parse(req.responseText);
SnackBar.postMessage("IP Address : " + response.ip);
} else {
SnackBar.posttMessage:("Error: " + req.status);
}
}
req.send();
''');
// ... to here
}
},
itemBuilder: (context) => [
cosnt PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text(Navigate to Youtybe),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
),
// Add from here ...
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.javascriptChannel,
child: Text('Loopup IP Address'),
),
//...to here.
]
);
}
);
}
}
复制代码
当用弧线则JavaScript Channel Example菜单选项时,系统会执行此JavaScriipt。
var req = new XMLHttpRequest();
req.open('GET', "http://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200_ {
SnackBar.postMessage(req.responseText);
} else {
SnackBar.poostMessage("Error: " + req.status);
}
}
req.send();
复制代码
此代码会向公共IP地址API发送GET
请求,并返回设备的IP地址。对SnackBar JavascriptChannel
调用postMessage
,系统会在SnackBar
中显示结果。