Create chrome extension using Flutter
How to create chrome extension using Flutter
Pengenalan
Melihat perkembangan Flutter pada acara Google I/O 2022 kemarin saya benar-benar sangat antusias. Dan benar saja sesuai prediksi saya bahwa tahun ini Flutter desktop sudah benar-benar bisa kita coba di production. Dan untuk Flutter web saya lihat juga sudah lumayan bagus ya performance-nya daripada versi yang sebelumnya. Nah, berhubung si Flutter ini sudah semakin bagus saja perkembangannya saya jadi tertarik untuk membahas Flutter web. Jadi, di tulisan kali ini saya akan coba membahas bagaimana cara membuat extension Google Chrome menggunakan Flutter. Oya, untuk versi Flutter-nya kita nggak perlu pakai yang versi 3 ya. Yang versi 2 saja sudah cukup.
Contoh projek
Untuk contoh projeknya kali ini kita akan membuat extension Google Chrome yang berfungsi untuk membuat QR kode dari teks yang diinput oleh user.
Buat projek
Langkah pertamanya silakan kita buka text editor favorit kita masing-masing terus buat projek baru dengan nama qr_code_chrome_extension.
Setup manifest.json
Buka file manifest.json dimana, didalamnya kita bisa lihat kode didalamnya kira-kira seperti berikut ini.
{
"name": "qr_code_chrome_extension",
"short_name": "qr_code_chrome_extension",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "QR code tools for chrome extension",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
Kemudian, kita ubah menjadi seperti berikut.
{
"name": "qr_code_chrome_extension",
"description": "QR code tools for chrome extension",
"version": "1.0.0",
"content_security_policy": {
"extension_pages": "script-src 'self' ; object-src 'self'"
},
"action": {
"default_popup": "index.html",
"default_icon": "/icons/Icon-192.png"
},
"manifest_version": 3
}
Catatan: Yang saya tandain bold harap disesuaikan dengan lokal kita masing-masing ya.
Setup index.html
Langkah berikutnya ialah kita buka file index.html.
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="QR code tools for chrome extension">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="qr_code_chrome_extension">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>qr_code_chrome_extension</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl)
.then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing || reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.',
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
</script>
</body>
</html>
Kemudian, kita ubah bagian tag script
-nya menjadi seperti berikut.
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="QR code tools for chrome extension">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="qr_code_chrome_extension">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>qr_code_chrome_extension</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
Lalu, kita perlu atur size window dari extension yang akan kita buat. Caranya, kita perlu tambahkan style di bagian tag html
-nya menjadi seperti berikut.
<html style="height: 300px; width: 300px">
Tes pasang extension
Sekarang kita coba build flutter web-nya menggunakan perintah berikut.
flutter build web --web-renderer html --csp
Setelah berhasil ter-build. Coba kita buka Google Chrome. Kemudian, buka chrome://extensions.
Pilih Load unpacked dan pilih directory build/web hasil dari perintah build diatas. Jika berhasil pada tahap-tahap sebelumnya maka, aplikasi yang kita build tadi seharusnya akan tampil.
Sekarang coba kita buka aplikasi extension-nya maka, tampil programnya seperti berikut.
Buat fitur QR kode
Nah, jika proses pembuatan extension-nya sudah berhasil. Maka, langkah berikutnya adalah kita tinggal buat fitur QR kode-nya aja nih.
Setup pubspec.yaml
Untuk membuat fitur tersebut kita perlu menggunakan plugin berikut ini.
Untuk menambahkan plugin tersebut kedalam projek silakan gunakan perintah berikut ini ya.
flutter pub add qr_flutter
Tunggu beberapa saat sampai proses download plugin-nya selesai. Jika proses tersebut berhasil seharusnya didalam file pubspec.yaml kita akan menemukan bahwa plugin qr_flutter sudah ditambahkan.
Buat tampilan utama
Nah, langkah berikutnya kita akan membuat tampilan utamanya ya. Untuk membuatnya silakan buka file main.dart dan ubah kode didalamnya menjadi seperti berikut.
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
void main() => runApp(const App());
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final controllerText = TextEditingController();
final valueNotifierQr = ValueNotifier('');
final formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Form(
key: formKey,
child: TextFormField(
controller: controllerText,
decoration: const InputDecoration(
isDense: true,
hintText: 'Enter a text or URL',
),
maxLines: 1,
minLines: 1,
onFieldSubmitted: (value) {
// TODO: Buat fitur membuat QR kode
},
),
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
height: 36,
child: ElevatedButton(
onPressed: () {
// TODO: Buat fitur membuat QR kode
},
child: const Text('Create QR'),
),
),
const SizedBox(height: 16),
ValueListenableBuilder(
valueListenable: valueNotifierQr,
builder: (BuildContext context, String value, _) {
return QrImage(
data: value,
version: QrVersions.auto,
size: 180,
);
},
),
],
),
),
);
}
}
Sekarang coba kita jalankan terlebih dahulu aplikasinya ya. Biar kelihatan tampilannya gimana.
flutter run -d chrome
Buat fitur QR kode
Jika tampilannya sudah selesai maka, langkah berikutnya adalah kita tinggal buat fungsi untuk membuat QR kode dari teks yang diinput oleh si user. Silakan kita buka kembali file main.dart dan buat function berikut.
void doCreateQrCode() {
if (formKey.currentState!.validate()) {
final qrData = controllerText.text.trim();
valueNotifierQr.value = qrData;
}
}
Lalu, kita ubah kode todo berikut ini.
// TODO: Buat fitur membuat QR kode
Menjadi seperti ini.
doCreateQrCode();
Kemudian, coba kita jalankan lagi programnya dan tes apakah fungsi buat QR kode sudah berhasil atau tidak.
Build ulang extension-nya
Sekarang coba kita build ulang extension-nya ya.
flutter build web --web-renderer --csp
Lalu, kita reload extension di Google chrome-nya dengan cara tekan tombol seperti yang ada di gambar berikut.
Tes fitur QR kode
Sekarang coba kita tes fitur QR kode di Google Chrome extension-nya.
Sekarang coba saya tes apakah QR kode-nya sudah sesuai atau belum ya menggunakan aplikasi QR code scanner di HP.
Kesimpulan
Jadi kesimpulannya adalah bahwa Flutter web sudah bisa membuat extension untuk Google Chrome. Dan ini merupakan tanda bahwa Flutter benar-benar serius dikembangkan untuk web. Dan mudah-mudahan saja Flutter web bisa ikut berpartisipasi dalam daftar web framework yang ada.