1. Giriş
Son Güncelleme: 2022-03-14
Cihazlar arası iletişim için FlutterFire
Çok sayıda ev otomasyonu, giyilebilir ve kişisel sağlık teknolojisi cihazının çevrimiçi hale geldiğine tanık olduğumuz için, cihazlar arası iletişim, mobil uygulama geliştirmenin giderek daha önemli bir parçası haline geliyor. Bir tarayıcıyı telefon uygulamasından kontrol etmek veya TV'nizde oynatılanları telefonunuzdan kontrol etmek gibi cihazlar arası iletişimi kurmak, geleneksel olarak normal bir mobil uygulama oluşturmaktan daha karmaşıktır.
Firebase'in Gerçek Zamanlı Veritabanı, kullanıcıların cihazlarının çevrimiçi/çevrimdışı durumunu görmesine olanak tanıyan Presence API'sini sağlar; Aynı kullanıcının oturum açtığı tüm cihazları takip etmek ve bağlamak için bunu Firebase Kurulum Hizmeti ile birlikte kullanacaksınız. Flutter'ı, birden çok platform için hızlı bir şekilde uygulamalar oluşturmak için kullanacaksınız ve ardından, oynatılan cihazlar arası bir prototip oluşturacaksınız. bir cihazda müzik ve diğerinde müziği kontrol eder!
Ne inşa edeceksin
Bu codelab'de basit bir müzik çalar uzaktan kumandası oluşturacaksınız. Uygulamanız:
- Flutter ile oluşturulmuş, Android, iOS ve web üzerinde basit bir müzik çalara sahip olun.
- Kullanıcıların oturum açmasına izin verin.
- Aynı kullanıcı birden fazla cihazda oturum açtığında cihazları bağlayın.
- Kullanıcıların bir cihazdaki müzik çalma işlemini başka bir cihazdan kontrol etmesine izin verin.
Ne öğreneceksin
- Flutter müzik çalar uygulaması nasıl oluşturulur ve çalıştırılır.
- Kullanıcıların Firebase Auth ile oturum açmasına nasıl izin verilir?
- Cihazları bağlamak için Firebase RTDB Presence API ve Firebase Kurulum Hizmeti nasıl kullanılır?
İhtiyacınız olan şey
- Flutter geliştirme ortamı. Kurulumu yapmak için Flutter kurulum kılavuzundaki talimatları izleyin.
- Minimum Flutter 2.10 veya daha yüksek bir sürüm gereklidir. Daha düşük bir sürümünüz varsa
flutter upgrade.
- Bir Firebase hesabı.
2. Kurulum
Başlangıç kodunu alın
Flutter'da bir müzik çalar uygulaması oluşturduk. Başlangıç kodu Git deposunda bulunur. Başlamak için komut satırında repoyu kopyalayın, başlangıç durumunun bulunduğu klasöre taşıyın ve bağımlılıkları yükleyin:
git clone https://github.com/FirebaseExtended/cross-device-controller.git
cd cross-device-controller/starter_code
flutter pub get
Uygulamayı oluşturun
Uygulamayı oluşturmak için favori IDE'nizle çalışabilir veya komut satırını kullanabilirsiniz.
Uygulama dizininizde, flutter run -d web-server.
Aşağıdaki istemi görebilmeniz gerekir.
lib/main.dart is being served at http://localhost:<port>
Müzik çaları görmek için http://localhost:<port>
ziyaret edin.
Android emülatörüne veya iOS simülatörüne aşina iseniz, bu platformlar için uygulamayı oluşturabilir ve flutter run -d <device_name>
komutuyla yükleyebilirsiniz.
Web uygulaması temel bir bağımsız müzik çalar göstermelidir. Oynatıcı özelliklerinin amaçlandığı gibi çalıştığından emin olun. Bu codelab için tasarlanmış basit bir müzik çalar uygulamasıdır. Yalnızca bir Firebase şarkısı olan Better Together'ı çalabilir.
Bir Android emülatörü veya iOS simülatörü ayarlayın
Geliştirme için zaten bir Android cihazınız veya iOS cihazınız varsa bu adımı atlayabilirsiniz.
Bir Android emülatörü oluşturmak için Flutter geliştirmeyi de destekleyen Android Studio'yu indirin ve Sanal cihazlar oluşturma ve yönetme bölümündeki talimatları izleyin.
Bir iOS simülatörü oluşturmak için bir Mac ortamına ihtiyacınız olacak. XCode'u indirin ve Simülatöre Genel Bakış > Simülatörü Kullan > Simülatörü açma ve kapatma bölümündeki talimatları izleyin.
3. Firebase'i kurma
Firebase projesi oluşturma
http://console.firebase.google.com/ adresine bir tarayıcı açın.
- Firebase'de oturum açın.
- Firebase konsolunda Proje Ekle'ye (veya Proje oluştur'a ) tıklayın ve Firebase projenize Firebase-Cross-Device-Codelab adını verin.
- Proje oluşturma seçeneklerine tıklayın. İstenirse Firebase şartlarını kabul edin. Bu uygulama için Analytics kullanmayacağınız için Google Analytics kurulumunu atlayın.
Bahsedilen dosyaları indirmenize veya build.gradle dosyalarını değiştirmenize gerek yoktur. FlutterFire'ı başlattığınızda bunları yapılandıracaksınız.
Firebase SDK'yı yükleyin
Firebase'i yüklemek için komut satırına döndüğünüzde proje dizininde aşağıdaki komutu çalıştırın:
flutter pub add firebase_core
pubspec.yaml
dosyasında firebase_core
sürümünü en az 1.13.1 olacak şekilde düzenleyin veya flutter upgrade
çalıştırın
FlutterFire'ı başlat
- Firebase CLI yüklü değilse
curl -sL https://firebase.tools | bash
. -
firebase login
çalıştırarak ve talimatları izleyerek giriş yapın. -
dart pub global activate flutterfire_cli
çalıştırarak FlutterFire CLI'yi yükleyin. - FlutterFire CLI'yi
flutterfire configure
çalıştırarak yapılandırın. - İstendiğinde, bu codelab için yeni oluşturduğunuz, Firebase-Cross-Device-Codelab gibi bir projeyi seçin.
- Yapılandırma desteğini seçmeniz istendiğinde iOS , Android ve Web'i seçin.
- Apple paket kimliği istendiğinde benzersiz bir alan adı yazın veya
com.example.appname
değerini girin; bu, bu codelab'in amacı açısından uygundur.
Yapılandırıldıktan sonra, başlatma için gerekli tüm seçenekleri içeren bir firebase_options.dart
dosyası sizin için oluşturulacaktır.
Flutter ve Firebase'i başlatmak için editörünüzde main.dart dosyanıza aşağıdaki kodu ekleyin:
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());
}
Uygulamayı şu komutla derleyin:
flutter run
Henüz hiçbir kullanıcı arayüzü öğesini değiştirmediğiniz için uygulamanın görünümü ve davranışı değişmedi. Ancak artık bir Firebase uygulamanız var ve aşağıdakiler de dahil olmak üzere Firebase ürünlerini kullanmaya başlayabilirsiniz:
- Kullanıcılarınızın uygulamanızda oturum açmasına olanak tanıyan Firebase Kimlik Doğrulaması .
- Firebase Gerçek Zamanlı Veritabanı(RTDB) ; cihazın çevrimiçi/çevrimdışı durumunu izlemek için iletişim durumu API'sini kullanacaksınız
- Firebase Güvenlik Kuralları veritabanının güvenliğini sağlamanıza olanak tanır.
- Tek bir kullanıcının oturum açtığı cihazları tanımlamak için Firebase Kurulum Hizmeti .
4. Firebase Kimlik Doğrulaması Ekleyin
Firebase Authentication için e-postayla oturum açmayı etkinleştir
Kullanıcıların web uygulamasında oturum açmasına izin vermek için E-posta/Parola oturum açma yöntemini kullanacaksınız:
- Firebase konsolunda sol paneldeki Oluştur menüsünü genişletin.
- Kimlik Doğrulama öğesine tıklayın ve ardından Başlayın düğmesine ve ardından Oturum açma yöntemi sekmesine tıklayın.
- Oturum açma sağlayıcıları listesinde E-posta/Parola'ya tıklayın, Etkinleştir anahtarını açık konuma getirin ve ardından Kaydet'e tıklayın.
Flutter'da Firebase Kimlik Doğrulamasını Yapılandırma
Gerekli flutter paketlerini yüklemek için komut satırında aşağıdaki komutları çalıştırın:
flutter pub add firebase_auth
flutter pub add provider
Bu yapılandırmayla artık oturum açma ve oturum kapatma akışını oluşturabilirsiniz. Kimlik doğrulama durumunun ekrandan ekrana değişmemesi gerektiğinden, oturum açma ve oturum kapatma gibi uygulama düzeyindeki durum değişikliklerini takip etmek için bir application_state.dart
sınıfı oluşturacaksınız. Bu konuda daha fazla bilgiyi Flutter durum yönetimi belgelerinde bulabilirsiniz.
Aşağıdakini yeni application_state.dart
dosyasına yapıştırın:
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();
}
}
Uygulama başlatıldığında ApplicationState
başlatılacağından emin olmak için main.dart
bir başlatma adımı ekleyeceksiniz:
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(),
));
}
Uygulama kullanıcı arayüzünün aynı kalması gerekirdi ancak artık kullanıcıların oturum açmasına ve uygulama durumlarını kaydetmesine izin verebilirsiniz.
Oturum açma akışı oluşturma
Bu adımda oturum açma ve oturum kapatma akışı üzerinde çalışacaksınız. Akış şu şekilde görünecek:
- Oturumu kapatmış bir kullanıcı, içerik menüsüne tıklayarak oturum açma akışını başlatacaktır. Uygulama çubuğunun sağ tarafında.
- Oturum açma akışı bir iletişim kutusunda görüntülenecektir.
- Kullanıcı daha önce hiç oturum açmadıysa geçerli bir e-posta adresi ve parola kullanarak bir hesap oluşturması istenecektir.
- Kullanıcı daha önce oturum açtıysa şifresini girmesi istenecektir.
- Kullanıcı oturum açtıktan sonra içerik menüsüne tıklandığında Oturumu Kapat seçeneği gösterilir.
Oturum açma akışının eklenmesi üç adım gerektirir.
Öncelikle bir AppBarMenuButton
widget'ı oluşturun. Bu widget, kullanıcının loginState
bağlı olarak içerik menüsü açılır penceresini kontrol edecektir. İçe aktarmaları ekleyin
lib/src/widgets.dart
import 'application_state.dart';
import 'package:provider/provider.dart';
import 'authentication.dart';
Aşağıdaki kodu 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),
),
),
];
}
}
İkinci olarak, aynı widgets.dart
sınıfında SignInDialog
widget'ını oluşturun.
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,
),
),
]),
);
}
}
Üçüncü olarak, main.dart.
Oturum aç veya Oturumu kapat seçeneğini görüntülemek için AppBarMenuButton
ekleyin.
lib/main.dart
import 'src/widgets.dart';
appBar: AppBar(
title: const Text('Music Box'),
backgroundColor: Colors.deepPurple.shade400,
actions: const <Widget>[
AppBarMenuButton(),
],
),
Uygulamayı bu değişikliklerle yeniden başlatmak için flutter run
komutunu çalıştırın. İçerik menüsünü görebilmelisiniz Uygulama çubuğunun sağ tarafında. Üzerine tıkladığınızda oturum açma iletişim kutusuna yönlendirilirsiniz.
Geçerli bir e-posta adresi ve şifreyle oturum açtıktan sonra içerik menüsünde Oturumu kapat seçeneğini görebilmeniz gerekir.
Firebase konsolunda Kimlik Doğrulama altında, e-posta adresinin yeni kullanıcı olarak listelendiğini görebilmeniz gerekir.
Tebrikler! Kullanıcılar artık uygulamada oturum açabilir!
5. Veritabanı bağlantısı ekleyin
Artık Firebase Presence API'yi kullanarak cihaz kaydına geçmeye hazırsınız.
Gerekli bağımlılıkları eklemek için komut satırında aşağıdaki komutları çalıştırın:
flutter pub add firebase_app_installations
flutter pub add firebase_database
Veritabanı oluştur
Firebase konsolunda,
- Firebase konsolunun Gerçek Zamanlı Veritabanı bölümüne gidin. Veritabanı Oluştur'u tıklayın.
- Güvenlik kurallarınız için bir başlangıç modu seçmeniz istenirse şimdilik Test Modu'nu seçin**.** (Test Modu, tüm isteklerin geçmesine izin veren Güvenlik Kuralları oluşturur. Güvenlik Kurallarını daha sonra ekleyeceksiniz. Hiçbir zaman üretime geçmemeniz önemlidir. Güvenlik Kurallarınız hâlâ Test Modundadır.)
Veritabanı şimdilik boş. databaseURL
URL'nizi Genel sekmesi altındaki Proje ayarlarında bulun. Web uygulamaları bölümüne ilerleyin.
databaseURL
firebase_options.dart
dosyasına ekleyin :
lib/firebase_options.dart
static const FirebaseOptions web = FirebaseOptions(
apiKey: yourApiKey,
...
databaseURL: 'https://<YOUR_DATABASE_URL>,
...
);
RTDB Presence API'yi kullanarak cihazları kaydedin
Bir kullanıcının cihazlarını çevrimiçi göründüklerinde kaydetmek istiyorsunuz. Bunu yapmak için, tek bir kullanıcının çevrimiçi cihazlarının listesini takip etmek amacıyla Firebase Kurulumlarından ve Firebase RTDB Presence API'sinden yararlanacaksınız. Aşağıdaki kod bu hedefe ulaşmanıza yardımcı olacaktır:
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';
}
Komut satırına geri döndüğünüzde, uygulamayı cihazınızda veya flutter run.
Uygulamanızda kullanıcı olarak oturum açın. Farklı platformlarda aynı kullanıcı olarak oturum açmayı unutmayın.
Firebase konsolunda , cihazlarınızın veritabanınızda tek bir kullanıcı kimliği altında göründüğünü görmelisiniz.
6. Cihaz durumunu senkronize edin
Bir öncü cihaz seçin
Durumları cihazlar arasında senkronize etmek için bir cihazı lider veya denetleyici olarak atayın. Lider cihaz, takipçi cihazlardaki durumları belirleyecektir.
application_state.dart
dosyasında bir setLeadDevice
yöntemi oluşturun ve bu cihazı RTDB'de active_device
anahtarıyla izleyin:
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;
});
}
}
Bu işlevselliği uygulama çubuğu içerik menüsüne eklemek için SignedInMenuButton
widget'ını değiştirerek Controller
adında bir PopupMenuItem
oluşturun. Bu menü kullanıcıların öncü cihazı ayarlamasına olanak tanır.
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();
}
}
}
Lider cihazın durumunu veritabanına yazın
Bir öncü cihazı ayarladıktan sonra, aşağıdaki kodla öncü cihazın durumlarını RTDB ile senkronize edebilirsiniz. Aşağıdaki kodu application_state.dart.
Bu, iki özelliği kaydetmeye başlayacaktır: oynatıcı durumu (oynatma veya duraklatma) ve kaydırıcı konumu.
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');
}
}
}
Ve son olarak, kontrol cihazının oynatıcı durumu güncellendiğinde setActiveDeviceState
çağırmanız gerekir. Mevcut player_widget.dart
dosyasında aşağıdaki değişiklikleri yapın:
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;
}
Lider cihazın durumunu veritabanından okuyun
Lead cihazının durumunu okumak ve kullanmak için iki bölüm vardır. İlk olarak, application_state
içinde baş oynatıcı durumunun bir veritabanı dinleyicisini ayarlamak istiyorsunuz. Bu dinleyici, takipçi cihazlara ekranın ne zaman güncelleneceğini bir geri arama yoluyla söyleyecektir. Bu adımda OnLeadDeviceChangeCallback
arayüzünü tanımladığınıza dikkat edin. Henüz uygulanmadı; bir sonraki adımda bu arayüzü player_widget.dart
uygulayacaksınız.
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();
});
}
}
İkinci olarak, oynatıcının başlatılması sırasında player_widget.dart
dosyasında veritabanı dinleyicisini başlatın. Veritabanı değeri değiştiğinde takipçi oynatıcı durumunun güncellenebilmesi için _updatePlayer
işlevini iletin.
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');
}
}
}
}
Artık uygulamayı test etmeye hazırsınız:
- Komut satırında uygulamayı emülatörlerde ve/veya bir tarayıcıda şunu çalıştırın:
flutter run -d <device-name>
- Uygulamaları bir tarayıcıda, bir iOS simülatöründe veya bir Android emülatöründe açın. Bağlam menüsüne gidin, lider cihaz olacak bir uygulamayı seçin. Lider cihaz güncellendikçe takipçi cihazların oynatıcılarının değiştiğini görebilmeniz gerekir.
- Şimdi lider cihazı değiştirin, müziği çalın veya duraklatın ve takipçi cihazların buna göre güncellendiğini gözlemleyin.
Takipçi cihazları düzgün bir şekilde güncellenirse, cihazlar arası denetleyici yapmayı başardınız. Geriye sadece çok önemli bir adım kaldı.
7. Güvenlik Kurallarını Güncelleyin
Daha iyi güvenlik kuralları yazmadığımız sürece birisi, sahibi olmadığı bir cihaza durum yazabilir! Bu nedenle, bitirmeden önce, bir cihazda okuma veya yazma yapabilen kullanıcıların yalnızca o cihazda oturum açan kullanıcı olduğundan emin olmak için Gerçek Zamanlı Veritabanı Güvenliği Kurallarını güncelleyin. Firebase Konsolunda Gerçek Zamanlı Veritabanına ve ardından Kurallar sekmesine gidin. Yalnızca oturum açmış kullanıcının kendi cihaz durumlarını okumasına ve yazmasına izin veren aşağıdaki kuralları yapıştırın:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
},
}
}
8. Tebrikler!
Tebrikler, Flutter'ı kullanarak başarılı bir şekilde cihazlar arası uzaktan kumanda oluşturdunuz!
Kredi
Birlikte Daha İyi, bir Firebase Şarkısı
- Müzik Ryan Vernon'a ait
- Şarkı sözleri ve albüm kapağı - Marissa Christy
- JP Gomez'in sesi
9.Bonus
Ek bir zorluk olarak, mevcut lider cihaz türünü kullanıcı arayüzüne eşzamansız olarak eklemek için Flutter FutureBuilder
kullanmayı düşünün. Yardıma ihtiyacınız varsa codelab'in tamamlanmış durumunu içeren klasöre uygulanır.