chrome_extension.dart
A library for accessing the chrome.* APIs available in Chrome extensions.
It lets you build Chrome extensions with Dart & Flutter and use the native APIs through a high-level, type-safe interface.
The JS interop is built on top of dart:js_interop, so the library works when compiled to JavaScript and to WebAssembly (dart compile wasm, flutter build web --wasm).
Using the library
Example
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']);
}
Available APIs
package:chrome_extension/accessibility_features.dart(API reference)package:chrome_extension/action.dart(API reference)package:chrome_extension/alarms.dart(API reference)package:chrome_extension/audio.dart(API reference)package:chrome_extension/bookmarks.dart(API reference)package:chrome_extension/browser_action.dart(API reference)package:chrome_extension/browsing_data.dart(API reference)package:chrome_extension/certificate_provider.dart(API reference)package:chrome_extension/commands.dart(API reference)package:chrome_extension/content_settings.dart(API reference)package:chrome_extension/context_menus.dart(API reference)package:chrome_extension/cookies.dart(API reference)package:chrome_extension/debugger.dart(API reference)package:chrome_extension/declarative_content.dart(API reference)package:chrome_extension/declarative_net_request.dart(API reference)package:chrome_extension/desktop_capture.dart(API reference)package:chrome_extension/devtools_inspected_window.dart(API reference)package:chrome_extension/devtools_network.dart(API reference)package:chrome_extension/devtools_panels.dart(API reference)package:chrome_extension/devtools_recorder.dart(API reference)package:chrome_extension/document_scan.dart(API reference)package:chrome_extension/dom.dart(API reference)package:chrome_extension/downloads.dart(API reference)package:chrome_extension/enterprise_device_attributes.dart(API reference)package:chrome_extension/enterprise_hardware_platform.dart(API reference)package:chrome_extension/enterprise_networking_attributes.dart(API reference)package:chrome_extension/enterprise_platform_keys.dart(API reference)package:chrome_extension/events.dart(API reference)package:chrome_extension/extension.dart(API reference)package:chrome_extension/extension_types.dart(API reference)package:chrome_extension/file_browser_handler.dart(API reference)package:chrome_extension/file_system_provider.dart(API reference)package:chrome_extension/font_settings.dart(API reference)package:chrome_extension/gcm.dart(API reference)package:chrome_extension/history.dart(API reference)package:chrome_extension/i18n.dart(API reference)package:chrome_extension/identity.dart(API reference)package:chrome_extension/idle.dart(API reference)package:chrome_extension/input_ime.dart(API reference)package:chrome_extension/instance_id.dart(API reference)package:chrome_extension/login_state.dart(API reference)package:chrome_extension/management.dart(API reference)package:chrome_extension/notifications.dart(API reference)package:chrome_extension/offscreen.dart(API reference)package:chrome_extension/omnibox.dart(API reference)package:chrome_extension/page_action.dart(API reference)package:chrome_extension/page_capture.dart(API reference)package:chrome_extension/permissions.dart(API reference)package:chrome_extension/platform_keys.dart(API reference)package:chrome_extension/power.dart(API reference)package:chrome_extension/printer_provider.dart(API reference)package:chrome_extension/printing.dart(API reference)package:chrome_extension/printing_metrics.dart(API reference)package:chrome_extension/privacy.dart(API reference)package:chrome_extension/processes.dart(API reference)package:chrome_extension/proxy.dart(API reference)package:chrome_extension/reading_list.dart(API reference)package:chrome_extension/runtime.dart(API reference)package:chrome_extension/scripting.dart(API reference)package:chrome_extension/search.dart(API reference)package:chrome_extension/sessions.dart(API reference)package:chrome_extension/side_panel.dart(API reference)package:chrome_extension/storage.dart(API reference)package:chrome_extension/system_cpu.dart(API reference)package:chrome_extension/system_display.dart(API reference)package:chrome_extension/system_memory.dart(API reference)package:chrome_extension/system_network.dart(API reference)package:chrome_extension/system_storage.dart(API reference)package:chrome_extension/tab_capture.dart(API reference)package:chrome_extension/tab_groups.dart(API reference)package:chrome_extension/tabs.dart(API reference)package:chrome_extension/top_sites.dart(API reference)package:chrome_extension/tts.dart(API reference)package:chrome_extension/tts_engine.dart(API reference)package:chrome_extension/types.dart(API reference)package:chrome_extension/user_scripts.dart(API reference)package:chrome_extension/vpn_provider.dart(API reference)package:chrome_extension/wallpaper.dart(API reference)package:chrome_extension/web_authentication_proxy.dart(API reference)package:chrome_extension/web_navigation.dart(API reference)package:chrome_extension/web_request.dart(API reference)package:chrome_extension/windows.dart(API reference)package:chrome_extension/usb.dart(API reference)
Documentation
- Chrome Extensions API reference
- See example folder for some examples of Flutter and Dart Chrome extensions
Tips to build Chrome extensions with Flutter
Here are some personal tips to build Chrome extensions using the Flutter UI framework.
Develop the app using Flutter Desktop
In order to develop in a comfortable environment with hot-reload, most of the app (the UI part) should be developed using Flutter desktop.
This requires an abstraction layer between the UI and the chrome_extension APIs.
In the Desktop entry point, a fake implementation of this abstraction layer is used, like this:
// lib/main_desktop.dart
void main() {
// Inject a fake service that doesn't use the real chrome_extension package.
var service = FakeBookmarkService();
runApp(MyExtensionPopup(service));
}
abstract class BookmarkService {
Future<List<Bookmark>> getBookmarks();
}
class FakeBookmarkService implements BookmarkService {
@override
Future<List<Bookmark>> getBookmarks() async => [Bookmark()];
}
Launch this entry point in desktop with
flutter run -t lib/main_desktop.dart -d macos|windows|linux
And the real entry point (the one used in the actual compiled extension) looks like:
// lib/main.dart
void main() {
var service = ChromeBookmarkService();
runApp(MyExtensionPopup(service));
}
class ChromeBookmarkService implements BookmarkService {
@override
Future<List<Bookmark>> getBookmarks() async {
// Real implementation using chrome.bookmarks
return (await chrome.bookmarks.getTree()).map(Bookmark.new).toList();
}
}
Build script
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',
'--wasm',
'--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',
]);
}
}
It builds the flutter app and compiles all the other Dart scripts (for example: options.dart.js, popup.dart.js, background.dart.js)
With --wasm, the Flutter app is compiled to WebAssembly (with a fallback to JavaScript).
web/index.html needs to load it with <script src="flutter_bootstrap.js" async></script>,
loading main.dart.js directly always uses the JavaScript build.
Keep compiling the background service worker and the content scripts to JavaScript: content scripts can't be ES modules, and a Wasm module is instantiated asynchronously while Chrome only dispatches the event that woke up the service worker to the listeners registered synchronously.
Testing
Write tests for the extension using puppeteer-dart.
browser.installExtension() (or puppeteer.launch(extensions: [...])) installs the extension through the
DevTools protocol, so the tests can run in headless mode and with Google Chrome, which ignores the
--load-extension flag since version 137.
import 'package:puppeteer/puppeteer.dart';
void main() async {
// Compile the extension
var extensionPath = '...';
var browser = await puppeteer.launch(
enableExtensions: true,
args: [
// Allow to connect to puppeteer from inside your extension if needed for the testing
'--remote-allow-origins=*',
],
);
var extensionId = await browser.installExtension(extensionPath);
// Go to the popup page
var page = await browser.newPage();
await page.goto('chrome-extension://$extensionId/popup.html');
// Etc...
await browser.close();
}
Libraries
- accessibility_features
- action
- alarms
- audio
- bookmarks
- browser_action
- browsing_data
- certificate_provider
- chrome
- commands
- content_settings
- debugger
- declarative_content
- declarative_net_request
- desktop_capture
- devtools
- devtools_inspected_window
- devtools_network
- devtools_panels
- devtools_recorder
- document_scan
- dom
- downloads
- enterprise
- enterprise_device_attributes
- enterprise_hardware_platform
- enterprise_networking_attributes
- enterprise_platform_keys
- events
- extension
- extension_types
- file_browser_handler
- file_system_provider
- font_settings
- gcm
- history
- i18n
- identity
- idle
- input
- input_ime
- instance_id
- login_state
- management
- notifications
- offscreen
- omnibox
- page_action
- page_capture
- permissions
- platform_keys
- power
- printer_provider
- printing
- printing_metrics
- privacy
- processes
- proxy
- reading_list
- runtime
- scripting
- search
- sessions
- side_panel
- storage
- system
- system_cpu
- system_display
- system_memory
- system_network
- system_storage
- tab_capture
- tab_groups
- tabs
- top_sites
- tts
- tts_engine
- types
- usb
- user_scripts
- vpn_provider
- wallpaper
- web_authentication_proxy
- web_request
- windows
