Multi-flavored authentication in Flutter utilizing flutter_bloc


On this tutorial, Godwin Alexander Ekainu will present you tips on how to add Google authentication for various flavors in your Flutter utility. We can be utilizing VS Code on this tutorial.

Intro

On this tutorial, we are going to study the definitions of the totally different phases of manufacturing and their significance in improvement. We can even cowl tips on how to use totally different Firebase configurations in numerous environments. Moreover, we are going to study bloc widgets and what they do whereas managing our state in our Flutter utility.

We’ll create a Flutter mission to implement Google authentication for various flavors in order that we are able to have totally different builds of the identical utility on our gadgets for testing.

Totally different phases

In giant tech corporations, tasks are sometimes accomplished in three phases: improvement, staging, and manufacturing (although these phases may range from firm to firm).

In these totally different phases, merchandise are totally examined to cope with bugs in order that high-quality software program merchandise might be shipped to the buyer.

Growth

On this stage, the preliminary constructing of the UI and integration of the API and again finish are achieved within the improvement atmosphere. The information you’re employed with on this atmosphere is normally a take a look at API or take a look at database, and not one of the information is actual. If new options are to be added to the applying after launch, they’re first applied from the event atmosphere.

This stage includes loads of code assessments to make sure that the code is absolutely useful and the app performs effectively. The kind of testing carried out on this stage known as unit testing.

Staging

In a staging atmosphere, chosen customers might be introduced in to check the app. This may give you a good suggestion of how the app will work as soon as it goes stay, as it will possibly work together with actual information. The staging atmosphere tries to mimic manufacturing, so even when there’s a main flaw and the system breaks, manufacturing doesn’t must shut down.

All database migrations are examined at this stage. Options are additionally pushed to examine for worst-case situations when new options are added. If new options break when pushed, the bugs are discovered and glued.

When you’ve got used WhatsApp Internet, you’ve gotten seemingly been prompted with a request to hitch a take a look at program to check a brand new characteristic earlier than it’s made official. That is an instance of what’s generally known as beta testing.

Manufacturing

That is the stage through which the app goes stay for customers to check out. That is an important section in your firm or shopper. Within the manufacturing stage, you gained’t need customers to note any main bugs, as you may find yourself shedding customers. Ideally, a lot of the main bugs within the software program may have been handled within the earlier phases by this level.

Common improvement tip: You don’t must roll out the entire software program’s options directly. Prioritize protecting points in examine and making certain the present options are steady earlier than pushing out a brand new one.

Constructing our Flutter utility

Handbook configuration is required to arrange flavors in our Flutter utility, which suggests we must work with many recordsdata in numerous directories. This may turn out to be very complicated, however issues might be made lots simpler with the assistance of very_good_cli.

Setup

To create a brand new Flutter mission, we can be utilizing a Dart package deal known as very_good_cli. This package deal will assist us create a normal construction and arrange all of the environments we want in our utility for each iOS and Android.

To put in the instrument, enter the next command in your terminal: dart pub world activate very_good_cli

After putting in and activating very_good_cli, we are able to use the next command to create a Flutter mission: very_good create my_app --desc "My new Flutter app" --org "com.customized.org"

Exchange the content material of your YAML file with the next:

title: googlesigninwithflavor
description: A Very Good Challenge created by Very Good CLI.
model: 1.0.0+1
publish_to: none
atmosphere:
  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
  property:
    - asset/

File construction

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                  

After we create our mission, we see three totally different important recordsdata named in accordance with the three phases of manufacturing. Every of those recordsdata can have totally different setups as required at that individual stage of manufacturing.

main_development.dart              
main_production.dart               
main_staging.dart  

We will run any taste by passing the next arguments into our terminal:

# For Growth
flutter run --flavor improvement --t lib/main_development.dart
# For Staging
flutter run --flavor improvement --t lib/main_staging.dart
# For Manufacturing
flutter run --flavor improvement --t lib/main_production.dart

For Android, the file we normally cope with throughout setups for various flavors is the construct.gradle file in our Android listing.

For iOS, the recordsdata we are going to work with are Xcode schemes. Nevertheless, we gained’t want to do that since they’ve already been generated for us by very_good_cli.

Organising Firebase for our totally different environments

Just lately, Firebase launched the Firebase CLI, which has made configuring Firebase tasks simple and seamless. Nevertheless, there are some options it doesn’t assist but, like analytics and Google Signal-In. Since we can be utilizing Google Signal-In, we have to manually arrange Firebase. Subsequently, we’ll be manually organising our Firebase tasks.

In our Firebase console, we are going to create three totally different tasks as follows:

  • taste dev
  • taste stg
  • taste prod
    Multiple-flavor Firebase project

When registering our Flutter mission in Firebase, we have now so as to add .dev, .stg, or .prd to our Android package deal title.

You could find the package deal title in your android/app/construct.gradle file. It’s displayed because the applicationId, as proven under.

 defaultConfig {
        applicationId "com.instance.verygoodcore.googlesigninwithflavor"
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    flavorDimensions "default"
    productFlavors { 
        manufacturing {
            dimension "default"
            applicationIdSuffix ""
            manifestPlaceholders = [appName: "Googlesigninwithflavor"]
        }
        staging {
            dimension "default"
            applicationIdSuffix ".stg"
            manifestPlaceholders = [appName: "[STG] Googlesigninwithflavor"]
        }        
        improvement {
            dimension "default"
            applicationIdSuffix ".dev"
            manifestPlaceholders = [appName: "[DEV] Googlesigninwithflavor"]
        }
    }

For iOS

When registering for iOS, we additionally must enter the proper bundle ID. Nevertheless, Xcode might be tough to navigate in the event you don’t have prior expertise with it. We will discover the bundle ID by following these steps:

  • Open Xcode
    What you see when you open Xcode

  • Click on on Open a mission or file.

  • Go to your Flutter mission and open the iOS listing. Choose the Runner.xcworkspace listing.

  • Subsequent, click on on the Runner dropdown. Within the Common View tab, choose Construct Settings, and we are going to discover our app bundle proper there.

We’ll repeat these steps for all of our Firebase tasks. After registration, we are able to obtain the google-services.json file for Android and GoogleService-Information.plist for iOS.

The google-services.json recordsdata can be moved to android/app/src/{respective atmosphere}. For iOS, we are going to create a brand new config listing that has subdirectories of our environments and add GoogleService-Information.plist to the varied environments. We’ll add this file to the Runner in Xcode. Learn this Firebase information for extra data.

Setup to implement Google Authentication

To make use of Google authentication in our utility, we have to allow Google Supplier with the next steps.
We can be enabling Google Supplier in our improvement atmosphere.

  • Go to Firebase. On this tutorial, we are going to begin with the event mission.

  • In the primary navigation bar, choose Authentication. It’s best to see the next:
    Enabling authentication

  • Subsequent, click on on Arrange sign-in methodology. A listing of suppliers can be displayed. Choose Google Signal-In, after which it is best to see this:
    Google Sign-In

  • Toggle Allow on and add a assist e mail for the mission, as proven within the picture under. Then save your settings.
    Add project support email

  • Within the navigation bar, click on the settings icon and choose Challenge settings from the dropdown. Then scroll to the underside of the web page. We have to add a SHA-1 key and a SHA-256 key from our mission.

  • So as to add SHA keys or fingerprints, we’d return to our mission, right-click on the Android folder, and click on on Open in an built-in terminal. This could open a brand new terminal for us in our VS Code atmosphere.

  • In your terminal, use the command ./gradlew signingReport to get the keys. After working this command, we should always get numerous signing keys due to the a number of environments. Use the event debug SHA-1 keys in your terminal.

  • Various: In your code editor’s terminal, you possibly can change the listing to the Android folder and run the command.
    Fingerprints/SHA keys

  • Click on the save button and obtain the up to date google-services.json file. Exchange the google-services.json file in your improvement atmosphere. In our case, we can be including it to the event atmosphere.

Observe: The SHA-1 key is required by Firebase to make Google Signal-In work correctly.

We simply enabled Google authentication! We’ll implement it within the subsequent part.

Implementing Google Authentication in our Flutter mission

We can be utilizing bloc for our state administration. Bloc is the state supervisor added by very_good_cli.

Making a repository

The repository is sort of a service that serves our bloc with the info we have to ship to our UI layer. The repository is accountable for making direct API calls as requested by the bloc. We’ll implement our repository as follows:

import 'dart:developer';
import 'package deal:firebase_auth/firebase_auth.dart';
import 'package deal:google_sign_in/google_sign_in.dart';
class AuthenticationRepository {
  Future<bool> signInWithGoogle() async {
    strive {
      ultimate consumer = GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
      if (consumer != null) {
        await GoogleSignIn().signOut();
      }
      ultimate googleAuth = await consumer?.authentication;
      ultimate credential = GoogleAuthProvider.credential(
        accessToken: googleAuth?.accessToken,
        idToken: googleAuth?.idToken,
      );
      await FirebaseAuth.occasion.signInWithCredential(credential);
      return true;
    } catch (e) {
      log('An Error Occurred $e');
      return false;
    }
  }
  
  Future<void> handleSignOut() => GoogleSignIn().disconnect();
  // Future<void> signOut() async {
  //   ultimate _googleSignIn = GoogleSignIn();
  //   _googleSignIn.disconnect();
  // }
}

Bloc occasions

For our mission, we can be needing two occasions, GoogleSignInRequested and GoogleSignOutRequested. We will implement this with the next:

a part of 'google_sign_in_bloc.dart';
summary class GoogleSignInEvent extends Equatable {
  const GoogleSignInEvent();
  @override
  Checklist<Object> get props => [];
}
class GoogleSignInRequested extends GoogleSignInEvent {}
class GoogleSignOutRequested extends GoogleSignInEvent {}

Creating bloc state

We can even want two states — one for when the consumer is Authenticated and one other for when the consumer is UnAuthenticated:

a part of 'google_sign_in_bloc.dart';
summary class GoogleSignInState extends Equatable {
  @override
  Checklist<Object?> get props => [];
}
class UnAuthenticated extends GoogleSignInState {}
class Authenticated extends GoogleSignInState {}

Creating our bloc

Our bloc can be exposing two states to our UI: Authenticated when the consumer is logged in and UnAuthenticated when the consumer logs out from the dashboard.

We’ll implement this as follows:

import 'package deal:bloc/bloc.dart';
import 'package deal:equatable/equatable.dart';
import 'package deal:googlesigninwithflavor/repository/authentication_repository.dart';
half 'google_sign_in_event.dart';
half 'google_sign_in_state.dart';
class GoogleSignInBloc extends Bloc<GoogleSignInEvent, GoogleSignInState> {
  GoogleSignInBloc({required this.authenticationRepository})
      : tremendous(UnAuthenticated()) {
    on<GoogleSignInRequested>(_onGoogleSignInPressed);
    on<GoogleSignOutRequested>(_onGoogleSignOutPressed);
  }
  ultimate AuthenticationRepository authenticationRepository;
  Future<void> _onGoogleSignInPressed(
    GoogleSignInRequested occasion,
    Emitter<GoogleSignInState> emit,
  ) async {
    ultimate response = await authenticationRepository.signInWithGoogle();
    if (response) {
      emit(Authenticated());
    }
  }
  void _onGoogleSignOutPressed(
    GoogleSignOutRequested occasion,
    Emitter<GoogleSignInState> emit,
  ) {
    authenticationRepository.handleSignOut();
    emit(UnAuthenticated());
  }
}

Constructing our UI

Our app.dart class will render our homescreen like this:

import 'package deal:flutter/materials.dart';
import 'package deal:googlesigninwithflavor/app/view/google_sign_in_view.dart';
class App extends StatelessWidget {
  const App({Key? key}) : tremendous(key: key);
  @override
  Widget construct(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        appBarTheme: const AppBarTheme(coloration: Colour(0xFF13B9FF)),
        colorScheme: ColorScheme.fromSwatch(
          accentColor: const Colour(0xFF13B9FF),
        ),
      ),
      house: const GoogleSignInView(),
    );
  }
}

google_sign_in_view.dart will maintain the implementation for our house display and a sign-in button.

class GoogleSignInView extends StatelessWidget {
  const GoogleSignInView({Key? key}) : tremendous(key: key);
  @override
  Widget construct(BuildContext context) {
    return RepositoryProvider(
      create: (context) => AuthenticationRepository(),
      little one: BlocProvider(
        create: (context) => GoogleSignInBloc(
          authenticationRepository: RepositoryProvider.of(context),
        ),
        little one: Scaffold(
          appBar: AppBar(
            title: const Textual content('Signal In With Google'),
          ),
          physique: const ShowSignInButton(),
        ),
      ),
    );
  }
}

Within the code above, we used the RepositoryProvider widget to create an occasion of our repository and a baby that may give us entry to the repository through RepositoryProvider.of(context).

We additionally used the BlocProvider widget to create an occasion of our Bloc in order that it may be accessed by the subtree or the kids widgets.

Subsequent, we are going to use the bloc in our kids widgets like this:

class ShowSignInButton extends StatelessWidget {
  const ShowSignInButton({Key? key}) : tremendous(key: key);
  @override
  Widget construct(BuildContext context) {
    return BlocListener<GoogleSignInBloc, GoogleSignInState>(
      listener: (context, state) {
        if (state is Authenticated) {
          Navigator.push<Sort>(
            context,
            MaterialPageRoute(builder: (_) => const DashBoard()),
          );
        }
      },
      little one: Column(
        mainAxisAlignment: MainAxisAlignment.heart,
        kids: [
          Center(
            child: Image.asset(
              'asset/google2.png',
              height: 60,
            ),
          ),
          ElevatedButton(
            onPressed: () {
              context.read<GoogleSignInBloc>().add(GoogleSignInRequested());
            },
            child: const Text('Sign In With Google'),
          ),
        ],
      ),
    );
  }
}

Right here, we used the BlocListner to navigate to a unique display based mostly on the state emitted by the bloc.

We additionally handed the GoogleSignInRequested occasion to our ElevatedButton, so when a consumer clicks the button to register with Google, the occasion is handed to the bloc, and a request is made to the GoogleSignIn API.

Let’s additionally implement a dashboard display to show the main points of the authenticated consumer. To implement this, we might want to name the Firebase Auth occasion to entry the main points of the present consumer. We can even create a logout button that may take the consumer again to the sign-in display utilizing the BlocListner widget:

class DashBoard extends StatelessWidget {
  const DashBoard({Key? key}) : tremendous(key: key);
  @override
  Widget construct(BuildContext context) {
    return RepositoryProvider(
      create: (context) => AuthenticationRepository(),
      little one: BlocProvider(
        create: (context) => GoogleSignInBloc(
          authenticationRepository: RepositoryProvider.of(context),
        ),
        little one: DashBoardDetails(),
      ),
    );
  }
}
class DashBoardDetails extends StatelessWidget {
  DashBoardDetails({
    Key? key,
  }) : tremendous(key: key);
  ultimate consumer = FirebaseAuth.occasion.currentUser!;
  @override
  Widget construct(BuildContext context) {
    return BlocListener<GoogleSignInBloc, GoogleSignInState>(
      listener: (context, state) {
        if (state is UnAuthenticated) {
          Navigator.of(context).pushAndRemoveUntil<Sort>(
            MaterialPageRoute(builder: (context) => const GoogleSignInView()),
            (route) => false,
          );
        }
      },
      little one: Scaffold(
        appBar: AppBar(
          title: const Textual content('Very Good Codemagic'),
        ),
        physique: BlocBuilder<GoogleSignInBloc, GoogleSignInState>(
          builder: (context, state) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.heart,
              kids: [
                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'),
                )
              ],
            );
          },
        ),
      ),
    );
  }
}

Hurray! 🎉 We simply efficiently created Google Signal-In authentication for our improvement, staging, and manufacturing environments.

Assets


This text is written by Godwin Alexander Ekainu. He’s a Nigerian based mostly software program developer who’s eager to passing data and explaining complicated subjects to assist different builders study.You could find him from Twitter and
LinkedIn.



Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles