Flutter 讓 app 程式與 WebView 網頁互動
在開發行動應用程式時,有時候會利用 WebView 連線到特定的網頁。如果遇到需要 app 端的程式和網頁端互相溝通的話,就可以利用「Javascript bridge」這種概念。它是實作一個介面,讓 app 程式可以呼叫網頁的 Javascript 程式,以此類推。
Android 和 iOS (原生)已有行之有年的做法,Flutter 也可以做到。
建立 Flutter 程式
這裡預期讀者已有基本的 Flutter 觀念,講解大致的流程:
- 新建 Flutter 專案
- 匯入 webview_flutter 3.0.4
- 在主程式中使用 WebView
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late WebViewController _controller;
_loadHtmlFromAssets() async {
String file = await rootBundle.loadString('assets/index.html');
_controller.loadUrl(Uri.dataFromString(file,
mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
.toString());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("WebView")),
body: WebView(
initialUrl: 'about:blank',
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: {
JavascriptChannel(
name: 'messageHandler',
onMessageReceived: (message) {
final snackBar = SnackBar(content: Text(message.message));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
})
},
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtmlFromAssets();
},
onPageFinished: (url) {},
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.arrow_upward),
onPressed: () {
_controller.runJavascript('fromFlutter("From Flutter")');
},
),
);
}
}
這裡用 WebView 建立頁面
- 呼叫 _loadHtmlFromAssets() 讀取存在專案裡的網頁
- 傳入 javascriptMode: JavascriptMode.unrestricted 允許網頁執行 Javascript
- 傳入 javascriptChannels 建立從網頁傳送訊息到 app 的程式
- 建立 FloatingActionButton 在點擊時,呼叫 fromFlutter() 方法,將訊息傳送到網頁。
準備示範網頁
在專案根目錄新增「assets」資料夾,然後在裡面新增 index.html。
新增以下程式
<html>
<head>
<title>My Local HTML File</title>
</head>
<body>
<h1 id="title">Hello World!</h1>
<button type="button" onclick="sendBack()">Send message</button>
<script type="text/javascript">
function fromFlutter(newTitle) {
document.getElementById("title").innerHTML = newTitle;
}
function sendBack() {
messageHandler.postMessage("Hello from JS");
}
</script>
</body>
</html>
這個網頁包含 Javascript 程式:
- fromFlutter(String) 是供 app 呼叫,會變更 title 區塊的文字。
- sendBack() 是供網頁呼叫,將參數傳送到 app 程式。
在 pubspec.yaml 新增資源來源
flutter:
uses-material-design: true
assets:
- assets/index.html
執行程式
點擊按鈕時,可看到網頁上的文字異動為「From Flutter」。
點擊網頁上的按鈕時,app 彈出了訊息條。
留言
張貼留言