ফায়ারবেস ক্রস ডিভাইস কোডল্যাব

1। পরিচিতি

শেষ আপডেট: 2022-03-14

ক্রস ডিভাইস যোগাযোগের জন্য FlutterFire

যেহেতু আমরা প্রচুর সংখ্যক হোম অটোমেশন, পরিধানযোগ্য এবং ব্যক্তিগত স্বাস্থ্য প্রযুক্তি ডিভাইস অনলাইনে আসছে, তাই ক্রস ডিভাইস যোগাযোগ মোবাইল অ্যাপ্লিকেশন তৈরির একটি ক্রমবর্ধমান গুরুত্বপূর্ণ অংশ হয়ে উঠেছে। ক্রস ডিভাইস কমিউনিকেশন সেট আপ করা যেমন একটি ফোন অ্যাপ থেকে একটি ব্রাউজার নিয়ন্ত্রণ করা, অথবা আপনার ফোন থেকে আপনার টিভিতে কী চলে তা নিয়ন্ত্রণ করা, একটি সাধারণ মোবাইল অ্যাপ তৈরির চেয়ে ঐতিহ্যগতভাবে আরও জটিল।

ফায়ারবেসের রিয়েলটাইম ডেটাবেস উপস্থিতি API প্রদান করে যা ব্যবহারকারীদের তাদের ডিভাইসের অনলাইন/অফলাইন অবস্থা দেখতে দেয়; আপনি ফায়ারবেস ইনস্টলেশন পরিষেবার সাথে এটি ব্যবহার করবেন যে সমস্ত ডিভাইসে একই ব্যবহারকারী সাইন ইন করেছেন সেগুলিকে ট্র্যাক এবং সংযোগ করতে। আপনি একাধিক প্ল্যাটফর্মের জন্য দ্রুত অ্যাপ্লিকেশন তৈরি করতে ফ্লাটার ব্যবহার করবেন এবং তারপরে আপনি একটি ক্রস ডিভাইস প্রোটোটাইপ তৈরি করবেন যা প্লে করে এক ডিভাইসে মিউজিক আর অন্য ডিভাইসে মিউজিক নিয়ন্ত্রণ করে!

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি একটি সাধারণ মিউজিক প্লেয়ার রিমোট কন্ট্রোলার তৈরি করবেন। আপনার অ্যাপ হবে:

  • অ্যান্ড্রয়েড, আইওএস এবং ওয়েবে একটি সাধারণ মিউজিক প্লেয়ার আছে, যা ফ্লটার দিয়ে তৈরি।
  • ব্যবহারকারীদের সাইন ইন করার অনুমতি দিন।
  • একই ব্যবহারকারী একাধিক ডিভাইসে সাইন ইন করলে ডিভাইসগুলিকে সংযুক্ত করুন৷
  • ব্যবহারকারীদের অন্য ডিভাইস থেকে একটি ডিভাইসে সঙ্গীত প্লেব্যাক নিয়ন্ত্রণ করার অনুমতি দিন।

7f0279938e1d3ab5.gif

আপনি কি শিখবেন

  • কিভাবে একটি ফ্লাটার মিউজিক প্লেয়ার অ্যাপ তৈরি এবং চালানো যায়।
  • কিভাবে ব্যবহারকারীদের Firebase Auth দিয়ে সাইন ইন করার অনুমতি দেবেন।
  • ডিভাইস সংযোগ করতে Firebase RTDB উপস্থিতি API এবং Firebase ইনস্টলেশন পরিষেবা কীভাবে ব্যবহার করবেন।

আপনি কি প্রয়োজন হবে

  • একটি ফ্লাটার উন্নয়ন পরিবেশ. এটি সেট আপ করতে ফ্লটার ইনস্টলেশন গাইডের নির্দেশাবলী অনুসরণ করুন৷
  • একটি ন্যূনতম ফ্লটার সংস্করণ 2.10 বা উচ্চতর প্রয়োজন৷ আপনার যদি নিম্ন সংস্করণ থাকে তবে flutter upgrade.
  • একটি ফায়ারবেস অ্যাকাউন্ট।

2. সেট আপ করা হচ্ছে

স্টার্টার কোড পান

আমরা ফ্লটারে একটি মিউজিক প্লেয়ার অ্যাপ তৈরি করেছি। স্টার্টার কোডটি একটি গিট রেপোতে অবস্থিত। শুরু করতে, কমান্ড লাইনে, রেপো ক্লোন করুন, প্রারম্ভিক অবস্থা সহ ফোল্ডারে যান এবং নির্ভরতা ইনস্টল করুন:

git clone https://github.com/FirebaseExtended/cross-device-controller.git

cd cross-device-controller/starter_code

flutter pub get

অ্যাপটি তৈরি করুন

আপনি অ্যাপটি তৈরি করতে আপনার প্রিয় IDE এর সাথে কাজ করতে পারেন, বা কমান্ড লাইন ব্যবহার করতে পারেন।

আপনার অ্যাপ ডিরেক্টরিতে, flutter run -d web-server. আপনি নিম্নলিখিত প্রম্পট দেখতে সক্ষম হওয়া উচিত.

lib/main.dart is being served at http://localhost:<port>

মিউজিক প্লেয়ার দেখতে http://localhost:<port> এ যান।

আপনি যদি অ্যান্ড্রয়েড এমুলেটর বা iOS সিমুলেটরের সাথে পরিচিত হন, আপনি সেই প্ল্যাটফর্মগুলির জন্য অ্যাপটি তৈরি করতে পারেন এবং flutter run -d <device_name> কমান্ড দিয়ে এটি ইনস্টল করতে পারেন।

ওয়েব অ্যাপের একটি মৌলিক স্বতন্ত্র সঙ্গীত প্লেয়ার দেখানো উচিত। নিশ্চিত করুন যে প্লেয়ার বৈশিষ্ট্যগুলি উদ্দেশ্য হিসাবে কাজ করছে। এটি এই কোডল্যাবের জন্য ডিজাইন করা একটি সাধারণ মিউজিক প্লেয়ার অ্যাপ। এটি শুধুমাত্র একটি ফায়ারবেস গান চালাতে পারে, বেটার টুগেদার

একটি Android এমুলেটর বা একটি iOS সিমুলেটর সেট আপ করুন৷

আপনার যদি ইতিমধ্যেই ডেভেলপমেন্টের জন্য একটি Android ডিভাইস বা iOS ডিভাইস থাকে, তাহলে আপনি এই ধাপটি এড়িয়ে যেতে পারেন।

একটি অ্যান্ড্রয়েড এমুলেটর তৈরি করতে, অ্যান্ড্রয়েড স্টুডিও ডাউনলোড করুন যা ফ্লটার ডেভেলপমেন্টকেও সমর্থন করে এবং ভার্চুয়াল ডিভাইস তৈরি এবং পরিচালনা করার নির্দেশাবলী অনুসরণ করুন।

একটি iOS সিমুলেটর তৈরি করতে, আপনার একটি ম্যাক পরিবেশের প্রয়োজন হবে। XCode ডাউনলোড করুন এবং সিমুলেটর ওভারভিউ > সিমুলেটর ব্যবহার করুন > একটি সিমুলেটর খুলুন এবং বন্ধ করুন এর নির্দেশাবলী অনুসরণ করুন।

3. ফায়ারবেস সেট আপ করা

একটি ফায়ারবেস প্রকল্প তৈরি করুন

http://console.firebase.google.com/ এ একটি ব্রাউজার খুলুন।

  1. Firebase এ সাইন ইন করুন।
  2. Firebase কনসোলে, প্রজেক্ট যোগ করুন (বা একটি প্রকল্প তৈরি করুন ) এ ক্লিক করুন এবং আপনার Firebase প্রকল্পের নাম দিন Firebase-Cross-Device-Codelab
  3. প্রকল্প তৈরির বিকল্পগুলির মাধ্যমে ক্লিক করুন। অনুরোধ করা হলে Firebase শর্তাবলী স্বীকার করুন। Google Analytics সেট আপ করা এড়িয়ে যান, কারণ আপনি এই অ্যাপের জন্য Analytics ব্যবহার করবেন না।

আপনাকে উল্লেখিত ফাইলগুলি ডাউনলোড করতে বা build.gradle ফাইলগুলি পরিবর্তন করতে হবে না। আপনি যখন FlutterFire শুরু করবেন তখন আপনি সেগুলি কনফিগার করবেন।

Firebase SDK ইনস্টল করুন

কমান্ড লাইনে ফিরে, প্রকল্প ডিরেক্টরিতে, Firebase ইনস্টল করতে নিম্নলিখিত কমান্ডটি চালান:

flutter pub add firebase_core

pubspec.yaml ফাইলে, firebase_core এর সংস্করণটি কমপক্ষে 1.13.1 হতে সম্পাদনা করুন বা flutter upgrade চালান

FlutterFire শুরু করুন

  1. আপনার যদি Firebase CLI ইনস্টল না থাকে, তাহলে আপনি curl -sL https://firebase.tools | bash
  2. firebase login চালিয়ে এবং প্রম্পট অনুসরণ করে লগ ইন করুন।
  3. dart pub global activate flutterfire_cli চালিয়ে FlutterFire CLI ইনস্টল করুন।
  4. flutterfire configure চালিয়ে FlutterFire CLI কনফিগার করুন।
  5. প্রম্পটে, Firebase-Cross-Device-Codelab- এর মতো এই কোডল্যাবের জন্য আপনি এইমাত্র যে প্রকল্পটি তৈরি করেছেন সেটি বেছে নিন।
  6. যখন আপনাকে কনফিগারেশন সমর্থন চয়ন করতে বলা হয় তখন iOS , Android এবং Web নির্বাচন করুন৷
  7. অ্যাপল বান্ডেল আইডির জন্য অনুরোধ করা হলে, একটি অনন্য ডোমেনে টাইপ করুন, বা com.example.appname লিখুন, যা এই কোডল্যাবের উদ্দেশ্যে ঠিক আছে।

কনফিগার হয়ে গেলে, আপনার জন্য একটি firebase_options.dart ফাইল তৈরি করা হবে যাতে আরম্ভ করার জন্য প্রয়োজনীয় সমস্ত বিকল্প রয়েছে।

আপনার এডিটরে, Flutter এবং Firebase আরম্ভ করতে আপনার main.dart ফাইলে নিম্নলিখিত কোড যোগ করুন:

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());
}

কমান্ড দিয়ে অ্যাপটি কম্পাইল করুন:

flutter run

আপনি এখনও কোনো UI উপাদান পরিবর্তন করেননি, তাই অ্যাপের চেহারা এবং আচরণ পরিবর্তন হয়নি। কিন্তু এখন আপনার কাছে একটি Firebase অ্যাপ আছে এবং Firebase পণ্যগুলি ব্যবহার করা শুরু করতে পারেন, যার মধ্যে রয়েছে:

  • Firebase প্রমাণীকরণ , যা আপনার ব্যবহারকারীদের আপনার অ্যাপে সাইন ইন করতে দেয়।
  • ফায়ারবেস রিয়েলটাইম ডেটাবেস (RTDB) ; আপনি ডিভাইসের অনলাইন/অফলাইন স্থিতি ট্র্যাক করতে উপস্থিতি API ব্যবহার করবেন
  • ফায়ারবেস নিরাপত্তা বিধি আপনাকে ডাটাবেস সুরক্ষিত করতে দেবে।
  • একক ব্যবহারকারী সাইন ইন করেছেন এমন ডিভাইসগুলি সনাক্ত করতে Firebase ইনস্টলেশন পরিষেবা

4. Firebase Auth যোগ করুন

Firebase প্রমাণীকরণের জন্য ইমেল সাইন-ইন সক্ষম করুন

ব্যবহারকারীদের ওয়েব অ্যাপে সাইন ইন করার অনুমতি দিতে, আপনি ইমেল/পাসওয়ার্ড সাইন-ইন পদ্ধতি ব্যবহার করবেন:

  1. Firebase কনসোলে, বাম প্যানেলে বিল্ড মেনুটি প্রসারিত করুন।
  2. প্রমাণীকরণ ক্লিক করুন, এবং তারপর শুরু করুন বোতামে ক্লিক করুন, তারপর সাইন-ইন পদ্ধতি ট্যাবে।
  3. সাইন-ইন প্রদানকারীর তালিকায় ইমেল/পাসওয়ার্ডে ক্লিক করুন, সক্ষম সুইচটি অন অবস্থানে সেট করুন এবং তারপর সংরক্ষণ করুন ক্লিক করুন। 58e3e3e23c2f16a4.png

ফ্লটারে ফায়ারবেস প্রমাণীকরণ কনফিগার করুন

কমান্ড লাইনে, প্রয়োজনীয় ফ্লটার প্যাকেজগুলি ইনস্টল করতে নিম্নলিখিত কমান্ডগুলি চালান:

flutter pub add firebase_auth

flutter pub add provider

এই কনফিগারেশনের মাধ্যমে, আপনি এখন সাইন-ইন এবং সাইন-আউট প্রবাহ তৈরি করতে পারেন। যেহেতু auth স্টেট স্ক্রীন থেকে স্ক্রীনে পরিবর্তন করা উচিত নয়, তাই আপনি একটি application_state.dart ক্লাস তৈরি করবেন যাতে লগ ইন এবং লগ আউট করার মতো অ্যাপ লেভেল স্টেট পরিবর্তনগুলি ট্র্যাক করা যায়। ফ্লটার স্টেট ম্যানেজমেন্ট ডকুমেন্টেশনে এই সম্পর্কে আরও জানুন।

নতুন application_state.dart ফাইলে নিম্নলিখিত পেস্ট করুন:

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();
  }
}

অ্যাপ শুরু হলে ApplicationState আরম্ভ করা হবে তা নিশ্চিত করতে, আপনি 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(),
  ));
}

আবার, অ্যাপ্লিকেশন UI একই থাকা উচিত ছিল, কিন্তু এখন আপনি ব্যবহারকারীদের সাইন ইন করতে এবং অ্যাপের অবস্থা সংরক্ষণ করতে দিতে পারেন।

একটি সাইন ইন ফ্লো তৈরি করুন

এই ধাপে, আপনি সাইন ইন এবং সাইন আউট প্রবাহে কাজ করবেন। প্রবাহটি দেখতে কেমন হবে তা এখানে:

  1. একটি লগ আউট ব্যবহারকারী প্রসঙ্গ মেনুতে ক্লিক করে সাইন-ইন প্রবাহ শুরু করবে 71fcc1030a336423.png অ্যাপ বারের ডানদিকে।
  2. সাইন-ইন প্রবাহ একটি ডায়ালগে প্রদর্শিত হবে৷
  3. ব্যবহারকারী যদি আগে কখনও সাইন ইন না করে থাকেন, তাহলে তাদের একটি বৈধ ইমেল ঠিকানা এবং একটি পাসওয়ার্ড ব্যবহার করে একটি অ্যাকাউন্ট তৈরি করতে বলা হবে৷
  4. ব্যবহারকারী যদি আগে সাইন ইন করে থাকেন, তাহলে তাদের পাসওয়ার্ড লিখতে বলা হবে।
  5. একবার ব্যবহারকারী সাইন ইন করলে, প্রসঙ্গ মেনুতে ক্লিক করলে একটি সাইন আউট বিকল্প দেখাবে।

c295f6fa2e1d40f3.png

সাইন-ইন প্রবাহ যোগ করার জন্য তিনটি ধাপ প্রয়োজন।

প্রথমত, একটি AppBarMenuButton উইজেট তৈরি করুন। এই উইজেটটি ব্যবহারকারীর loginState উপর নির্ভর করে প্রসঙ্গ মেনু পপআপ নিয়ন্ত্রণ করবে। আমদানি যোগ করুন

lib/src/widgets.dart

import 'application_state.dart';
import 'package:provider/provider.dart';
import 'authentication.dart';

নিম্নলিখিত কোডটি 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),
        ),
      ),
    ];
  }
}

দ্বিতীয়ত, একই widgets.dart ক্লাসে, 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,
          ),
        ),
      ]),
    );
  }
}

তৃতীয়ত, main.dart. সাইন ইন বা সাইন আউট বিকল্পটি প্রদর্শন করতে AppBarMenuButton যোগ করুন।

lib/main.dart

import 'src/widgets.dart';
appBar: AppBar(
  title: const Text('Music Box'),
  backgroundColor: Colors.deepPurple.shade400,
  actions: const <Widget>[
    AppBarMenuButton(),
  ],
),

এই পরিবর্তনগুলির সাথে অ্যাপটি পুনরায় চালু করতে flutter run কমান্ডটি চালান। আপনি প্রসঙ্গ মেনু দেখতে সক্ষম হওয়া উচিত 71fcc1030a336423.png অ্যাপ বারের ডানদিকে। এটিতে ক্লিক করা আপনাকে একটি সাইন-ইন ডায়ালগে নিয়ে যাবে।

একবার আপনি একটি বৈধ ইমেল ঠিকানা এবং একটি পাসওয়ার্ড দিয়ে সাইন ইন করলে, আপনি প্রসঙ্গ মেনুতে একটি সাইন আউট বিকল্প দেখতে সক্ষম হবেন৷

Firebase কনসোলে, প্রমাণীকরণের অধীনে, আপনি একটি নতুন ব্যবহারকারী হিসাবে তালিকাভুক্ত ইমেল ঠিকানা দেখতে সক্ষম হবেন।

888506c86a28a72c.png

অভিনন্দন! ব্যবহারকারীরা এখন অ্যাপে সাইন ইন করতে পারবেন!

5. ডাটাবেস সংযোগ যোগ করুন

এখন আপনি Firebase Presence API ব্যবহার করে ডিভাইস রেজিস্ট্রেশনে যেতে প্রস্তুত।

কমান্ড লাইনে, প্রয়োজনীয় নির্ভরতা যোগ করতে নিম্নলিখিত কমান্ডগুলি চালান:

flutter pub add firebase_app_installations

flutter pub add firebase_database

একটি ডাটাবেস তৈরি করুন

ফায়ারবেস কনসোলে,

  1. Firebase কনসোলের রিয়েলটাইম ডেটাবেস বিভাগে নেভিগেট করুন। ডেটাবেস তৈরি করুন ক্লিক করুন।
  2. আপনার নিরাপত্তা নিয়মের জন্য একটি প্রারম্ভিক মোড নির্বাচন করার জন্য অনুরোধ করা হলে, এখনকার জন্য পরীক্ষা মোড নির্বাচন করুন**.** (পরীক্ষা মোড নিরাপত্তা নিয়ম তৈরি করে যা সমস্ত অনুরোধের মাধ্যমে অনুমতি দেয়। আপনি পরে নিরাপত্তা বিধি যোগ করবেন। এর সাথে কখনই উৎপাদনে না যাওয়া গুরুত্বপূর্ণ আপনার নিরাপত্তা নিয়ম এখনও পরীক্ষা মোডে আছে।)

ডাটাবেস আপাতত খালি। সাধারণ ট্যাবের অধীনে, প্রজেক্ট সেটিংসে আপনার databaseURL সনাক্ত করুন। ওয়েব অ্যাপস বিভাগে নিচে স্ক্রোল করুন।

1b6076f60a36263b.png

firebase_options.dart ফাইলে আপনার databaseURL যোগ করুন :

lib/firebase_options.dart

 static const FirebaseOptions web = FirebaseOptions(
    apiKey: yourApiKey,
    ...
    databaseURL: 'https://<YOUR_DATABASE_URL>,
    ...
  );

RTDB উপস্থিতি API ব্যবহার করে ডিভাইস নিবন্ধন করুন

আপনি একটি ব্যবহারকারীর ডিভাইসগুলি অনলাইনে উপস্থিত হলে নিবন্ধন করতে চান৷ এটি করার জন্য, আপনি Firebase ইনস্টলেশন এবং Firebase RTDB উপস্থিতি API-এর সুবিধা নেবেন যাতে একজন একক ব্যবহারকারীর অনলাইন ডিভাইসের তালিকার উপর নজর রাখতে পারেন। নিম্নলিখিত কোড এই লক্ষ্য পূরণ করতে সাহায্য করবে:

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';
  }

কমান্ড লাইনে ফিরে যান, আপনার ডিভাইসে বা flutter run.

আপনার অ্যাপে, ব্যবহারকারী হিসেবে সাইন ইন করুন। বিভিন্ন প্ল্যাটফর্মে একই ব্যবহারকারী হিসেবে সাইন ইন করতে ভুলবেন না।

Firebase কনসোলে , আপনি আপনার ডিভাইসগুলিকে আপনার ডাটাবেসের একটি ব্যবহারকারী আইডির অধীনে প্রদর্শিত দেখতে পাবেন।

5bef49cea3564248.png

6. ডিভাইসের অবস্থা সিঙ্ক করুন

একটি লিড ডিভাইস নির্বাচন করুন

ডিভাইসগুলির মধ্যে অবস্থা সিঙ্ক করতে, একটি ডিভাইসকে নেতা বা নিয়ামক হিসাবে মনোনীত করুন। লিড ডিভাইস ফলোয়ার ডিভাইসে রাজ্যগুলি নির্দেশ করবে।

application_state.dart এ একটি setLeadDevice পদ্ধতি তৈরি করুন এবং RTDB-তে active_device কী দিয়ে এই ডিভাইসটিকে ট্র্যাক করুন:

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;
      });
    }
  }

অ্যাপ বার প্রসঙ্গ মেনুতে এই কার্যকারিতা যোগ করতে, SignedInMenuButton উইজেট পরিবর্তন করে Controller নামে একটি PopupMenuItem তৈরি করুন। এই মেনু ব্যবহারকারীদের লিড ডিভাইস সেট করার অনুমতি দেবে।

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();
    }
  }
}

ডাটাবেসে লিড ডিভাইসের অবস্থা লিখুন

একবার আপনি একটি লিড ডিভাইস সেট করার পরে, আপনি নিম্নলিখিত কোডের সাথে RTDB-এর সাথে লিড ডিভাইসের অবস্থা সিঙ্ক করতে পারেন৷ নিচের কোডটি application_state.dart. এটি দুটি বৈশিষ্ট্য সংরক্ষণ করা শুরু করবে: প্লেয়ারের অবস্থা (খেলা বা বিরতি) এবং স্লাইডার অবস্থান।

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');
      }
    }
  }

এবং অবশেষে, যখনই কন্ট্রোলারের প্লেয়ার স্টেট আপডেট হয় তখন আপনাকে setActiveDeviceState কল করতে হবে। বিদ্যমান player_widget.dart ফাইলে নিম্নলিখিত পরিবর্তনগুলি করুন:

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;
  }

ডাটাবেস থেকে লিড ডিভাইসের অবস্থা পড়ুন

লিড ডিভাইসের অবস্থা পড়তে এবং ব্যবহার করার জন্য দুটি অংশ রয়েছে। প্রথমে, আপনি application_state এ লিড প্লেয়ার স্টেটের একটি ডাটাবেস লিসেনার সেট আপ করতে চান। এই শ্রোতা একটি কলব্যাকের মাধ্যমে স্ক্রীন আপডেট করার সময় অনুসরণকারী ডিভাইসগুলিকে বলবেন৷ লক্ষ্য করুন আপনি এই ধাপে একটি ইন্টারফেস OnLeadDeviceChangeCallback সংজ্ঞায়িত করেছেন। এটা এখনো বাস্তবায়িত হয়নি; আপনি পরবর্তী ধাপে player_widget.dart এ এই ইন্টারফেসটি বাস্তবায়ন করবেন।

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();
      });
    }
  }

দ্বিতীয়ত, player_widget.dart এ প্লেয়ার শুরু করার সময় ডাটাবেস লিসেনার শুরু করুন। _updatePlayer ফাংশনটি পাস করুন যাতে ফলোয়ার প্লেয়ার স্টেট আপডেট করা যায় যখনই ডাটাবেসের মান পরিবর্তন হয়।

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');
        }
      }
    }
  }

এখন আপনি অ্যাপটি পরীক্ষা করার জন্য প্রস্তুত:

  1. কমান্ড লাইনে, এমুলেটরগুলিতে এবং/অথবা একটি ব্রাউজারে অ্যাপটি চালান: flutter run -d <device-name>
  2. একটি ব্রাউজারে, একটি iOS সিমুলেটর বা একটি Android এমুলেটরে অ্যাপগুলি খুলুন৷ প্রসঙ্গ মেনুতে যান, লিডার ডিভাইস হতে একটি অ্যাপ বেছে নিন। লিডার ডিভাইস আপডেট হওয়ার সাথে সাথে আপনি অনুসরণকারী ডিভাইসের প্লেয়ারের পরিবর্তন দেখতে সক্ষম হবেন।
  3. এখন লিডার ডিভাইস পরিবর্তন করুন, সঙ্গীত চালান বা বিরতি দিন এবং অনুসরণকারী ডিভাইসগুলি সেই অনুযায়ী আপডেট করা পর্যবেক্ষণ করুন।

ফলোয়ার ডিভাইসগুলি সঠিকভাবে আপডেট হলে, আপনি একটি ক্রস ডিভাইস কন্ট্রোলার তৈরি করতে সফল হয়েছেন। শুধুমাত্র একটি গুরুত্বপূর্ণ পদক্ষেপ বাকি আছে.

7. নিরাপত্তা বিধি আপডেট করুন

আমরা আরও ভাল নিরাপত্তা নিয়ম না লিখলে, কেউ এমন একটি ডিভাইসে একটি রাষ্ট্র লিখতে পারে যেটির মালিকানা তাদের নেই! সুতরাং আপনি শেষ করার আগে, রিয়েলটাইম ডেটাবেস সুরক্ষা নিয়মগুলি আপডেট করুন নিশ্চিত করুন যে কেবলমাত্র ব্যবহারকারীরা একটি ডিভাইসে পড়তে বা লিখতে পারেন সেই ব্যবহারকারীই সেই ডিভাইসে সাইন ইন করেছেন৷ ফায়ারবেস কনসোলে, রিয়েলটাইম ডেটাবেসে নেভিগেট করুন এবং তারপরে নিয়ম ট্যাবে যান। শুধুমাত্র সাইন ইন করা ব্যবহারকারীদের তাদের নিজস্ব ডিভাইসের অবস্থা পড়তে এবং লিখতে অনুমতি দিয়ে নিম্নলিখিত নিয়মগুলি আটকান:

{
  "rules": {
    "users": {
           "$uid": {
               ".read": "$uid === auth.uid",
               ".write": "$uid === auth.uid"
           }
    },
  }
}

8. অভিনন্দন!

bcd986f7106d892b.gif

অভিনন্দন, আপনি ফ্লটার ব্যবহার করে সফলভাবে একটি ক্রস ডিভাইস রিমোট কন্ট্রোলার তৈরি করেছেন!

ক্রেডিট

বেটার টুগেদার, একটি ফায়ারবেস গান

  • রায়ান ভার্ননের সঙ্গীত
  • গানের কথা এবং অ্যালবামের কভার মারিসা ক্রিস্টি
  • জেপি গোমেজের কণ্ঠ

9. বোনাস

একটি অতিরিক্ত চ্যালেঞ্জ হিসাবে, UI এ অ্যাসিঙ্ক্রোনাসভাবে বর্তমান লিড ডিভাইসের ধরন যোগ করতে Flutter FutureBuilder ব্যবহার করার কথা বিবেচনা করুন। আপনার যদি কোনও সহায়তার প্রয়োজন হয়, এটি কোডল্যাবের সমাপ্ত অবস্থা ধারণকারী ফোল্ডারে প্রয়োগ করা হয়।

রেফারেন্স ডক্স এবং পরবর্তী পদক্ষেপ