Logowanie na Androidzie za pomocą FirebaseUI

Te warsztaty są częścią kursu Zaawansowany Android w Kotlinie. Najwięcej korzyści z tego kursu uzyskasz, jeśli przejdziesz wszystkie ćwiczenia w kolejności, ale nie jest to obowiązkowe. Wszystkie ćwiczenia z tego kursu znajdziesz na stronie docelowej ćwiczeń z zaawansowanego Androida w Kotlinie.

Wprowadzenie

Obsługa logowania użytkowników w aplikacji na Androida przynosi wiele korzyści. Umożliwiając użytkownikom tworzenie tożsamości w aplikacji, możesz zapewnić im więcej sposobów na korzystanie z niej.

Dzięki spersonalizowanym kontom użytkownicy mogą dostosowywać działanie aplikacji, wchodzić w interakcje z innymi użytkownikami oraz przechowywać i przenosić dane, jeśli korzystają z aplikacji na innym urządzeniu (np. w internecie lub na nowym telefonie).

Z tego przewodnika dowiesz się, jak obsługiwać logowanie w aplikacji za pomocą biblioteki FirebaseUI. Biblioteka FirebaseUI ułatwia deweloperom tworzenie procesu logowania i zarządzanie kontami użytkowników.

Co warto wiedzieć

  • Podstawy tworzenia aplikacji na Androida
  • LiveData i ViewModel

Czego się nauczysz

  • Jak dodać Firebase do projektu
  • Jak obsługiwać logowanie w aplikacji na Androida
  • Jak sprawdzić bieżący stan uwierzytelniania aplikacji
  • Wylogowywanie użytkowników

Jakie zadania wykonasz

  • Użyj konsoli Firebase, aby zintegrować Firebase z aplikacją.
  • Wdróż funkcję logowania.
  • Dodawanie w aplikacji dostosowań dla zalogowanych użytkowników.
  • Wdrażanie wylogowywania użytkowników.

Więcej informacji o klasach LiveData i ViewModel

W przypadku aplikacji w tym ćwiczeniu musisz mieć podstawową wiedzę o klasach LiveData i ViewModel. Jeśli chcesz poznać te koncepcje, przeczytaj omówienia LiveData i ViewModel.

Możesz też przejść kurs Tworzenie aplikacji na Androida w Kotlinie, aby poznać podstawowe zagadnienia związane z Androidem, które pojawią się w tym ćwiczeniu. Ten kurs jest dostępny zarówno jako kurs Udacity, jak i kurs codelabs.

W tym ćwiczeniu z programowania utworzysz aplikację, która wyświetla ciekawe fakty o Androidzie. Co ważniejsze, aplikacja będzie miała przycisk Zaloguj się/Wyloguj się. Gdy użytkownik jest zalogowany w aplikacji, każdy wyświetlany fakt dotyczący Androida będzie zawierać powitanie, które zwiększy poziom personalizacji.

Pobierz przykładową aplikację. Możesz to zrobić na 2 sposoby:

Pobierz plik ZIP

… lub sklonuj repozytorium GitHub z wiersza poleceń, używając tego polecenia, i przejdź do gałęzi start repozytorium:

$  git clone https://github.com/googlecodelabs/android-kotlin-login

Ważne: ponieważ będziesz integrować aplikację z Firebase, aplikacja startowa wymaga pewnej konfiguracji, aby można było ją skompilować i uruchomić. Zrobisz to w następnym kroku tego laboratorium.

Krok 1. Utwórz projekt Firebase

Zanim dodasz Firebase do aplikacji na Androida, musisz utworzyć projekt Firebase, aby połączyć go z tą aplikacją.

  1. W konsoli Firebase kliknij Dodaj projekt.
  2. Wybierz lub wpisz nazwę projektu. Nazwa projektu może być dowolna, ale warto wybrać taką, która jest związana z tworzoną aplikacją.
  3. Kliknij Dalej.
  4. Możesz pominąć konfigurowanie Google Analytics i wybrać opcję Nie teraz.
  5. Aby zakończyć konfigurowanie projektu Firebase, kliknij Utwórz projekt.

Krok 2. Zarejestruj aplikację w Firebase

Mając projekt Firebase, możesz dodać do niego swoją aplikację na Androida.

  1. W centrum strony „Opis” projektu w konsoli Firebase kliknij ikonę Android, aby uruchomić proces konfiguracji.
  2. Wpisz identyfikator aplikacji w polu Nazwa pakietu na Androida. Pamiętaj, aby wpisać identyfikator używany przez aplikację, ponieważ po zarejestrowaniu aplikacji w projekcie Firebase nie możesz dodać ani zmodyfikować tej wartości.
  1. Identyfikator aplikacji jest czasami nazywany nazwą pakietu.
  2. Znajdź ten identyfikator aplikacji w pliku Gradle modułu (na poziomie aplikacji), zwykle app/build.gradle (przykładowy identyfikator: com.yourcompany.yourproject).
  3. Wpisz certyfikat SHA-1 do podpisywania aplikacji przed debugowaniem. Ten klucz możesz wygenerować, wpisując w terminalu wiersza poleceń to polecenie:
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Kliknij Zarejestruj aplikację.

Krok 3. Dodaj do projektu plik konfiguracji Firebase

Dodaj do aplikacji plik konfiguracyjny Firebase na Androida:

  1. Kliknij Pobierz google-services.json, aby pobrać plik konfiguracyjny Firebase na Androida (google-services.json).
  1. Przenieś plik konfiguracyjny do katalogu modułu (na poziomie aplikacji).

Krok 4. Skonfiguruj projekt na Androida, aby włączyć usługi Firebase

  1. Aby włączyć usługi Firebase w aplikacji, dodaj wtyczkę usług Google do plików Gradle.
  1. W pliku Gradle na poziomie głównym (poziomie projektu) (build.gradle) dodaj reguły, aby uwzględnić wtyczkę Usług Google. Sprawdź też, czy masz repozytorium Google Maven.

build.gradle

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath 'com.google.gms:google-services:4.3.0'  // Google Services plugin
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}
  1. W pliku Gradle modułu (na poziomie aplikacji) (zazwyczaj app/build.gradle) dodaj na końcu wiersz.

app/build.gradle

apply plugin: 'com.android.application'

android {
  // ...
}

// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin

Krok 4. Dodaj zależność Firebase

W tym laboratorium głównym powodem integracji Firebase jest możliwość tworzenia użytkowników i zarządzania nimi. W tym celu musisz dodać bibliotekę Firebase, która umożliwia wdrożenie logowania.

  1. Dodaj do pliku build.gradle (Module:app) tę zależność, aby móc używać pakietu SDK w aplikacji. Pakiet SDK firebase-auth umożliwia zarządzanie uwierzytelnionymi użytkownikami aplikacji.

app/build.gradle:

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Zsynchronizuj projekt z plikami Gradle, aby mieć pewność, że wszystkie zależności są dostępne dla aplikacji. Jeśli nie pojawi się odpowiedni komunikat, wybierz Plik > Synchronizuj projekt z plikami Gradle w Android Studio lub na pasku narzędzi.

Krok 5. Uruchom aplikację i sprawdź kod

  1. Uruchom aplikację w emulatorze lub na urządzeniu fizycznym, aby sprawdzić, czy środowisko zostało prawidłowo skonfigurowane i możesz rozpocząć tworzenie aplikacji.

Jeśli się uda, na ekranie głównym pojawi się ciekawy fakt o Androidzie oraz przycisk logowania w lewym górnym rogu. Kliknięcie przycisku logowania nie powoduje jeszcze żadnej reakcji.

Jest to aplikacja z jedną aktywnością i wieloma fragmentami. Element MainFragment zawiera wszystkie elementy interfejsu widoczne na ekranie poniżej. (W kolejnych ćwiczeniach z programowania będziesz pracować z LoginFragmentSettingsFragment).

  1. Zapoznaj się z kodem. Zwróć szczególną uwagę na te kwestie:
  • FirebaseUserLiveData to klasa, którą zaimplementujesz, aby obserwować bieżącego użytkownika Firebase powiązanego z aplikacją. W późniejszym kroku użyjesz instancji FirebaseAuth jako punktu wejścia, aby uzyskać informacje o tym użytkowniku.
  • Urządzenie MainFragment jest powiązane z urządzeniem LoginViewModel. LoginViewModel to klasa, którą zaimplementujesz, aby użyć FirebaseUserLiveData do utworzenia zmiennej authenticationState. Korzystając z tej zmiennej authenticationState, MainFragment może obserwować wartość, aby odpowiednio zaktualizować interfejs.

W tym kroku skonfigurujesz w konsoli Firebase metody uwierzytelniania, które mają być obsługiwane przez Twoją aplikację. W tym laboratorium skupisz się na umożliwieniu użytkownikom logowania się za pomocą podanego przez nich adresu e-mail lub konta Google.

  1. Otwórz konsolę Firebase. (Uwaga: jeśli nadal jesteś w procesie dodawania Firebase, kliknij X w lewym górnym rogu, aby wrócić do konsoli.
  2. Wybierz projekt, jeśli nie jesteś jeszcze w nim.
  3. Otwórz menu po lewej stronie i wybierz Tworzenie > Uwierzytelnianie .

  1. Na pasku nawigacyjnym u góry kliknij kartę Metoda logowania.

  1. Kliknij wiersz E-mail/hasło.
  2. W wyskakującym okienku ustaw przełącznik Włączono i kliknij Zapisz.
  3. Podobnie kliknij wiersz Google.
  4. Ustaw przełącznik Włączono, wpisz adres e-mail pomocy dotyczącej projektu i kliknij Zapisz.

W tym zadaniu zaimplementujesz funkcję logowania dla użytkowników.

  1. Otwórz pokój MainFragment.kt.
  2. W układzie MainFragment zwróć uwagę na auth_button. Obecnie nie jest skonfigurowany do obsługi danych wprowadzanych przez użytkowników.
  3. W onViewCreated(), dodaj onClickListener do auth_button, aby zadzwonić na numer launchSignInFlow().

MainFragment.kt

binding.authButton.setOnClickListener { launchSignInFlow() }
  1. Znajdź metodę launchSignInFlow() w MainFragment.kt. Obecnie zawiera TODO.
  2. Uzupełnij funkcję launchSignInFlow(), jak pokazano poniżej.

MainFragment.kt

private fun launchSignInFlow() {
   // Give users the option to sign in / register with their email or Google account.
   // If users choose to register with their email,
   // they will need to create a password as well.
   val providers = arrayListOf(
       AuthUI.IdpConfig.EmailBuilder().build(), AuthUI.IdpConfig.GoogleBuilder().build()

       // This is where you can provide more ways for users to register and 
       // sign in.
   )

   // Create and launch sign-in intent.
   // We listen to the response of this activity with the
   // SIGN_IN_REQUEST_CODE 
   startActivityForResult(
       AuthUI.getInstance()
           .createSignInIntentBuilder()
           .setAvailableProviders(providers)
           .build(),
       MainFragment.SIGN_IN_REQUEST_CODE
   )
}

Umożliwia to użytkownikom rejestrowanie się i logowanie przy użyciu adresu e-mail lub konta Google. Jeśli użytkownik zdecyduje się zarejestrować za pomocą adresu e-mail, utworzona przez niego kombinacja adresu e-mail i hasła będzie unikalna dla Twojej aplikacji. Oznacza to, że będzie mógł logować się w Twojej aplikacji za pomocą tej kombinacji, ale nie będzie mógł logować się w żadnej innej aplikacji obsługiwanej przez Firebase przy użyciu tych samych danych logowania.

  1. MainFragment.kt możesz nasłuchiwać wyniku procesu logowania, implementując metodę onActivityResult(), jak pokazano poniżej. Ponieważ proces logowania został rozpoczęty za pomocą SIGN_IN_REQUEST_CODE, możesz też odsłuchać jego wynik, filtrując moment, w którym SIGN_IN_REQUEST_CODE jest przekazywany z powrotem do onActivityResult(). Zacznij od dodania kilku instrukcji logowania, aby sprawdzić, czy użytkownik zalogował się prawidłowo.

MainFragment.kt

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   super.onActivityResult(requestCode, resultCode, data)
   if (requestCode == SIGN_IN_REQUEST_CODE) {
       val response = IdpResponse.fromResultIntent(data)
       if (resultCode == Activity.RESULT_OK) {
           // User successfully signed in
           Log.i(TAG, "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}!")
       } else {
           // Sign in failed. If response is null the user canceled the
           // sign-in flow using the back button. Otherwise check
           // response.getError().getErrorCode() and handle the error.
           Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
       }
   }
}

Aplikacja powinna teraz obsługiwać rejestrację i logowanie użytkowników.

  1. Uruchom aplikację i sprawdź, czy po kliknięciu przycisku Zaloguj się pojawia się ekran logowania.
  2. Możesz się teraz zalogować, podając adres e-mail i hasło lub używając konta Google.
  3. Po zalogowaniu interfejs się nie zmieni (zaktualizujesz go w następnym kroku), ale jeśli wszystko działa prawidłowo, po przejściu procesu rejestracji powinna się pojawić wiadomość w dzienniku Successfully signed in user ${your name}!.
  4. Możesz też otworzyć konsolę Firebase i kliknąć Tworzenie > Uwierzytelnianie > Użytkownicy, aby sprawdzić, czy aplikacja ma teraz 1 zarejestrowanego użytkownika.
  5. Pamiętaj, że gdy użytkownicy tworzą konto w Twojej aplikacji, jest ono powiązane tylko z nią, a nie z żadną inną aplikacją, która korzysta z Firebase do logowania.

W tym zadaniu zaimplementujesz aktualizowanie interfejsu na podstawie stanu uwierzytelniania. Gdy użytkownik jest zalogowany, możesz spersonalizować jego ekran główny, wyświetlając jego imię i nazwisko. Zaktualizujesz też przycisk Zaloguj się, aby po zalogowaniu użytkownika zmienić go na przycisk Wyloguj się.

  1. Otwórz klasę FirebaseUserLiveData.kt, która została już utworzona. Pierwszą rzeczą, którą musisz zrobić, jest zapewnienie innym klasom w aplikacji możliwości sprawdzenia, kiedy użytkownik się zalogował lub wylogował. Klasa nie robi jednak jeszcze nic, ponieważ wartość LiveData nie jest aktualizowana.
  2. Ponieważ używasz biblioteki FirebaseAuth, możesz nasłuchiwać zmian zalogowanego użytkownika za pomocą wywołania zwrotnego FirebaseUser.AuthStateListener, które jest zaimplementowane w bibliotece FirebaseUI. To wywołanie zwrotne jest wywoływane za każdym razem, gdy użytkownik loguje się w aplikacji lub z niej wylogowuje.
  3. Zwróć uwagę, że FirebaseUserLiveData.kt definiuje zmienną authStateListener. Ta zmienna będzie służyć do przechowywania wartości LiveData. Zmienna authStateListener została utworzona, aby umożliwić Ci prawidłowe rozpoczęcie i zakończenie nasłuchiwania zmian stanu uwierzytelniania w zależności od stanu aplikacji. Jeśli na przykład użytkownik przełączy aplikację w tryb tła, powinna ona przestać nasłuchiwać zmian stanu uwierzytelniania, aby zapobiec potencjalnym wyciekom pamięci.
  4. Zaktualizuj authStateListener, aby wartość FirebaseUserLiveData odpowiadała bieżącemu użytkownikowi Firebase.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Otwórz pokój LoginViewModel.kt.
  2. W LoginViewModel.kt utwórz zmienną authenticationState na podstawie obiektu FirebaseUserLiveData, który właśnie został wdrożony. Dzięki utworzeniu tej zmiennej authenticationState inne klasy mogą teraz sprawdzać, czy użytkownik jest zalogowany, za pomocą zmiennej LoginViewModel.

LoginViewModel.kt

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Otwórz aplikację MainFragment.kt.
  2. MainFragment.ktobserveAuthenticationState() możesz użyć zmiennej authenticationState, którą właśnie dodano w LoginViewModel, i odpowiednio zmienić interfejs. Jeśli użytkownik jest zalogowany, w miejscu authButton powinna się wyświetlać opcja Wyloguj.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }

                // TODO 2. If the user is logged in, 
                 // you can customize the welcome message they see by
                 // utilizing the getFactWithPersonalization() function provided

           }
           else -> {
               // TODO 3. Lastly, if there is no logged-in user, 
                // auth_button should display Login and
                //  launch the sign in screen when clicked.
           }
       }
   })
}
  1. Jeśli użytkownik jest zalogowany, możesz też dostosować wyświetlaną mu wiadomość powitalną za pomocą funkcji getFactWithPersonalization() dostępnej w MainFragment.

MainFragment.kt

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Jeśli nie ma zalogowanego użytkownika (gdy authenticationState ma wartość inną niż LoginViewModel.AuthenticationState.AUTHENTICATED), auth_button powinno wyświetlać Zaloguj się i po kliknięciu uruchamiać ekran logowania. Wyświetlana wiadomość nie powinna być też spersonalizowana.

MainFragment.kt

binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay

Po wykonaniu wszystkich czynności ostateczna metoda observeAuthenticationState() powinna wyglądać podobnie do kodu poniżej.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
        // TODO 1. Use the authenticationState variable you just added 
         // in LoginViewModel and change the UI accordingly.
       when (authenticationState) {
            // TODO 2.  If the user is logged in, 
             // you can customize the welcome message they see by
             // utilizing the getFactWithPersonalization() function provided
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }
           }
           else -> {
                // TODO 3. Lastly, if there is no logged-in user, 
                 // auth_button should display Login and
                 // launch the sign in screen when clicked.
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Uruchom aplikację. Interfejs powinien się zaktualizować w zależności od tego, czy użytkownik jest zalogowany. Jeśli wszystko działa prawidłowo i jesteś zalogowany(-a), na ekranie głównym powinna się teraz wyświetlać Twoja nazwa oraz ciekawostka o Androidzie. Przycisk Zaloguj się powinien teraz wyświetlać Wyloguj się.

W tym zadaniu zaimplementujesz funkcję wylogowywania.

Skoro aplikacja umożliwia użytkownikom logowanie się, powinna też pozwalać im na wylogowanie się. Oto przykład wylogowania użytkownika za pomocą tylko 1 wiersza kodu:

AuthUI.getInstance().signOut(requireContext())
  1. Otwórz pokój MainFragment.kt.
  2. MainFragment.ktobserveAuthenticationState() dodaj logikę wylogowywania, aby funkcja auth_button działała prawidłowo, gdy użytkownik jest zalogowany. Ostateczny wynik metody wygląda jak poniższy kod.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)

               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   AuthUI.getInstance().signOut(requireContext())
               }
           }
           else -> {
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Uruchom aplikację.
  2. Kliknij przycisk Wyloguj się i sprawdź, czy użytkownik został wylogowany, a stan przycisku zmienił się na Zaloguj się.

Ostateczną wersję gotowej aplikacji znajdziesz tutaj: https://github.com/googlecodelabs/android-kotlin-login.

Z tego przewodnika dowiedzieliśmy się:

  • Jak dodać Firebase do projektu, dodając niezbędne zależności w pliku Gradle i konfigurując projekt w konsoli Firebase.
  • Jak wdrożyć logowanie w aplikacji za pomocą biblioteki FirebaseUI i określić, w jaki sposób użytkownicy mają się logować. Pamiętaj, że każde konto utworzone przez użytkownika w Twojej aplikacji jest specyficzne tylko dla tej aplikacji i nie jest udostępniane wszystkim aplikacjom, które korzystają z Firebase do logowania.
  • Jak sprawdzić bieżący stan uwierzytelniania aplikacji za pomocą LiveData.
  • Jak wylogować użytkowników.

W tym samouczku omówiliśmy podstawy obsługi logowania w aplikacji na Androida.

W tym laboratorium użytkownicy mogli rejestrować się i logować przy użyciu adresu e-mail. Jednak dzięki bibliotece FirebaseUI możesz też obsługiwać inne metody uwierzytelniania, takie jak logowanie się przy użyciu numeru telefonu. Aby dowiedzieć się więcej o możliwościach biblioteki FirebaseUI i korzystaniu z innych funkcji, zapoznaj się z tymi materiałami:

Więcej informacji o sprawdzonych metodach dotyczących logowania znajdziesz w tych materiałach:

Codelabs:

Dokumentacja dla deweloperów aplikacji na Androida:

Materiały wideo:

Linki do innych ćwiczeń z tego kursu znajdziesz na stronie docelowej ćwiczeń z zaawansowanego Androida w Kotlinie.