Эта статья изначально была опубликована в блоге Codemagic.
В этом руководстве Годвин Александр Экайну покажет вам, как добавить аутентификацию Google для разных вкусов в ваше приложение Flutter. В этом уроке мы будем использовать VS Code.
- Введение
- Различные стадии
- Разработка
- Staging
- Производство
- Сборка нашего приложения Flutter
- Установка
- Структура файла
- Настройка Firebase для наших различных окружений
- Для iOS
- Настройка для реализации аутентификации Google
- Реализация аутентификации Google в нашем проекте Flutter
- События блока
- Создание блочного состояния
- Создание нашего блока
- Создание нашего пользовательского интерфейса
- Ресурсы
Введение
В этом уроке мы познакомимся с определениями различных этапов производства и их значением в разработке. Мы также рассмотрим, как использовать различные конфигурации Firebase в различных средах. Кроме того, мы узнаем о блочных виджетах и о том, что они делают при управлении состоянием в нашем Flutter-приложении.
Мы создадим проект Flutter для реализации аутентификации Google для различных вкусов, чтобы мы могли иметь разные сборки одного и того же приложения на наших устройствах для тестирования.
Различные стадии
В крупных технологических компаниях проекты обычно выполняются в три этапа: разработка, постановка и производство (хотя в разных компаниях эти этапы могут отличаться).
На этих различных этапах продукты тщательно тестируются для устранения ошибок, чтобы высококачественные программные продукты могли быть отправлены потребителю.
Разработка
На этом этапе в среде разработки происходит первоначальное создание пользовательского интерфейса и интеграция API и бэк-энда. Данные, с которыми вы работаете в этой среде, обычно представляют собой тестовый API или тестовую базу данных, и ни одна из этих данных не является реальной. Если после выпуска приложения необходимо добавить в него новые функции, они сначала внедряются из среды разработки.
На этом этапе проводится множество тестов кода, чтобы убедиться, что код полностью функционален и приложение работает эффективно. Тип тестирования, проводимого на этом этапе, называется unit testing
.
Staging
В среде постановки можно привлечь отдельных пользователей для тестирования приложения. Это может дать вам хорошее представление о том, как приложение будет работать после запуска, поскольку оно может взаимодействовать с реальными данными. Среда тестирования пытается имитировать производство, поэтому даже в случае серьезного недостатка и поломки системы производство не придется останавливать.
На этом этапе тестируются все миграции баз данных. Функции также тестируются для проверки наихудших сценариев при добавлении новых функций. Если новые функции ломаются при продвижении, ошибки обнаруживаются и исправляются.
Если вы пользовались WhatsApp Web, вам, скорее всего, предлагали присоединиться к программе тестирования, чтобы проверить новую функцию до того, как она станет официальной. Это пример того, что известно как бета-тестирование.
Производство
Это этап, на котором приложение запускается для опробования пользователями. Это самый важный этап для вашей компании или клиента. На этапе производства вы не хотите, чтобы пользователи заметили какие-либо серьезные ошибки, так как в итоге вы можете потерять пользователей. В идеале к этому моменту большинство серьезных ошибок в программном обеспечении будет устранено на предыдущих этапах.
Общий совет по разработке: не стоит сразу внедрять все функции программы. Приоритетнее держать проблемы под контролем и обеспечивать стабильность текущих функций, прежде чем внедрять новые.
Сборка нашего приложения Flutter
Для настройки вкусов в нашем приложении Flutter потребуется ручная настройка, что означает, что нам придется работать с множеством файлов в разных каталогах. Это может стать очень запутанным, но с помощью very_good_cli все можно сделать намного проще.
Установка
Для создания нового проекта Flutter мы будем использовать пакет Dart под названием very_good_cli. Этот пакет поможет нам создать стандартную структуру и настроить все окружения, необходимые в нашем приложении как для iOS, так и для Android.
Чтобы установить инструмент, введите в терминале следующую команду: dart pub global activate very_good_cli
.
После установки и активации very_good_cli мы можем использовать следующую команду для создания проекта Flutter: very_good create my_app --desc "My new Flutter app" --org "com.custom.org"
.
Замените содержимое вашего YAML-файла на следующее:
name: googlesigninwithflavor
description: A Very Good Project created by Very Good CLI.
version: 1.0.0+1
publish_to: none
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
bloc: ^8.0.3
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
intl: ^0.17.0
google_sign_in: ^5.2.4
equatable: ^2.0.3
firebase_core: ^1.14.0
firebase_auth: ^3.3.13
dev_dependencies:
bloc_test: ^9.0.3
flutter_test:
sdk: flutter
mocktail: ^0.3.0
very_good_analysis: ^2.4.0
flutter:
uses-material-design: true
generate: true
assets:
- asset/
Структура файла
lib
├─ app
│ ├─ bloc
│ │ ├─ google_sign_in_bloc.dart
│ │ ├─ google_sign_in_event.dart
│ │ └─ google_sign_in_state.dart
│ ├─ view
│ │ ├─ app.dart
│ │ └─ google_sign_in_view.dart
│ └─ app.dart
├─ dashboard
│ └─ dashboard.dart
├─ repository
│ └─ authentication_repository.dart
├─ bootstrap.dart
├─ generated_plugin_registrant.dart
├─ main_development.dart
├─ main_production.dart
└─ main_staging.dart
Когда мы создаем наш проект, мы видим три разных основных файла, названных в соответствии с тремя этапами производства. Каждый из этих файлов может иметь различные настройки, необходимые на данном этапе производства.
main_development.dart
main_production.dart
main_staging.dart
Мы можем запустить любой флавор, передав в терминал следующие аргументы:
# For Development
flutter run --flavor development --t lib/main_development.dart
# For Staging
flutter run --flavor development --t lib/main_staging.dart
# For Production
flutter run --flavor development --t lib/main_production.dart
Для Android файлом, с которым мы обычно работаем во время установки различных вкусов, является файл build.gradle
в нашей директории Android.
Для iOS файлы, с которыми мы будем работать, — это схемы Xcode. Однако нам не понадобится этого делать, поскольку они уже сгенерированы за нас very_good_cli.
Настройка Firebase для наших различных окружений
Недавно Firebase представила Firebase CLI, который сделал настройку проектов Firebase простой и удобной. Однако есть некоторые функции, которые он пока не поддерживает, например, аналитика и Google Sign-In. Поскольку мы будем использовать Google Sign-In, нам необходимо вручную настроить Firebase. Поэтому мы будем вручную настраивать наши проекты Firebase.
В нашей консоли Firebase мы создадим три различных проекта следующим образом:
-
flavor dev
-
flavor stg
-
flavor prod
.
При регистрации нашего проекта Flutter в Firebase мы должны добавить .dev
, .stg
или .prd
к имени нашего пакета Android.
Имя пакета можно найти в файле android/app/build.gradle
. Оно отображается как applicationId
, как показано ниже.
defaultConfig {
applicationId "com.example.verygoodcore.googlesigninwithflavor"
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationIdSuffix ""
manifestPlaceholders = [appName: "Googlesigninwithflavor"]
}
staging {
dimension "default"
applicationIdSuffix ".stg"
manifestPlaceholders = [appName: "[STG] Googlesigninwithflavor"]
}
development {
dimension "default"
applicationIdSuffix ".dev"
manifestPlaceholders = [appName: "[DEV] Googlesigninwithflavor"]
}
}
Для iOS
При регистрации для iOS нам также необходимо ввести правильный идентификатор пакета. Однако в Xcode может быть трудно ориентироваться, если у вас нет опыта работы с ним. Мы можем найти идентификатор пакета, выполнив следующие действия:
-
Откройте Xcode
-
Нажмите на
Open a project or file
. -
Перейдите к своему проекту Flutter и откройте каталог iOS. Выберите директорию
Runner.xcworkspace
. -
Далее нажмите на выпадающий список Runner. На вкладке General View выберите
Build Settings
, и мы найдем наш пакет приложений прямо там.
Мы повторим эти шаги для всех наших проектов Firebase. После регистрации мы можем загрузить файл google-services.json
для Android и GoogleService-Info.plist
для iOS.
Файлы google-services.json
будут перемещены в android/app/src/{перспективная среда}
. Для iOS мы создадим новый каталог config, содержащий подкаталоги наших окружений, и добавим GoogleService-Info.plist
в различные окружения. Мы добавим этот файл в Runner
в Xcode. Прочитайте это руководство по Firebase для получения дополнительной информации.
Настройка для реализации аутентификации Google
Чтобы использовать аутентификацию Google в нашем приложении, нам нужно включить Google Provider, выполнив следующие шаги. Мы будем включать Google Provider в нашей среде разработки.
-
Перейдите в Firebase. В этом руководстве мы начнем с проекта разработки.
-
На главной панели навигации выберите Аутентификация. Вы должны увидеть следующее:
-
Далее нажмите на
Set up sign-in method
. Отобразится список провайдеров. Выберите Google Sign-In, после чего вы увидите следующее: -
Включите
Enable
и добавьте электронную почту поддержки для проекта, как показано на изображении ниже. Затем сохраните настройки. -
На панели навигации нажмите на значок настроек и выберите
Настройки проекта
из выпадающего списка. Затем прокрутите страницу в самый низ. Нам нужно добавитьSHA-1 ключ
иSHA-256 ключ
из нашего проекта. -
Чтобы добавить ключи SHA или отпечатки пальцев, мы вернемся к нашему проекту, щелкнем правой кнопкой мыши на папке Android и нажмем
Открыть в интегрированном терминале
. Это должно открыть для нас новый терминал в нашей среде VS Code. -
В терминале используйте команду
./gradlew signingReport
для получения ключей. После выполнения этой команды мы должны получить различные ключи подписи из-за нескольких окружений. Используйте отладочные ключи SHA-1 в терминале. -
Альтернативный вариант: В терминале вашего редактора кода вы можете изменить каталог на папку Android и выполнить команду.
-
Нажмите кнопку сохранения и загрузите обновленный файл
google-services.json
. Замените файлgoogle-services.json
в вашей среде разработки. В нашем случае мы будем добавлять его в среду разработки.
Примечание: Ключ SHA-1 необходим Firebase для правильной работы Google Sign-In.
Мы только что включили аутентификацию Google! Мы реализуем ее в следующем разделе.
Реализация аутентификации Google в нашем проекте Flutter
Для управления состояниями мы будем использовать Bloc. Bloc — это менеджер состояний, добавленный very_good_cli
.
Создание репозитория
Репозиторий — это как сервис, который обслуживает наш блок с данными, которые мы должны отправлять в наш слой пользовательского интерфейса. Репозиторий отвечает за выполнение прямых вызовов API по запросу блока. Мы реализуем наш репозиторий следующим образом:
import 'dart:developer';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthenticationRepository {
Future<bool> signInWithGoogle() async {
try {
final user = GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (user != null) {
await GoogleSignIn().signOut();
}
final googleAuth = await user?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
return true;
} catch (e) {
log('An Error Occurred $e');
return false;
}
}
Future<void> handleSignOut() => GoogleSignIn().disconnect();
// Future<void> signOut() async {
// final _googleSignIn = GoogleSignIn();
// _googleSignIn.disconnect();
// }
}
События блока
Для нашего проекта нам понадобятся два события, GoogleSignInRequested
и GoogleSignOutRequested
. Мы можем реализовать это следующим образом:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInEvent extends Equatable {
const GoogleSignInEvent();
@override
List<Object> get props => [];
}
class GoogleSignInRequested extends GoogleSignInEvent {}
class GoogleSignOutRequested extends GoogleSignInEvent {}
Создание блочного состояния
Нам также понадобится два состояния — одно для случая, когда пользователь Authenticated
и другое для случая, когда пользователь UnAuthenticated
:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInState extends Equatable {
@override
List<Object?> get props => [];
}
class UnAuthenticated extends GoogleSignInState {}
class Authenticated extends GoogleSignInState {}
Создание нашего блока
Наш блок будет отображать два состояния в пользовательском интерфейсе: Authenticated
, когда пользователь вошел в систему, и UnAuthenticated
, когда пользователь вышел из приборной панели.
Мы реализуем это следующим образом:
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:googlesigninwithflavor/repository/authentication_repository.dart';
part 'google_sign_in_event.dart';
part 'google_sign_in_state.dart';
class GoogleSignInBloc extends Bloc<GoogleSignInEvent, GoogleSignInState> {
GoogleSignInBloc({required this.authenticationRepository})
: super(UnAuthenticated()) {
on<GoogleSignInRequested>(_onGoogleSignInPressed);
on<GoogleSignOutRequested>(_onGoogleSignOutPressed);
}
final AuthenticationRepository authenticationRepository;
Future<void> _onGoogleSignInPressed(
GoogleSignInRequested event,
Emitter<GoogleSignInState> emit,
) async {
final response = await authenticationRepository.signInWithGoogle();
if (response) {
emit(Authenticated());
}
}
void _onGoogleSignOutPressed(
GoogleSignOutRequested event,
Emitter<GoogleSignInState> emit,
) {
authenticationRepository.handleSignOut();
emit(UnAuthenticated());
}
}
Создание нашего пользовательского интерфейса
Наш класс app.dart
будет отображать наш домашний экран следующим образом:
import 'package:flutter/material.dart';
import 'package:googlesigninwithflavor/app/view/google_sign_in_view.dart';
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: const AppBarTheme(color: Color(0xFF13B9FF)),
colorScheme: ColorScheme.fromSwatch(
accentColor: const Color(0xFF13B9FF),
),
),
home: const GoogleSignInView(),
);
}
}
google_sign_in_view.dart
будет содержать реализацию для нашего домашнего экрана и кнопку входа.
class GoogleSignInView extends StatelessWidget {
const GoogleSignInView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: Scaffold(
appBar: AppBar(
title: const Text('Sign In With Google'),
),
body: const ShowSignInButton(),
),
),
);
}
}
В приведенном выше коде мы использовали виджет RepositoryProvider
для создания экземпляра нашего хранилища и дочернего элемента, который даст нам доступ к хранилищу через RepositoryProvider.of(context)
.
Мы также использовали виджет BlocProvider
для создания экземпляра нашего Bloc
, чтобы к нему могли обращаться виджеты поддерева и дочерних элементов.
Далее мы будем использовать блок в наших дочерних виджетах следующим образом:
class ShowSignInButton extends StatelessWidget {
const ShowSignInButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is Authenticated) {
Navigator.push<Type>(
context,
MaterialPageRoute(builder: (_) => const DashBoard()),
);
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
'asset/google2.png',
height: 60,
),
),
ElevatedButton(
onPressed: () {
context.read<GoogleSignInBloc>().add(GoogleSignInRequested());
},
child: const Text('Sign In With Google'),
),
],
),
);
}
}
Здесь мы использовали BlocListner
для перехода на другой экран на основе состояния, излучаемого блоком.
Мы также передали событие GoogleSignInRequested
нашей ElevatedButton
, поэтому, когда пользователь нажимает кнопку для входа в Google, событие передается блоку, и делается запрос к API GoogleSignIn
.
Давайте также реализуем экран приборной панели для отображения данных аутентифицированного пользователя. Чтобы реализовать это, нам нужно будет вызвать экземпляр Firebase Auth для доступа к данным текущего пользователя. Мы также создадим кнопку выхода, которая вернет пользователя на экран входа в систему с помощью виджета BlocListner
:
class DashBoard extends StatelessWidget {
const DashBoard({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: DashBoardDetails(),
),
);
}
}
class DashBoardDetails extends StatelessWidget {
DashBoardDetails({
Key? key,
}) : super(key: key);
final user = FirebaseAuth.instance.currentUser!;
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is UnAuthenticated) {
Navigator.of(context).pushAndRemoveUntil<Type>(
MaterialPageRoute(builder: (context) => const GoogleSignInView()),
(route) => false,
);
}
},
child: Scaffold(
appBar: AppBar(
title: const Text('Very Good Codemagic'),
),
body: BlocBuilder<GoogleSignInBloc, GoogleSignInState>(
builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Center(
child: Text('Welcome to your Dashboard'),
),
Text('${user.displayName}'),
if (user.photoURL != null)
Image.network('${user.photoURL}')
else
Container(),
ElevatedButton(
onPressed: () {
context
.read<GoogleSignInBloc>()
.add(GoogleSignOutRequested());
},
child: const Text('Sign Out'),
)
],
);
},
),
),
);
}
}
Ура! 🎉 Мы только что успешно создали аутентификацию Google Sign-In для наших сред разработки, постановки и производства.
Ресурсы
- Узнайте, как вручную использовать Flutter flavors
- Flutter готов к работе
- very_good_cli
- GitHub