Flutter浏览器扩展交互插件chrome_extension的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter浏览器扩展交互插件chrome_extension的使用

chrome_extension.dart

pub package Build Status

chrome_extension.dart 是一个用于访问Chrome扩展中可用的 chrome.* APIs 的库。

这使得我们可以用 Dart & Flutter 构建 Chrome 扩展,并与原生 API 轻松互操作,提供高级类型安全接口。JS 互操作基于 dart:js_interop(静态互操作),使其为未来的 WASM 编译做好准备。

如果您喜欢这个项目,可以请我喝杯咖啡: Buy Me A Coffee

使用该库

示例

chrome.tabs

import 'package:chrome_extension/tabs.dart';

void main() async {
  var tabs = await chrome.tabs.query(QueryInfo(
    active: true,
    currentWindow: true,
  ));
  print(tabs.first.title);
}

chrome.alarms

import 'package:chrome_extension/alarms.dart';

void main() async {
  await chrome.alarms.create('MyAlarm', AlarmCreateInfo(delayInMinutes: 2));

  var alarm = await chrome.alarms.get('MyAlarm');
  print(alarm!.name);
}

chrome.power

import 'package:chrome_extension/power.dart';

void main() {
  chrome.power.requestKeepAwake(Level.display);
}

chrome.runtime

import 'dart:js_interop';
import 'package:chrome_extension/runtime.dart';

void main() async {
  chrome.runtime.onInstalled.listen((e) {
    print('OnInstalled: ${e.reason}');
  });

  chrome.runtime.onMessage.listen((e) {
    e.sendResponse.callAsFunction(null, {'the_response': 1}.jsify());
  });
}

chrome.storage

import 'package:chrome_extension/storage.dart';

void main() async {
  await chrome.storage.local.set({'mykey': 'value'});
  var values = await chrome.storage.local.get(null /* all */);
  print(values['mykey']);
}

可用的 APIs

以下是部分可用的 API 列表:

文档

使用 Flutter 构建 Chrome 扩展的技巧

使用 Flutter Desktop 开发应用

为了在具备热重载功能的舒适环境中开发,大部分应用程序(UI部分)应该使用 Flutter desktop 开发。

这需要在 UI 和 chrome_extension API 之间创建一个抽象层。

在桌面入口点,使用此抽象层的假实现,例如:

// lib/main_desktop.dart
void main() {
  // 注入一个不使用真实 chrome_extension 包的假服务
  var service = FakeBookmarkService();
  runApp(MyExtensionPopup(service));
}

abstract class BookmarkService {
  Future<List<Bookmark>> getBookmarks();
}

class FakeBookmarkService implements BookmarkService {
  @override
  Future<List<Bookmark>> getBookmarks() async => [Bookmark()];
}

通过以下命令启动此入口点:

flutter run -t lib/main_desktop.dart -d macos|windows|linux

实际编译扩展中使用的真正入口点如下所示:

// lib/main.dart
void main() {
  var service = ChromeBookmarkService();
  runApp(MyExtensionPopup(service));
}

class ChromeBookmarkService implements BookmarkService {
  @override
  Future<List<Bookmark>> getBookmarks() async {
    // 真实实现使用 chrome.bookmarks
    return (await chrome.bookmarks.getTree()).map(Bookmark.new).toList();
  }
}

构建脚本

web/manifest.json

{
  "manifest_version": 3,
  "name": "my_extension",
  "permissions": [
    "activeTab"
  ],
  "options_page": "options.html",
  "background": {
    "service_worker": "background.dart.js"
  },
  "action": {
    "default_popup": "index.html",
    "default_icon": {
      "16": "icons-16.png"
    }
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  }
}

tool/build.dart

void main() async {
  await _process.runProcess([
    'flutter',
    'build',
    'web',
    '-t',
    'web/popup.dart',
    '--csp',
    '--web-renderer=canvaskit',
    '--no-web-resources-cdn',
  ]);
  for (var script in [
    'background.dart',
    'content_script.dart',
    'options.dart'
  ]) {
    await _process.runProcess([
      Platform.resolvedExecutable,
      'compile',
      'js',
      'web/$script',
      '--output',
      'build/web/$script.js',
    ]);
  }
}

它会构建 Flutter 应用并编译所有其他 Dart 脚本(例如:options.dart.js, popup.dart.js, background.dart.js)

测试

编写使用 puppeteer-dart 的测试代码如下:

import 'package:collection/collection.dart';
import 'package:puppeteer/puppeteer.dart';

void main() async {
  // 编译扩展
  var extensionPath = '...';

  var browser = await puppeteer.launch(
    headless: false,
    args: [
      '--disable-extensions-except=$extensionPath',
      '--load-extension=$extensionPath',
      // 如果需要从扩展内部连接到 puppeteer,则允许进行测试
      '--remote-allow-origins=*',
    ],
  );

  // 查找后台页面目标
  var targetName = 'service_worker';
  var backgroundPageTarget =
      browser.targets.firstWhereOrNull((t) => t.type == targetName);
  backgroundPageTarget ??=
      await browser.waitForTarget((target) => target.type == targetName);
  var worker = (await backgroundPageTarget.worker)!;

  var url = Uri.parse(worker.url!);
  assert(url.scheme == 'chrome-extension');
  var extensionId = url.host;

  // 前往弹出页面
  await (await browser.pages)
      .first
      .goto('chrome-extension://$extensionId/popup.html');

  // 更多测试代码...
}

以上就是关于 chrome_extension 插件的详细介绍和使用方法,希望对您有所帮助!


更多关于Flutter浏览器扩展交互插件chrome_extension的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter浏览器扩展交互插件chrome_extension的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中与Chrome扩展进行交互的示例代码,使用chrome_extension插件。请注意,由于chrome_extension插件的具体实现和API可能会根据插件版本和Chrome扩展的复杂性有所不同,以下代码是一个简化的示例,用于展示基本思路。

首先,确保你的Flutter项目已经添加了chrome_extension插件。你可以在pubspec.yaml文件中添加以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  chrome_extension: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,我们假设你有一个Chrome扩展,它提供了一个名为myExtension的对象,并且这个对象有一个方法sendMessage,用于发送消息到扩展。以下是如何在Flutter中使用这个扩展的示例代码:

  1. android/app/src/main/AndroidManifest.xml中添加必要的权限(如果需要):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <!-- 其他配置 -->

    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 如果需要其他权限,也请在这里添加 -->

</manifest>
  1. ios/Runner/Info.plist中添加必要的配置(如果需要与iOS上的Chrome交互):

确保你的iOS应用有适当的权限和配置来与Chrome应用交互。

  1. 在Flutter代码中与Chrome扩展交互
import 'package:flutter/material.dart';
import 'package:chrome_extension/chrome_extension.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String responseFromExtension = '';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Chrome Extension Interaction'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Response from Chrome Extension:'),
              Text(responseFromExtension),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _sendMessageToExtension,
                child: Text('Send Message to Extension'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _sendMessageToExtension() async {
    try {
      // 假设Chrome扩展的ID是`my-extension-id`,并且它提供了一个全局对象`myExtension`
      var extension = await ChromeExtension.connect('my-extension-id');

      // 发送消息到扩展
      var result = await extension.sendMessage({
        'type': 'hello',
        'message': 'Hello from Flutter app!',
      });

      // 更新状态以显示响应
      setState(() {
        responseFromExtension = result.toString();
      });
    } catch (error) {
      print('Error communicating with Chrome extension: $error');
      setState(() {
        responseFromExtension = 'Error: $error';
      });
    }
  }
}

注意

  1. 上述代码中的ChromeExtension.connect('my-extension-id')extension.sendMessage(...)是假设的方法调用,实际使用时需要参考chrome_extension插件的文档和API。

  2. Chrome扩展的ID和全局对象名称需要替换为你实际使用的值。

  3. 由于Chrome扩展的复杂性,可能需要在Chrome扩展中编写特定的代码来监听和处理来自Flutter应用的消息。

  4. 确保Chrome扩展已经正确安装并启用,且其权限和配置允许与Flutter应用进行交互。

  5. 在实际开发中,可能还需要处理更多的错误情况和边界情况。

由于chrome_extension插件的具体实现细节可能有所不同,建议查阅该插件的官方文档和示例代码以获取更准确的信息。

回到顶部