├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── simple_firebase_auth │ │ │ │ │ └── MainActivity.java │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── build.gradle ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── AppDelegate.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── main.m │ ├── AppDelegate.m │ ├── Info.plist │ └── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── WorkspaceSettings.xcsettings ├── Podfile └── Podfile.lock ├── .metadata ├── test └── widget_test.dart ├── README.md ├── lib ├── home_page.dart ├── auth.dart ├── main.dart └── login_page.dart ├── .gitignore ├── pubspec.yaml ├── pubspec.lock ├── readme2.md └── readme1.md /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronksaunders/simple_firebase_auth/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/simple_firebase_auth/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.simple_firebase_auth; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:simple_firebase_auth/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Firebase Login Flow in Flutter 2 | 3 | Click here to view read me with step by step instructions 4 | - [Documentation for Simple Firebase Login Flow in Flutter - Part One](https://github.com/aaronksaunders/simple_firebase_auth/blob/master/readme1.md) source code is on [branch](https://github.com/aaronksaunders/simple_firebase_auth/tree/completed-part-one) 5 | - [Documentation for Simple Firebase Login Flow in Flutter - Part Two](https://github.com/aaronksaunders/simple_firebase_auth/blob/master/readme2.md) source code is on the [head](https://github.com/aaronksaunders/simple_firebase_auth/) 6 | 7 | >There is a more complete example with login and account creation available here 8 | >- https://github.com/aaronksaunders/flutter_firebase_auth_app 9 | 10 | ## Getting Started 11 | 12 | This project is a starting point for a Flutter application. 13 | 14 | A few resources to get you started if this is your first Flutter project: 15 | 16 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 17 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 18 | 19 | For help getting started with Flutter, view our 20 | [online documentation](https://flutter.dev/docs), which offers tutorials, 21 | samples, guidance on mobile development, and a full API reference. 22 | -------------------------------------------------------------------------------- /lib/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | import 'auth.dart'; 6 | 7 | class HomePage extends StatefulWidget { 8 | final FirebaseUser currentUser; 9 | 10 | HomePage(this.currentUser); 11 | 12 | @override 13 | _HomePageState createState() => _HomePageState(); 14 | } 15 | 16 | class _HomePageState extends State { 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text("Home Flutter Firebase"), 22 | //actions: [LogoutButton()], 23 | ), 24 | body: Center( 25 | child: Column( 26 | children: [ 27 | SizedBox(height: 20.0), 28 | Text( 29 | 'Home Page Flutter Firebase Content', 30 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), 31 | ), 32 | SizedBox(height: 20.0), 33 | Text( 34 | 'Welcome ${widget.currentUser.email}', 35 | style: TextStyle( 36 | fontSize: 18, 37 | fontWeight: FontWeight.bold, 38 | fontStyle: FontStyle.italic), 39 | ), 40 | SizedBox(height: 20.0), 41 | RaisedButton( 42 | child: Text("LOGOUT"), 43 | onPressed: () async { 44 | await Provider.of(context).logout(); 45 | 46 | //Navigator.pushReplacementNamed(context, "/"); 47 | }) 48 | ], 49 | ), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'dart:async'; 3 | 4 | import 'package:flutter/cupertino.dart'; 5 | 6 | class AuthService with ChangeNotifier { 7 | final FirebaseAuth _auth = FirebaseAuth.instance; 8 | 9 | /// 10 | /// return the Future with firebase user object FirebaseUser if one exists 11 | /// 12 | Future getUser() { 13 | return _auth.currentUser(); 14 | } 15 | 16 | // wrapping the firebase calls 17 | Future logout() async { 18 | var result = FirebaseAuth.instance.signOut(); 19 | notifyListeners(); 20 | return result; 21 | } 22 | 23 | // wrapping the firebase calls 24 | Future createUser( 25 | {String firstName, 26 | String lastName, 27 | String email, 28 | String password}) async { 29 | var r = await FirebaseAuth.instance 30 | .createUserWithEmailAndPassword(email: email, password: password); 31 | 32 | var u = r.user; 33 | UserUpdateInfo info = UserUpdateInfo(); 34 | info.displayName = '$firstName $lastName'; 35 | return await u.updateProfile(info); 36 | } 37 | 38 | /// 39 | /// wrapping the firebase call to signInWithEmailAndPassword 40 | /// `email` String 41 | /// `password` String 42 | /// 43 | Future loginUser({String email, String password}) async { 44 | try { 45 | var result = await FirebaseAuth.instance 46 | .signInWithEmailAndPassword(email: email, password: password); 47 | // since something changed, let's notify the listeners... 48 | notifyListeners(); 49 | return result.user; 50 | } catch (e) { 51 | throw new AuthException(e.code, e.message); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | simple_firebase_auth 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # ignore the google credentials file 66 | **/android/app/google-services.json 67 | **/ios/Runner/GoogleService-Info.plist 68 | 69 | # Exceptions to above rules. 70 | !**/ios/**/default.mode1v3 71 | !**/ios/**/default.mode2v3 72 | !**/ios/**/default.pbxuser 73 | !**/ios/**/default.perspectivev3 74 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 75 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'home_page.dart'; 5 | import 'auth.dart'; 6 | import 'login_page.dart'; 7 | 8 | void main() => runApp( 9 | ChangeNotifierProvider( 10 | child: MyApp(), 11 | builder: (BuildContext context) { 12 | return AuthService(); 13 | }, 14 | ), 15 | ); 16 | 17 | class MyApp extends StatelessWidget { 18 | // This widget is the root of your application. 19 | @override 20 | Widget build(BuildContext context) { 21 | return MaterialApp( 22 | title: 'Flutter Demo', 23 | theme: ThemeData(primarySwatch: Colors.blue), 24 | home: FutureBuilder( 25 | future: Provider.of(context).getUser(), 26 | builder: (context, AsyncSnapshot snapshot) { 27 | if (snapshot.connectionState == ConnectionState.done) { 28 | // log error to console 29 | if (snapshot.error != null) { 30 | print("error"); 31 | return Text(snapshot.error.toString()); 32 | } 33 | 34 | // redirect to the proper page 35 | return snapshot.hasData ? HomePage(snapshot.data) : LoginPage(); 36 | } else { 37 | // show loading indicator 38 | return LoadingCircle(); 39 | } 40 | }, 41 | ), 42 | ); 43 | } 44 | } 45 | 46 | class LoadingCircle extends StatelessWidget { 47 | @override 48 | Widget build(BuildContext context) { 49 | return Center( 50 | child: Container( 51 | child: CircularProgressIndicator(), 52 | alignment: Alignment(0.0, 0.0), 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.simple_firebase_auth" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 37 | # referring to absolute paths on developers' machines. 38 | system('rm -rf .symlinks') 39 | system('mkdir -p .symlinks/plugins') 40 | 41 | # Flutter Pods 42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 43 | if generated_xcode_build_settings.empty? 44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 45 | end 46 | generated_xcode_build_settings.map { |p| 47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 48 | symlink = File.join('.symlinks', 'flutter') 49 | File.symlink(File.dirname(p[:path]), symlink) 50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 51 | end 52 | } 53 | 54 | # Plugin Pods 55 | plugin_pods = parse_KV_file('../.flutter-plugins') 56 | plugin_pods.map { |p| 57 | symlink = File.join('.symlinks', 'plugins', p[:name]) 58 | File.symlink(p[:path], symlink) 59 | pod p[:name], :path => File.join(symlink, 'ios') 60 | } 61 | end 62 | 63 | post_install do |installer| 64 | installer.pods_project.targets.each do |target| 65 | target.build_configurations.each do |config| 66 | config.build_settings['ENABLE_BITCODE'] = 'NO' 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: simple_firebase_auth 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.2.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | # The following adds the Cupertino Icons font to your application. 24 | # Use with the CupertinoIcons class for iOS style icons. 25 | cupertino_icons: ^0.1.2 26 | provider: 2.0.1 27 | firebase_core: 0.4.0+1 28 | firebase_auth: 0.11.1 29 | cloud_firestore: 0.11.0+2 30 | 31 | dev_dependencies: 32 | flutter_test: 33 | sdk: flutter 34 | 35 | 36 | # For information on the generic Dart part of this file, see the 37 | # following page: https://www.dartlang.org/tools/pub/pubspec 38 | 39 | # The following section is specific to Flutter. 40 | flutter: 41 | 42 | # The following line ensures that the Material Icons font is 43 | # included with your application, so that you can use the icons in 44 | # the material Icons class. 45 | uses-material-design: true 46 | 47 | # To add assets to your application, add an assets section, like this: 48 | # assets: 49 | # - images/a_dot_burr.jpeg 50 | # - images/a_dot_ham.jpeg 51 | 52 | # An image asset can refer to one or more resolution-specific "variants", see 53 | # https://flutter.dev/assets-and-images/#resolution-aware. 54 | 55 | # For details regarding adding assets from package dependencies, see 56 | # https://flutter.dev/assets-and-images/#from-packages 57 | 58 | # To add custom fonts to your application, add a fonts section here, 59 | # in this "flutter" section. Each entry in this list should have a 60 | # "family" key with the font family name, and a "fonts" key with a 61 | # list giving the asset and other descriptors for the font. For 62 | # example: 63 | # fonts: 64 | # - family: Schyler 65 | # fonts: 66 | # - asset: fonts/Schyler-Regular.ttf 67 | # - asset: fonts/Schyler-Italic.ttf 68 | # style: italic 69 | # - family: Trajan Pro 70 | # fonts: 71 | # - asset: fonts/TrajanPro.ttf 72 | # - asset: fonts/TrajanPro_Bold.ttf 73 | # weight: 700 74 | # 75 | # For details regarding fonts from package dependencies, 76 | # see https://flutter.dev/custom-fonts/#from-packages 77 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'auth.dart'; 5 | 6 | class LoginPage extends StatefulWidget { 7 | @override 8 | _LoginPageState createState() => _LoginPageState(); 9 | } 10 | 11 | class _LoginPageState extends State { 12 | final _formKey = GlobalKey(); 13 | String _password; 14 | String _email; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("Login Page Flutter Firebase"), 21 | ), 22 | body: Container( 23 | padding: EdgeInsets.all(20.0), 24 | child: Form( 25 | key: _formKey, 26 | child: Column(children: [ 27 | SizedBox(height: 20.0), 28 | Text( 29 | 'Login Information', 30 | style: TextStyle(fontSize: 20), 31 | ), 32 | SizedBox(height: 20.0), 33 | TextFormField( 34 | onSaved: (value) => _email = value, 35 | keyboardType: TextInputType.emailAddress, 36 | decoration: InputDecoration(labelText: "Email Address")), 37 | TextFormField( 38 | onSaved: (value) => _password = value, 39 | obscureText: true, 40 | decoration: InputDecoration(labelText: "Password")), 41 | SizedBox(height: 20.0), 42 | RaisedButton( 43 | child: Text("LOGIN"), 44 | onPressed: () async { 45 | // save the fields.. 46 | final form = _formKey.currentState; 47 | form.save(); 48 | 49 | // Validate will return true if is valid, or false if invalid. 50 | if (form.validate()) { 51 | try { 52 | FirebaseUser result = 53 | await Provider.of(context).loginUser( 54 | email: _email, password: _password); 55 | print(result); 56 | } on AuthException catch (error) { 57 | return _buildErrorDialog(context, error.message); 58 | } on Exception catch (error) { 59 | return _buildErrorDialog(context, error.toString()); 60 | } 61 | } 62 | }, 63 | ) 64 | ])))); 65 | } 66 | 67 | Future _buildErrorDialog(BuildContext context, _message) { 68 | return showDialog( 69 | builder: (context) { 70 | return AlertDialog( 71 | title: Text('Error Message'), 72 | content: Text(_message), 73 | actions: [ 74 | FlatButton( 75 | child: Text('Cancel'), 76 | onPressed: () { 77 | Navigator.of(context).pop(); 78 | }) 79 | ], 80 | ); 81 | }, 82 | context: context, 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | cloud_firestore: 26 | dependency: "direct main" 27 | description: 28 | name: cloud_firestore 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "0.11.0+2" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.14.11" 39 | cupertino_icons: 40 | dependency: "direct main" 41 | description: 42 | name: cupertino_icons 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.1.2" 46 | firebase_auth: 47 | dependency: "direct main" 48 | description: 49 | name: firebase_auth 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.11.1" 53 | firebase_core: 54 | dependency: "direct main" 55 | description: 56 | name: firebase_core 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.4.0+1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | matcher: 71 | dependency: transitive 72 | description: 73 | name: matcher 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "0.12.5" 77 | meta: 78 | dependency: transitive 79 | description: 80 | name: meta 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.1.6" 84 | path: 85 | dependency: transitive 86 | description: 87 | name: path 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.6.2" 91 | pedantic: 92 | dependency: transitive 93 | description: 94 | name: pedantic 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.5.0" 98 | provider: 99 | dependency: "direct main" 100 | description: 101 | name: provider 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "2.0.1" 105 | quiver: 106 | dependency: transitive 107 | description: 108 | name: quiver 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "2.0.2" 112 | sky_engine: 113 | dependency: transitive 114 | description: flutter 115 | source: sdk 116 | version: "0.0.99" 117 | source_span: 118 | dependency: transitive 119 | description: 120 | name: source_span 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.5.5" 124 | stack_trace: 125 | dependency: transitive 126 | description: 127 | name: stack_trace 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.9.3" 131 | stream_channel: 132 | dependency: transitive 133 | description: 134 | name: stream_channel 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "2.0.0" 138 | string_scanner: 139 | dependency: transitive 140 | description: 141 | name: string_scanner 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.0.4" 145 | term_glyph: 146 | dependency: transitive 147 | description: 148 | name: term_glyph 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.1.0" 152 | test_api: 153 | dependency: transitive 154 | description: 155 | name: test_api 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "0.2.4" 159 | typed_data: 160 | dependency: transitive 161 | description: 162 | name: typed_data 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "1.1.6" 166 | vector_math: 167 | dependency: transitive 168 | description: 169 | name: vector_math 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "2.0.8" 173 | sdks: 174 | dart: ">=2.2.0 <3.0.0" 175 | flutter: ">=1.2.0 <2.0.0" 176 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BoringSSL-GRPC (0.0.3): 3 | - BoringSSL-GRPC/Implementation (= 0.0.3) 4 | - BoringSSL-GRPC/Interface (= 0.0.3) 5 | - BoringSSL-GRPC/Implementation (0.0.3): 6 | - BoringSSL-GRPC/Interface (= 0.0.3) 7 | - BoringSSL-GRPC/Interface (0.0.3) 8 | - cloud_firestore (0.0.1): 9 | - Firebase/Core 10 | - Firebase/Firestore (~> 6.0) 11 | - Flutter 12 | - Firebase/Auth (6.1.0): 13 | - Firebase/CoreOnly 14 | - FirebaseAuth (~> 6.1.0) 15 | - Firebase/Core (6.1.0): 16 | - Firebase/CoreOnly 17 | - FirebaseAnalytics (= 6.0.1) 18 | - Firebase/CoreOnly (6.1.0): 19 | - FirebaseCore (= 6.0.1) 20 | - Firebase/Firestore (6.1.0): 21 | - Firebase/CoreOnly 22 | - FirebaseFirestore (~> 1.3.1) 23 | - firebase_auth (0.0.1): 24 | - Firebase/Auth (~> 6.0) 25 | - Firebase/Core 26 | - Flutter 27 | - firebase_core (0.0.1): 28 | - Firebase/Core 29 | - Flutter 30 | - FirebaseAnalytics (6.0.1): 31 | - FirebaseCore (~> 6.0) 32 | - FirebaseInstanceID (~> 4.1) 33 | - GoogleAppMeasurement (= 6.0.1) 34 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 35 | - GoogleUtilities/MethodSwizzler (~> 6.0) 36 | - GoogleUtilities/Network (~> 6.0) 37 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 38 | - nanopb (~> 0.3) 39 | - FirebaseAuth (6.1.0): 40 | - FirebaseAuthInterop (~> 1.0) 41 | - FirebaseCore (~> 6.0) 42 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 43 | - GoogleUtilities/Environment (~> 6.0) 44 | - GTMSessionFetcher/Core (~> 1.1) 45 | - FirebaseAuthInterop (1.0.0) 46 | - FirebaseCore (6.0.1): 47 | - GoogleUtilities/Environment (~> 6.0) 48 | - GoogleUtilities/Logger (~> 6.0) 49 | - FirebaseFirestore (1.3.1): 50 | - FirebaseAuthInterop (~> 1.0) 51 | - FirebaseCore (~> 6.0) 52 | - FirebaseFirestore/abseil-cpp (= 1.3.1) 53 | - "gRPC-C++ (= 0.0.8)" 54 | - leveldb-library (~> 1.20) 55 | - nanopb (~> 0.3.901) 56 | - Protobuf (~> 3.1) 57 | - FirebaseFirestore/abseil-cpp (1.3.1): 58 | - FirebaseAuthInterop (~> 1.0) 59 | - FirebaseCore (~> 6.0) 60 | - "gRPC-C++ (= 0.0.8)" 61 | - leveldb-library (~> 1.20) 62 | - nanopb (~> 0.3.901) 63 | - Protobuf (~> 3.1) 64 | - FirebaseInstanceID (4.1.0): 65 | - FirebaseCore (~> 6.0) 66 | - GoogleUtilities/Environment (~> 6.0) 67 | - GoogleUtilities/UserDefaults (~> 6.0) 68 | - Flutter (1.0.0) 69 | - GoogleAppMeasurement (6.0.1): 70 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0) 71 | - GoogleUtilities/MethodSwizzler (~> 6.0) 72 | - GoogleUtilities/Network (~> 6.0) 73 | - "GoogleUtilities/NSData+zlib (~> 6.0)" 74 | - nanopb (~> 0.3) 75 | - GoogleUtilities/AppDelegateSwizzler (6.2.0): 76 | - GoogleUtilities/Environment 77 | - GoogleUtilities/Logger 78 | - GoogleUtilities/Network 79 | - GoogleUtilities/Environment (6.2.0) 80 | - GoogleUtilities/Logger (6.2.0): 81 | - GoogleUtilities/Environment 82 | - GoogleUtilities/MethodSwizzler (6.2.0): 83 | - GoogleUtilities/Logger 84 | - GoogleUtilities/Network (6.2.0): 85 | - GoogleUtilities/Logger 86 | - "GoogleUtilities/NSData+zlib" 87 | - GoogleUtilities/Reachability 88 | - "GoogleUtilities/NSData+zlib (6.2.0)" 89 | - GoogleUtilities/Reachability (6.2.0): 90 | - GoogleUtilities/Logger 91 | - GoogleUtilities/UserDefaults (6.2.0): 92 | - GoogleUtilities/Logger 93 | - "gRPC-C++ (0.0.8)": 94 | - "gRPC-C++/Implementation (= 0.0.8)" 95 | - "gRPC-C++/Interface (= 0.0.8)" 96 | - "gRPC-C++/Implementation (0.0.8)": 97 | - "gRPC-C++/Interface (= 0.0.8)" 98 | - gRPC-Core (= 1.19.0) 99 | - nanopb (~> 0.3) 100 | - "gRPC-C++/Interface (0.0.8)" 101 | - gRPC-Core (1.19.0): 102 | - gRPC-Core/Implementation (= 1.19.0) 103 | - gRPC-Core/Interface (= 1.19.0) 104 | - gRPC-Core/Implementation (1.19.0): 105 | - BoringSSL-GRPC (= 0.0.3) 106 | - gRPC-Core/Interface (= 1.19.0) 107 | - nanopb (~> 0.3) 108 | - gRPC-Core/Interface (1.19.0) 109 | - GTMSessionFetcher/Core (1.2.2) 110 | - leveldb-library (1.20) 111 | - nanopb (0.3.901): 112 | - nanopb/decode (= 0.3.901) 113 | - nanopb/encode (= 0.3.901) 114 | - nanopb/decode (0.3.901) 115 | - nanopb/encode (0.3.901) 116 | - Protobuf (3.8.0) 117 | 118 | DEPENDENCIES: 119 | - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) 120 | - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) 121 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`) 122 | - Flutter (from `.symlinks/flutter/ios`) 123 | 124 | SPEC REPOS: 125 | https://github.com/cocoapods/specs.git: 126 | - BoringSSL-GRPC 127 | - Firebase 128 | - FirebaseAnalytics 129 | - FirebaseAuth 130 | - FirebaseAuthInterop 131 | - FirebaseCore 132 | - FirebaseFirestore 133 | - FirebaseInstanceID 134 | - GoogleAppMeasurement 135 | - GoogleUtilities 136 | - "gRPC-C++" 137 | - gRPC-Core 138 | - GTMSessionFetcher 139 | - leveldb-library 140 | - nanopb 141 | - Protobuf 142 | 143 | EXTERNAL SOURCES: 144 | cloud_firestore: 145 | :path: ".symlinks/plugins/cloud_firestore/ios" 146 | firebase_auth: 147 | :path: ".symlinks/plugins/firebase_auth/ios" 148 | firebase_core: 149 | :path: ".symlinks/plugins/firebase_core/ios" 150 | Flutter: 151 | :path: ".symlinks/flutter/ios" 152 | 153 | SPEC CHECKSUMS: 154 | BoringSSL-GRPC: db8764df3204ccea016e1c8dd15d9a9ad63ff318 155 | cloud_firestore: c6f34148c1dfbb57a6147f9bb49c1c9f5c27036e 156 | Firebase: 8d77bb33624ae9b62d745d82ec023de5f70f7e4f 157 | firebase_auth: 7a2cc520766f90212b845a5b35316601707bfa25 158 | firebase_core: ce5006bb48508ee4e71e0f429a3f519bb8ee2961 159 | FirebaseAnalytics: 629301c2b9925f3537d4093a17a72751ae5b7084 160 | FirebaseAuth: 4281d6d98a90881e00710fa8d9e37c2ccdfc7d80 161 | FirebaseAuthInterop: 0ffa57668be100582bb7643d4fcb7615496c41fc 162 | FirebaseCore: 66bdef3b310a026880e2a5bc8aa586ab62ce4543 163 | FirebaseFirestore: 8feac73d330bf7ed6945518e5ffc0aeb164a07f6 164 | FirebaseInstanceID: 27bed93a59b6685f5c3e0c028a878a764fd75c33 165 | Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a 166 | GoogleAppMeasurement: 51d8d9ea48f0ca44484d29cfbdef976fbd4fc336 167 | GoogleUtilities: 996e0db07153674fd1b54b220fda3a3dc3547cba 168 | "gRPC-C++": 98be881723177d8c4faf5fdffacb582c7b4971a2 169 | gRPC-Core: bd9472c8daa2e414b9f8038ba667bf56ce0e02b8 170 | GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23 171 | leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5 172 | nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48 173 | Protobuf: 3f617b9a6e73605565086864c9bc26b2bf2dd5a3 174 | 175 | PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09 176 | 177 | COCOAPODS: 1.6.0 178 | -------------------------------------------------------------------------------- /readme2.md: -------------------------------------------------------------------------------- 1 | # Simple Firebase Login Flow in Flutter - Part Two 2 | 3 | In part one we created a simple application with the following components 4 | - Default Main App Entry Point 5 | - Use of [FutureBuilder Widget](https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html 6 | ) to wait for data before rendering UI, a concept used throughout the app 7 | - Login Page 8 | - Home Page 9 | - Authentication Service 10 | - Demonstrate the use of the Provider as discussed here in the Flutter Documentation [Simple App State Management](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#accessing-the-state) 11 | 12 | Now in part two we will integrate firebase into the application. 13 | 14 | >There are plenty of examples online about setting up Firebase for Flutter so I will jump right into the code instead of walking thru the basics. 15 | >See [Google CodeLabs Flutter for Firebase](https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..index#5) for step by step instructions for setting up you project on iOS or Android 16 | 17 | ### Create a Test User in Firebase 18 | Since we are just building the application and there is no functionality to create users in the application right now, please login to your [Firebase Console]([https://console.firebase.google.com/u/0/](https://console.firebase.google.com/u/0/)) and add a user to your project. Please be sure to enable email authentication when updating the project in your Firebase Console. 19 | 20 | ### Steps For Adding Firebase Functionality to the Project 21 | - Add the Firebase methods to the `AuthService` 22 | - Access the `getUser` property from the `AuthService` at startup to determine which page to load in `main.dart` 23 | - Modify `HomePage` to show email address of the logged in `FirebaseUser` 24 | - Modify `LoginPage` to call the `loginUser` method on the `AuthService` to login a user using the Firebase API to see if we can login a real `FirebaseUser` 25 | - Finally handle the errors appropriately when logging in and when looking for a current user at startup 26 | 27 | #### Authentication Service: Adding Firebase API Functionality 28 | First the authentication service which is where we are just wrapping some of the basic firebase functions that we need for authentication and determining if there is already a user persisted from a previous session 29 | ```dart 30 | import 'package:firebase_auth/firebase_auth.dart'; 31 | import 'dart:async'; 32 | 33 | import 'package:flutter/cupertino.dart'; 34 | 35 | class AuthService with ChangeNotifier { 36 | final FirebaseAuth _auth = FirebaseAuth.instance; 37 | 38 | /// 39 | /// return the Future with firebase user object FirebaseUser if one exists 40 | /// 41 | Future getUser() { 42 | return _auth.currentUser(); 43 | } 44 | 45 | // wrapping the firebase calls 46 | Future logout() async { 47 | var result = FirebaseAuth.instance.signOut(); 48 | notifyListeners(); 49 | return result; 50 | } 51 | 52 | /// 53 | /// wrapping the firebase call to signInWithEmailAndPassword 54 | /// `email` String 55 | /// `password` String 56 | /// 57 | Future loginUser({String email, String password}) async { 58 | try { 59 | var result = await FirebaseAuth.instance 60 | .signInWithEmailAndPassword(email: email, password: password); 61 | // since something changed, let's notify the listeners... 62 | notifyListeners(); 63 | return result; 64 | } catch (e) { 65 | // throw the Firebase AuthException that we caught 66 | throw new AuthException(e.code, e.message); 67 | } 68 | } 69 | } 70 | 71 | ``` 72 | As you can see from the code above, we still have the same methods for accessing our `AuthService` the only difference now is that we have replaces the call with real calls to the Firebase backend that you have set up. 73 | 74 | Notice we no longer need to keep a property with the current user since Firebase will manage that for us. All we need to do is call the method `getUser` and if there is a user we will get an object, otherwise it will return null. 75 | 76 | Most important to notice is that we are calling `notifyListeners()` when the login state is changing during logging in or logging out. 77 | 78 | #### Modifying `main.dart` 79 | There are no real modifications needed to the file since we are working with the same external API, the only difference is that now we are returning a `FirebaseUser` object so let's add a specific type to the code, and touch up a few more things 80 | ```dart 81 | class MyApp extends StatelessWidget { 82 | // This widget is the root of your application. 83 | @override 84 | Widget build(BuildContext context) { 85 | return MaterialApp( 86 | title: 'Flutter Demo', 87 | theme: ThemeData(primarySwatch: Colors.blue), 88 | home: FutureBuilder( 89 | future: Provider.of(context).getUser(), 90 | builder: (context, AsyncSnapshot snapshot) { // ⇐ NEW 91 | if (snapshot.connectionState == ConnectionState.done) { 92 | // log error to console ⇐ NEW 93 | if (snapshot.error != null) { 94 | print("error"); 95 | return Text(snapshot.error.toString()); 96 | } 97 | // redirect to the proper page, pass the user into the 98 | // `HomePage` so we can display the user email in welcome msg ⇐ NEW 99 | return snapshot.hasData ? HomePage(snapshot.data) : LoginPage(); 100 | } else { 101 | // show loading indicator ⇐ NEW 102 | return LoadingCircle(); 103 | } 104 | }, 105 | ), 106 | ); 107 | } 108 | } 109 | ``` 110 | We have added the object type, `FirebaseUser`, associated with the `AsyncSnapshot` and we are now checking for an error in case there is a problem loading Firebase initially. 111 | 112 | We have also added a new parameter to the constructor of the `HomePage` widget which is the `FirebaseUser` object returned from `getUser` call made to the `AuthService`. We will a see in the next section how the new parameter is used. 113 | 114 | Finally we added a new widget called `LoadingCircle` to give us a nice user experience when the application is starting up and accessing `Firebase` to check for a new user; See the code below for the `LoadingCircle` widget. 115 | > See documentation on [`CircularProgressIndicator` ]([https://api.flutter.dev/flutter/material/CircularProgressIndicator/CircularProgressIndicator.html](https://api.flutter.dev/flutter/material/CircularProgressIndicator/CircularProgressIndicator.html)) 116 | ```dart 117 | class LoadingCircle extends StatelessWidget { 118 | @override 119 | Widget build(BuildContext context) { 120 | return Center( 121 | child: Container( 122 | child: CircularProgressIndicator(), 123 | alignment: Alignment(0.0, 0.0), 124 | ), 125 | ); 126 | } 127 | } 128 | ``` 129 | #### Modifying HomePage Widget in `home_page.dart` 130 | We need to first modify the widget by adding a new constructor that will hold the firebase user passed in from the FutureBuilder in `main.dart` 131 | ```dart 132 | class HomePage extends StatefulWidget { 133 | final FirebaseUser currentUser; // ⇐ NEW 134 | 135 | HomePage(this.currentUser); // ⇐ NEW 136 | 137 | @override 138 | _HomePageState createState() => _HomePageState(); 139 | } 140 | ``` 141 | Now we have access to the information on the current user from the widget; we can access it when rendering the `HomePage` by make the modifications you see below. We will just add a few more widgets to the build method: 142 | ```dart 143 | children: [ 144 | SizedBox(height: 20.0), // ⇐ NEW 145 | Text( // ⇐ NEW 146 | 'Home Page Flutter Firebase Content', 147 | style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), 148 | ), 149 | SizedBox(height: 20.0), // ⇐ NEW 150 | Text( // ⇐ NEW 151 | `Welcome ${widget.currentUser.email}`, 152 | style: TextStyle( 153 | fontSize: 18, 154 | fontWeight: FontWeight.bold, 155 | fontStyle: FontStyle.italic), 156 | ), 157 | SizedBox(height: 20.0), 158 | RaisedButton( 159 | child: Text("LOGOUT"), 160 | onPressed: () async { 161 | await Provider.of(context).logout(); 162 | }) 163 | ], 164 | ``` 165 | #### Modifying LoginPage Widget in `login_page.dart` 166 | Since the API signature hasn't changed we need to do very little to this function to get the desired results, however it would be best to do some better error checking. 167 | 168 | With `Future` we need to wrap the call with a `try` `catch` block since any errors that happen with Firebase will be thrown as exceptions. We then will display the error message in a dialog, see code for the method `_buildErrorDialog` and the rest of the changes below. 169 | 170 | Add the new import for the error exception 171 | ```dart 172 | import 'package:firebase_auth/firebase_auth.dart'; 173 | ``` 174 | Make the appropriate changes to the `onPressed` method of the login button. 175 | ```dart 176 | onPressed: () async { 177 | // save the fields.. 178 | final form = _formKey.currentState; 179 | form.save(); 180 | 181 | // Validate will return true if is valid, or false if invalid. 182 | if (form.validate()) { 183 | try { 184 | FirebaseUser result = 185 | await Provider.of(context).loginUser( 186 | email: _email, password: _password); 187 | print(result); 188 | } on AuthException catch (error) { 189 | // handle the firebase specific error 190 | return _buildErrorDialog(context, error.message); 191 | } on Exception catch (error) { 192 | // gracefully handle anything else that might happen.. 193 | return _buildErrorDialog(context, error.toString()); 194 | } 195 | } 196 | }, 197 | ``` 198 | Add the code for the new private `_buildErrorDialog` method that will display errors from the call to the `AuthService` login method. 199 | ```dart 200 | Future _buildErrorDialog(BuildContext context, _message) { 201 | return showDialog( 202 | builder: (context) { 203 | return AlertDialog( 204 | title: Text('Error Message'), 205 | content: Text(_message), 206 | actions: [ 207 | FlatButton( 208 | child: Text('Cancel'), 209 | onPressed: () { 210 | Navigator.of(context).pop(); 211 | }) 212 | ], 213 | ); 214 | }, 215 | context: context, 216 | ); 217 | } 218 | ``` -------------------------------------------------------------------------------- /readme1.md: -------------------------------------------------------------------------------- 1 | # Simple Firebase Login Flow in Flutter - Part One 2 | 3 | We will create a simple application with the following components 4 | - Default Main App Entry Point 5 | - Use of [FutureBuilder Widget](https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html 6 | ) to wait for data before rendering UI, concept used throughout the app 7 | - Login Page 8 | - Home Page 9 | - Authentication Service 10 | - Demonstrate the use of the Provider as discussed here in the Flutter Documentation [Simple App State Management](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#accessing-the-state) 11 | 12 | There are plenty of examples online about setting up Firebase for Flutter so I will jump right into the code instead of walking thru the basics. 13 | 14 | >See [Google CodeLabs Flutter for Firebase](https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..index#5) for step by step instructions for setting up you project on iOS or Android 15 | 16 | 17 | ### Create a Test User in Firebase 18 | Since we are just building the application and there is no functionalty to create users in the application right now, please login to you Firebase Console and add an user to your project. Please be sure to enable email authentication when updating the project in your Firebase Console. 19 | 20 | 21 | ### Cleaning Up the Default Flutter Project 22 | first lets create the project 23 | ``` 24 | flutter create simple_firebase_auth 25 | ``` 26 | Now lets do some project cleanup, open up the project and delete the existing `HomePage` and `HomePageState` widget from the file `main.dart`. 27 | 28 | Change the `home` property of the `MaterialApp` widget to point to the `LoginPage` widget we are about to create in the next section 29 | 30 | The file should look similar to this when completed 31 | ```javascript 32 | import 'package:flutter/material.dart'; 33 | import 'package:simple_firebase_auth/login_page.dart'; 34 | 35 | void main() => runApp(MyApp()); 36 | 37 | class MyApp extends StatelessWidget { 38 | // This widget is the root of your application. 39 | @override 40 | Widget build(BuildContext context) { 41 | return MaterialApp( 42 | title: 'Flutter Demo', 43 | theme: ThemeData( 44 | primarySwatch: Colors.blue, 45 | ), 46 | home: LoginPage(), 47 | ); 48 | } 49 | } 50 | ``` 51 | 52 | 53 | ### Create the LoginPage Widget 54 | Lets walk through the creation of the `LoginPage` for the application. We need capture an `email` and a `password` to pass to the `AuthService` to call the login function. 55 | 56 | We are going to create a simple page with the required `TextFormField` widgets and one `RaisedButton` to click to make the login happen. 57 | 58 | 1. Open your editor and create a new file in the `lib` directory named `login_page.dart` 59 | 1. Paste the contents below into the file `login_page.dart` 60 | ```javascript 61 | import 'package:flutter/material.dart'; 62 | 63 | class LoginPage extends StatefulWidget { 64 | @override 65 | _LoginPageState createState() => _LoginPageState(); 66 | } 67 | 68 | class _LoginPageState extends State { 69 | @override 70 | Widget build(BuildContext context) { 71 | return Scaffold( 72 | appBar: AppBar( 73 | title: Text("Login Page Flutter Firebase"), 74 | ), 75 | body: Center( 76 | child: Text('Login Page Flutter Firebase Content'), 77 | ), 78 | ); 79 | } 80 | } 81 | 82 | ``` 83 | you should be able to run the code to see what the screen looks like now. Be sure to change the default route or `home` property in `main.dart` widget to `LoginPage` while we work through the UI so you can see the changes with live reload 84 | 85 | #### Style and Adding Text Fields 86 | 87 | Lets make the body of the page a centered `Column` with the childre of the column being primarily the `TextFormField`s and the `RaisedButton` 88 | 89 | the centered container to hold the form fields and buttons 90 | ```javascript 91 | body: Container( 92 | padding: EdgeInsets.all(20.0), 93 | child: Column() 94 | ) 95 | ``` 96 | Next add the actual form field widgets and the buttons as children of the `Column` widget. We will do some basic styling of the form fields so that this looks presentable. See the Flutter documentation for more information on [TextFormFields](https://api.flutter.dev/flutter/material/TextFormField-class.html) 97 | ```javascript 98 | body: Container( 99 | padding: EdgeInsets.all(20.0), 100 | child: Column( 101 | children: [ 102 | Text( 103 | 'Login Information', 104 | style: TextStyle(fontSize: 20), 105 | ), 106 | TextFormField( 107 | keyboardType: TextInputType.emailAddress, 108 | decoration: InputDecoration(labelText: "Email Address")), 109 | TextFormField( 110 | obscureText: true, 111 | decoration: InputDecoration(labelText: "Password")), 112 | RaisedButton(child: Text("LOGIN"), onPressed: () {}), 113 | ], 114 | ), 115 | ), 116 | ``` 117 | Lets add some spacing between the fields in the column so it is more presentable. We are going to use the `SizedBox` widget and set the `height` property to get some spacing in the application. Replace the `children` property of the `Column` widget to get the desired spacing 118 | ```javascript 119 | children: [ 120 | SizedBox(height: 20.0), // <= NEW 121 | Text( 122 | 'Login Information', 123 | style: TextStyle(fontSize: 20), 124 | ), 125 | SizedBox(height: 20.0), // <= NEW 126 | TextFormField( 127 | keyboardType: TextInputType.emailAddress, 128 | decoration: InputDecoration(labelText: "Email Address")), 129 | TextFormField( 130 | obscureText: true, 131 | decoration: InputDecoration(labelText: "Password")), 132 | SizedBox(height: 20.0), // <= NEW 133 | RaisedButton(child: Text("LOGIN"), onPressed: () {}), 134 | ], 135 | ``` 136 | #### Getting Text Values from Form Fields 137 | We are going to be using a `Form` widget and a `GlobalKey`, additional information on these concepts can be found in the flutter cookbook section [Building a form with validation](https://flutter.dev/docs/cookbook/forms/validation) 138 | 139 | Add the formKey in the `LoginPage` widget 140 | ```javascript 141 | class _LoginPageState extends State { 142 | final _formKey = GlobalKey(); 143 | ``` 144 | Then add two new fields to hold the email address and password values we will need to send to Firebase for authentication 145 | ```javascript 146 | class _LoginPageState extends State { 147 | final _formKey = GlobalKey(); 148 | String _password; 149 | String _email; 150 | ``` 151 | Next we add a property `onSaved` to the `TextFormFields` we have for email and password, when the `save` method is called on the form, all of the widgets onSaved methods will be called to update the local variables. 152 | ```javascript 153 | TextFormField( 154 | onSaved: (value) => _email = value, // <= NEW 155 | keyboardType: TextInputType.emailAddress, 156 | decoration: InputDecoration(labelText: "Email Address")), 157 | TextFormField( 158 | onSaved: (value) => _password = value, // <= NEW 159 | obscureText: true, 160 | decoration: InputDecoration(labelText: "Password")), 161 | ``` 162 | Wrap the `Column` Widget with a new `Form` Widget, the code should look similar to this 163 | ```javascript 164 | body: Container( 165 | padding: EdgeInsets.all(20.0), 166 | child: Form( // <= NEW 167 | key: _formKey, // <= NEW 168 | child: Column( 169 | children: [ 170 | .... 171 | ], 172 | ), 173 | ), 174 | ), 175 | ``` 176 | Now that the fields are set, the `TextFormField` are updated, we can using the `_formKey` to not only validate the fields provided, but to also get the values locally by calling the `save` method. 177 | 178 | Replace the code in the `RaisedButton` `onPressed` method to the following, and you will see that we are getting the values for email and password set in out widget. We can now pass these values to the `AuthService` that wraps the Firebase signin functionality. 179 | 180 | ```javascript 181 | // save the fields.. 182 | final form = _formKey.currentState; 183 | form.save(); 184 | 185 | // Validate will return true if is valid, or false if invalid. 186 | if (form.validate()) { 187 | print("$_email $_password"); 188 | } 189 | ``` 190 | 191 | 192 | ### Create the HomePage Widget 193 | For now, we will keep the home page simple since we are just trying to demonstrate how the flow works. Ignore the commented out `LogoutButton` widget, we will discuss that in a later section of the tutorial. 194 | 195 | 1. Open your editor and create a new file in the `lib` directory named `home_page.dart` 196 | 1. Paste the contents below into the file `home_page.dart` 197 | 198 | ```javascript 199 | import 'package:flutter/material.dart'; 200 | 201 | class HomePage extends StatefulWidget { 202 | @override 203 | _HomePageState createState() => _HomePageState(); 204 | } 205 | 206 | class _HomePageState extends State { 207 | @override 208 | Widget build(BuildContext context) { 209 | return Scaffold( 210 | appBar: AppBar( 211 | title: Text("Home Flutter Firebase"), 212 | //actions: [LogoutButton()], 213 | ), 214 | body: Center( 215 | child: Text('Home Page Flutter Firebase Content'), 216 | ), 217 | ); 218 | } 219 | } 220 | ``` 221 | 3. Open `main.dart` and add the following import statement 222 | ```javascript 223 | import 'home_page.dart'; 224 | ``` 225 | 4. Change the `home` property from this: 226 | ```javascript 227 | home: HomePage(title: 'Flutter Demo Home Page'), 228 | ``` 229 |        to this so you can verify that the page is working properly 230 | ```javascript 231 | home: HomePage(), 232 | ``` 233 | ### Creating a Template for An Authentication Service 234 | Here we will build out the authentication service separate from Firebase, validate that everything works and then integrate Firebase. 235 | 236 | In this service, we are using a mixin called `ChangeNotifier` and a method `notifyListeners` this will allow for the widgets that are using this Service to be updated when the method is called. We are calling `notifyListeners` when we update the `currentUser` property because that means that the user has either logged in or logged out and we want the application to update based on the users state. 237 | 238 | >More information on `Provider` and State Management can be found here in the [Flutter Documentation]([https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple)) 239 | 240 | What we need as a baseline is the following: 241 | ```javascript 242 | import 'dart:async'; 243 | import 'package:flutter/material.dart'; 244 | 245 | class AuthService with ChangeNotifier { 246 | var currentUser; 247 | 248 | AuthService() { 249 | print("new AuthService"); 250 | } 251 | 252 | Future getUser() { 253 | return Future.value(currentUser); 254 | } 255 | 256 | // wrappinhg the firebase calls 257 | Future logout() { 258 | this.currentUser = null; 259 | notifyListeners(); 260 | return Future.value(currentUser); 261 | } 262 | 263 | // wrapping the firebase calls 264 | Future createUser( 265 | {String firstName, 266 | String lastName, 267 | String email, 268 | String password}) async {} 269 | 270 | // logs in the user if password matches 271 | Future loginUser({String email, String password}) { 272 | if (password == 'password123') { 273 | this.currentUser = {'email': email}; 274 | notifyListeners(); 275 | return Future.value(currentUser); 276 | } else { 277 | this.currentUser = null; 278 | return Future.value(null); 279 | } 280 | } 281 | } 282 | ``` 283 | We will keep a local property in the service call `currentUser` which is the object storing the user, when the user calls the `login` method, if the password matches we will set `currentUser` and the user will be logged in. This will now provide a user when the call is made to `getUser` method. For logging the user out, we will set the `currentUser`property to null indicating that we are no longer logged into the system. 284 | 285 | 286 | ### Determining User State On Application Launch 287 | The first challenge when working with the application is to determine which page to open when the application starts up. What we want to do here is determine if we have a user or not. We will be using an `AuthService` we will created above combined with the `FutureBuilder` widget from flutter to render the correct first page of either a `HomePage` or a `LoginPage` 288 | 289 | #### Using the Provider 290 | In `main.dart` we will need to update the default `main` method to look like this; we are wrapping the whole application with the `ChangeNotifierProvider` to get the ability to scan up the widget tree and find an object of type `AuthService`. 291 | 292 | ```javascript 293 | void main() => runApp( 294 | ChangeNotifierProvider( 295 | child: MyApp(), 296 | builder: (BuildContext context) { 297 | return AuthService(); 298 | }, 299 | ), 300 | ); 301 | ``` 302 | 303 | #### Modifying the MyApp Widget 304 | Go into the `main.dart` and make the following changes that will allow the `MyApp` Widget to set the route. This widget will determine if the application should navigate to the `HomePage` widget or `LoginPage` widget when the app is launched. 305 | 306 | ```javascript 307 | class MyApp extends StatelessWidget { 308 | // This widget is the root of your application. 309 | @override 310 | Widget build(BuildContext context) { 311 | return MaterialApp( 312 | title: 'Flutter Demo', 313 | theme: ThemeData(primarySwatch: Colors.blue), 314 | home: FutureBuilder( 315 | // get the Provider, and call the getUser method 316 | future: Provider.of(context).getUser(), 317 | // wait for the future to resolve and render the appropriate 318 | // widget for HomePage or LoginPage 319 | builder: (context, AsyncSnapshot snapshot) { 320 | if (snapshot.connectionState == ConnectionState.done) { 321 | return snapshot.hasData ? HomePage() : LoginPage(); 322 | } else { 323 | return Container(color: Colors.white); 324 | } 325 | }, 326 | ), 327 | ); 328 | } 329 | } 330 | ``` 331 | 332 | ### Modifying the LoginPage Widget 333 | Now that the `AuthService` can be accessed using the Provider, we can call the login function when the used clicks the button. Go and open the file `login_page.dart` and find the `onPressed` method for the login button and make the following change 334 | 335 | ```dart 336 | // Validate will return true if is valid, or false if invalid. 337 | if (form.validate()) { 338 | var result = await Provider.of(context) 339 | .loginUser(email: _email, password: _password); 340 | if (result == null) { 341 | // see project in github for this code 342 | //return _buildShowErrorDialog(context, 343 | // "Error Logging In With Those Credentials"); 344 | } 345 | } 346 | ``` 347 | We are using the `Provider.of` method to look up the widget tree and get our `AuthService` and then we have access to all of the methods, specifically the `loginUser` method. 348 | 349 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 183D4FF3E5ED8DE01F907A34 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D39E6B3BB58CC1348D862C /* libPods-Runner.a */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 8DE4883122A4C27700ADFE7D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8DE4883022A4C27700ADFE7D /* GoogleService-Info.plist */; }; 16 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 17 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 19 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 20 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 21 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 22 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 23 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXCopyFilesBuildPhase section */ 27 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 28 | isa = PBXCopyFilesBuildPhase; 29 | buildActionMask = 2147483647; 30 | dstPath = ""; 31 | dstSubfolderSpec = 10; 32 | files = ( 33 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 34 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 35 | ); 36 | name = "Embed Frameworks"; 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 7CDD7F71C724078E02937891 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 50 | 7EBA0EBE560CCE22B2FB9D0C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 51 | 816B86576B91AC9A96A64A38 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 52 | 8DE4883022A4C27700ADFE7D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 53 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 54 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 55 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 56 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 58 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 59 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 60 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 61 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | E5D39E6B3BB58CC1348D862C /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 71 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 72 | 183D4FF3E5ED8DE01F907A34 /* libPods-Runner.a in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 9740EEB11CF90186004384FC /* Flutter */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 3B80C3931E831B6300D905FE /* App.framework */, 83 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 84 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 85 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 86 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 87 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 88 | ); 89 | name = Flutter; 90 | sourceTree = ""; 91 | }; 92 | 97C146E51CF9000F007C117D = { 93 | isa = PBXGroup; 94 | children = ( 95 | 9740EEB11CF90186004384FC /* Flutter */, 96 | 97C146F01CF9000F007C117D /* Runner */, 97 | 97C146EF1CF9000F007C117D /* Products */, 98 | EC2E01F5E238D03474C86063 /* Pods */, 99 | DD0919FB333546DB430515E5 /* Frameworks */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 97C146EF1CF9000F007C117D /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 97C146EE1CF9000F007C117D /* Runner.app */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 97C146F01CF9000F007C117D /* Runner */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 8DE4883022A4C27700ADFE7D /* GoogleService-Info.plist */, 115 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 116 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 117 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 118 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 119 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 120 | 97C147021CF9000F007C117D /* Info.plist */, 121 | 97C146F11CF9000F007C117D /* Supporting Files */, 122 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 123 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 124 | ); 125 | path = Runner; 126 | sourceTree = ""; 127 | }; 128 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 97C146F21CF9000F007C117D /* main.m */, 132 | ); 133 | name = "Supporting Files"; 134 | sourceTree = ""; 135 | }; 136 | DD0919FB333546DB430515E5 /* Frameworks */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | E5D39E6B3BB58CC1348D862C /* libPods-Runner.a */, 140 | ); 141 | name = Frameworks; 142 | sourceTree = ""; 143 | }; 144 | EC2E01F5E238D03474C86063 /* Pods */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 816B86576B91AC9A96A64A38 /* Pods-Runner.debug.xcconfig */, 148 | 7CDD7F71C724078E02937891 /* Pods-Runner.release.xcconfig */, 149 | 7EBA0EBE560CCE22B2FB9D0C /* Pods-Runner.profile.xcconfig */, 150 | ); 151 | path = Pods; 152 | sourceTree = ""; 153 | }; 154 | /* End PBXGroup section */ 155 | 156 | /* Begin PBXNativeTarget section */ 157 | 97C146ED1CF9000F007C117D /* Runner */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 160 | buildPhases = ( 161 | 99EC970B43A4235DF25B25FE /* [CP] Check Pods Manifest.lock */, 162 | 9740EEB61CF901F6004384FC /* Run Script */, 163 | 97C146EA1CF9000F007C117D /* Sources */, 164 | 97C146EB1CF9000F007C117D /* Frameworks */, 165 | 97C146EC1CF9000F007C117D /* Resources */, 166 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 167 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 168 | 8BF9924D59788BF4DBD754A4 /* [CP] Embed Pods Frameworks */, 169 | 0DEB039F41A7089EA5E26B7D /* [CP] Copy Pods Resources */, 170 | ); 171 | buildRules = ( 172 | ); 173 | dependencies = ( 174 | ); 175 | name = Runner; 176 | productName = Runner; 177 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 178 | productType = "com.apple.product-type.application"; 179 | }; 180 | /* End PBXNativeTarget section */ 181 | 182 | /* Begin PBXProject section */ 183 | 97C146E61CF9000F007C117D /* Project object */ = { 184 | isa = PBXProject; 185 | attributes = { 186 | LastUpgradeCheck = 0910; 187 | ORGANIZATIONNAME = "The Chromium Authors"; 188 | TargetAttributes = { 189 | 97C146ED1CF9000F007C117D = { 190 | CreatedOnToolsVersion = 7.3.1; 191 | }; 192 | }; 193 | }; 194 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 195 | compatibilityVersion = "Xcode 3.2"; 196 | developmentRegion = English; 197 | hasScannedForEncodings = 0; 198 | knownRegions = ( 199 | English, 200 | en, 201 | Base, 202 | ); 203 | mainGroup = 97C146E51CF9000F007C117D; 204 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 205 | projectDirPath = ""; 206 | projectRoot = ""; 207 | targets = ( 208 | 97C146ED1CF9000F007C117D /* Runner */, 209 | ); 210 | }; 211 | /* End PBXProject section */ 212 | 213 | /* Begin PBXResourcesBuildPhase section */ 214 | 97C146EC1CF9000F007C117D /* Resources */ = { 215 | isa = PBXResourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 219 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 220 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 221 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 222 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 223 | 8DE4883122A4C27700ADFE7D /* GoogleService-Info.plist in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXResourcesBuildPhase section */ 228 | 229 | /* Begin PBXShellScriptBuildPhase section */ 230 | 0DEB039F41A7089EA5E26B7D /* [CP] Copy Pods Resources */ = { 231 | isa = PBXShellScriptBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | ); 235 | inputFileListPaths = ( 236 | ); 237 | inputPaths = ( 238 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", 239 | "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++/gRPCCertificates.bundle", 240 | ); 241 | name = "[CP] Copy Pods Resources"; 242 | outputFileListPaths = ( 243 | ); 244 | outputPaths = ( 245 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | shellPath = /bin/sh; 249 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; 250 | showEnvVarsInLog = 0; 251 | }; 252 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 253 | isa = PBXShellScriptBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | ); 257 | inputPaths = ( 258 | ); 259 | name = "Thin Binary"; 260 | outputPaths = ( 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | shellPath = /bin/sh; 264 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 265 | }; 266 | 8BF9924D59788BF4DBD754A4 /* [CP] Embed Pods Frameworks */ = { 267 | isa = PBXShellScriptBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | inputFileListPaths = ( 272 | ); 273 | inputPaths = ( 274 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 275 | "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", 276 | ); 277 | name = "[CP] Embed Pods Frameworks"; 278 | outputFileListPaths = ( 279 | ); 280 | outputPaths = ( 281 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | shellPath = /bin/sh; 285 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 286 | showEnvVarsInLog = 0; 287 | }; 288 | 9740EEB61CF901F6004384FC /* Run Script */ = { 289 | isa = PBXShellScriptBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | ); 293 | inputPaths = ( 294 | ); 295 | name = "Run Script"; 296 | outputPaths = ( 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | shellPath = /bin/sh; 300 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 301 | }; 302 | 99EC970B43A4235DF25B25FE /* [CP] Check Pods Manifest.lock */ = { 303 | isa = PBXShellScriptBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | inputFileListPaths = ( 308 | ); 309 | inputPaths = ( 310 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 311 | "${PODS_ROOT}/Manifest.lock", 312 | ); 313 | name = "[CP] Check Pods Manifest.lock"; 314 | outputFileListPaths = ( 315 | ); 316 | outputPaths = ( 317 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | shellPath = /bin/sh; 321 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 322 | showEnvVarsInLog = 0; 323 | }; 324 | /* End PBXShellScriptBuildPhase section */ 325 | 326 | /* Begin PBXSourcesBuildPhase section */ 327 | 97C146EA1CF9000F007C117D /* Sources */ = { 328 | isa = PBXSourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 332 | 97C146F31CF9000F007C117D /* main.m in Sources */, 333 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | /* End PBXSourcesBuildPhase section */ 338 | 339 | /* Begin PBXVariantGroup section */ 340 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 341 | isa = PBXVariantGroup; 342 | children = ( 343 | 97C146FB1CF9000F007C117D /* Base */, 344 | ); 345 | name = Main.storyboard; 346 | sourceTree = ""; 347 | }; 348 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | 97C147001CF9000F007C117D /* Base */, 352 | ); 353 | name = LaunchScreen.storyboard; 354 | sourceTree = ""; 355 | }; 356 | /* End PBXVariantGroup section */ 357 | 358 | /* Begin XCBuildConfiguration section */ 359 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 360 | isa = XCBuildConfiguration; 361 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 362 | buildSettings = { 363 | ALWAYS_SEARCH_USER_PATHS = NO; 364 | CLANG_ANALYZER_NONNULL = YES; 365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 366 | CLANG_CXX_LIBRARY = "libc++"; 367 | CLANG_ENABLE_MODULES = YES; 368 | CLANG_ENABLE_OBJC_ARC = YES; 369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_COMMA = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INFINITE_RECURSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 381 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 382 | CLANG_WARN_STRICT_PROTOTYPES = YES; 383 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 384 | CLANG_WARN_UNREACHABLE_CODE = YES; 385 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 386 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 387 | COPY_PHASE_STRIP = NO; 388 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 389 | ENABLE_NS_ASSERTIONS = NO; 390 | ENABLE_STRICT_OBJC_MSGSEND = YES; 391 | GCC_C_LANGUAGE_STANDARD = gnu99; 392 | GCC_NO_COMMON_BLOCKS = YES; 393 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 394 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 395 | GCC_WARN_UNDECLARED_SELECTOR = YES; 396 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 397 | GCC_WARN_UNUSED_FUNCTION = YES; 398 | GCC_WARN_UNUSED_VARIABLE = YES; 399 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 400 | MTL_ENABLE_DEBUG_INFO = NO; 401 | SDKROOT = iphoneos; 402 | TARGETED_DEVICE_FAMILY = "1,2"; 403 | VALIDATE_PRODUCT = YES; 404 | }; 405 | name = Profile; 406 | }; 407 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 408 | isa = XCBuildConfiguration; 409 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 410 | buildSettings = { 411 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 412 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 413 | DEVELOPMENT_TEAM = S8QB4VV633; 414 | ENABLE_BITCODE = NO; 415 | FRAMEWORK_SEARCH_PATHS = ( 416 | "$(inherited)", 417 | "$(PROJECT_DIR)/Flutter", 418 | ); 419 | INFOPLIST_FILE = Runner/Info.plist; 420 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 421 | LIBRARY_SEARCH_PATHS = ( 422 | "$(inherited)", 423 | "$(PROJECT_DIR)/Flutter", 424 | ); 425 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleFirebaseAuth; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | VERSIONING_SYSTEM = "apple-generic"; 428 | }; 429 | name = Profile; 430 | }; 431 | 97C147031CF9000F007C117D /* Debug */ = { 432 | isa = XCBuildConfiguration; 433 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 434 | buildSettings = { 435 | ALWAYS_SEARCH_USER_PATHS = NO; 436 | CLANG_ANALYZER_NONNULL = YES; 437 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 438 | CLANG_CXX_LIBRARY = "libc++"; 439 | CLANG_ENABLE_MODULES = YES; 440 | CLANG_ENABLE_OBJC_ARC = YES; 441 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 442 | CLANG_WARN_BOOL_CONVERSION = YES; 443 | CLANG_WARN_COMMA = YES; 444 | CLANG_WARN_CONSTANT_CONVERSION = YES; 445 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 446 | CLANG_WARN_EMPTY_BODY = YES; 447 | CLANG_WARN_ENUM_CONVERSION = YES; 448 | CLANG_WARN_INFINITE_RECURSION = YES; 449 | CLANG_WARN_INT_CONVERSION = YES; 450 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 451 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 453 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 454 | CLANG_WARN_STRICT_PROTOTYPES = YES; 455 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 456 | CLANG_WARN_UNREACHABLE_CODE = YES; 457 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 458 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 459 | COPY_PHASE_STRIP = NO; 460 | DEBUG_INFORMATION_FORMAT = dwarf; 461 | ENABLE_STRICT_OBJC_MSGSEND = YES; 462 | ENABLE_TESTABILITY = YES; 463 | GCC_C_LANGUAGE_STANDARD = gnu99; 464 | GCC_DYNAMIC_NO_PIC = NO; 465 | GCC_NO_COMMON_BLOCKS = YES; 466 | GCC_OPTIMIZATION_LEVEL = 0; 467 | GCC_PREPROCESSOR_DEFINITIONS = ( 468 | "DEBUG=1", 469 | "$(inherited)", 470 | ); 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 478 | MTL_ENABLE_DEBUG_INFO = YES; 479 | ONLY_ACTIVE_ARCH = YES; 480 | SDKROOT = iphoneos; 481 | TARGETED_DEVICE_FAMILY = "1,2"; 482 | }; 483 | name = Debug; 484 | }; 485 | 97C147041CF9000F007C117D /* Release */ = { 486 | isa = XCBuildConfiguration; 487 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 488 | buildSettings = { 489 | ALWAYS_SEARCH_USER_PATHS = NO; 490 | CLANG_ANALYZER_NONNULL = YES; 491 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 492 | CLANG_CXX_LIBRARY = "libc++"; 493 | CLANG_ENABLE_MODULES = YES; 494 | CLANG_ENABLE_OBJC_ARC = YES; 495 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 496 | CLANG_WARN_BOOL_CONVERSION = YES; 497 | CLANG_WARN_COMMA = YES; 498 | CLANG_WARN_CONSTANT_CONVERSION = YES; 499 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INFINITE_RECURSION = YES; 503 | CLANG_WARN_INT_CONVERSION = YES; 504 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 505 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 506 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 507 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 508 | CLANG_WARN_STRICT_PROTOTYPES = YES; 509 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 510 | CLANG_WARN_UNREACHABLE_CODE = YES; 511 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 512 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 513 | COPY_PHASE_STRIP = NO; 514 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 515 | ENABLE_NS_ASSERTIONS = NO; 516 | ENABLE_STRICT_OBJC_MSGSEND = YES; 517 | GCC_C_LANGUAGE_STANDARD = gnu99; 518 | GCC_NO_COMMON_BLOCKS = YES; 519 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 520 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 521 | GCC_WARN_UNDECLARED_SELECTOR = YES; 522 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 523 | GCC_WARN_UNUSED_FUNCTION = YES; 524 | GCC_WARN_UNUSED_VARIABLE = YES; 525 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 526 | MTL_ENABLE_DEBUG_INFO = NO; 527 | SDKROOT = iphoneos; 528 | TARGETED_DEVICE_FAMILY = "1,2"; 529 | VALIDATE_PRODUCT = YES; 530 | }; 531 | name = Release; 532 | }; 533 | 97C147061CF9000F007C117D /* Debug */ = { 534 | isa = XCBuildConfiguration; 535 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 536 | buildSettings = { 537 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 538 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 539 | ENABLE_BITCODE = NO; 540 | FRAMEWORK_SEARCH_PATHS = ( 541 | "$(inherited)", 542 | "$(PROJECT_DIR)/Flutter", 543 | ); 544 | INFOPLIST_FILE = Runner/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 546 | LIBRARY_SEARCH_PATHS = ( 547 | "$(inherited)", 548 | "$(PROJECT_DIR)/Flutter", 549 | ); 550 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleFirebaseAuth; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | VERSIONING_SYSTEM = "apple-generic"; 553 | }; 554 | name = Debug; 555 | }; 556 | 97C147071CF9000F007C117D /* Release */ = { 557 | isa = XCBuildConfiguration; 558 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 559 | buildSettings = { 560 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 561 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 562 | ENABLE_BITCODE = NO; 563 | FRAMEWORK_SEARCH_PATHS = ( 564 | "$(inherited)", 565 | "$(PROJECT_DIR)/Flutter", 566 | ); 567 | INFOPLIST_FILE = Runner/Info.plist; 568 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 569 | LIBRARY_SEARCH_PATHS = ( 570 | "$(inherited)", 571 | "$(PROJECT_DIR)/Flutter", 572 | ); 573 | PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleFirebaseAuth; 574 | PRODUCT_NAME = "$(TARGET_NAME)"; 575 | VERSIONING_SYSTEM = "apple-generic"; 576 | }; 577 | name = Release; 578 | }; 579 | /* End XCBuildConfiguration section */ 580 | 581 | /* Begin XCConfigurationList section */ 582 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 583 | isa = XCConfigurationList; 584 | buildConfigurations = ( 585 | 97C147031CF9000F007C117D /* Debug */, 586 | 97C147041CF9000F007C117D /* Release */, 587 | 249021D3217E4FDB00AE95B9 /* Profile */, 588 | ); 589 | defaultConfigurationIsVisible = 0; 590 | defaultConfigurationName = Release; 591 | }; 592 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 593 | isa = XCConfigurationList; 594 | buildConfigurations = ( 595 | 97C147061CF9000F007C117D /* Debug */, 596 | 97C147071CF9000F007C117D /* Release */, 597 | 249021D4217E4FDB00AE95B9 /* Profile */, 598 | ); 599 | defaultConfigurationIsVisible = 0; 600 | defaultConfigurationName = Release; 601 | }; 602 | /* End XCConfigurationList section */ 603 | }; 604 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 605 | } 606 | --------------------------------------------------------------------------------