1. Perkenalan
Terakhir Diperbarui: 14-03-2022
FlutterFire untuk komunikasi lintas perangkat
Saat kita menyaksikan sejumlah besar perangkat otomatisasi rumah, perangkat wearable, dan teknologi kesehatan pribadi mulai online, komunikasi lintas perangkat menjadi bagian yang semakin penting dalam membangun aplikasi seluler. Menyiapkan komunikasi lintas perangkat seperti mengontrol browser dari aplikasi ponsel, atau mengontrol apa yang diputar di TV dari ponsel, biasanya lebih rumit dibandingkan membuat aplikasi seluler biasa.
Realtime Database Firebase menyediakan API Kehadiran yang memungkinkan pengguna melihat status online/offline perangkat mereka; Anda akan menggunakannya dengan Layanan Instalasi Firebase untuk melacak dan menghubungkan semua perangkat tempat pengguna yang sama telah masuk. Anda akan menggunakan Flutter untuk membuat aplikasi dengan cepat untuk berbagai platform, lalu Anda akan membuat prototipe lintas perangkat yang dapat diputar musik di satu perangkat dan mengontrol musik di perangkat lain!
Apa yang akan Anda bangun
Dalam codelab ini, Anda akan membuat pengontrol jarak jauh pemutar musik sederhana. Aplikasi Anda akan:
- Miliki pemutar musik sederhana di Android, iOS, dan web, yang dibuat dengan Flutter.
- Izinkan pengguna untuk masuk.
- Hubungkan perangkat saat pengguna yang sama masuk di beberapa perangkat.
- Izinkan pengguna mengontrol pemutaran musik di satu perangkat dari perangkat lain.
Apa yang akan Anda pelajari
- Cara membuat dan menjalankan aplikasi pemutar musik Flutter.
- Cara mengizinkan pengguna masuk dengan Firebase Auth.
- Cara menggunakan Firebase RTDB Presence API dan Layanan Instalasi Firebase untuk menghubungkan perangkat.
Apa yang Anda perlukan
- Lingkungan pengembangan Flutter. Ikuti instruksi dalam panduan instalasi Flutter untuk menyiapkannya.
- Diperlukan versi Flutter minimum 2.10 atau lebih tinggi. Jika Anda memiliki versi yang lebih rendah, jalankan
flutter upgrade.
- Akun Firebase.
2. Persiapan
Dapatkan kode awal
Kami telah membuat aplikasi pemutar musik di Flutter. Kode awal terletak di repo Git. Untuk memulai, pada baris perintah, kloning repo, pindahkan 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
Bangun aplikasinya
Anda dapat menggunakan IDE favorit Anda untuk membangun aplikasi, atau menggunakan baris perintah.
Di direktori aplikasi Anda, buat aplikasi untuk web dengan perintah flutter run -d web-server.
Anda seharusnya dapat melihat prompt berikut.
lib/main.dart is being served at http://localhost:<port>
Kunjungi http://localhost:<port>
untuk melihat pemutar musik.
Jika Anda familiar dengan emulator Android atau simulator iOS, Anda dapat membuat aplikasi untuk platform tersebut dan menginstalnya dengan perintah flutter run -d <device_name>
.
Aplikasi web harus menampilkan pemutar musik dasar yang berdiri sendiri. Pastikan fitur pemutar berfungsi sebagaimana mestinya. Ini adalah aplikasi pemutar musik sederhana yang dirancang untuk codelab ini. Ia hanya dapat memutar lagu Firebase, Better Together .
Siapkan emulator Android atau simulator iOS
Jika Anda sudah memiliki perangkat Android atau perangkat iOS untuk pengembangan, Anda dapat melewati langkah ini.
Untuk membuat emulator Android, unduh Android Studio yang juga mendukung pengembangan Flutter, dan ikuti petunjuk di Membuat dan mengelola perangkat virtual .
Untuk membuat simulator iOS, Anda memerlukan lingkungan Mac. Unduh XCode , dan ikuti petunjuk di Ikhtisar Simulator > Gunakan Simulator > Buka dan tutup simulator .
3. Menyiapkan Firebase
Buat proyek Firebase
Buka browser ke http://console.firebase.google.com/ .
- Masuk ke Firebase .
- Di Firebase console, klik Tambahkan Proyek (atau Buat proyek ), dan beri nama proyek Firebase Anda Firebase-Cross-Device-Codelab .
- Klik opsi pembuatan proyek. Terima persyaratan Firebase jika diminta. Lewati penyiapan Google Analytics, karena Anda tidak akan menggunakan Analytics untuk aplikasi ini.
Anda tidak perlu mengunduh file yang disebutkan atau mengubah file build.gradle. Anda akan mengonfigurasinya saat menginisialisasi FlutterFire.
Instal Firebase SDK
Kembali ke baris perintah, di direktori proyek, jalankan perintah berikut untuk menginstal Firebase:
flutter pub add firebase_core
Di file pubspec.yaml
, edit versi firebase_core
menjadi setidaknya 1.13.1, atau jalankan flutter upgrade
Inisialisasi FlutterFire
- Jika Anda belum menginstal Firebase CLI, Anda dapat menginstalnya dengan menjalankan
curl -sL https://firebase.tools | bash
. - Masuk dengan menjalankan
firebase login
dan ikuti petunjuknya. - Instal FlutterFire CLI dengan menjalankan
dart pub global activate flutterfire_cli
. - Konfigurasikan FlutterFire CLI dengan menjalankan
flutterfire configure
. - Saat diminta, pilih proyek yang baru saja Anda buat untuk codelab ini, seperti Firebase-Cross-Device-Codelab .
- Pilih iOS , Android dan Web ketika Anda diminta untuk memilih dukungan konfigurasi.
- Saat diminta memasukkan ID paket Apple , ketik domain unik, atau masukkan
com.example.appname
, yang sesuai 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 Anda 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 tidak berubah. Namun kini Anda telah memiliki aplikasi Firebase, dan dapat mulai menggunakan produk Firebase, antara lain:
- Firebase Authentication , yang memungkinkan pengguna masuk ke aplikasi Anda.
- Basis Data Waktu Nyata Firebase (RTDB) ; Anda akan menggunakan API kehadiran untuk melacak status online/offline perangkat
- Aturan Keamanan Firebase akan memungkinkan Anda mengamankan database.
- Layanan Penginstalan Firebase untuk mengidentifikasi perangkat yang telah digunakan oleh satu pengguna.
4. Tambahkan Firebase Auth
Aktifkan login email untuk Firebase Authentication
Untuk mengizinkan pengguna masuk ke aplikasi web, Anda akan menggunakan metode masuk Email/Kata Sandi :
- Di Firebase console, perluas menu Build di panel kiri.
- Klik Autentikasi , lalu klik tombol Memulai , lalu tab Metode masuk .
- Klik Email/Kata Sandi di daftar Penyedia masuk , atur tombol Aktifkan ke posisi aktif, lalu klik Simpan .
Konfigurasikan Firebase Authentication di Flutter
Pada baris perintah, 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 masuk dan keluar. Karena status autentikasi tidak boleh berubah dari layar ke layar, Anda akan membuat kelas application_state.dart
untuk melacak perubahan status tingkat aplikasi, seperti masuk dan keluar. Pelajari lebih lanjut tentang hal ini di dokumentasi pengelolaan status Flutter .
Rekatkan yang berikut ini ke file application_state.dart
yang 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, namun sekarang Anda dapat mengizinkan pengguna masuk dan menyimpan status aplikasi.
Buat alur masuk
Pada langkah ini, Anda akan mengerjakan alur masuk dan keluar. Berikut tampilan alurnya:
- Pengguna yang keluar akan memulai alur masuk dengan mengklik menu konteks di sisi kanan bilah aplikasi.
- Alur masuk akan ditampilkan dalam dialog.
- Jika pengguna belum pernah masuk sebelumnya, mereka akan diminta untuk membuat akun menggunakan alamat email dan kata sandi yang valid.
- Jika pengguna telah masuk sebelumnya, mereka akan diminta memasukkan kata sandi.
- Setelah pengguna masuk, mengklik menu konteks akan menampilkan opsi Keluar .
Menambahkan alur masuk memerlukan tiga langkah.
Pertama-tama, buat widget AppBarMenuButton
. Widget ini akan mengontrol popup menu konteks tergantung 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 kelas 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 Masuk atau Keluar .
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 seharusnya dapat melihat menu konteks di sisi kanan bilah aplikasi. Mengkliknya akan membawa Anda ke dialog masuk.
Setelah Anda masuk dengan alamat email dan kata sandi yang valid, Anda akan melihat opsi Keluar di menu konteks.
Di Firebase console, pada Authentication , Anda seharusnya dapat melihat alamat email yang terdaftar sebagai pengguna baru.
Selamat! Pengguna sekarang dapat masuk ke aplikasi!
5. Tambahkan koneksi database
Sekarang Anda siap untuk melanjutkan ke pendaftaran perangkat menggunakan Firebase Presence API.
Pada baris perintah, jalankan perintah berikut untuk menambahkan dependensi yang diperlukan:
flutter pub add firebase_app_installations
flutter pub add firebase_database
Buat basis data
Di konsol Firebase,
- Navigasikan ke bagian Realtime Database di Firebase console . Klik Buat Basis Data .
- Jika diminta untuk memilih mode awal untuk aturan keamanan Anda, pilih Mode Uji untuk saat ini**.** (Mode Uji membuat Aturan Keamanan yang mengizinkan semua permintaan lewat. Anda akan menambahkan Aturan Keamanan nanti. Penting untuk tidak pernah masuk ke produksi dengan Aturan Keamanan Anda masih dalam Mode Uji.)
Basis datanya kosong untuk saat ini. Temukan databaseURL
Anda di Pengaturan proyek , di bawah tab Umum . Gulir 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>,
...
);
Daftarkan perangkat menggunakan RTDB Presence API
Anda ingin mendaftarkan perangkat pengguna saat perangkat tersebut muncul online. Untuk melakukannya, Anda akan memanfaatkan Instalasi Firebase dan Firebase RTDB Presence API untuk melacak daftar perangkat 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 baris perintah, buat dan jalankan aplikasi di perangkat Anda atau di browser dengan flutter run.
Di aplikasi Anda, masuk sebagai pengguna. Ingatlah untuk masuk sebagai pengguna yang sama pada platform yang berbeda.
Di Firebase console , Anda akan melihat perangkat Anda muncul dengan satu ID pengguna di database Anda.
6. Sinkronkan status perangkat
Pilih perangkat utama
Untuk menyinkronkan status antar perangkat, tetapkan satu perangkat sebagai pemimpin, atau pengontrol. Perangkat utama akan menentukan status pada 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 fungsionalitas ini ke menu konteks bilah aplikasi, buat PopupMenuItem
bernama Controller
dengan memodifikasi widget SignedInMenuButton
. Menu ini memungkinkan pengguna untuk mengatur 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();
}
}
}
Tulis status perangkat utama ke database
Setelah Anda menetapkan perangkat utama, Anda dapat menyinkronkan status perangkat utama ke RTDB dengan kode berikut. Tambahkan kode berikut ke 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');
}
}
}
Dan terakhir, Anda perlu memanggil setActiveDeviceState
setiap kali status pemutar 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;
}
Baca status perangkat utama dari database
Ada dua bagian untuk membaca dan menggunakan status perangkat utama. Pertama, Anda ingin menyiapkan pendengar database status pemain utama di application_state
. Pendengar ini akan memberi tahu perangkat pengikut kapan harus memperbarui layar melalui panggilan balik. Perhatikan Anda telah mendefinisikan antarmuka OnLeadDeviceChangeCallback
pada langkah ini. Hal ini belum dilaksanakan; Anda akan mengimplementasikan 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 pendengar basis data selama inisialisasi pemutar di player_widget.dart
. Lewati fungsi _updatePlayer
sehingga status pemain 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:
- Pada baris perintah, 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 pemimpin. Anda akan dapat melihat pemain di perangkat pengikut berubah seiring pembaruan perangkat pemimpin.
- Sekarang ubah perangkat pemimpin, putar atau jeda musik, dan amati pembaruan perangkat pengikut.
Jika perangkat pengikut diperbarui dengan benar, Anda telah berhasil membuat pengontrol lintas perangkat. Tinggal satu langkah penting lagi.
7. Perbarui Aturan Keamanan
Kecuali kita menulis aturan keamanan yang lebih baik, seseorang dapat menulis status ke perangkat yang bukan miliknya! Jadi sebelum Anda menyelesaikannya, perbarui Aturan Keamanan Realtime Database untuk memastikan satu-satunya pengguna yang dapat membaca atau menulis ke perangkat adalah pengguna yang masuk ke perangkat tersebut. Di Firebase Console, navigasikan ke Realtime Database, lalu ke tab Rules . Tempelkan aturan berikut yang hanya mengizinkan pengguna yang masuk 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 remote kontrol lintas perangkat menggunakan Flutter!
Kredit
Better Together, Lagu Firebase
- Musik oleh Ryan Vernon
- Lirik dan sampul album oleh Marissa Christy
- Suara oleh JP Gomez
9. Bonusnya
Sebagai tantangan tambahan, pertimbangkan untuk menggunakan Flutter FutureBuilder
untuk menambahkan jenis perangkat utama saat ini ke UI secara asinkron. Jika Anda memerlukan bantuan, bantuan ini diterapkan di folder yang berisi status codelab yang telah selesai.