Logowanie do Androida za pomocą Firebase

To ćwiczenie programowania jest częścią kursu „Android dla zaawansowanych w Kotlinie”. Korzyści z tego kursu będą dla Ciebie najbardziej wartościowe, jeśli wykonasz je w sekwencjach ćwiczeń z programowania, ale nie jest to obowiązkowe. Wszystkie ćwiczenia z kursu są wymienione na stronie Zaawansowane ćwiczenia z programowania na Androida w Kotlin.

Wstęp

Tworzenie aplikacji na Androida daje użytkownikom wiele korzyści z logowania. Jeśli zezwolisz użytkownikom na tworzenie tożsamości w aplikacji, zyskasz więcej możliwości interakcji z nią.

Dzięki spersonalizowanym kontom użytkownicy mogą dostosować sposób korzystania z aplikacji, nawiązać kontakt z innymi użytkownikami oraz zachować swoje dane i przenieść je, jeśli używają aplikacji na innym urządzeniu (np. w przeglądarce lub na nowym telefonie).

Z tego modułu dowiesz się, jak obsługiwać logowanie się w aplikacji przy użyciu biblioteki FirebaseUI. Biblioteka FirebaseUI ułatwia m.in. tworzenie aplikacji i przepływ pracy związanych z zarządzaniem kontami użytkowników.

Co musisz wiedzieć

  • Podstawy tworzenia aplikacji na Androida
  • LiveData i ModelModel

Czego się nauczysz

  • Jak dodać Firebase do projektu
  • Jak obsługiwać logowanie do aplikacji na Androida
  • Jak sprawdzić obecny stan uwierzytelniania aplikacji
  • Jak wylogować użytkowników

Jakie zadania wykonasz:

  • Aby zintegrować Firebase z aplikacją, użyj konsoli Firebase.
  • Zaimplementuj funkcję logowania.
  • Dodaj dostosowania w aplikacji dla zalogowanych użytkowników.
  • Wdrażanie wylogowania użytkowników.

Więcej informacji o LiveData i ViewModel

W przypadku tego ćwiczenia z programowania musisz znać podstawy LiveData i ViewModel. Przeczytaj też omówienie LiveData i ViewModel, jeśli chcesz zapoznać się z tymi zagadnieniami.

Możesz też zapoznać się z kursem Tworzenie aplikacji na Androida z Kotlin, by poznać podstawowe tematy związane z Androidem, które znajdziesz podczas tego ćwiczenia. Ten kurs jest dostępny w ramach kursu Udacity i ćwiczeń z programowania.

W tym ćwiczeniu utworzysz aplikację, która będzie pokazywać zabawne fakty na temat Androida. Co ważniejsze, aplikacja będzie miała przycisk Login/Wyloguj. Gdy użytkownik zaloguje się w aplikacji, wszystkie wyświetlane informacje o Androidzie będą zawierać powitanie dla użytkownika, co umożliwia dodanie personalizacji.

Pobierz przykładową aplikację:

Pobierz aplikację Zip

... lub skopiuj repozytorium GitHub z wiersza poleceń, używając poniższego polecenia, i przejdź do gałęzi start repozytorium:

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

Ważne: ponieważ będziesz integrować aplikacje tak, aby korzystały z Firebase, aplikacja wstępna wymaga pewnej konfiguracji, aby mogła zostać utworzona i uruchomiona. Zrobisz to w następnym kroku ćwiczenia.

Krok 1. Utwórz projekt Firebase

Zanim dodasz Firebase do swojej aplikacji na Androida, musisz utworzyć projekt Firebase i połączyć się z aplikacją na Androida.

  1. W konsoli Firebase kliknij Dodaj projekt.
  2. Wybierz lub wpisz nazwę projektu. Możesz nadać projektowi dowolną nazwę, ale postaraj się wybrać nazwę zgodną z aplikacją, którą tworzysz.
  3. Kliknij Dalej.
  4. Możesz pominąć konfigurowanie Google Analytics i wybrać opcję Nie teraz.
  5. Kliknij Utwórz projekt, aby zakończyć konfigurowanie projektu Firebase.

Krok 2. Zarejestruj aplikację w Firebase

Po utworzeniu projektu Firebase możesz dodać do niego aplikację na Androida.

  1. Na środku strony podsumowania projektu w konsoli Firebase kliknij ikonę Androida, aby uruchomić przepływ konfiguracji.
  2. Wpisz identyfikator aplikacjiaplikacji w polu nazwa pakietu na Androida. Wpisz identyfikator, którego używa Twoja aplikacja, ponieważ nie możesz jej dodać ani zmienić po zarejestrowaniu aplikacji w projekcie Firebase.
  1. Identyfikator aplikacji jest czasem 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 podpisania aplikacji. Możesz wygenerować ten klucz, wpisując następujące polecenie w terminalu wiersza poleceń:
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Kliknij Zarejestruj aplikację.

Krok 3. Dodaj plik konfiguracji Firebase do projektu

Dodaj do aplikacji plik konfiguracji Firebase na Androida:

  1. Kliknij Pobierz google-services.json, aby uzyskać plik konfiguracyjny Firebase na Androida (google-services.json).
  • W każdej chwili możesz ponownie pobrać plik konfiguracyjny Firebase na Androida.
  • Upewnij się, że plik konfiguracji nie zawiera dodatkowych znaków i powinien mieć tylko nazwę google-services.json.
  1. Przenieś plik konfiguracyjny do katalogu modułu (na poziomie aplikacji) aplikacji.

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

  1. Aby włączyć usługi Firebase w aplikacji, dodaj wtyczkę google-services do plików Gradle.
  1. W pliku Gradle na poziomie projektu (build.gradle) dodaj reguły, by uwzględnić wtyczkę Google Services. Sprawdź też, czy masz repozytorium 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 wiersz na dole pliku.

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ść z Firebase

W ramach tych ćwiczeń głównym celem integracji Firebase jest tworzenie kont użytkowników i zarządzanie nimi. Aby to zrobić, musisz dodać bibliotekę Firebase umożliwiającą implementację logowania.

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

app/build.gradle:

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Zsynchronizuj swój projekt z plikami Gradle, aby mieć pewność, że wszystkie zależności są dostępne dla aplikacji. Jeśli nie pojawi się taka prośba, wybierz File > Sync Project with Gradle Files w menu Android Studio lub na pasku narzędzi.

Krok 5. Uruchom aplikację i sprawdź kod

  1. Uruchom aplikację w emulatorze lub na fizycznym urządzeniu, aby upewnić się, że środowisko zostało skonfigurowane tak, by można było rozpocząć programowanie.

Jeśli wszystko się uda, na ekranie głównym powinien wyświetlić się ciekawostka dotycząca Androida i przycisk logowania w lewym górnym rogu. Naciśnięcie przycisku logowania jeszcze nic nie robi.

Ogólnie rzecz biorąc, jest to aplikacja z jedną aktywnością z wieloma fragmentami. MainFragment zawiera wszystkie elementy interfejsu, które widzisz na ekranie poniżej. (Będziesz ćwiczyć LoginFragment i SettingsFragment podczas kolejnego kursu).

  1. Zapoznaj się z tym kodem. Zwróć uwagę na te kwestie:
  • FirebaseUserLiveData to klasa, którą wdrożysz, aby obserwować bieżącego użytkownika Firebase powiązanego z aplikacją. Wykorzystasz instancję FirebaseAuth jako punkt wejścia, aby uzyskać te informacje o użytkowniku w późniejszym kroku.
  • MainFragment remisuje z LoginViewModel. LoginViewModel to klasa, którą wdrożysz, aby użyć zmiennej FirebaseUserLiveData do utworzenia zmiennej authenticationState. Korzystając z tej zmiennej authenticationState, MainFragment może następnie zauważyć wartość, aby odpowiednio zaktualizować interfejs użytkownika.

W tym kroku skonfigurujesz w konsoli Firebase metody uwierzytelniania, które ma obsługiwać Twoja aplikacja. W ramach tego ćwiczenia skupisz się na umożliwieniu użytkownikom logowania się przy użyciu podanego przez nich adresu e-mail lub konta Google.

  1. Otwórz konsolę Firebase. (Uwaga: jeśli nadal korzystasz z procesu dodawania Firebase, kliknij X w lewym górnym rogu, aby wrócić do konsoli.
  2. Wybierz projekt, jeśli jeszcze nie jesteś w jego projekcie.
  3. W menu po lewej stronie wybierz Developer > Authentication (Rozwijanie uwierzytelniania).

  1. Wybierz kartę Metoda logowania na górnym pasku nawigacyjnym.

  1. Kliknij wiersz E-mail / Hasło.
  2. W wyskakującym okienku włącz przełącznik Włączony i kliknij Zapisz.
  3. Kliknij też wiersz Google.
  4. Kliknij przełącznik Włączony, wpisz adres e-mail pomocy dla projektu i kliknij Zapisz.

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

  1. Otwórz aplikację MainFragment.kt.
  2. Spójrz na układ MainFragment i auth_button. Obecnie nie jest skonfigurowana do obsługi danych wejściowych użytkownika.
  3. W aplikacji onViewCreated(), dodaj: onClickListener do: auth_button, by zadzwonić pod numer launchSignInFlow().

GłównyFragment.kt

binding.authButton.setOnClickListener { launchSignInFlow() }
  1. Znajdź metodę launchSignInFlow() w MainFragment.kt. Obecnie zawiera TODO.
  2. Wykonaj podaną niżej funkcję launchSignInFlow().

GłównyFragment.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
   )
}

Dzięki temu mogą rejestrować się i logować przy użyciu adresu e-mail lub konta Google. Jeśli użytkownik zdecyduje się zarejestrować za pomocą swojego adresu e-mail, utworzona przez niego kombinacja adresu e-mail i hasła jest unikalna dla Twojej aplikacji. Będzie on mógł logować się do Twojej aplikacji za pomocą kombinacji adresu e-mail i hasła, ale nie oznacza to, że będą mogli logować się do dowolnej innej aplikacji obsługiwanej przez Firebase za pomocą tych samych danych logowania.

  1. W usłudze MainFragment.kt możesz sprawdzić wynik logowania, stosując metodę onActivityResult(), jak pokazano poniżej. Rozpoczęłeś proces logowania w SIGN_IN_REQUEST_CODE, więc możesz też odsłuchać przebieg procesu logowania, filtrując, gdy SIGN_IN_REQUEST_CODE zostanie zwrócony do onActivityResult(). Zacznij od dodania do instrukcji logowania informacji o tym, czy użytkownik zalogował się prawidłowo.

GłównyFragment.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}")
       }
   }
}

Twoja aplikacja powinna już obsługiwać rejestrację i logowanie użytkowników.

  1. Uruchom aplikację i sprawdź, czy dotknięcie przycisku Login (Zaloguj się) powoduje wyświetlenie ekranu logowania.
  2. Możesz teraz logować się za pomocą adresu e-mail i hasła lub konta Google.
  3. Po zalogowaniu się nic się nie zmieni (w następnym kroku wdrożysz interfejs użytkownika). Jeśli jednak wszystko działa prawidłowo, po zakończeniu procesu rejestracji powinien pojawić się komunikat Successfully signed in user ${your name}!.
  4. Możesz też otworzyć konsolę Firebase i przejść do sekcji Programowanie > Uwierzytelnianie > Użytkownicy, aby sprawdzić, czy aplikacja ma teraz jednego zarejestrowanego użytkownika.
  5. Pamiętaj, że gdy użytkownicy tworzą konto do Twojej aplikacji, jest ono powiązane tylko z Twoją aplikacją, a nie z żadną aplikacją korzystającą z Firebase do obsługi logowania.

W tym zadaniu wdrożysz aktualizowanie interfejsu na podstawie stanu uwierzytelniania. Gdy użytkownik jest zalogowany, możesz spersonalizować jego ekran główny, wyświetlając jego nazwę. Zaktualizujesz też przycisk Zaloguj, gdy będzie zalogowany(-a) jako Wyloguj.

  1. Otwórz zajęcia FirebaseUserLiveData.kt, które zostały już dla Ciebie utworzone. Najpierw musisz udostępnić w innej aplikacji informacje o tym, kiedy użytkownicy są zalogowani lub wylogowani. Klasa nie może jednak nic zrobić, ponieważ wartość elementu LiveData nie jest aktualizowana.
  2. Ponieważ używasz biblioteki FirebaseAuth, możesz słuchać zmian dotyczących zalogowanego użytkownika za pomocą wywołania zwrotnego FirebaseUser.AuthStateListener, które znajdziesz w bibliotece FirebaseUI. To wywołanie zwrotne jest wywoływane za każdym razem, gdy użytkownik się zaloguje lub wyloguje z Twojej aplikacji.
  3. Zwróć uwagę, że FirebaseUserLiveData.kt określa zmienną authStateListener. Użyjesz tej zmiennej do przechowywania wartości właściwości LiveData. Zmienna authStateListener została utworzona, by prawidłowo rozpoczynać i zatrzymywać słuchanie zmian w stanie uwierzytelniania na podstawie stanu aplikacji. Jeśli na przykład użytkownik umieści aplikację w tle, aplikacja powinna przestać nasłuchiwać zmian w stanie uwierzytelniania, aby zapobiec ewentualnym wyciekom pamięci.
  4. Zaktualizuj wartość authStateListener, by wartość FirebaseUserLiveData odpowiadała wartości bieżącego użytkownika Firebase.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Otwórz aplikację LoginViewModel.kt.
  2. W LoginViewModel.kt utwórz zmienną authenticationState na podstawie właśnie wdrożonego obiektu FirebaseUserLiveData. Po utworzeniu tej zmiennej authenticationState inne klasy mogą teraz wysyłać zapytanie o to, czy użytkownik jest zalogowany za pomocą LoginViewModel.

LoginViewModel.kt,

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Otwórz: MainFragment.kt.
  2. W przeglądarce MainFragment.ktobserveAuthenticationState() możesz użyć zmiennej authenticationState dodanej przed chwilą w LoginViewModel i odpowiednio zmienić interfejs. W przypadku zalogowanych użytkowników authButton powinien wyświetlać się Wyloguj.

GłównyFragment.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ć komunikat powitalny, używając funkcji getFactWithPersonalization() dostępnej w MainFragment.

GłównyFragment.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 powinien wyświetlić Login i zalogować się, a następnie kliknąć ekran logowania. Wiadomość nie powinna też być personalizowana.

GłównyFragment.kt

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

Po wykonaniu wszystkich kroków ostateczna metoda observeAuthenticationState() powinna wyglądać podobnie do poniższego kodu.

GłównyFragment.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 być aktualizowany w zależności od tego, czy użytkownik jest zalogowany. Jeśli wszystko działa prawidłowo i jesteś zalogowany, ekran główny nie tylko powinien wyświetlić komunikat o Androidzie, ale też zawierać Twoje imię i nazwisko. Przycisk Login (Zaloguj się) powinien teraz pokazywać Wyloguj.

W tym zadaniu wdrożysz funkcję wylogowania.

Ponieważ aplikacja umożliwia logowanie, użytkownicy powinni mieć możliwość wylogowania się. Oto przykład wylogowywania użytkownika z jednym wierszem kodu:

AuthUI.getInstance().signOut(requireContext())
  1. Otwórz aplikację MainFragment.kt.
  2. W sekcji MainFragment.ktobserveAuthenticationState() dodaj logi wylogowania, aby auth_button działał prawidłowo, gdy zalogowany użytkownik jest zalogowany. Końcowy wynik metody wygląda tak:

GłównyFragment.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 jest wylogowany, a jego stan zmieni się na Logowanie.

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

Dzięki niemu dowiesz się:

  • Jak dodać do projektu Firebase z użyciem niezbędnych zależności w pliku Gradle i skonfigurować projekt w konsoli Firebase.
  • Jak zaimplementować logowanie się w aplikacji za pomocą biblioteki FirebaseUI i określić, jak chcesz zezwolić użytkownikom na logowanie się. Pamiętaj, że każde konto utworzone przez użytkownika w Twojej aplikacji jest związane tylko z Twoją aplikacją i nie jest wspólne dla wszystkich aplikacji, które korzystają z Firebase do obsługi logowania.
  • Jak sprawdzić obecny stan uwierzytelniania aplikacji za pomocą LiveData.
  • Jak wylogować użytkowników.

Ćwiczenia z programowania zawierały podstawowe informacje o obsłudze logowania w aplikacji na Androida.

W ramach tych ćwiczeń zezwalałeś użytkownikom na rejestrowanie się i logowanie za pomocą ich adresów e-mail. W bibliotece Firebase możesz też obsługiwać inne metody uwierzytelniania, na przykład logowanie się przy użyciu numeru telefonu. Aby dowiedzieć się więcej o możliwościach biblioteki FirebaseUI i o tym, jak korzystać z innych jej funkcji, zapoznaj się z tymi zasobami:

Aby dowiedzieć się więcej o sprawdzonych metodach logowania, zapoznaj się z tymi materiałami:

Ćwiczenia z programowania:

Dokumentacja dla programistów Androida:

Materiały wideo:

Linki do innych ćwiczeń z programowania znajdziesz w kursie dotyczącym programowania na Androida dla zaawansowanych w Kotlin.