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 membuat aplikasi seluler. Menyiapkan komunikasi lintas perangkat seperti mengontrol browser dari aplikasi ponsel, atau mengontrol apa yang diputar di TV dari ponsel, secara tradisional lebih kompleks daripada mem-build aplikasi seluler normal.
Realtime Database Firebase menyediakan Presence API yang memungkinkan pengguna melihat status perangkat mereka saat online/offline; Anda akan menggunakannya dengan Layanan Penginstalan Firebase untuk melacak dan menghubungkan semua perangkat yang digunakan pengguna yang sama untuk login. Anda akan menggunakan Flutter untuk membuat aplikasi dengan cepat untuk beberapa platform, lalu Anda akan mem-build 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 mem-build 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.
- Hubungkan perangkat jika pengguna yang sama login di beberapa perangkat.
- Memungkinkan pengguna mengontrol pemutaran musik di satu perangkat dari perangkat lain.
Hal yang akan Anda pelajari
- Cara membangun dan menjalankan aplikasi pemutar musik Flutter.
- Cara mengizinkan pengguna login dengan Firebase Auth.
- Cara menggunakan Firebase RTDB Presence API dan Layanan Penginstalan Firebase untuk menghubungkan perangkat.
Hal yang akan Anda perlukan
- Lingkungan pengembangan Flutter. Ikuti petunjuk dalam panduan penginstalan Flutter untuk menyiapkannya.
- Diperlukan versi Flutter minimum 2.10 atau yang lebih baru. 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 Anda 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 terbiasa 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 mandiri dasar. Pastikan fitur pemutar berfungsi sebagaimana mestinya. Ini adalah aplikasi pemutar musik sederhana yang dirancang untuk codelab ini. Aplikasi ini hanya dapat memutar lagu Firebase, Better Together.
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, dan ikuti petunjuk di Membuat dan mengelola perangkat virtual.
Untuk membuat simulator iOS, Anda memerlukan lingkungan Mac. Download XCode, dan ikuti petunjuk di Ringkasan Simulator > Gunakan Simulator > Membuka dan menutup simulator.
3. Menyiapkan Firebase
Buat project Firebase
Buka browser ke http://console.firebase.google.com/.
- Login ke Firebase.
- Di Firebase console, klik Add Project (atau Create a project), dan beri nama project Firebase Anda Firebase-Cross-Device-Codelab.
- Klik opsi pembuatan project. Setujui persyaratan Firebase jika diminta. Lewati penyiapan Google Analytics, karena Anda tidak akan menggunakan Analytics untuk aplikasi ini.
Anda tidak perlu mendownload file yang disebutkan atau mengubah file build.gradle. Anda akan mengonfigurasinya saat melakukan inisialisasi FlutterFire.
Menginstal 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 minimal 1.13.1, atau jalankan flutter upgrade
Melakukan inisialisasi 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
. - Konfigurasikan FlutterFire CLI dengan menjalankan
flutterfire configure
. - Pada 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 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 Anda untuk melakukan inisialisasi 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 API kehadiran untuk melacak status perangkat online/offline
- Aturan Keamanan Firebase akan memungkinkan Anda mengamankan database.
- Layanan Penginstalan Firebase untuk mengidentifikasi perangkat yang digunakan untuk login oleh satu pengguna.
4. Menambahkan Firebase Auth
Mengaktifkan login dengan email untuk Firebase Authentication
Untuk mengizinkan pengguna login ke aplikasi web, Anda akan menggunakan metode login Email/Sandi:
- Di Firebase console, luaskan menu Build di panel kiri.
- Klik Authentication, lalu klik tombol Mulai, lalu tab Metode login.
- Klik Email/Sandi di daftar Penyedia login, setel tombol Aktifkan ke posisi aktif, lalu klik Simpan.
Mengonfigurasi Firebase Authentication di Flutter
Pada 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 hal ini lebih lanjut di dokumentasi Pengelolaan status Flutter.
Tempel 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 adalah tampilan alur:
- Pengguna yang sudah 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 telah login sebelumnya, mereka akan diminta untuk memasukkan sandi.
- 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. Menambahkan 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 untuk 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 memilih mode awal untuk aturan keamanan Anda, pilih Test Mode untuk saat ini**.** (Mode Pengujian membuat Aturan Keamanan yang mengizinkan semua permintaan lewat. Anda akan menambahkan Aturan Keamanan nanti. Penting untuk tidak pernah melakukan produksi dengan Aturan Keamanan yang masih dalam Mode Pengujian.)
Untuk saat ini database kosong. Temukan databaseURL
Anda di Project settings, di bagian 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 online dari satu pengguna. Kode berikut akan membantu mencapai sasaran 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 atau di browser dengan flutter run.
Di aplikasi Anda, login sebagai pengguna. Jangan lupa login sebagai pengguna yang sama di platform yang berbeda.
Di Firebase console, Anda akan melihat perangkat muncul dengan satu ID pengguna di database.
6. Menyinkronkan status perangkat
Memilih perangkat prospek
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
yang disebut Controller
dengan mengubah widget SignedInMenuButton
. Menu ini akan memungkinkan pengguna menyetel perangkat prospek.
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 prospek ke database
Setelah menetapkan perangkat prospek, Anda dapat menyinkronkan status perangkat prospek 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 harus 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 prospek dari database
Ada dua bagian untuk membaca dan menggunakan status perangkat prospek. Pertama, Anda ingin menyiapkan pemroses database status pemain utama di application_state
. Pemroses ini akan memberi tahu perangkat pengikut kapan harus memperbarui layar melalui callback. Perhatikan bahwa Anda telah menentukan antarmuka OnLeadDeviceChangeCallback
di langkah ini. Hal ini belum diimplementasikan; 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
agar 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 untuk menguji aplikasi:
- Di command line, jalankan aplikasi di emulator dan/atau di browser dengan:
flutter run -d <device-name>
- Buka aplikasi di browser, pada simulator iOS, atau emulator Android. Buka menu konteks, pilih satu aplikasi untuk menjadi perangkat pemimpin. Anda akan dapat melihat perangkat pengikut pemain berubah saat perangkat pemimpin diperbarui.
- Sekarang ganti perangkat pemimpin, putar atau jeda musik, dan amati pembaruan perangkat pengikut yang sesuai.
Jika perangkat pengikut diupdate dengan benar, Anda telah berhasil membuat pengontrol lintas-perangkat. Hanya ada satu langkah penting lagi yang tersisa.
7. Memperbarui Aturan Keamanan
Kecuali jika kita menulis aturan keamanan yang lebih baik, seseorang dapat menulis status ke perangkat yang bukan miliknya. Jadi, sebelum Anda selesai, perbarui Aturan Keamanan Realtime Database untuk memastikan satu-satunya pengguna yang dapat membaca atau menulis ke perangkat adalah pengguna yang login ke perangkat tersebut. Di Firebase Console, buka Realtime Database, lalu tab Aturan. Tempelkan 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 membangun remote control 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. Bonus
Sebagai tantangan tambahan, pertimbangkan untuk menggunakan Flutter FutureBuilder
untuk menambahkan jenis perangkat prospek saat ini ke UI secara asinkron. Jika Anda memerlukan bantuan, bantuan tersebut akan diterapkan di folder yang berisi status selesai codelab.