1. Giriş
Son Güncelleme: 14.03.2022
Cihazlar arası iletişim için FlutterFire
Ev otomasyonu, giyilebilir ve kişisel sağlık teknolojisi cihazlarının çok sayıda online hale gelmesine şahit olduğumuz için cihazlar arası iletişim, mobil uygulama geliştirmenin giderek daha önemli bir parçası haline geliyor. Cihazlar arası iletişimin kurulumu, normal bir mobil uygulama oluşturmaktan geleneksel olarak daha karmaşıktır. Bu işlem, geleneksel olarak daha karmaşık bir süreçtir. Bu işlem, geleneksel olarak daha karmaşık bir süreçtir.
Firebase'in Realtime Database'i, kullanıcıların cihazlarının online/çevrimdışı durumunu görmelerine olanak tanıyan Presence API 'yi sunar. aynı kullanıcının oturum açtığı tüm cihazları izlemek ve bağlamak için bu uygulamayı Firebase Yüklemeler Hizmeti ile birlikte kullanırsınız. Farklı platformlara yönelik uygulamaları hızlıca oluşturmak için Flutter'ı kullanacaksınız. Ardından bir cihazda müzik çalan, diğer cihazda müziği kontrol eden cihazlar arası bir prototip oluşturacaksınız.
Oluşturacaklarınız
Bu codelab'de basit bir müzik çaların uzaktan kumandası geliştireceksiniz. Uygulamanız şunları yapabilecek:
- Android, iOS ve web'de Flutter ile geliştirilmiş 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ğlayabilirsiniz.
- Kullanıcıların bir cihazda başka bir cihazdaki müzik çalmayı kontrol etmesine izin verin.
Neler öğreneceksiniz?
- Flutter müzik çalar uygulaması nasıl geliştirilir ve çalıştırılır?
- Kullanıcıların Firebase Auth ile oturum açmasına izin verme
- Cihazları bağlamak için Firebase RTDB Presence API ve Firebase Kurulum Hizmeti'ni kullanma.
Gerekenler
- Flutter geliştirme ortamı. Uzantıyı ayarlamak için Flutter yükleme kılavuzundaki talimatları uygulayın.
- En az Flutter 2.10 veya sonraki sürümleri gerekir. Daha düşük bir sürüme sahipseniz
flutter upgrade.
komutunu çalıştırın. - Firebase hesabı.
2. Kurulum
Başlangıç kodunu al
Flutter'da bir müzik çalar uygulaması oluşturduk. Başlangıç kodu bir Git deposunda bulunur. Başlamak için komut satırında depoyu klonlayı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şturma
Uygulamayı derlemek için favori IDE'nizle çalışabilir veya komut satırını kullanabilirsiniz.
Uygulama dizininizde şu komutu kullanarak uygulamayı web için oluşturun: flutter run -d web-server.
Aşağıdaki istemi göreceksiniz.
lib/main.dart is being served at http://localhost:<port>
Müzik çaları görmek için http://localhost:<port>
adresini ziyaret edin.
Android emülatörü veya iOS simülatörü hakkında bilginiz varsa bu platformlar için uygulama geliştirip flutter run -d <device_name>
komutuyla yükleyebilirsiniz.
Web uygulaması temel bir bağımsız müzik çalar göstermelidir. Oynatıcı özelliklerinin beklendiği gibi çalıştığından emin olun. Bu, codelab için tasarlanmış basit bir müzik çalma uygulamasıdır. Yalnızca Better Together adlı bir Firebase şarkısı çalınabilir.
Android emülatörü veya iOS simülatörü kurma
Geliştirme için zaten bir Android veya iOS cihazınız varsa bu adımı atlayabilirsiniz.
Android emülatörü oluşturmak için Flutter ile geliştirmeyi de destekleyen Android Studio'yu indirin ve Sanal cihazları oluşturma ve yönetme başlıklı makaledeki talimatları uygulayın.
iOS simülatörü oluşturmak için Mac ortamına ihtiyacınız vardır. XCode'u indirin ve Simulator Overview (Simülatöre Genel Bakış) bölümündeki talimatları uygulayın > Simülatörü Kullan > Bir simülasyon aracını açıp kapatın.
3. Firebase'i ayarlama
Firebase projesi oluşturma
Bir tarayıcı açarak http://console.firebase.google.com/ adresine gidin.
- Firebase'de oturum açın.
- Firebase konsolunda Proje Ekle'yi (veya Proje oluştur'u) tıklayın ve Firebase projenizi Firebase-Cross-Device-Codelab olarak adlandırın.
- Proje oluşturma seçeneklerini tıklayarak ilerleyin. İstenirse Firebase şartlarını kabul edin. Bu uygulama için Analytics'i kullanmayacağınızdan Google Analytics kurulumunu atlayın.
Belirtilen dosyaları indirmeniz veya build.gradle dosyalarını değiştirmeniz gerekmez. FlutterFire'ı başlattığınızda bunları yapılandıracaksınız.
Firebase SDK'sını yükleme
Firebase'i yüklemek için komut satırına dönüp 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
komutunu çalıştırın
FlutterFire'ı başlatma
- Firebase CLI'ı yüklemediyseniz
curl -sL https://firebase.tools | bash
komutunu çalıştırarak yükleyebilirsiniz. firebase login
komutunu çalıştırıp talimatları uygulayarak giriş yapın.dart pub global activate flutterfire_cli
komutunu çalıştırarak FlutterFire KSA'yı yükleyin.flutterfire configure
komutunu çalıştırarak FlutterFire KSA'yı yapılandırın.- Komut isteminde, bu codelab için oluşturduğunuz projeyi (ör. Firebase-Cihazlar-Codelab) 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 kod bu codelab'in amacına uygun değildir.
Yapılandırıldığında sizin için başlatma için gereken tüm seçenekleri içeren bir firebase_options.dart
dosyası oluşturulur.
Flutter ve Firebase'i başlatmak için düzenleyicinizde 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ğıdaki Firebase ürünlerini kullanmaya başlayabilirsiniz:
- Firebase Kimlik Doğrulaması, kullanıcılarınızın uygulamanızda oturum açmasına olanak tanır.
- Firebase Realtime Database(RTDB); Cihazın çevrimiçi/çevrimdışı durumunu izlemek için varlık API'sini kullanmanız gerekir.
- Firebase Güvenlik Kuralları, veritabanının güvenliğini sağlamanıza olanak tanır.
- Firebase Kurulum Hizmeti, tek bir kullanıcının oturum açtığı cihazları tanımlar.
4. Firebase Auth Ekle
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/Şifre oturum açma yöntemini kullanırsınız:
- Firebase konsolunda sol paneldeki Derleme menüsünü genişletin.
- Kimlik Doğrulama'yı tıklayın, ardından Başlayın düğmesini ve ardından Oturum açma yöntemi sekmesini tıklayın.
- Oturum açma sağlayıcıları listesinde E-posta/Şifre'yi tıklayın, Etkinleştir anahtarını açık konuma getirin ve Kaydet'i tıklayın.
Firebase Authentication'ı Flutter'da 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 giriş ve çıkış 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 bilgiye Flutter durumu yönetimi dokümanlarından ulaşabilirsiniz.
Şunu 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
ürününün başlatıldığından emin olmak için main.dart
yazılımına bir başlatma adımı eklersiniz:
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(),
));
}
Yine, uygulamanın kullanıcı arayüzü aynı kalmalıydı 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 oturumu kapatma akışı üzerinde çalışacaksınız. Akış şöyle görünecektir:
- Çıkış yapmış bir kullanıcı, uygulama çubuğunun sağ tarafındaki içerik menüsünü tıklayarak oturum açma akışını başlatır.
- Oturum açma akışı, iletişim kutusunda görüntülenir.
- Kullanıcı daha önce hiç oturum açmadıysa geçerli bir e-posta adresi ve şifre kullanarak hesap oluşturması istenir.
- Kullanıcı daha önce oturum açmışsa şifresini girmesi istenir.
- Kullanıcı oturum açtıktan sonra içerik menüsünü tıkladığında Oturumu kapat seçeneği gösterilir.
Oturum açma akışı eklemek için üç adım gerekir.
Her şeyden önce bir AppBarMenuButton
widget'ı oluşturun. Bu widget, kullanıcının loginState
ürününe bağlı olarak içerik menüsü pop-up'ını kontrol eder. İçe aktarma işlemlerini ekleme
lib/src/widgets.dart
import 'application_state.dart';
import 'package:provider/provider.dart';
import 'authentication.dart';
Aşağıdaki kodu widgets.dart.
adlı reklam grubuna ekleyin
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üsü, main.dart.
ürününde mevcut appBar widget'ını bulun. Oturum aç veya Oturumu kapat seçeneğinin gösterilmesini sağlamak için AppBarMenuButton
simgesini 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. Uygulama çubuğunun sağ tarafında içerik menüsünü görebiliyorsunuz. Bu düğmeyi tıkladığınızda oturum açma iletişim kutusuna yönlendirilirsiniz.
Geçerli bir e-posta adresi ve şifre ile oturum açtığınızda, içerik menüsünde Oturumu kapat seçeneğini görebilirsiniz.
Firebase konsolundaki Kimlik Doğrulama altında, e-posta adresinin yeni kullanıcı olarak listelendiğini görebilirsiniz.
Tebrikler! Kullanıcılar artık uygulamada oturum açabilirler.
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şturun
Firebase konsolunda
- Firebase konsolunun Realtime Database 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 isteklere izin veren Güvenlik Kuralları oluşturur. Güvenlik Kuralları'nı daha sonra ekleyeceksiniz. Güvenlik Kurallarınız hâlâ Test Modu'ndayken hiçbir zaman üretime geçmemek önemlidir.)
Veritabanı şu anda boş. databaseURL
öğenizi Genel sekmesinin altındaki Proje ayarları bölümünde bulun. Aşağı kaydırarak Web uygulamaları bölümüne gidin.
firebase_options.dart
dosyasına databaseURL
ekleyin:
lib/firebase_options.dart
static const FirebaseOptions web = FirebaseOptions(
apiKey: yourApiKey,
...
databaseURL: 'https://<YOUR_DATABASE_URL>,
...
);
RTDB Presence API'yi kullanarak cihazları kaydetme
Kullanıcıların cihazlarını internette göründüklerinde kaydettirmek istiyorsunuz. Bunu yapmak için, tek bir kullanıcıya ait online cihazların listesini izlemek amacıyla Firebase INSTALLs ve Firebase RTDB Presence API'den yararlanırsınız. Aşağıdaki kod bu hedefe ulaşmaya 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 dönerek uygulamayı cihazınızda veya tarayıcıda flutter run.
ile derleyip çalıştırın
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ızdaki tek bir kullanıcı kimliği altında listelendiğini göreceksiniz.
6. Cihaz durumunu senkronize et
Hizmet talebi cihazı seçin
Cihazlar arasında durum senkronizasyonu yapmak için bir cihazı lider veya denetleyici olarak atayın. Potansiyel müşteri cihazı, takip eden cihazlarda durumları belirtir.
application_state.dart
ürününde bir setLeadDevice
yöntemi oluşturun ve bu cihazı RTDB'de active_device
anahtarıyla takip edin:
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şlevi, uygulama çubuğu içerik menüsüne eklemek için SignedInMenuButton
widget'ını değiştirerek Controller
adlı bir PopupMenuItem
oluşturun. Bu menü, kullanıcıların potansiyel müşteri cihazını 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();
}
}
}
Potansiyel müşteri cihazının durumunu veritabanına yazma
Hizmet talebi cihazını ayarladıktan sonra aşağıdaki kodu kullanarak hizmet talebi cihazının durumlarını RTDB ile senkronize edebilirsiniz. Aşağıdaki kodu application_state.dart.
öğesinin sonuna ekleyin. Bu işlem, iki özelliği kaydetmeye başlar: oynatıcı durumu (oynatma veya duraklatma) ve kaydırma çubuğu 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');
}
}
}
Son olarak da kumandanın oyuncu durumu güncellendiğinde setActiveDeviceState
çağrısı yapmanız gerekir. Mevcut player_widget.dart
dosyasında şu 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;
}
Potansiyel müşteri cihazının durumunu veritabanından okuma
Hizmet talebi cihazının durumunu okumak ve kullanmak için iki bölüm vardır. İlk olarak application_state
bölgesindeki potansiyel müşteri oyuncu durumu için bir veritabanı dinleyicisi oluşturmanız gerekir. Bu dinleyici, geri arama yoluyla izleyenlerin ekranı ne zaman güncelleyeceğini belirtir. Bu adımda bir OnLeadDeviceChangeCallback
arayüzü tanımladığınıza dikkat edin. Henüz uygulanmadı; bu arayüzü bir sonraki adımda player_widget.dart
içinde 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, player_widget.dart
uygulamasındaki oynatıcı başlatma sırasında veritabanı dinleyiciyi 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 şu komutu kullanarak uygulamayı emülatörlerde ve/veya bir tarayıcıda çalıştırın:
flutter run -d <device-name>
- Uygulamaları tarayıcıda, iOS simülatöründe veya Android emülatöründe açın. İçerik menüsüne gidin ve bir uygulamayı öncü cihaz olarak seçin. Takipçi cihazlarını görebilirsiniz. Lider cihaz güncellendiğinde oyuncular değişir.
- Şimdi lider cihazı değiştirin, müzik çalın veya duraklatın ve takipçi cihazlarının buna göre güncellendiğini gözlemleyin.
Takipçi cihazları düzgün bir şekilde güncelleniyorsa cihazlar arası kumanda oluşturmayı başarmışsınız demektir. Tek bir önemli adım kaldı.
7. Güvenlik Kurallarını Güncelleme
Daha iyi güvenlik kuralları yazmadığımız sürece, başka biri sahibi olmadığı bir cihaza durum yazabilir. Bu nedenle, işlemi tamamlamadan önce Realtime Database Güvenlik Kuralları'nı güncelleyerek bir cihazda okuma veya yazma işlemi yapabilen tek kullanıcının söz konusu cihazda oturum açan kullanıcı olduğundan emin olun. Firebase konsolunda Realtime Database'e, ardından Kurallar sekmesine gidin. Yalnızca oturum açmış kullanıcının kendi cihaz durumlarını okuyup 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 cihazlar arası uzaktan kumandayı başarıyla geliştirdiniz.
Kredi
Better Together, Bir Firebase Şarkısı
- Müzikleri Ryan Vernon'a ait
- Şarkı sözleri ve Marissa Christy'den albüm kapağı
- Seslendiren: JP Gomez
9. Bonus
Ek bir zorluk olarak, mevcut potansiyel müşteri cihaz türünü kullanıcı arayüzüne eşzamansız olarak eklemek için Flutter FutureBuilder
'ı kullanabilirsiniz. Yardıma ihtiyacınız varsa bu destek, codelab'in bitmiş durumunu içeren klasöre uygulanır.