HomeLập trìnhJavaScriptCách xây dựng...

Cách xây dựng cầu giao tiếp gốc trong Flutter với WebView và JavaScript


Theo dõi bài viết của tôi giải thích cách tạo cầu nối giao tiếp trong Android và iOS, tôi nghĩ có thể nên làm điều tương tự cho Flutter.

Mặc dù có vẻ như đây là một vấn đề đơn giản, nhưng bạn sẽ sớm nhận ra rằng phải mất một chút công sức để chức năng này hoạt động.

Đầu tiên và quan trọng nhất, điều quan trọng là phải nhận ra rằng (tại thời điểm viết bài này) Flutter không không phải đã tích hợp hỗ trợ cho các WebView được nhúng.

Không giống như một ứng dụng gốc trong Kotlin hoặc Swift, nơi bạn chỉ có thể khởi tạo một thành phần WebView, bạn không thể thêm một thành phần WebView vào ứng dụng Flutter của mình ngay lập tức.

Trong bài viết này, chúng ta sẽ tìm hiểu cách định cấu hình WebView trong các ứng dụng Flutter và cách giao tiếp giữa Flutter và Webview.

Cách định cấu hình WebView trong ứng dụng Flutter

Sau khi tạo dự án Flutter mới, chúng ta cần sử dụng gói webview_flutter để có thể sử dụng WebView. Chúng tôi sẽ thêm sự phụ thuộc vào pubspec.yaml tập tin:

dependencies:  
       flutter:    
           sdk: flutter
       webview_flutter: ^1.0.7

Sau đó, chúng ta cần chạy pub get trong thiết bị đầu cuối:

flutter pub get

Tiếp theo, chúng tôi nhập gói trong main.dart tập tin:

import 'package:webview_flutter/webview_flutter.dart';

Nếu bạn chưa dọn dẹp mã từ dự án khởi động, bây giờ là thời điểm tốt để làm việc đó.

Sau khi bạn xóa tất cả các nhận xét, nút hành động nổi và mọi thứ liên quan đến nó, bạn sẽ chỉ còn lại cái này (tôi đã thêm một tiện ích văn bản chỉ để hiển thị):

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Communication Bridge',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Native - JS Communication Bridge'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  WebViewController _controller;

  @override
  Widget build(BuildContext context) {
    return Text(
      "Flutter JS-Native Communication Bridge"
    );
  }
}

Mà sẽ cung cấp cho bạn kết quả này:

Đọc thêm  Xác thực biểu mẫu cơ bản trong JavaScript
1_txc-SxRUBZFMR4mdJq-tCA

Tạo nội dung HTML cục bộ

Vì chúng tôi sẽ sử dụng tệp HTML cục bộ có mã JavaScript được nhúng bên trong tệp, nên chúng tôi cần tạo tệp đó trong dự án của mình.

Tất cả nội dung cục bộ trong ứng dụng Flutter cần phải ở trong một assets danh mục.

Tạo ra một assets trong hệ thống phân cấp dự án chính của bạn bằng cách nhấp chuột phải vào bảng điều khiển bên trái và chọn Mới → Thư mục:

1_xlBwiAWJUdKiZWDsAdx7SQ
Hệ thống phân cấp tệp sau khi tạo thư mục asses

Sau đó, tiếp tục và tạo index.html bên trong thư mục tài sản và thêm đoạn mã sau:

<html>

    <head>
        <title>My Local HTML File</title>
    </head>

    <body>
        <h1 id="title">Hello World!</h1>
        <script type="text/javascript">
            function fromFlutter(newTitle) {
                document.getElementById("title").innerHTML = newTitle;
                sendBack();
             }

             function sendBack() {
                messageHandler.postMessage("Hello from JS");
             }
        </script>
    </body>
</html>
index.html

Bạn sẽ nhận thấy rằng chúng tôi đã viết hai phương thức trong phần JavaScript của html của chúng tôi:

  1. fromFlutter là phương thức chúng ta sẽ gọi từ Flutter với một chuỗi đại diện cho tiêu đề mới cho trang
  2. sendBack là phương thức chúng ta sẽ gọi để liên lạc lại với Flutter. Trong đó, chúng tôi đang gửi một chuỗi tin nhắn.

Chúng tôi sẽ xem nội dung của sendBack sau một phút, nhưng trước đó, chúng tôi phải thiết lập WebView trong ứng dụng của mình.

✋ Đừng quên thêm index.html cho bạn pubspec.yaml dưới một assets phần (sử dụng thụt đầu dòng chính xác):

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^1.0.7
  cupertino_icons: ^1.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
    
flutter:
  uses-material-design: true
  
  assets:
    - assets/index.html
một phần của chúng tôi pubspec.yaml tập tin

Thiết lập WebView

Vì chúng tôi đã nhập gói vào main.dart tệp, chúng ta cần thay thế tiện ích Văn bản bằng tiện ích WebView:

class _MyHomePageState extends State<MyHomePage> {

  WebViewController _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Webview')),
      body: WebView(
        initialUrl: 'about:blank',
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
    );
  }

  _loadHtmlFromAssets() async {
    String file = await rootBundle.loadString('assets/index.html');
    _controller.loadUrl(Uri.dataFromString(
        file,
        mimeType: 'text/html',
        encoding: Encoding.getByName('utf-8')).toString());
  }

}

Chúng ta đã bao bọc WebView của mình bằng một tiện ích Scaffold (chúng ta sẽ nói kỹ hơn về vấn đề này ở phần sau của bài viết), nhưng hãy tập trung vào các trường khác nhau của tiện ích WebView đã thấy ở trên:

  • initialUrl là nơi chúng ta có thể xác định URL mà WebView trỏ tới. Ở đây, chúng tôi quyết định trỏ nó vào không có gì vì chúng tôi sẽ tải tệp HTML cục bộ của mình
  • onWebViewCreated là một cuộc gọi lại mà chúng tôi nhận được từ gói sau khi WebView được tạo. Vì chúng tôi muốn lưu phiên bản bộ điều khiển mà chúng tôi nhận được từ cuộc gọi lại này, chúng tôi đã tạo một thành viên riêng để lưu trữ nó vào, _controller

Bạn cũng sẽ nhận thấy rằng chúng tôi đã tạo một phương thức gọi là _loadHtmlFromAssetsđúng như tên gọi của nó, sẽ tải tệp HTML cục bộ của chúng ta vào WebView.

Đọc thêm  JavaScript đã hoàn thành Turing— Giải thích

Bên trong phương pháp này, chúng tôi sử dụng cá thể WebViewController riêng của chúng tôi, _controllervà đó là phương pháp tiếp xúc loadUrl để tải tệp HTML cục bộ của chúng tôi. Do logic trong phương thức này, việc thực thi của nó không đồng bộ.

Nếu chúng tôi chạy ứng dụng của mình, chúng tôi sẽ nhận được như sau:

1_hE6jeEprGAW3YkVt0AiYrA

Cách giao tiếp từ Flutter sang WebView

Bây giờ hãy thêm một số chức năng để gọi fromFlutter phương pháp chúng tôi đã xác định trong tệp HTML cục bộ của mình.

Để làm điều đó, chúng tôi sẽ thêm Nút hành động nổi (hoặc FAB) vào bố cục của chúng tôi và kết nối nó onPressed phương pháp để gọi các fromFlutter phương pháp.

Đây cũng là lý do đằng sau việc sử dụng tiện ích Giàn giáo – vì vậy chúng tôi có thể dễ dàng thêm FAB:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Webview')),
      body: WebView(
        initialUrl: 'about:blank',
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript('fromFlutter("From Flutter")');
        },
      ),
    );
  }

Để thực hiện các cuộc gọi từ Flutter đến HTML đã tải của chúng tôi, chúng tôi đang sử dụng evaluateJavascript phương pháp. Để có thể sử dụng nó, chúng ta phải thêm một thuộc tính khác vào WebView của mình có tên là javascriptMode.

Trong đoạn mã trên, chúng tôi đang đặt nó thành không hạn chế. Nếu chúng tôi không đặt nó, chúng tôi sẽ không thể giao tiếp giữa Flutter và WebView:

Đọc thêm  Cách sử dụng thư viện JavaScript trong ứng dụng Angular 2+
1_odgcLrPQUlhGHdbaF4rO4A

Cách liên lạc lại từ WebView sang Flutter

Hãy nhớ làm thế nào tôi nói chúng ta sẽ nói về nội dung của chúng tôi sendBack phương pháp? Hãy làm điều đó ngay bây giờ:

function sendBack() {
  messageHandler.postMessage("Hello from JS");
}

bên trong sendBack phương pháp, chúng tôi đang sử dụng một đối tượng được gọi là messageHandler, và đó là phương thức đính kèm được gọi là postMessage.

Giống như việc tạo một cầu nối giao tiếp trong một ứng dụng gốc, sau khi bạn thiết lập một cầu nối, bạn sẽ thêm một đối tượng vào ứng dụng toàn cầu. Window đối tượng trong lớp JavaScript được sử dụng để liên lạc.

Bạn có thể đặt tên cho đối tượng này theo bất cứ thứ gì bạn thích miễn là bạn tham chiếu nó khi thực hiện lệnh gọi từ JavaScript đến ứng dụng gốc của mình.

Bạn có thể hỏi đối tượng này được thêm vào lớp JavaScript trong ứng dụng của chúng tôi như thế nào? Bằng cách thêm JavascriptChannels thuộc tính cho tiện ích WebView của chúng tôi:

class _MyHomePageState extends State<MyHomePage> {

  WebViewController _controller;
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text('Webview')),
      body: WebView(
        initialUrl: 'about:blank',
        javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: Set.from([
          JavascriptChannel(
              name: 'messageHandler',
              onMessageReceived: (JavascriptMessage message) {
               _scaffoldKey.currentState.showSnackBar(
                  SnackBar(
                      content: Text(message)
                  )
                 );
              })
        ]),
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript('fromFlutter("From Flutter")');
        },
      ),
    );

  }

Chúng tôi đã xác định một JavascriptChannel với một cái tên và một onMessageReceived người xử lý. Tên chúng tôi đã đặt cho kênh này, messageHandlerlà tên chúng tôi đang sử dụng để giao tiếp từ tệp HTML cục bộ mà chúng tôi đã tải lên lớp gốc của mình.

1_AGpwDR2o8Fh7Re_Cwtg7fA
Thành công lớn

Đối với những người tinh mắt, bạn có thể nhận thấy rằng một biến riêng tư mới đã được thêm vào, _scaffoldKey. Điều này là do chúng tôi cần thêm khóa vào tiện ích Scaffold để có thể hiển thị thanh đồ ăn nhanh.

Bạn có thể lấy mã nguồn cho ứng dụng được mô tả trong bài viết dưới đây:

TomerPacific/Medium Articles

Một kho lưu trữ chứa mã được liên kết với các bài viết trên Phương tiện khác nhau mà tôi đã viết – TomerPacific/MediumArticles

23402988?s=400&v=4

Hai điểm cuối cùng cần lưu ý:

  1. Phương thức cảnh báo bị hỏng trong gói webview_flutter
  2. Để sử dụng gói trong iOS, bạn phải thêm khóa sau vào info.plist tập tin: <key>io.flutter.embedded_views_preview</key><string>yes</string>

Dưới đây là một số nguồn khác mà bạn có thể thấy hữu ích nếu muốn tìm hiểu thêm về Flutter và WebViews:



Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status