1. Pengantar
Terakhir Diperbarui: 14-03-2022
FlutterFire untuk komunikasi lintas perangkat
Seiring dengan banyaknya perangkat teknologi kesehatan pribadi, perangkat wearable, dan otomatisasi rumah yang terhubung ke internet, komunikasi lintas perangkat menjadi bagian yang semakin penting dalam membangun aplikasi seluler. Menyiapkan komunikasi lintas perangkat seperti mengontrol browser dari aplikasi ponsel, atau mengontrol konten yang diputar di TV dari ponsel, biasanya lebih rumit daripada membuat aplikasi seluler biasa .
Realtime Database Firebase menyediakan Presence API yang memungkinkan pengguna melihat status online/offline perangkat mereka; Anda akan menggunakannya dengan Firebase Installations Service untuk melacak dan menghubungkan semua perangkat tempat pengguna yang sama telah login. Anda akan menggunakan Flutter untuk membuat aplikasi dengan cepat untuk beberapa platform, lalu Anda akan membuat prototipe lintas perangkat yang memutar musik di satu perangkat dan mengontrol musik di perangkat lain.
Hal yang akan Anda build
Dalam codelab ini, Anda akan membuat pengontrol jarak jauh pemutar musik sederhana. Aplikasi Anda akan:
- Memiliki pemutar musik sederhana di Android, iOS, dan web, yang dibuat dengan Flutter.
- Izinkan pengguna login.
- Menghubungkan perangkat saat pengguna yang sama login di beberapa perangkat.
- Mengizinkan pengguna mengontrol pemutaran musik di satu perangkat dari perangkat lain.
Hal yang akan Anda pelajari
- Cara mem-build dan menjalankan aplikasi pemutar musik Flutter.
- Cara mengizinkan pengguna login dengan Firebase Auth.
- Cara menggunakan Firebase RTDB Presence API dan Firebase Installation Service untuk menghubungkan perangkat.
Hal yang akan Anda perlukan
- Lingkungan pengembangan Flutter. Ikuti petunjuk di panduan penginstalan Flutter untuk menyiapkannya.
- Diperlukan versi Flutter minimum 2.10 atau yang lebih tinggi. Jika Anda memiliki versi yang lebih rendah, jalankan
flutter upgrade.
- Akun Firebase.
2. Mempersiapkan
Mendapatkan kode awal
Kita telah membuat aplikasi pemutar musik di Flutter. Kode awal terletak di repositori Git. Untuk memulai, di command line, clone repo, pindah ke folder dengan status awal, dan instal dependensi:
git clone https://github.com/FirebaseExtended/cross-device-controller.git
cd cross-device-controller/starter_code
flutter pub get
Membangun aplikasi
Anda dapat menggunakan IDE favorit untuk membangun aplikasi, atau menggunakan command line.
Di direktori aplikasi, build aplikasi untuk web dengan perintah flutter run -d web-server.
Anda akan dapat melihat perintah berikut.
lib/main.dart is being served at http://localhost:<port>
Buka http://localhost:<port>
untuk melihat pemutar musik.
Jika sudah terbiasa dengan emulator Android atau simulator iOS, Anda dapat mem-build aplikasi untuk platform tersebut dan menginstalnya dengan perintah flutter run -d <device_name>
.
Aplikasi web akan menampilkan pemutar musik mandiri dasar. Pastikan fitur pemutar berfungsi sebagaimana mestinya. Ini adalah aplikasi pemutar musik sederhana yang didesain untuk codelab ini. Fitur ini hanya dapat memutar lagu Firebase, Lebih Baik Bersama.
Menyiapkan emulator Android atau simulator iOS
Jika sudah memiliki perangkat Android atau perangkat iOS untuk pengembangan, Anda dapat melewati langkah ini.
Untuk membuat emulator Android, download Android Studio yang juga mendukung pengembangan Flutter, lalu ikuti petunjuk di Membuat dan mengelola perangkat virtual.
Untuk membuat simulator iOS, Anda memerlukan lingkungan Mac. Download XCode, lalu ikuti petunjuk di Ringkasan Simulator > Menggunakan Simulator > Membuka dan menutup simulator.
3. Menyiapkan Firebase
Membuat project Firebase
- Login ke Firebase console menggunakan Akun Google Anda.
- Klik tombol untuk membuat project baru, lalu masukkan nama project (misalnya,
Firebase-Cross-Device-Codelab
).
- Klik Lanjutkan.
- Jika diminta, tinjau dan setujui persyaratan Firebase, lalu klik Continue.
- (Opsional) Aktifkan bantuan AI di Firebase console (disebut "Gemini di Firebase").
- Untuk codelab ini, Anda tidak memerlukan Google Analytics, jadi nonaktifkan opsi Google Analytics.
- Klik Buat project, tunggu hingga project Anda disediakan, lalu klik Lanjutkan.
Instal Firebase SDK
Kembali ke command line, di direktori project, jalankan perintah berikut untuk menginstal Firebase:
flutter pub add firebase_core
Di file pubspec.yaml
, edit versi untuk firebase_core
menjadi setidaknya 1.13.1, atau jalankan flutter upgrade
Menginisialisasi FlutterFire
- Jika Anda belum menginstal Firebase CLI, Anda dapat menginstalnya dengan menjalankan
curl -sL https://firebase.tools | bash
. - Login dengan menjalankan
firebase login
dan mengikuti petunjuknya. - Instal FlutterFire CLI dengan menjalankan
dart pub global activate flutterfire_cli
. - Konfigurasi FlutterFire CLI dengan menjalankan
flutterfire configure
. - Di perintah, pilih project yang baru saja Anda buat untuk codelab ini, seperti Firebase-Cross-Device-Codelab.
- Pilih iOS, Android, dan Web saat Anda diminta untuk memilih dukungan konfigurasi.
- Saat diminta untuk memasukkan ID paket Apple, ketik domain unik, atau masukkan
com.example.appname
, yang tidak masalah untuk tujuan codelab ini.
Setelah dikonfigurasi, file firebase_options.dart
akan dibuat untuk Anda yang berisi semua opsi yang diperlukan untuk inisialisasi.
Di editor Anda, tambahkan kode berikut ke file main.dart untuk menginisialisasi Flutter dan Firebase:
lib/main.dart
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyMusicBoxApp());
}
Kompilasi aplikasi dengan perintah:
flutter run
Anda belum mengubah elemen UI apa pun, sehingga tampilan dan perilaku aplikasi belum berubah. Namun, kini Anda memiliki aplikasi Firebase dan dapat mulai menggunakan produk Firebase, termasuk:
- Firebase Authentication, yang memungkinkan pengguna login ke aplikasi Anda.
- Firebase Realtime Database(RTDB); Anda akan menggunakan presence API untuk melacak status online/offline perangkat
- Aturan Keamanan Firebase akan memungkinkan Anda mengamankan database.
- Firebase Installations Service untuk mengidentifikasi perangkat yang telah digunakan untuk login oleh satu pengguna.
4. Menambahkan Firebase Auth
Mengaktifkan login email untuk Firebase Authentication
Untuk mengizinkan pengguna login ke aplikasi web, Anda akan menggunakan metode login Email/Password:
- Di Firebase console, luaskan menu Build di panel kiri.
- Klik Authentication, lalu klik tombol Get Started, lalu tab Sign-in method.
- Klik Email/Password di daftar Sign-in providers, setel tombol akses Enable ke posisi aktif, lalu klik Save.
Mengonfigurasi Firebase Authentication di Flutter
Di command line, jalankan perintah berikut untuk menginstal paket flutter yang diperlukan:
flutter pub add firebase_auth
flutter pub add provider
Dengan konfigurasi ini, Anda kini dapat membuat alur login dan logout. Karena status autentikasi tidak boleh berubah dari layar ke layar, Anda akan membuat class application_state.dart
untuk melacak perubahan status tingkat aplikasi, seperti login dan logout. Pelajari lebih lanjut hal ini di dokumentasi pengelolaan status Flutter.
Tempelkan kode berikut ke dalam file application_state.dart
baru:
lib/src/application_state.dart
import 'package:firebase_auth/firebase_auth.dart'; // new
import 'package:firebase_core/firebase_core.dart'; // new
import 'package:flutter/material.dart';
import '../firebase_options.dart';
import 'authentication.dart';
class ApplicationState extends ChangeNotifier {
ApplicationState() {
init();
}
Future<void> init() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseAuth.instance.userChanges().listen((user) {
if (user != null) {
_loginState = ApplicationLoginState.loggedIn;
} else {
_loginState = ApplicationLoginState.loggedOut;
}
notifyListeners();
});
}
ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
ApplicationLoginState get loginState => _loginState;
String? _email;
String? get email => _email;
void startLoginFlow() {
_loginState = ApplicationLoginState.emailAddress;
notifyListeners();
}
Future<void> verifyEmail(
String email,
void Function(FirebaseAuthException e) errorCallback,
) async {
try {
var methods =
await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
if (methods.contains('password')) {
_loginState = ApplicationLoginState.password;
} else {
_loginState = ApplicationLoginState.register;
}
_email = email;
notifyListeners();
} on FirebaseAuthException catch (e) {
errorCallback(e);
}
}
Future<void> signInWithEmailAndPassword(
String email,
String password,
void Function(FirebaseAuthException e) errorCallback,
) async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
} on FirebaseAuthException catch (e) {
errorCallback(e);
}
}
void cancelRegistration() {
_loginState = ApplicationLoginState.emailAddress;
notifyListeners();
}
Future<void> registerAccount(
String email,
String displayName,
String password,
void Function(FirebaseAuthException e) errorCallback) async {
try {
var credential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
await credential.user!.updateDisplayName(displayName);
} on FirebaseAuthException catch (e) {
errorCallback(e);
}
}
void signOut() {
FirebaseAuth.instance.signOut();
}
}
Untuk memastikan ApplicationState
akan diinisialisasi saat aplikasi dimulai, Anda akan menambahkan langkah inisialisasi ke main.dart
:
lib/main.dart
import 'src/application_state.dart';
import 'package:provider/provider.dart';
void main() async {
...
runApp(ChangeNotifierProvider(
create: (context) => ApplicationState(),
builder: (context, _) => const MyMusicBoxApp(),
));
}
Sekali lagi, UI aplikasi seharusnya tetap sama, tetapi sekarang Anda dapat mengizinkan pengguna login dan menyimpan status aplikasi.
Membuat alur login
Pada langkah ini, Anda akan mengerjakan alur login dan logout. Berikut tampilan alurnya:
- Pengguna yang logout akan memulai alur login dengan mengklik menu konteks
di sisi kanan panel aplikasi.
- Alur login akan ditampilkan dalam dialog.
- Jika pengguna belum pernah login sebelumnya, mereka akan diminta untuk membuat akun menggunakan alamat email dan sandi yang valid.
- Jika pengguna pernah login sebelumnya, mereka akan diminta untuk memasukkan sandi mereka.
- Setelah pengguna login, mengklik menu konteks akan menampilkan opsi Logout.
Menambahkan alur login memerlukan tiga langkah.
Pertama-tama, buat widget AppBarMenuButton
. Widget ini akan mengontrol pop-up menu konteks bergantung pada loginState
pengguna. Tambahkan impor
lib/src/widgets.dart
import 'application_state.dart';
import 'package:provider/provider.dart';
import 'authentication.dart';
Tambahkan kode berikut ke widgets.dart.
lib/src/widgets.dart
class AppBarMenuButton extends StatelessWidget {
const AppBarMenuButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<ApplicationState>(
builder: (context, appState, child) {
if (appState.loginState == ApplicationLoginState.loggedIn) {
return SignedInMenuButton(buildContext: context);
}
return SignInMenuButton(buildContext: context);
},
);
}
}
class SignedInMenuButton extends StatelessWidget {
const SignedInMenuButton({Key? key, required this.buildContext})
: super(key: key);
final BuildContext buildContext;
@override
Widget build(BuildContext context) {
return PopupMenuButton<String>(
onSelected: _handleSignedInMenu,
color: Colors.deepPurple.shade300,
itemBuilder: (context) => _getMenuItemBuilder(),
);
}
List<PopupMenuEntry<String>> _getMenuItemBuilder() {
return [
const PopupMenuItem<String>(
value: 'Sign out',
child: Text(
'Sign out',
style: TextStyle(color: Colors.white),
),
)
];
}
Future<void> _handleSignedInMenu(String value) async {
switch (value) {
case 'Sign out':
Provider.of<ApplicationState>(buildContext, listen: false).signOut();
break;
}
}
}
class SignInMenuButton extends StatelessWidget {
const SignInMenuButton({Key? key, required this.buildContext})
: super(key: key);
final BuildContext buildContext;
@override
Widget build(BuildContext context) {
return PopupMenuButton<String>(
onSelected: _signIn,
color: Colors.deepPurple.shade300,
itemBuilder: (context) => _getMenuItemBuilder(context),
);
}
Future<void> _signIn(String value) async {
return showDialog<void>(
context: buildContext,
builder: (context) => const SignInDialog(),
);
}
List<PopupMenuEntry<String>> _getMenuItemBuilder(BuildContext context) {
return [
const PopupMenuItem<String>(
value: 'Sign in',
child: Text(
'Sign in',
style: TextStyle(color: Colors.white),
),
),
];
}
}
Kedua, di class widgets.dart
yang sama, buat widget SignInDialog
.
lib/src/widgets.dart
class SignInDialog extends AlertDialog {
const SignInDialog({Key? key}) : super(key: key);
@override
AlertDialog build(BuildContext context) {
return AlertDialog(
content: Column(mainAxisSize: MainAxisSize.min, children: [
Consumer<ApplicationState>(
builder: (context, appState, _) => Authentication(
email: appState.email,
loginState: appState.loginState,
startLoginFlow: appState.startLoginFlow,
verifyEmail: appState.verifyEmail,
signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
cancelRegistration: appState.cancelRegistration,
registerAccount: appState.registerAccount,
signOut: appState.signOut,
),
),
]),
);
}
}
Ketiga, temukan widget appBar yang ada di main.dart.
Tambahkan AppBarMenuButton
untuk menampilkan opsi Login atau Logout.
lib/main.dart
import 'src/widgets.dart';
appBar: AppBar(
title: const Text('Music Box'),
backgroundColor: Colors.deepPurple.shade400,
actions: const <Widget>[
AppBarMenuButton(),
],
),
Jalankan perintah flutter run
untuk memulai ulang aplikasi dengan perubahan ini. Anda akan dapat melihat menu konteks di sisi kanan panel aplikasi. Mengkliknya akan mengarahkan Anda ke dialog login.
Setelah login dengan alamat email dan sandi yang valid, Anda akan dapat melihat opsi Logout di menu konteks.
Di Firebase console, di bagian Authentication, Anda akan dapat melihat alamat email yang tercantum sebagai pengguna baru.
Selamat! Pengguna kini dapat login ke aplikasi.
5. Menambahkan koneksi database
Sekarang Anda siap melanjutkan ke pendaftaran perangkat menggunakan Firebase Presence API.
Pada command line, jalankan perintah berikut untuk menambahkan dependensi yang diperlukan:
flutter pub add firebase_app_installations
flutter pub add firebase_database
Buat database
Di Firebase console,
- Buka bagian Realtime Database di Firebase console. Klik Create Database.
- Jika diminta untuk memilih mode awal untuk aturan keamanan Anda, pilih Test Mode untuk saat ini**.** (Mode Pengujian membuat Aturan Keamanan yang mengizinkan semua permintaan. Anda akan menambahkan Aturan Keamanan nanti. Penting untuk tidak pernah menggunakan aplikasi produksi dengan Aturan Keamanan Anda masih dalam Mode Pengujian.)
Database saat ini kosong. Temukan databaseURL
Anda di Project settings, di tab General. Scroll ke bawah ke bagian Aplikasi web.
Tambahkan databaseURL
Anda ke file firebase_options.dart
:
lib/firebase_options.dart
static const FirebaseOptions web = FirebaseOptions(
apiKey: yourApiKey,
...
databaseURL: 'https://<YOUR_DATABASE_URL>,
...
);
Mendaftarkan perangkat menggunakan RTDB Presence API
Anda ingin mendaftarkan perangkat pengguna saat perangkat tersebut muncul secara online. Untuk melakukannya, Anda akan memanfaatkan Firebase Installations dan Firebase RTDB Presence API untuk melacak daftar perangkat yang online dari satu pengguna. Kode berikut akan membantu mencapai tujuan ini:
lib/src/application_state.dart
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_app_installations/firebase_app_installations.dart';
class ApplicationState extends ChangeNotifier {
String? _deviceId;
String? _uid;
Future<void> init() async {
...
FirebaseAuth.instance.userChanges().listen((user) {
if (user != null) {
_loginState = ApplicationLoginState.loggedIn;
_uid = user.uid;
_addUserDevice();
}
...
});
}
Future<void> _addUserDevice() async {
_uid = FirebaseAuth.instance.currentUser?.uid;
String deviceType = _getDevicePlatform();
// Create two objects which we will write to the
// Realtime database when this device is offline or online
var isOfflineForDatabase = {
'type': deviceType,
'state': 'offline',
'last_changed': ServerValue.timestamp,
};
var isOnlineForDatabase = {
'type': deviceType,
'state': 'online',
'last_changed': ServerValue.timestamp,
};
var devicesRef =
FirebaseDatabase.instance.ref().child('/users/$_uid/devices');
FirebaseInstallations.instance
.getId()
.then((id) => _deviceId = id)
.then((_) {
// Use the semi-persistent Firebase Installation Id to key devices
var deviceStatusRef = devicesRef.child('$_deviceId');
// RTDB Presence API
FirebaseDatabase.instance
.ref()
.child('.info/connected')
.onValue
.listen((data) {
if (data.snapshot.value == false) {
return;
}
deviceStatusRef.onDisconnect().set(isOfflineForDatabase).then((_) {
deviceStatusRef.set(isOnlineForDatabase);
});
});
});
}
String _getDevicePlatform() {
if (kIsWeb) {
return 'Web';
} else if (Platform.isIOS) {
return 'iOS';
} else if (Platform.isAndroid) {
return 'Android';
}
return 'Unknown';
}
Kembali ke command line, build dan jalankan aplikasi di perangkat Anda atau di browser dengan flutter run.
Di aplikasi Anda, login sebagai pengguna. Jangan lupa untuk login sebagai pengguna yang sama di platform yang berbeda.
Di Firebase console, Anda akan melihat perangkat Anda muncul di bawah satu ID pengguna di database Anda.
6. Status sinkronisasi perangkat
Pilih perangkat utama
Untuk menyinkronkan status antar-perangkat, tetapkan satu perangkat sebagai pemimpin, atau pengontrol. Perangkat utama akan menentukan status di perangkat pengikut.
Buat metode setLeadDevice
di application_state.dart
, dan lacak perangkat ini dengan kunci active_device
di RTDB:
lib/src/application_state.dart
bool _isLeadDevice = false;
String? leadDeviceType;
Future<void> setLeadDevice() async {
if (_uid != null && _deviceId != null) {
var playerRef =
FirebaseDatabase.instance.ref().child('/users/$_uid/active_device');
await playerRef
.update({'id': _deviceId, 'type': _getDevicePlatform()}).then((_) {
_isLeadDevice = true;
});
}
}
Untuk menambahkan fungsi ini ke menu konteks panel aplikasi, buat PopupMenuItem
bernama Controller
dengan mengubah widget SignedInMenuButton
. Menu ini akan memungkinkan pengguna menyetel perangkat utama.
lib/src/widgets.dart
class SignedInMenuButton extends StatelessWidget {
const SignedInMenuButton({Key? key, required this.buildContext})
: super(key: key);
final BuildContext buildContext;
List<PopupMenuEntry<String>> _getMenuItemBuilder() {
return [
const PopupMenuItem<String>(
value: 'Sign out',
child: Text(
'Sign out',
style: TextStyle(color: Colors.white),
),
),
const PopupMenuItem<String>(
value: 'Controller',
child: Text(
'Set as controller',
style: TextStyle(color: Colors.white),
),
)
];
}
void _handleSignedInMenu(String value) async {
switch (value) {
...
case 'Controller':
Provider.of<ApplicationState>(buildContext, listen: false)
.setLeadDevice();
}
}
}
Menulis status perangkat utama ke database
Setelah menetapkan perangkat utama, Anda dapat menyinkronkan status perangkat utama ke RTDB dengan kode berikut. Tambahkan kode berikut di akhir application_state.dart.
Ini akan mulai menyimpan dua atribut: status pemutar (putar atau jeda) dan posisi penggeser.
lib/src/application_state.dart
Future<void> setLeadDeviceState(
int playerState, double sliderPosition) async {
if (_isLeadDevice && _uid != null && _deviceId != null) {
var leadDeviceStateRef =
FirebaseDatabase.instance.ref().child('/users/$_uid/active_device');
try {
var playerSnapshot = {
'id': _deviceId,
'state': playerState,
'type': _getDevicePlatform(),
'slider_position': sliderPosition
};
await leadDeviceStateRef.set(playerSnapshot);
} catch (e) {
throw Exception('updated playerState with error');
}
}
}
Terakhir, Anda perlu memanggil setActiveDeviceState
setiap kali status pemain pengontrol diperbarui. Buat perubahan berikut pada file player_widget.dart
yang ada:
lib/player_widget.dart
import 'package:provider/provider.dart';
import 'application_state.dart';
void _onSliderChangeHandler(v) {
...
// update player state in RTDB if device is active
Provider.of<ApplicationState>(context, listen: false)
.setLeadDeviceState(_playerState.index, _sliderPosition);
}
Future<int> _pause() async {
...
// update DB if device is active
Provider.of<ApplicationState>(context, listen: false)
.setLeadDeviceState(_playerState.index, _sliderPosition);
return result;
}
Future<int> _play() async {
var result = 0;
// update DB if device is active
Provider.of<ApplicationState>(context, listen: false)
.setLeadDeviceState(PlayerState.PLAYING.index, _sliderPosition);
if (_playerState == PlayerState.PAUSED) {
result = await _audioPlayer.resume();
return result;
}
...
}
Future<int> _updatePositionAndSlider(Duration tempPosition) async {
...
// update DB if device is active
Provider.of<ApplicationState>(context, listen: false)
.setLeadDeviceState(_playerState.index, _sliderPosition);
return result;
}
Membaca status perangkat utama dari database
Ada dua bagian untuk membaca dan menggunakan status perangkat utama. Pertama, Anda ingin menyiapkan pemroses database status pemutar utama di application_state
. Pemroses ini akan memberi tahu perangkat pengikut kapan harus memperbarui layar melalui callback. Perhatikan bahwa Anda telah menentukan antarmuka OnLeadDeviceChangeCallback
pada langkah ini. Antarmuka ini belum diterapkan; Anda akan menerapkan antarmuka ini di player_widget.dart
pada langkah berikutnya.
lib/src/application_state.dart
// Interface to be implemented by PlayerWidget
typedef OnLeadDeviceChangeCallback = void Function(
Map<dynamic, dynamic> snapshot);
class ApplicationState extends ChangeNotifier {
...
OnLeadDeviceChangeCallback? onLeadDeviceChangeCallback;
Future<void> init() async {
FirebaseAuth.instance.userChanges().listen((user) {
if (user != null) {
_loginState = ApplicationLoginState.loggedIn;
_uid = user.uid;
_addUserDevice().then((_) => listenToLeadDeviceChange());
}
...
});
}
Future<void> listenToLeadDeviceChange() async {
if (_uid != null) {
var activeDeviceRef =
FirebaseDatabase.instance.ref().child('/users/$_uid/active_device');
activeDeviceRef.onValue.listen((event) {
final activeDeviceState = event.snapshot.value as Map<dynamic, dynamic>;
String activeDeviceKey = activeDeviceState['id'] as String;
_isLeadDevice = _deviceId == activeDeviceKey;
leadDeviceType = activeDeviceState['type'] as String;
if (!_isLeadDevice) {
onLeadDeviceChangeCallback?.call(activeDeviceState);
}
notifyListeners();
});
}
}
Kedua, mulai pemroses database selama inisialisasi pemutar di player_widget.dart
. Teruskan fungsi _updatePlayer
sehingga status pemutar pengikut dapat diperbarui setiap kali nilai database berubah.
lib/player_widget.dart
class _PlayerWidgetState extends State<PlayerWidget> {
@override
void initState() {
...
Provider.of<ApplicationState>(context, listen: false)
.onLeadDeviceChangeCallback = updatePlayer;
}
void updatePlayer(Map<dynamic, dynamic> snapshot) {
_updatePlayer(snapshot['state'], snapshot['slider_position']);
}
void _updatePlayer(dynamic state, dynamic sliderPosition) {
if (state is int && sliderPosition is double) {
try {
_updateSlider(sliderPosition);
final PlayerState newState = PlayerState.values[state];
if (newState != _playerState) {
switch (newState) {
case PlayerState.PLAYING:
_play();
break;
case PlayerState.PAUSED:
_pause();
break;
case PlayerState.STOPPED:
case PlayerState.COMPLETED:
_stop();
break;
}
_playerState = newState;
}
} catch (e) {
if (kDebugMode) {
print('sync player failed');
}
}
}
}
Sekarang Anda siap menguji aplikasi:
- Di command line, jalankan aplikasi di emulator dan/atau di browser dengan:
flutter run -d <device-name>
- Buka aplikasi di browser, di simulator iOS, atau emulator Android. Buka menu konteks, pilih satu aplikasi untuk menjadi perangkat utama. Anda akan dapat melihat perubahan pemutar perangkat pengikut saat perangkat pemimpin diupdate.
- Sekarang, ubah perangkat utama, putar atau jeda musik, dan amati perangkat pengikut yang diperbarui dengan tepat.
Jika perangkat pengikut diupdate dengan benar, Anda telah berhasil membuat pengontrol lintas perangkat. Hanya ada satu langkah penting lagi.
7. Memperbarui Aturan Keamanan
Jika kita tidak menulis aturan keamanan yang lebih baik, seseorang dapat menulis status ke perangkat yang bukan miliknya. Jadi, sebelum Anda menyelesaikan, perbarui Aturan Keamanan Realtime Database untuk memastikan bahwa hanya pengguna yang login ke perangkat tersebut yang dapat membaca atau menulis ke perangkat. Di Firebase Console, buka Realtime Database, lalu buka tab Rules. Tempel aturan berikut yang hanya mengizinkan pengguna yang login untuk membaca dan menulis status perangkat mereka sendiri:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
},
}
}
8. Selamat!
Selamat, Anda telah berhasil membuat pengontrol jarak jauh lintas perangkat menggunakan Flutter.
Kredit
Better Together, sebuah Lagu Firebase
- Musik oleh Ryan Vernon
- Lirik dan sampul album oleh Marissa Christy
- Suara oleh JP Gomez
9. Bonus
Sebagai tantangan tambahan, pertimbangkan untuk menggunakan FutureBuilder
Flutter untuk menambahkan jenis perangkat utama saat ini ke UI secara asinkron. Jika Anda memerlukan bantuan, fitur ini diimplementasikan di folder yang berisi status akhir codelab.