با Firebase و Jetpack Compose یک برنامه اندروید بسازید

1. معرفی

آخرین به روز رسانی: 2022-11-16

ساخت اپلیکیشن اندروید با Firebase و Jetpack Compose

در این کد لبه، شما یک برنامه اندرویدی به نام Make It So را خواهید ساخت. رابط کاربری این برنامه به طور کامل با Jetpack Compose ساخته شده است، که ابزار مدرن اندروید برای ایجاد رابط کاربری بومی است - بصری است و نیاز به کد کمتری نسبت به نوشتن فایل‌های xml و اتصال آن‌ها به Activities، Fragments یا View دارد.

اولین قدم برای درک اینکه Firebase و Jetpack Compose چقدر با هم کار می کنند، درک معماری مدرن اندروید است. یک معماری خوب باعث می شود سیستم به راحتی قابل درک، توسعه و نگهداری آسان باشد، زیرا نحوه سازماندهی و ارتباط اجزا با یکدیگر را کاملاً روشن می کند. در دنیای اندروید، معماری پیشنهادی Model - View - ViewModel نامیده می‌شود. Model لایه ای را نشان می دهد که به داده ها در برنامه دسترسی دارد. View لایه رابط کاربری است و نباید چیزی در مورد منطق تجاری بداند. و ViewModel جایی است که منطق تجاری اعمال می شود، که گاهی اوقات ViewModel نیاز به فراخوانی لایه Model دارد.

خواندن این مقاله را قویاً توصیه می‌کنیم تا متوجه شوید که Model - View - ViewModel چگونه در یک برنامه Android ساخته شده با Jetpack Compose اعمال می‌شود، زیرا درک پایه کد را آسان‌تر می‌کند و مراحل بعدی را آسان‌تر می‌کند.

چیزی که خواهی ساخت

Make It So یک برنامه ساده لیست کارهایی است که به کاربر امکان می دهد وظایف را اضافه و ویرایش کند، پرچم ها، اولویت ها و تاریخ های مقرر را اضافه کند و وظایف را به عنوان تکمیل شده علامت گذاری کند. تصاویر زیر دو صفحه اصلی این اپلیکیشن را نشان می دهد: صفحه ایجاد وظایف و صفحه اصلی با لیست وظایف ایجاد شده.

آن را بسازید بنابراین صفحه کار را اضافه کنیدآن را به صفحه اصلی تبدیل کنید

برخی از ویژگی هایی که در این برنامه وجود ندارد را اضافه خواهید کرد:

  • احراز هویت کاربران با ایمیل و رمز عبور
  • یک شنونده به مجموعه Firestore اضافه کنید و رابط کاربری را به تغییرات واکنش نشان دهید
  • ردیابی های سفارشی را برای نظارت بر عملکرد کد خاص در برنامه اضافه کنید
  • با استفاده از Remote Config یک تغییر ویژگی ایجاد کنید و از عرضه مرحله‌ای برای راه‌اندازی آن استفاده کنید

چیزی که یاد خواهید گرفت

  • نحوه استفاده از Firebase Authentication، Performance Monitoring، Remote Config و Cloud Firestore در یک برنامه اندرویدی مدرن
  • چگونه API های Firebase را در یک معماری MVVM قرار دهیم
  • نحوه منعکس کردن تغییرات ایجاد شده با APIهای Firebase در یک رابط کاربری Compose

آنچه شما نیاز دارید

2. برنامه نمونه را دریافت کنید و Firebase را راه اندازی کنید

کد برنامه نمونه را دریافت کنید

مخزن GitHub را از خط فرمان کلون کنید:

git clone https://github.com/FirebaseExtended/make-it-so-android.git

Firebase را راه اندازی کنید

اولین کاری که باید انجام دهید این است که به کنسول Firebase بروید و با کلیک بر روی دکمه "+ Add project" یک پروژه Firebase ایجاد کنید، همانطور که در زیر مشاهده می کنید:

کنسول Firebase

مراحل روی صفحه را برای تکمیل ساخت پروژه دنبال کنید.

در داخل هر پروژه Firebase، می توانید برنامه های مختلفی ایجاد کنید: برای Android، iOS، Web، Flutter و Unity. همانطور که در اینجا می بینید گزینه Android را انتخاب کنید:

مروری بر پروژه Firebase

سپس این مراحل را دنبال کنید:

  1. com.example.makeitso به عنوان نام بسته وارد کنید و در صورت تمایل، یک نام مستعار وارد کنید. برای این کد لبه، نیازی نیست گواهی امضای اشکال زدایی را اضافه کنید.
  2. برای ثبت برنامه و دسترسی به فایل پیکربندی Firebase روی Next کلیک کنید.
  3. برای دانلود فایل پیکربندی خود و ذخیره آن در فهرست راهنمای make-it-so-android/app روی Download google-services.json کلیک کنید.
  4. روی Next کلیک کنید. از آنجایی که SDK های Firebase از قبل در فایل build.gradle در پروژه نمونه گنجانده شده اند، روی Next کلیک کنید تا به مراحل بعدی بروید.
  5. برای پایان روی Continue to console کلیک کنید.

برای اینکه اپلیکیشن Make it So به درستی کار کند، دو کار وجود دارد که باید قبل از پرش به کد در کنسول انجام دهید: فعال کردن ارائه دهندگان احراز هویت و ایجاد پایگاه داده Firestore. ابتدا، اجازه دهید Authentication را فعال کنیم تا کاربران بتوانند وارد برنامه شوند:

  1. از منوی Build ، Authentication را انتخاب کنید و سپس روی Get Started کلیک کنید.
  2. از کارت روش ورود ، ایمیل/رمز عبور را انتخاب کنید و آن را فعال کنید.
  3. سپس، روی افزودن ارائه‌دهنده جدید کلیک کنید و Anonymous را انتخاب و فعال کنید.

بعد، Firestore را راه اندازی کنید. شما از Firestore برای ذخیره وظایف یک کاربر وارد شده به سیستم استفاده خواهید کرد. هر کاربر سند خود را در مجموعه ای از پایگاه داده دریافت می کند.

  1. از منوی Build ، Firestore را انتخاب کنید، سپس روی ایجاد پایگاه داده کلیک کنید.
  2. شروع را در حالت تولید فعال نگه دارید و روی Next کلیک کنید.
  3. وقتی از شما خواسته شد، مکانی را انتخاب کنید که داده‌های Cloud Firestore شما در آن ذخیره می‌شوند. هنگام توسعه یک برنامه تولیدی، می‌خواهید این برنامه در منطقه‌ای نزدیک به اکثر کاربران شما باشد و با سایر سرویس‌های Firebase مانند Functions مشترک باشد. برای این کد لبه، می توانید منطقه پیش فرض را حفظ کنید یا نزدیک ترین منطقه به خود را انتخاب کنید.
  4. برای ارائه پایگاه داده Firestore خود روی Enable کلیک کنید.

بیایید چند لحظه برای ایجاد قوانین امنیتی قوی در پایگاه داده Firestore وقت بگذاریم. داشبورد Firestore را باز کنید و به تب Rules بروید. سپس قوانین امنیتی را به شکل زیر به روز کنید:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
    }
  }
}

این قوانین اساساً می گویند که هر کاربر وارد شده در برنامه می تواند در هر مجموعه ای سندی برای خود ایجاد کند. سپس، پس از ایجاد، تنها کاربری که آن سند را ایجاد کرده است می‌تواند آن سند را مشاهده، به‌روزرسانی یا حذف کند.

برنامه را اجرا کنید

اکنون شما آماده اجرای برنامه هستید! پوشه make-it-so-android/start در اندروید استودیو باز کنید و برنامه را اجرا کنید (این کار را می توان با استفاده از شبیه ساز اندروید یا یک دستگاه اندروید واقعی انجام داد).

3. احراز هویت Firebase

کدام ویژگی را می خواهید اضافه کنید؟

در وضعیت فعلی برنامه نمونه Make It So ، کاربر می‌تواند بدون نیاز به ورود ابتدا از برنامه استفاده کند. برای رسیدن به این هدف از احراز هویت ناشناس استفاده می کند. با این حال، حساب‌های ناشناس به کاربر اجازه دسترسی به داده‌های خود را در دستگاه‌های دیگر یا حتی در جلسات آینده نمی‌دهند. اگرچه احراز هویت ناشناس برای ورود به سیستم گرم مفید است، اما همیشه باید این گزینه را برای کاربران فراهم کنید که به شکل دیگری از ورود به سیستم تبدیل شوند. با در نظر گرفتن این موضوع، در این لبه کد، احراز هویت ایمیل و رمز عبور را به برنامه Make It So اضافه خواهید کرد.

زمان کدنویسی است!

به محض اینکه کاربر یک حساب کاربری ایجاد کرد، با تایپ یک ایمیل و یک رمز عبور، باید از Firebase Authentication API یک اعتبار نامه ایمیل بخواهید، سپس اعتبار جدید را به حساب ناشناس پیوند دهید. فایل AccountServiceImpl.kt را در Android Studio باز کنید و تابع linkAccount را به‌روزرسانی کنید تا به شکل زیر باشد:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String) {
    val credential = EmailAuthProvider.getCredential(email, password)
    auth.currentUser!!.linkWithCredential(credential).await()
}

اکنون SignUpViewModel.kt باز کنید و تابع سرویس linkAccount را در بلوک launchCatching تابع onSignUpClick فراخوانی کنید:

screens/sign_up/SignUpViewModel.kt

launchCatching {
    accountService.linkAccount(email, password)
    openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}

ابتدا سعی می کند احراز هویت کند، و اگر تماس موفق شد، به صفحه بعدی ( SettingsScreen ) می رود. همانطور که شما در حال اجرای این تماس‌ها در داخل یک بلوک launchCatching هستید، اگر خطایی در خط اول رخ دهد، استثنا گرفته می‌شود و رسیدگی می‌شود و به خط دوم اصلا دسترسی پیدا نمی‌کند.

به محض باز شدن مجدد SettingsScreen ، باید مطمئن شوید که گزینه های Sign in و Create account از بین رفته اند، زیرا اکنون کاربر قبلاً احراز هویت شده است. برای انجام این کار، اجازه دهید SettingsViewModel به وضعیت کاربر فعلی (موجود در AccountService.kt ) گوش دهد تا بررسی کنیم که آیا حساب ناشناس است یا خیر. برای انجام این کار، uiState را در SettingsViewModel.kt به‌صورت زیر به‌روزرسانی کنید:

screens/settings/SettingsViewModel.kt

val uiState = accountService.currentUser.map {
    SettingsUiState(it.isAnonymous)
}

آخرین کاری که باید انجام دهید این است که uiState را در SettingsScreen.kt به‌روزرسانی کنید تا حالت‌های منتشر شده توسط SettingsViewModel را جمع‌آوری کند:

screens/settings/SettingsScreen.kt

val uiState by viewModel.uiState.collectAsState(
    initial = SettingsUiState(false)
)

اکنون هر بار که کاربر تغییر می کند، SettingsScreen خود را دوباره ترکیب می کند تا گزینه ها را مطابق با وضعیت احراز هویت جدید کاربر نمایش دهد.

وقت آزمایش است!

Make it So را اجرا کنید و با کلیک بر روی نماد چرخ دنده در گوشه سمت راست بالای صفحه به تنظیمات بروید. از آنجا روی گزینه create account کلیک کنید:

صفحه تنظیمات آن را بسازیدآن را بسازید بنابراین صفحه ثبت نام کنید

یک ایمیل معتبر و یک رمز عبور قوی برای ایجاد حساب کاربری خود تایپ کنید. باید کار کند و باید به صفحه تنظیمات هدایت شوید، جایی که دو گزینه جدید را مشاهده خواهید کرد: خروج از سیستم و حذف حساب خود. می‌توانید حساب جدید ایجاد شده در داشبورد Authentication در کنسول Firebase را با کلیک کردن بر روی زبانه Users بررسی کنید.

4. Cloud Firestore

کدام ویژگی را می خواهید اضافه کنید؟

برای Cloud Firestore، شنونده ای به مجموعه Firestore اضافه می کنید که اسنادی را که نشان دهنده وظایف نمایش داده شده در Make it So هستند را ذخیره می کند. هنگامی که این شنونده را اضافه کردید، هر به روز رسانی ایجاد شده در این مجموعه را دریافت خواهید کرد.

زمان کدنویسی است!

Flow موجود در StorageServiceImpl.kt را به شکل زیر به روز کنید:

model/service/impl/StorageServiceImpl.kt

override val tasks: Flow<List<Task>>
    get() =
      auth.currentUser.flatMapLatest { user ->
        firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
      }

این کد یک شنونده به مجموعه وظایف بر اساس user.id اضافه می کند. هر کار با یک سند در مجموعه ای به نام tasks نشان داده می شود و هر یک از آنها دارای فیلدی به نام userId است. لطفاً توجه داشته باشید که در صورت تغییر وضعیت currentUser (مثلاً با خروج از سیستم) یک Flow جدید منتشر می شود.

اکنون باید کاری کنید که Flow در TasksViewModel.kt مانند سرویس منعکس شود:

screens/tasks/TasksViewModel.kt

val tasks = storageService.tasks

و آخرین چیز این است که composable function در TasksScreens.kt که نمایانگر UI است، از این جریان آگاه کنید و آن را به عنوان یک حالت جمع آوری کنید. هر بار که وضعیت تغییر می کند، تابع composable به طور خودکار خود را دوباره ترکیب می کند و آخرین وضعیت را به کاربر نمایش می دهد. این را به TasksScreen composable function اضافه کنید:

screens/tasks/TasksScreen.kt

val tasks = viewModel
    .tasks
    .collectAsStateWithLifecycle(emptyList())

هنگامی که تابع composable به این حالت ها دسترسی پیدا کرد، می توانید LazyColumn (که ساختاری است که برای نمایش لیست روی صفحه استفاده می کنید) را به صورت زیر به روز کنید:

screens/tasks/TasksScreen.kt

LazyColumn {
    items(tasks.value, key = { it.id }) { taskItem ->
        TaskItem( [...] )
    }
}

وقت آزمایش است!

به منظور آزمایش کارایی آن، با استفاده از برنامه یک کار جدید اضافه کنید (با کلیک بر روی دکمه افزودن در گوشه سمت راست پایین صفحه). پس از اتمام ایجاد کار، باید در مجموعه Firestore در Firestore Console ظاهر شود. اگر در دستگاه‌های دیگر با همین حساب وارد Make it So شوید، می‌توانید موارد کارهای خود را ویرایش کنید و به‌روزرسانی آن‌ها را در همه دستگاه‌ها به‌طور هم‌زمان مشاهده کنید.

5. نظارت بر عملکرد

کدام ویژگی را می خواهید اضافه کنید؟

عملکرد نکته بسیار مهمی است که باید به آن توجه کرد زیرا اگر کاربران برنامه شما خوب نباشد و زمان زیادی را صرف انجام یک کار ساده با استفاده از آن کنند، احتمالاً از استفاده از برنامه شما صرف نظر می کنند. به همین دلیل است که گاهی اوقات جمع آوری معیارهای مربوط به سفر خاصی که کاربر در برنامه شما انجام می دهد مفید است. و برای کمک به شما در این زمینه، Firebase Performance Monitoring ردیابی های سفارشی را ارائه می دهد. مراحل بعدی را برای افزودن ردیابی های سفارشی و اندازه گیری عملکرد در قطعات مختلف کد در Make it So دنبال کنید.

زمان کدنویسی است!

اگر فایل Performance.kt را باز کنید، یک تابع درون خطی به نام trace خواهید دید. این تابع Performance Monitoring API را فراخوانی می کند تا یک ردیابی سفارشی ایجاد کند و نام ردیابی را به عنوان یک پارامتر ارسال کند. پارامتر دیگری که مشاهده می کنید بلوک کدی است که می خواهید نظارت کنید. متریک پیش‌فرض جمع‌آوری‌شده برای هر ردیابی، زمان اجرای کامل آن است:

model/service/Performance.kt

inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

شما می توانید انتخاب کنید که کدام قسمت از پایگاه کد برای اندازه گیری مهم است و ردیابی های سفارشی را به آن اضافه کنید. در اینجا نمونه ای از افزودن یک ردیابی سفارشی به تابع linkAccount است که قبلاً (در AccountServiceImpl.kt ) در این لبه کد مشاهده کردید:

model/service/impl/AccountServiceImpl.kt

override suspend fun linkAccount(email: String, password: String): Unit =
  trace(LINK_ACCOUNT_TRACE) {
      val credential = EmailAuthProvider.getCredential(email, password)
      auth.currentUser!!.linkWithCredential(credential).await()
  }

حالا نوبت شماست! برخی از ردیابی‌های سفارشی را به برنامه Make it So اضافه کنید و به بخش بعدی بروید تا بررسی کنید که آیا مطابق انتظار کار می‌کند یا خیر.

وقت آزمایش است!

پس از اتمام افزودن ردیابی های سفارشی، برنامه را اجرا کنید و مطمئن شوید که چند بار از ویژگی هایی که می خواهید اندازه گیری کنید استفاده کنید. سپس به کنسول Firebase بروید و به داشبورد Performance بروید. در پایین صفحه، سه برگه را خواهید دید: درخواست‌های شبکه ، ردیابی سفارشی و نمایش صفحه .

به تب Custom Traces بروید و بررسی کنید که ردیابی هایی که در پایگاه کد اضافه کرده اید در آنجا نمایش داده می شوند و می توانید ببینید که معمولا چقدر زمان برای اجرای این قطعات کد نیاز است.

6. Remote Config

کدام ویژگی را می خواهید اضافه کنید؟

موارد استفاده زیادی برای Remote Config وجود دارد، از تغییر ظاهر برنامه شما از راه دور تا پیکربندی رفتارهای مختلف برای بخش های مختلف کاربر. در این لبه کد، می‌خواهید از Remote Config برای ایجاد یک تغییر ویژگی استفاده کنید که ویژگی جدید ویرایش وظیفه را در برنامه Make it So نشان می‌دهد یا پنهان می‌کند.

زمان کدنویسی است!

اولین کاری که باید انجام دهید این است که پیکربندی را در کنسول Firebase ایجاد کنید. برای انجام این کار، باید به داشبورد Remote Config بروید و روی دکمه افزودن پارامتر کلیک کنید. مطابق تصویر زیر فیلدها را پر کنید:

Remote Config یک گفتگوی پارامتر ایجاد کنید

پس از پر شدن تمام فیلدها، می توانید روی دکمه ذخیره و سپس انتشار کلیک کنید. اکنون که پارامتر ایجاد شده و برای پایگاه کد شما در دسترس است، باید کدی را اضافه کنید که مقادیر جدید را به برنامه شما واکشی کند. فایل ConfigurationServiceImpl.kt را باز کنید و اجرای این دو تابع را به روز کنید:

model/service/impl/ConfigurationServiceImpl.kt

override suspend fun fetchConfiguration(): Boolean {
  return remoteConfig.fetchAndActivate().await()
}

override val isShowTaskEditButtonConfig: Boolean
  get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()

اولین تابع مقادیر را از سرور واکشی می کند و به محض شروع برنامه در SplashViewModel.kt فراخوانی می شود. این بهترین راه برای اطمینان از اینکه به‌روزترین مقادیر از همان ابتدا در همه صفحه‌ها در دسترس خواهند بود، است. اگر بعداً، زمانی که کاربر در وسط انجام کاری است، رابط کاربری یا رفتار برنامه را تغییر دهید، تجربه کاربری خوبی نیست!

تابع دوم، مقدار بولی را که برای پارامتری که به تازگی در کنسول ایجاد کرده اید منتشر شده، برمی گرداند. و شما باید این اطلاعات را در TasksViewModel.kt با افزودن موارد زیر به تابع loadTaskOptions بازیابی کنید:

screens/tasks/TasksViewModel.kt

fun loadTaskOptions() {
  val hasEditOption = configurationService.isShowTaskEditButtonConfig
  options.value = TaskActionOption.getOptions(hasEditOption)
}

شما در حال بازیابی مقدار در خط اول هستید و از آن برای بارگیری گزینه های منو برای آیتم های وظیفه در خط دوم استفاده می کنید. اگر مقدار false باشد، به این معنی است که منو شامل گزینه ویرایش نخواهد بود. اکنون که لیست گزینه ها را دارید، باید کاری کنید که رابط کاربری آن را به درستی نمایش دهد. همانطور که در حال ساختن یک برنامه با Jetpack Compose هستید، باید به دنبال composable function باشید که نشان می‌دهد رابط کاربری TasksScreen چگونه باید باشد. بنابراین فایل TasksScreen.kt را باز کنید و LazyColum به روز کنید تا به گزینه های موجود در TasksViewModel.kt اشاره کند:

screens/tasks/TasksScreen.kt

val options by viewModel.options

LazyColumn {
  items(tasks.value, key = { it.id }) { taskItem ->
    TaskItem(
      options = options,
      [...]
    )
  }
}

TaskItem یکی دیگر از composable function است که نشان می دهد رابط کاربری یک کار منفرد چگونه باید باشد. و هر کار دارای یک منو با گزینه هایی است که با کلیک کاربر بر روی نماد سه نقطه در انتهای آن نمایش داده می شود.

وقت آزمایش است!

اکنون شما آماده اجرای برنامه هستید! بررسی کنید مقداری که با استفاده از کنسول Firebase منتشر کردید با رفتار برنامه مطابقت داشته باشد:

  • اگر false است، هنگام کلیک کردن روی نماد سه نقطه فقط باید دو گزینه را مشاهده کنید.
  • اگر true باشد، هنگام کلیک بر روی نماد سه نقطه باید سه گزینه را مشاهده کنید.

سعی کنید مقدار را چند بار در کنسول تغییر دهید و برنامه را مجددا راه اندازی کنید. راه اندازی ویژگی های جدید در برنامه خود با استفاده از Remote Config به همین سادگی است!

7. تبریک می گویم

تبریک می‌گوییم، شما با موفقیت یک برنامه Android با Firebase و Jetpack Compose ساخته‌اید!

شما Firebase Authentication، نظارت بر عملکرد، Remote Config و Cloud Firestore را به یک برنامه اندرویدی که کاملاً با Jetpack Compose برای رابط کاربری ساخته شده است اضافه کردید و آن را با معماری توصیه شده MVVM مطابقت دادید!

بیشتر خواندن

اسناد مرجع