├── .firebaserc ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── 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 │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── asset │ └── icon.png ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── 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-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ ├── landing_page.dart │ ├── login_page.dart │ ├── main.dart │ └── user_credential_provider.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── firebase.json ├── functions ├── .gitignore ├── index.js ├── kakao.js ├── package-lock.json └── package.json ├── lib ├── firebase_auth_simplify.dart └── src │ ├── api │ ├── base_auth_api.dart │ ├── firebase_apple_auth_api.dart │ ├── firebase_email_auth_api.dart │ ├── firebase_facebook_auth_api.dart │ ├── firebase_google_auth_api.dart │ ├── firebase_kakao_auth_api.dart │ └── firebase_phone_auth_api.dart │ └── firebase_auth_provider.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshots ├── link.PNG └── signin.PNG └── test └── firebase_auth_simplify_test.dart /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-auth-simplify-28bbc" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Flutter Doctor -v** 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.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 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 76 | example/android/app/google-services.json 77 | example/android/app/src/main/res/values/kakao_strings.xml 78 | example/android/app/src/main/res/values/strings.xml 79 | example/ios/Runner/Info.plist 80 | -------------------------------------------------------------------------------- /.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: 27321ebbad34b0a3fafe99fac037102196d655ff 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.1.1] - 27/Jan/2021 2 | 3 | - Removed firebase analytics 4 | 5 | ## [2.1.0] - 26/Jan/2021 6 | 7 | - Updated firebase versions and Kakao SDK. 8 | 9 | ## [2.0.5] - 24/Nov/2020 10 | 11 | - Added emailRequired parameter for Kakao Login. Setting true will force Kakao sign-in to have email. 12 | 13 | ## [2.0.4] - 24/Nov/2020 14 | 15 | - Removed debug print. 16 | 17 | ## [2.0.3] - 24/Nov/2020 18 | 19 | - Kakao bug fix. 20 | 21 | ## [2.0.2] - 24/Nov/2020 22 | 23 | - Added await for other login methods' email updates. 24 | 25 | ## [2.0.1] - 23/Nov/2020 26 | 27 | - Fixed bug by adding await as updating email from Kakao login was not respecting 'Future' return. 28 | 29 | ## [2.0.0] - 10/Nov/2020 30 | 31 | - Refactored to allow new verison of firebase packages as the firebase core version has critical changes since version 0.5.0 32 | 33 | ## [1.3.0] - 05/Oct/2020 34 | 35 | - Update kaka_flutter_sdk version to support Flutter 1.22.0 error 36 | 37 | ## [1.2.0] - 25/Sep/2020 38 | 39 | - Supporting Apple sign in. 40 | 41 | ## [1.1.2] - 13/Aug/2020 42 | 43 | - Removed codes that uses existing token for Kakao login. 44 | 45 | ## [1.1.1] - 12/Aug/2020 46 | 47 | - Reverted retrieveToken() function to private. We can use AccessTokenStore.instance.fromStore() to fetch access token after logged in. 48 | 49 | ## [1.1.0] - 12/Aug/2020 50 | 51 | - Made retrieveToken() function public so that we can use it for other Kakao APIs. 52 | 53 | ## [1.0.0] - 11/Aug/2020 54 | 55 | - Switched Kakao SDK to the official package. 56 | 57 | ## [0.6.4] - 29/Jul/2020 58 | 59 | - Added exception code on missing email for facebook auth. 60 | 61 | ## [0.6.3] - 29/Jul/2020 62 | 63 | - Fixed typo of Kakao exception code. 64 | 65 | ## [0.6.2] - 20/Jul/2020 66 | 67 | - Updated fierbase pacakge versions. 68 | 69 | ## [0.6.1] - 21/Apr/2020 70 | 71 | - Updated getUserClaim() function to check null on user data. 72 | 73 | ## [0.6.0] - 20/Apr/2020 74 | 75 | - Added unlink feature. 76 | 77 | ## [0.5.0] - 15/Apr/2020 78 | 79 | - Fixed 'com.google.firebase.messaging.FirebaseMessagingService is inaccessible' erorr by updating firebase_auth package version. 80 | 81 | ## [0.4.4] - 2/Feb/2020 82 | 83 | - Bug Fix. 84 | 85 | ## [0.4.3] - 1/Feb/2020 86 | 87 | - Update document 88 | 89 | ## [0.4.2] - 30/Jan/2020 90 | 91 | - Added information about app crash regarding Facebook package issue 92 | 93 | ## [0.4.1] - 30/Jan/2020 94 | 95 | - Added example screenshots 96 | 97 | ## [0.4.0] - 29/Jan/2020 98 | 99 | - Added Phone authentication 100 | - Added Phone authentication example 101 | - Added assertion for sign-in logic 102 | 103 | ## [0.3.3] - 29/Jan/2020 104 | 105 | - Fixed bug that Kakao sign-in links automatically with existing e-mail. It will throw an error and only can be linked by using link function. 106 | - Kakao sign-in will throw a new exception in regards to above issue. 107 | - Added try-catch block for email authentication. It will now catch error correctly. 108 | - Fixed bug at example code. It will now trim the white space before sending to the server. 109 | - Fixed bug at example code. Sign-in/out dialog will be disappear as expected when sign-in/out is succeeded. 110 | 111 | ## [0.3.2] - 29/Jan/2020 112 | 113 | - Minor bug fix 114 | 115 | ## [0.3.1] - 29/Jan/2020 116 | 117 | - Added getUserClaim function so that we can get claim data from provider 118 | - Changed logic of signing-out from 3rd party providers 119 | 120 | ## [0.3.0] - 28/Jan/2020 121 | 122 | - Updated cloud function for verifiying/creating Kakao token 123 | - Changed logic of Kakao sign in 124 | - Refactoring Kakao sign in 125 | - Refactoring other sign ins 126 | - Added linking function 127 | - Made email and password as a required field 128 | 129 | ## [0.2.0] - 27/Jan/2020 130 | 131 | - Supporting Facebook sign in 132 | 133 | ## [0.1.0] - 27/Jan/2020 134 | 135 | - Supporting Kakao sign in 136 | 137 | ## [0.0.1] - 25/Jan/2020 138 | 139 | - Initial release with Firebase email and Gmail support 140 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Terry Kwon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firebase Authentication Simplify 2 | 3 | Wrapper package of framework of [Firebase Auth](https://pub.dev/packages/firebase_auth) package that wraps several lines of codes to one line in order to easily use sign-in function. 4 | 5 | ![](screenshots/signin.PNG) 6 | ![](screenshots/link.PNG) 7 | 8 | ## Why/Who should use this 9 | 10 | You may want to use [firebase_auth](https://pub.dev/packages/firebase_auth) package directly if you need specific customization on sign-in/out logic. 11 | However, although the most of usecases have almost the same signing-in and out codes, it is pain to write redundant codes everytime even if it is just a several lines of code. Especially, when you provide more than 2 sign-in methods. 12 | 13 | You will basically write some codes like below for **Each** of sign-in methods, and you want to manage it seperatly from the widget you use. 14 | 15 | ```dart 16 | // Example of typical Google sign in (What you will do with original packages) 17 | 18 | final GoogleSignIn _googleSignIn = GoogleSignIn(); 19 | final FirebaseAuth _auth = FirebaseAuth.instance; 20 | 21 | Future _handleSignIn() async { 22 | final GoogleSignInAccount googleUser = await _googleSignIn.signIn(); 23 | final GoogleSignInAuthentication googleAuth = await googleUser.authentication; 24 | 25 | final AuthCredential credential = GoogleAuthProvider.getCredential( 26 | accessToken: googleAuth.accessToken, 27 | idToken: googleAuth.idToken, 28 | ); 29 | 30 | final FirebaseUser user = (await _auth.signInWithCredential(credential)).user; 31 | print("signed in " + user.displayName); 32 | return user; 33 | } 34 | 35 | _handleSignIn() 36 | .then((FirebaseUser user) => print(user)) 37 | .catchError((e) => print(e)); 38 | 39 | _handleSignOut() { 40 | ... 41 | } 42 | ``` 43 | 44 | **This package has nothing fancy but just do the dirty things for you and what you will have is something like:** 45 | 46 | ```dart 47 | import 'package:firebase_auth_simplify/firebase_auth_simplify.dart'; 48 | 49 | // Google 50 | FirebaseAuthProvider.signInWith(GoogleSignInAPI()); 51 | 52 | // Facebook 53 | FirebaseAuthProvider.signInWith(FacebookSignInAPI()); 54 | 55 | ... 56 | ``` 57 | 58 | So if your priority is 'simplicity' and 'less code' for 3rd party integration, it is worth using this package. 59 | 60 | ## Who should consider NOT using this 61 | Firstly, if your project only uses firebase provided sign-in methods, such as email or phone auth, it is better using [firebase_auth](https://pub.dev/packages/firebase_auth) package directly. 62 | 63 | Secondly, as this package includes several 3rd party sign-ins, such as google, facebook and kakao, it contains related packages which you might not need it. For example, even though you only provide email and google sign-in methods to the customer, your project will still contain facebook or other sign-in packages which is not necessary in your case. If the issue matters to you, I recommend using your own way instead of implementing this package 64 | 65 | ## Currently supporting Sign-ins 66 | - [X] Email 67 | - [X] Phone 68 | - [X] Google 69 | - [ ] Google Play Games 70 | - [X] Facebook 71 | - [X] Kakao 72 | - [X] Apple 73 | - [ ] GameCenter 74 | - [ ] Twitter 75 | - [ ] Github 76 | - [ ] Line 77 | 78 | ## Support 79 | If the package was useful or saved your time, please do not hesitate to buy me a cup of coffee! ;) 80 | The more caffeine I get, the more useful projects I can make in the future. 81 | 82 | Buy Me A Coffee 83 | 84 | 85 | ## Getting Started 86 | 87 | > **NOTE: Only setup what you need. No need to configure all of followings** 88 | > 89 | > IF you encounter app crashes, you must [configure Facebook setting](https://pub.dev/packages/flutter_facebook_login). 90 | > ``` 91 | > Caused by com.facebook.FacebookSdkNotInitializedException 92 | > The SDK has not been initialized, make sure to call FacebookSdk.sdkInitialize() first. 93 | > ``` 94 | > 95 | > The crash is happening because facebook auth package checkes the app id even if you do not use it and throws an exception when it is not set properly. 96 | > 97 | 98 | ### Firebase Auth Setup 99 | This project uses firebase_auth package and is just a wrapper of it. So please make sure you follow setup instruction of [firebase_auth](https://pub.dev/packages/firebase_auth). 100 | 101 | You basically need to [set google services](https://pub.dev/packages/firebase_auth) at Android build.gradle files, and then **you must [add App](https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html#6) at Firebase Console**. 102 | 103 | > **NOTE**: If previous setting is not completed you will get an error like below. 104 | 105 | > ``` 106 | > java.lang.IllegalStateException: 107 | > Default FirebaseApp is not initialized in this process [package name]. 108 | > Make sure to call FirebaseApp.initializeApp(Context) first. 109 | > ``` 110 | 111 | ### Google sign in Setup 112 | Import [google_sign_in](https://pub.dev/packages/google_sign_in) package and follow the instruction. 113 | 114 | ### Facebook sign in Setup 115 | Import [flutter_facebook_login](https://pub.dev/packages/flutter_facebook_login) package and follow the instruction. 116 | 117 | > **Note**: Use [openssl-0.9.8e_X64](https://code.google.com/archive/p/openssl-for-windows/downloads) for getting key hash. Otherwise, it will fail to authenticate. 118 | > Also, on Windows platform, DO NOT use keytool at powershall using vs code's terminal. Use cmd. 119 | 120 | ### Apple sign in Setup 121 | Import [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package and follow the instruction there or follow the instruction on [this package](https://pub.dev/packages/apple_sign_in) for setting stuffs on apple developer site only. 122 | 123 | ### Kakao sign in Setup 124 | Import [kakao_flutter_sdk](https://github.com/kakao/kakao_flutter_sdk) package and follow the instruction. Steps are similar to Facebook settings. 125 | 1. Create an app at kakao developer portal. 126 | 2. Set key hash in there. 127 | > **Note**: Use [openssl-0.9.8e_X64](https://code.google.com/archive/p/openssl-for-windows/downloads) for getting key hash. Otherwise, it will fail to authenticate. 128 | > Also, on Windows platform, DO NOT use keytool at powershall using vs code's terminal. Use cmd. 129 | 130 | For Android, 131 | Set AndroidManfest.xml 132 | 133 | For iOS, 134 | Set info.plist and import SDK into xcode before building. 135 | 136 | For Firebase, 137 | We need a [cloud function](https://pub.dev/packages/cloud_functions) which creates custom token with kakao access token. Please refer to below documents. 138 | 1. [Issue ticket](https://github.com/FirebaseExtended/custom-auth-samples/issues/10) at FirebaseExtended github. 139 | 2. [Basic implementation](https://github.com/FirebaseExtended/custom-auth-samples/blob/master/kakao/KakaoLoginServer/app.js) at FirebaseExtended github. 140 | 3. [Improved implementation](https://github.com/CoderSpinoza/custom-auth-samples/blob/kakao/update-versions/kakao/KakaoLoginServer/app.js) by CorderSpinoza at github. 141 | 4. [Usage of userClaims](https://stackoverflow.com/a/58373886/12567737) at Stackoverflow. 142 | 5. npm install --save request request-promise to use 'request-promise module' 143 | 6. **IMPORTANT: Make sure to call 'createCustomToken' with { provider: "kakaocorp.com" } at 2nd parameter. If not, you won't be able to call sign-out for it.** 144 | 145 | **Note: Either using config.json file or using config 'firebase functions:config:set kakao.appid=your_kakao_app_id' for cloud function is recommended instead of coding it directely into cloud function code. 146 | Then, you can decalre like:** 147 | ``` 148 | const kakaoId = require("./config.json"); 149 | const kakaoId = functions.config().kakao.appid; 150 | ``` 151 | 152 | If you encounter below error, follow the link and enable API. 153 | ``` 154 | {error: {codePrefix: auth, errorInfo: {code: auth/insufficient-permission, message: Identity and Access Management (IAM) API has not been used in project YOUR_PROJECT_ID before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=YOUR_PROJECT_ID then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature.}}} 155 | ``` 156 | 157 | If you see below error, you also need to set Permission of iam.serviceAccounts.signBolb. 158 | ``` 159 | {error: {codePrefix: auth, errorInfo: {code: auth/insufficient-permission, message: Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/YOUR_PROJECT_NAME@appspot.gserviceaccount.com.; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature.}}} 160 | ``` 161 | [Grant permission](https://stackoverflow.com/a/54066988/12567737) in console. 162 | 163 | Lastly, as this uses external request, you need to **change your plan to 'Blaze'**. Otherwise, you will get 500 error. 164 | 165 | ## Usage 166 | 167 | ### Simple Sign-up/in/out 168 | Simply initialize the class you want to sign in for, and call signIn() function. 169 | **NOTE: If you use it this way, you need to manage 3rd party sign-'out' logic yourself, because ['firebase_auth' package does not support the function](https://github.com/FirebaseExtended/flutterfire/issues/891) yet. It only provides signOut() function which signs out from the firebase, not from 3rd party providers. You also have to manage linking option yourself if needed.** 170 | 171 | #### Sign-Up / Sign-In 172 | ```dart 173 | // e-mail 174 | FirebaseEmailAuthAPI(email: inputEmail, password: inputPassword).signUp(); 175 | FirebaseEmailAuthAPI(email: inputEmail, password: inputPassword).signIn(); 176 | 177 | // phone auth 178 | FirebasePhoneAuthAPI phoneAuthAPI = FirebasePhoneAuthAPI(); 179 | phoneAuthAPI.verifyNumber(phoneNumber, ....); 180 | phoneAuthAPI.submitVerificationCode(code); 181 | phoneAuthAPI.signIn(); 182 | 183 | // google 184 | FirebaseGoogleAuthAPI().signIn(); 185 | FirebaseGoogleAuthAPI(scopes: ['email', 'https://www.googleapis.com/auth/contacts.readonly']).signIn(); 186 | 187 | // Kakao 188 | FirebaseKakaoAuthAPI().signIn(); 189 | 190 | // Facebook 191 | FirebaseFacebookAuthAPI().signIn(); 192 | ``` 193 | 194 | #### Sign-Out 195 | ```dart 196 | // Signing out using original package of firebase_auth. 197 | // IMPORTANT: This will NOT sign out from 3rd party provider 198 | FirebaseAuth.instance.signOut(); 199 | ``` 200 | 201 | ### Using the wrapper (Recommended) 202 | We provide FirebaseAuthProvider so that we can manage sign-out and 3rd party providers' account linking function for you. 203 | 204 | #### Sign-Up / Sign-In 205 | ```dart 206 | FirebaseAuthProvider.instance.signUpWith(FirebaseWhateverAuthAPI()); // Only works with firebase provided auth. (eg. email) 207 | FirebaseAuthProvider.instance.signInWith(FirebaseWhateverAuthAPI()); 208 | ``` 209 | 210 | *Phone authenticate needs few more lines.* 211 | ```dart 212 | FirebasePhoneAuthAPI phoneAuthAPI = FirebasePhoneAuthAPI(); 213 | phoneAuthAPI.verifyNumber(phoneNumber, ....); 214 | phoneAuthAPI.submitVerificationCode(code); 215 | 216 | FirebaseAuthProvider.instance.signInWith(phoneAuthAPI); 217 | ``` 218 | 219 | #### Sign-Out 220 | ``` dart 221 | // Then you can sign-out anywhere. 222 | FirebaseAuthProvider.instance.signOut(); 223 | ``` 224 | **NOTE: Good thing to use this way is it does not only sign out from Firestore, but also sign out from 3rd party provider which we can allow user to sign-in with another account to the same provider. Also, you can manage account linking easily.** 225 | 226 | #### Linking 227 | ```dart 228 | FirebaseAuthProvider.instance.linkCurrentUserWith(FirebaseWhateverAuthAPI()); 229 | ``` 230 | 231 | *Phone authenticate needs few more lines.* 232 | ```dart 233 | final FirebasePhoneAuthAPI phoneAuthAPI = FirebasePhoneAuthAPI(); // Initialize first 234 | phoneAuthAPI.verifyNumber(phoneNumber, ......); // Send phone number to get code 235 | phoneAuthAPI.submitVerificationCode(code); // Submit the 6 digit code 236 | 237 | FirebaseAuthProvider.instance.linkCurrentUserWith(phoneAuthAPI); // Then try link (Will get ERROR_INVALID_VERIFICATION_CODE exception if code is wrong) 238 | ``` 239 | 240 | #### Unlinking 241 | ```dart 242 | FirebaseAuthProvider.instance.unlinkCurrentUserFrom(FirebaseWhateverAuthAPI()); 243 | ``` 244 | 245 | ### Other useful packages you might be instrested 246 | [Material design Speed Dial](https://pub.dev/packages/flutter_speed_dial_material_design) 247 | [Google Maps Place Picker](https://pub.dev/packages/google_maps_place_picker) 248 | 249 | Buy Me A Coffee 250 | -------------------------------------------------------------------------------- /example/.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 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /example/.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: 27321ebbad34b0a3fafe99fac037102196d655ff 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /example/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 | // Add this line for google services 26 | apply plugin: 'com.google.gms.google-services' 27 | 28 | apply plugin: 'kotlin-android' 29 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 30 | 31 | android { 32 | compileSdkVersion 28 33 | 34 | sourceSets { 35 | main.java.srcDirs += 'src/main/kotlin' 36 | } 37 | 38 | lintOptions { 39 | disable 'InvalidPackage' 40 | } 41 | 42 | defaultConfig { 43 | applicationId "com.gixgames.app.flutter.firebaseauthsimplify" 44 | minSdkVersion 21 45 | targetSdkVersion 28 46 | versionCode flutterVersionCode.toInteger() 47 | versionName flutterVersionName 48 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 49 | } 50 | 51 | buildTypes { 52 | release { 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' 65 | testImplementation 'junit:junit:4.12' 66 | androidTestImplementation 'androidx.test:runner:1.1.1' 67 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 68 | } -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 9 | 10 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | // Add the google services classpath 12 | classpath 'com.google.gms:google-services:4.3.3' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | } 21 | } 22 | 23 | rootProject.buildDir = '../build' 24 | subprojects { 25 | project.buildDir = "${rootProject.buildDir}/${project.name}" 26 | } 27 | subprojects { 28 | project.evaluationDependsOn(':app') 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /example/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-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/asset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/asset/icon.png -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/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 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 18 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 19 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXCopyFilesBuildPhase section */ 23 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 24 | isa = PBXCopyFilesBuildPhase; 25 | buildActionMask = 2147483647; 26 | dstPath = ""; 27 | dstSubfolderSpec = 10; 28 | files = ( 29 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 30 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 31 | ); 32 | name = "Embed Frameworks"; 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXCopyFilesBuildPhase section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 39 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 40 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 41 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 42 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 43 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 45 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 46 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 47 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 48 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 61 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 9740EEB11CF90186004384FC /* Flutter */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 3B80C3931E831B6300D905FE /* App.framework */, 72 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 73 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 74 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 75 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 76 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 77 | ); 78 | name = Flutter; 79 | sourceTree = ""; 80 | }; 81 | 97C146E51CF9000F007C117D = { 82 | isa = PBXGroup; 83 | children = ( 84 | 9740EEB11CF90186004384FC /* Flutter */, 85 | 97C146F01CF9000F007C117D /* Runner */, 86 | 97C146EF1CF9000F007C117D /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 97C146EF1CF9000F007C117D /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 97C146EE1CF9000F007C117D /* Runner.app */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 97C146F01CF9000F007C117D /* Runner */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 102 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 103 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 104 | 97C147021CF9000F007C117D /* Info.plist */, 105 | 97C146F11CF9000F007C117D /* Supporting Files */, 106 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 107 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 108 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 109 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 110 | ); 111 | path = Runner; 112 | sourceTree = ""; 113 | }; 114 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | ); 118 | name = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | 97C146ED1CF9000F007C117D /* Runner */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 127 | buildPhases = ( 128 | 9740EEB61CF901F6004384FC /* Run Script */, 129 | 97C146EA1CF9000F007C117D /* Sources */, 130 | 97C146EB1CF9000F007C117D /* Frameworks */, 131 | 97C146EC1CF9000F007C117D /* Resources */, 132 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 133 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 134 | ); 135 | buildRules = ( 136 | ); 137 | dependencies = ( 138 | ); 139 | name = Runner; 140 | productName = Runner; 141 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 142 | productType = "com.apple.product-type.application"; 143 | }; 144 | /* End PBXNativeTarget section */ 145 | 146 | /* Begin PBXProject section */ 147 | 97C146E61CF9000F007C117D /* Project object */ = { 148 | isa = PBXProject; 149 | attributes = { 150 | LastUpgradeCheck = 1020; 151 | ORGANIZATIONNAME = "The Chromium Authors"; 152 | TargetAttributes = { 153 | 97C146ED1CF9000F007C117D = { 154 | CreatedOnToolsVersion = 7.3.1; 155 | LastSwiftMigration = 1100; 156 | }; 157 | }; 158 | }; 159 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = en; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | Base, 166 | ); 167 | mainGroup = 97C146E51CF9000F007C117D; 168 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 169 | projectDirPath = ""; 170 | projectRoot = ""; 171 | targets = ( 172 | 97C146ED1CF9000F007C117D /* Runner */, 173 | ); 174 | }; 175 | /* End PBXProject section */ 176 | 177 | /* Begin PBXResourcesBuildPhase section */ 178 | 97C146EC1CF9000F007C117D /* Resources */ = { 179 | isa = PBXResourcesBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 183 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 184 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 185 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXResourcesBuildPhase section */ 190 | 191 | /* Begin PBXShellScriptBuildPhase section */ 192 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 193 | isa = PBXShellScriptBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | ); 197 | inputPaths = ( 198 | ); 199 | name = "Thin Binary"; 200 | outputPaths = ( 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | shellPath = /bin/sh; 204 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 205 | }; 206 | 9740EEB61CF901F6004384FC /* Run Script */ = { 207 | isa = PBXShellScriptBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | ); 211 | inputPaths = ( 212 | ); 213 | name = "Run Script"; 214 | outputPaths = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | shellPath = /bin/sh; 218 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 219 | }; 220 | /* End PBXShellScriptBuildPhase section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | 97C146EA1CF9000F007C117D /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 228 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin PBXVariantGroup section */ 235 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | 97C146FB1CF9000F007C117D /* Base */, 239 | ); 240 | name = Main.storyboard; 241 | sourceTree = ""; 242 | }; 243 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 244 | isa = PBXVariantGroup; 245 | children = ( 246 | 97C147001CF9000F007C117D /* Base */, 247 | ); 248 | name = LaunchScreen.storyboard; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXVariantGroup section */ 252 | 253 | /* Begin XCBuildConfiguration section */ 254 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 255 | isa = XCBuildConfiguration; 256 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_ANALYZER_NONNULL = YES; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_COMMA = YES; 267 | CLANG_WARN_CONSTANT_CONVERSION = YES; 268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_EMPTY_BODY = YES; 271 | CLANG_WARN_ENUM_CONVERSION = YES; 272 | CLANG_WARN_INFINITE_RECURSION = YES; 273 | CLANG_WARN_INT_CONVERSION = YES; 274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 279 | CLANG_WARN_STRICT_PROTOTYPES = YES; 280 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 286 | ENABLE_NS_ASSERTIONS = NO; 287 | ENABLE_STRICT_OBJC_MSGSEND = YES; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 297 | MTL_ENABLE_DEBUG_INFO = NO; 298 | SDKROOT = iphoneos; 299 | SUPPORTED_PLATFORMS = iphoneos; 300 | TARGETED_DEVICE_FAMILY = "1,2"; 301 | VALIDATE_PRODUCT = YES; 302 | }; 303 | name = Profile; 304 | }; 305 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 306 | isa = XCBuildConfiguration; 307 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 308 | buildSettings = { 309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 310 | CLANG_ENABLE_MODULES = YES; 311 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 312 | ENABLE_BITCODE = NO; 313 | FRAMEWORK_SEARCH_PATHS = ( 314 | "$(inherited)", 315 | "$(PROJECT_DIR)/Flutter", 316 | ); 317 | INFOPLIST_FILE = Runner/Info.plist; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 319 | LIBRARY_SEARCH_PATHS = ( 320 | "$(inherited)", 321 | "$(PROJECT_DIR)/Flutter", 322 | ); 323 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 324 | PRODUCT_NAME = "$(TARGET_NAME)"; 325 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 326 | SWIFT_VERSION = 5.0; 327 | VERSIONING_SYSTEM = "apple-generic"; 328 | }; 329 | name = Profile; 330 | }; 331 | 97C147031CF9000F007C117D /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 334 | buildSettings = { 335 | ALWAYS_SEARCH_USER_PATHS = NO; 336 | CLANG_ANALYZER_NONNULL = YES; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 342 | CLANG_WARN_BOOL_CONVERSION = YES; 343 | CLANG_WARN_COMMA = YES; 344 | CLANG_WARN_CONSTANT_CONVERSION = YES; 345 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 347 | CLANG_WARN_EMPTY_BODY = YES; 348 | CLANG_WARN_ENUM_CONVERSION = YES; 349 | CLANG_WARN_INFINITE_RECURSION = YES; 350 | CLANG_WARN_INT_CONVERSION = YES; 351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 356 | CLANG_WARN_STRICT_PROTOTYPES = YES; 357 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 358 | CLANG_WARN_UNREACHABLE_CODE = YES; 359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 360 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 361 | COPY_PHASE_STRIP = NO; 362 | DEBUG_INFORMATION_FORMAT = dwarf; 363 | ENABLE_STRICT_OBJC_MSGSEND = YES; 364 | ENABLE_TESTABILITY = YES; 365 | GCC_C_LANGUAGE_STANDARD = gnu99; 366 | GCC_DYNAMIC_NO_PIC = NO; 367 | GCC_NO_COMMON_BLOCKS = YES; 368 | GCC_OPTIMIZATION_LEVEL = 0; 369 | GCC_PREPROCESSOR_DEFINITIONS = ( 370 | "DEBUG=1", 371 | "$(inherited)", 372 | ); 373 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 374 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 375 | GCC_WARN_UNDECLARED_SELECTOR = YES; 376 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 377 | GCC_WARN_UNUSED_FUNCTION = YES; 378 | GCC_WARN_UNUSED_VARIABLE = YES; 379 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 380 | MTL_ENABLE_DEBUG_INFO = YES; 381 | ONLY_ACTIVE_ARCH = YES; 382 | SDKROOT = iphoneos; 383 | TARGETED_DEVICE_FAMILY = "1,2"; 384 | }; 385 | name = Debug; 386 | }; 387 | 97C147041CF9000F007C117D /* Release */ = { 388 | isa = XCBuildConfiguration; 389 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 390 | buildSettings = { 391 | ALWAYS_SEARCH_USER_PATHS = NO; 392 | CLANG_ANALYZER_NONNULL = YES; 393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 394 | CLANG_CXX_LIBRARY = "libc++"; 395 | CLANG_ENABLE_MODULES = YES; 396 | CLANG_ENABLE_OBJC_ARC = YES; 397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 398 | CLANG_WARN_BOOL_CONVERSION = YES; 399 | CLANG_WARN_COMMA = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_EMPTY_BODY = YES; 404 | CLANG_WARN_ENUM_CONVERSION = YES; 405 | CLANG_WARN_INFINITE_RECURSION = YES; 406 | CLANG_WARN_INT_CONVERSION = YES; 407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 412 | CLANG_WARN_STRICT_PROTOTYPES = YES; 413 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 417 | COPY_PHASE_STRIP = NO; 418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 419 | ENABLE_NS_ASSERTIONS = NO; 420 | ENABLE_STRICT_OBJC_MSGSEND = YES; 421 | GCC_C_LANGUAGE_STANDARD = gnu99; 422 | GCC_NO_COMMON_BLOCKS = YES; 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNDECLARED_SELECTOR = YES; 426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 427 | GCC_WARN_UNUSED_FUNCTION = YES; 428 | GCC_WARN_UNUSED_VARIABLE = YES; 429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 430 | MTL_ENABLE_DEBUG_INFO = NO; 431 | SDKROOT = iphoneos; 432 | SUPPORTED_PLATFORMS = iphoneos; 433 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 434 | TARGETED_DEVICE_FAMILY = "1,2"; 435 | VALIDATE_PRODUCT = YES; 436 | }; 437 | name = Release; 438 | }; 439 | 97C147061CF9000F007C117D /* Debug */ = { 440 | isa = XCBuildConfiguration; 441 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 442 | buildSettings = { 443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 444 | CLANG_ENABLE_MODULES = YES; 445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 446 | ENABLE_BITCODE = NO; 447 | FRAMEWORK_SEARCH_PATHS = ( 448 | "$(inherited)", 449 | "$(PROJECT_DIR)/Flutter", 450 | ); 451 | INFOPLIST_FILE = Runner/Info.plist; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | LIBRARY_SEARCH_PATHS = ( 454 | "$(inherited)", 455 | "$(PROJECT_DIR)/Flutter", 456 | ); 457 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 461 | SWIFT_VERSION = 5.0; 462 | VERSIONING_SYSTEM = "apple-generic"; 463 | }; 464 | name = Debug; 465 | }; 466 | 97C147071CF9000F007C117D /* Release */ = { 467 | isa = XCBuildConfiguration; 468 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 469 | buildSettings = { 470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 471 | CLANG_ENABLE_MODULES = YES; 472 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 473 | ENABLE_BITCODE = NO; 474 | FRAMEWORK_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "$(PROJECT_DIR)/Flutter", 477 | ); 478 | INFOPLIST_FILE = Runner/Info.plist; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 480 | LIBRARY_SEARCH_PATHS = ( 481 | "$(inherited)", 482 | "$(PROJECT_DIR)/Flutter", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 487 | SWIFT_VERSION = 5.0; 488 | VERSIONING_SYSTEM = "apple-generic"; 489 | }; 490 | name = Release; 491 | }; 492 | /* End XCBuildConfiguration section */ 493 | 494 | /* Begin XCConfigurationList section */ 495 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 496 | isa = XCConfigurationList; 497 | buildConfigurations = ( 498 | 97C147031CF9000F007C117D /* Debug */, 499 | 97C147041CF9000F007C117D /* Release */, 500 | 249021D3217E4FDB00AE95B9 /* Profile */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | 97C147061CF9000F007C117D /* Debug */, 509 | 97C147071CF9000F007C117D /* Release */, 510 | 249021D4217E4FDB00AE95B9 /* Profile */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | /* End XCConfigurationList section */ 516 | }; 517 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 518 | } 519 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/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. -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 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 | KAKAO_APP_KEY 46 | afb19754a1d9f6ffd3441ad737c39311 47 | 48 | LSApplicationQueriesSchemes 49 | 50 | kakaoafb19754a1d9f6ffd3441ad737c39311 51 | kakaokompassauth 52 | storykompassauth 53 | kakaolink 54 | kakaotalk-5.9.7 55 | 56 | 57 | CFBundleURLTypes 58 | 59 | 64 | 65 | CFBundleTypeRole 66 | Editor 67 | CFBundleURLName 68 | 69 | CFBundleURLSchemes 70 | 71 | kakao0123456789abcdefghijklmn 72 | 73 | 74 | 75 | CFBundleURLSchemes 76 | 77 | 81 | fb479673482974182 82 | 83 | 84 | 85 | 86 | FacebookAppID 87 | 88 | 89 | 479673482974182 90 | FacebookDisplayName 91 | 92 | 93 | Flutter Firebase Auth Simplify 94 | 95 | LSApplicationQueriesSchemes 96 | 97 | fbapi 98 | fb-messenger-share-api 99 | fbauth2 100 | fbshareextension 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /example/lib/landing_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/user_credential_provider.dart'; 2 | import 'package:firebase_auth_simplify/firebase_auth_simplify.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class LandingPage extends StatefulWidget { 6 | const LandingPage({Key key}) : super(key: key); 7 | 8 | @override 9 | _LandingPageState createState() => _LandingPageState(); 10 | } 11 | 12 | class _LandingPageState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | print(">>> Build [Landing] Page"); 16 | return SingleChildScrollView( 17 | child: Container( 18 | child: Column( 19 | mainAxisAlignment: MainAxisAlignment.center, 20 | children: [ 21 | _buildSignOutButton(), 22 | _displayUserInfo(), 23 | Row( 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | _buildFacebookLinkButton(), 27 | SizedBox(width: 10), 28 | _buildFacebookUnlinkButton(), 29 | ], 30 | ), 31 | Row( 32 | mainAxisAlignment: MainAxisAlignment.center, 33 | children: [ 34 | _buildGoogleLinkButton(), 35 | SizedBox(width: 10), 36 | _buildGoogleUnlinkButton(), 37 | ], 38 | ), 39 | Row( 40 | mainAxisAlignment: MainAxisAlignment.center, 41 | children: [ 42 | _buildKakaoLinkButton(), 43 | SizedBox(width: 10), 44 | _buildKakaoUnlinkButton(), 45 | ], 46 | ), 47 | Text( 48 | "May take some time linking account for Kakao if the cloud server is on cold start"), 49 | Row( 50 | mainAxisAlignment: MainAxisAlignment.center, 51 | children: [ 52 | _buildPhoneLinkButton(), 53 | SizedBox(width: 10), 54 | _buildPhoneUnlinkButton(), 55 | ], 56 | ), 57 | ], 58 | )), 59 | ); 60 | } 61 | 62 | Widget _buildSignOutButton() { 63 | return RaisedButton( 64 | child: Text("Log out"), 65 | onPressed: () { 66 | FirebaseAuthProvider.instance.signOut(); 67 | }, 68 | ); 69 | } 70 | 71 | Widget _displayUserInfo() { 72 | return FutureBuilder>( 73 | future: FirebaseAuthProvider.instance.getUserClaim(), 74 | builder: (_, snapshot) { 75 | if (snapshot.connectionState == ConnectionState.waiting) { 76 | return Text("Fetching user info"); 77 | } else { 78 | if (snapshot.hasData) { 79 | return Text(snapshot.data.toString()); 80 | } else { 81 | return Text("Could not fetch user info"); 82 | } 83 | } 84 | }, 85 | ); 86 | } 87 | 88 | Widget _buildFacebookLinkButton() { 89 | return RaisedButton( 90 | child: Text("Link with Facebook"), 91 | onPressed: () async { 92 | try { 93 | await FirebaseAuthProvider.instance 94 | .linkCurrentUserWith(FirebaseFacebookAuthAPI()); 95 | setState(() {}); 96 | } catch (e) { 97 | print(e); 98 | } 99 | }, 100 | ); 101 | } 102 | 103 | Widget _buildFacebookUnlinkButton() { 104 | return RaisedButton( 105 | child: Text("Unlink with Facebook"), 106 | onPressed: () async { 107 | try { 108 | await FirebaseAuthProvider.instance 109 | .unlinkCurrentUserFrom(FirebaseFacebookAuthAPI()); 110 | setState(() {}); 111 | } catch (e) { 112 | print(e); 113 | } 114 | }, 115 | ); 116 | } 117 | 118 | Widget _buildGoogleLinkButton() { 119 | return RaisedButton( 120 | child: Text("Link with Google"), 121 | onPressed: () async { 122 | try { 123 | await FirebaseAuthProvider.instance 124 | .linkCurrentUserWith(FirebaseGoogleAuthAPI()); 125 | setState(() {}); 126 | } catch (e) { 127 | print(e); 128 | } 129 | }, 130 | ); 131 | } 132 | 133 | Widget _buildGoogleUnlinkButton() { 134 | return RaisedButton( 135 | child: Text("Unlink with Google"), 136 | onPressed: () async { 137 | try { 138 | await FirebaseAuthProvider.instance 139 | .unlinkCurrentUserFrom(FirebaseGoogleAuthAPI()); 140 | setState(() {}); 141 | } catch (e) { 142 | print(e); 143 | } 144 | }, 145 | ); 146 | } 147 | 148 | Widget _buildKakaoLinkButton() { 149 | return RaisedButton( 150 | child: Text("Link with Kakao"), 151 | onPressed: () async { 152 | try { 153 | await FirebaseAuthProvider.instance 154 | .linkCurrentUserWith(FirebaseKakaoAuthAPI()); 155 | setState(() {}); 156 | } catch (e) { 157 | print(e); 158 | } 159 | }, 160 | ); 161 | } 162 | 163 | Widget _buildKakaoUnlinkButton() { 164 | return RaisedButton( 165 | child: Text("Unlink with Kakao"), 166 | onPressed: () async { 167 | try { 168 | await FirebaseAuthProvider.instance 169 | .unlinkCurrentUserFrom(FirebaseKakaoAuthAPI()); 170 | setState(() {}); 171 | } catch (e) { 172 | print(e); 173 | } 174 | }, 175 | ); 176 | } 177 | 178 | Widget _buildPhoneLinkButton() { 179 | final FirebasePhoneAuthAPI phoneAuthAPI = FirebasePhoneAuthAPI(); 180 | 181 | return RaisedButton( 182 | shape: RoundedRectangleBorder( 183 | borderRadius: BorderRadius.circular(8.0), 184 | ), 185 | child: Text("Link with Phone"), 186 | onPressed: () { 187 | showDialog( 188 | context: context, 189 | child: Dialog( 190 | shape: RoundedRectangleBorder( 191 | borderRadius: BorderRadius.circular(10), 192 | ), 193 | child: Container( 194 | height: 300, 195 | child: Column( 196 | children: [ 197 | Container( 198 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 199 | child: TextField( 200 | decoration: InputDecoration( 201 | border: OutlineInputBorder( 202 | borderSide: BorderSide(color: Colors.grey[700]), 203 | borderRadius: 204 | const BorderRadius.all(Radius.circular(10)), 205 | ), 206 | hintText: "+11 123-456-7890", 207 | labelText: "Phone Number"), 208 | keyboardType: TextInputType.phone, 209 | onChanged: (text) { 210 | UserCredentialProvider.of(context, listen: false) 211 | .phoneNumber = text.trim(); 212 | }, 213 | ), 214 | ), 215 | RaisedButton( 216 | child: Text("Send Code"), 217 | onPressed: () async { 218 | final UserCredentialProvider provider = 219 | UserCredentialProvider.of(context, listen: false); 220 | phoneAuthAPI.verifyNumber(provider.phoneNumber, codeSent: 221 | (String verificationId, [int forceResendingToken]) { 222 | print("Code sent"); 223 | }); 224 | }, 225 | ), 226 | SizedBox(height: 20), 227 | Container( 228 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 229 | child: TextField( 230 | decoration: InputDecoration( 231 | border: OutlineInputBorder( 232 | borderSide: BorderSide(color: Colors.grey[700]), 233 | borderRadius: 234 | const BorderRadius.all(Radius.circular(10)), 235 | ), 236 | hintText: "123456", 237 | labelText: "Code", 238 | ), 239 | keyboardType: TextInputType.number, 240 | onChanged: (text) { 241 | UserCredentialProvider.of(context, listen: false).code = 242 | text.trim(); 243 | }, 244 | ), 245 | ), 246 | RaisedButton( 247 | child: Text("Link"), 248 | onPressed: () async { 249 | final UserCredentialProvider provider = 250 | UserCredentialProvider.of(context, listen: false); 251 | phoneAuthAPI.submitVerificationCode(provider.code); 252 | 253 | bool succeed; 254 | try { 255 | final User user = await FirebaseAuthProvider.instance 256 | .linkCurrentUserWith(phoneAuthAPI); 257 | succeed = user != null; 258 | } catch (e) { 259 | print(e); 260 | succeed = false; 261 | } 262 | 263 | if (succeed) { 264 | print("Succeed"); 265 | Navigator.of(context).pop(); 266 | setState(() {}); 267 | } 268 | }, 269 | ) 270 | ], 271 | ), 272 | ), 273 | ), 274 | ); 275 | }, 276 | ); 277 | } 278 | 279 | Widget _buildPhoneUnlinkButton() { 280 | return RaisedButton( 281 | child: Text("Unlink with Phone"), 282 | onPressed: () async { 283 | try { 284 | await FirebaseAuthProvider.instance 285 | .unlinkCurrentUserFrom(FirebasePhoneAuthAPI()); 286 | setState(() {}); 287 | } catch (e) { 288 | print(e); 289 | } 290 | }, 291 | ); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /example/lib/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:firebase_auth_simplify/firebase_auth_simplify.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | import 'user_credential_provider.dart'; 6 | 7 | class LoginPage extends StatefulWidget { 8 | const LoginPage({ 9 | Key key, 10 | }) : super(key: key); 11 | 12 | @override 13 | _LoginPageState createState() => _LoginPageState(); 14 | } 15 | 16 | class _LoginPageState extends State { 17 | bool _isLoading = false; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | print(">>> Build [Login] Page"); 22 | return Scaffold( 23 | body: Stack( 24 | children: [ 25 | _buildBackground(), 26 | _buildCredentialOptions(context), 27 | ], 28 | ), 29 | ); 30 | } 31 | 32 | Widget _buildBackground() { 33 | return Container( 34 | padding: EdgeInsets.only(bottom: 270), 35 | width: double.maxFinite, 36 | height: double.maxFinite, 37 | child: Image.asset( 38 | "asset/icon.png", 39 | fit: BoxFit.scaleDown, 40 | ), 41 | ); 42 | } 43 | 44 | Widget _buildCredentialOptions(BuildContext context) { 45 | return Align( 46 | alignment: Alignment.bottomCenter, 47 | child: Container( 48 | width: double.maxFinite, 49 | height: 300.0, 50 | color: Colors.transparent, 51 | child: Container( 52 | decoration: BoxDecoration( 53 | color: Colors.grey, 54 | borderRadius: BorderRadius.only( 55 | topLeft: Radius.circular(30.0), 56 | topRight: Radius.circular(30.0), 57 | ), 58 | ), 59 | child: Column( 60 | mainAxisAlignment: MainAxisAlignment.center, 61 | crossAxisAlignment: CrossAxisAlignment.center, 62 | children: _isLoading 63 | ? [ 64 | _buildLoadingIndicator(), 65 | ] 66 | : [ 67 | _emailSignInButton(context), 68 | _phoneSignInButton(context), 69 | _googleSignInButton(), 70 | _facebookSignInButton(), 71 | _kakaoSignInButton(), 72 | ]), 73 | ), 74 | ), 75 | ); 76 | } 77 | 78 | Widget _buildLoadingIndicator() { 79 | return SizedBox( 80 | child: CircularProgressIndicator(), 81 | height: 25, 82 | width: 25, 83 | ); 84 | } 85 | 86 | Widget _emailSignInButton(BuildContext context) { 87 | return RaisedButton( 88 | shape: RoundedRectangleBorder( 89 | borderRadius: BorderRadius.circular(8.0), 90 | ), 91 | child: Text("Sign in with Email"), 92 | onPressed: () { 93 | showDialog( 94 | context: context, 95 | child: Dialog( 96 | shape: RoundedRectangleBorder( 97 | borderRadius: BorderRadius.circular(10), 98 | ), 99 | child: Container( 100 | height: 300, 101 | child: Column( 102 | children: [ 103 | Container( 104 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 105 | child: TextField( 106 | decoration: InputDecoration( 107 | border: OutlineInputBorder( 108 | borderSide: BorderSide(color: Colors.grey[700]), 109 | borderRadius: 110 | const BorderRadius.all(Radius.circular(10)), 111 | ), 112 | hintText: "example@flutter.com", 113 | labelText: "e-mail"), 114 | keyboardType: TextInputType.emailAddress, 115 | onChanged: (text) { 116 | UserCredentialProvider.of(context, listen: false) 117 | .email = text.trimRight(); 118 | }, 119 | ), 120 | ), 121 | Container( 122 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 123 | child: TextField( 124 | decoration: InputDecoration( 125 | border: OutlineInputBorder( 126 | borderSide: BorderSide(color: Colors.grey[700]), 127 | borderRadius: 128 | const BorderRadius.all(Radius.circular(10)), 129 | ), 130 | hintText: "********", 131 | labelText: "password", 132 | ), 133 | obscureText: true, 134 | onChanged: (text) { 135 | UserCredentialProvider.of(context, listen: false) 136 | .password = text.trimRight(); 137 | }, 138 | ), 139 | ), 140 | SizedBox(height: 5), 141 | RaisedButton( 142 | child: Text("Sign in"), 143 | onPressed: () async { 144 | final UserCredentialProvider provider = 145 | UserCredentialProvider.of(context, listen: false); 146 | final FirebaseEmailAuthAPI api = FirebaseEmailAuthAPI( 147 | email: provider.email, password: provider.password); 148 | bool succeed = await _performSignIn(api); 149 | if (succeed) Navigator.of(context).pop(); 150 | }, 151 | ), 152 | RaisedButton( 153 | child: Text("Create New Account"), 154 | onPressed: () async { 155 | final UserCredentialProvider provider = 156 | UserCredentialProvider.of(context, listen: false); 157 | final FirebaseEmailAuthAPI api = FirebaseEmailAuthAPI( 158 | email: provider.email, password: provider.password); 159 | bool succeed = await _createAccount(api); 160 | if (succeed) Navigator.of(context).pop(); 161 | }, 162 | ) 163 | ], 164 | ), 165 | ), 166 | ), 167 | ); 168 | }, 169 | ); 170 | } 171 | 172 | Widget _phoneSignInButton(BuildContext context) { 173 | final FirebasePhoneAuthAPI phoneAuthAPI = FirebasePhoneAuthAPI(); 174 | 175 | return RaisedButton( 176 | shape: RoundedRectangleBorder( 177 | borderRadius: BorderRadius.circular(8.0), 178 | ), 179 | child: Text("Sign in with Phone"), 180 | onPressed: () { 181 | showDialog( 182 | context: context, 183 | child: Dialog( 184 | shape: RoundedRectangleBorder( 185 | borderRadius: BorderRadius.circular(10), 186 | ), 187 | child: Container( 188 | height: 300, 189 | child: Column( 190 | children: [ 191 | Container( 192 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 193 | child: TextField( 194 | decoration: InputDecoration( 195 | border: OutlineInputBorder( 196 | borderSide: BorderSide(color: Colors.grey[700]), 197 | borderRadius: 198 | const BorderRadius.all(Radius.circular(10)), 199 | ), 200 | hintText: "+11 123-456-7890", 201 | labelText: "Phone Number"), 202 | keyboardType: TextInputType.phone, 203 | onChanged: (text) { 204 | UserCredentialProvider.of(context, listen: false) 205 | .phoneNumber = text.trim(); 206 | }, 207 | ), 208 | ), 209 | RaisedButton( 210 | child: Text("Send Code"), 211 | onPressed: () async { 212 | final UserCredentialProvider provider = 213 | UserCredentialProvider.of(context, listen: false); 214 | phoneAuthAPI.verifyNumber(provider.phoneNumber, codeSent: 215 | (String verificationId, [int forceResendingToken]) { 216 | print("Code sent"); 217 | }); 218 | }, 219 | ), 220 | SizedBox(height: 20), 221 | Container( 222 | margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0), 223 | child: TextField( 224 | decoration: InputDecoration( 225 | border: OutlineInputBorder( 226 | borderSide: BorderSide(color: Colors.grey[700]), 227 | borderRadius: 228 | const BorderRadius.all(Radius.circular(10)), 229 | ), 230 | hintText: "123456", 231 | labelText: "Code", 232 | ), 233 | keyboardType: TextInputType.number, 234 | onChanged: (text) { 235 | UserCredentialProvider.of(context, listen: false).code = 236 | text.trim(); 237 | }, 238 | ), 239 | ), 240 | RaisedButton( 241 | child: Text("Sign in"), 242 | onPressed: () async { 243 | final UserCredentialProvider provider = 244 | UserCredentialProvider.of(context, listen: false); 245 | phoneAuthAPI.submitVerificationCode(provider.code); 246 | final result = await FirebaseAuthProvider.instance 247 | .signInWith(phoneAuthAPI); 248 | bool succeed = result != null; 249 | if (succeed) Navigator.of(context).pop(); 250 | }, 251 | ) 252 | ], 253 | ), 254 | ), 255 | ), 256 | ); 257 | }, 258 | ); 259 | } 260 | 261 | Widget _googleSignInButton() { 262 | return RaisedButton( 263 | shape: RoundedRectangleBorder( 264 | borderRadius: BorderRadius.circular(8.0), 265 | ), 266 | child: Text("Sign in with Google"), 267 | onPressed: () { 268 | _performSignIn(FirebaseGoogleAuthAPI()); 269 | }, 270 | ); 271 | } 272 | 273 | Widget _facebookSignInButton() { 274 | return RaisedButton( 275 | shape: RoundedRectangleBorder( 276 | borderRadius: BorderRadius.circular(8.0), 277 | ), 278 | child: Text("Sign in with Facebook"), 279 | onPressed: () { 280 | _performSignIn(FirebaseFacebookAuthAPI()); 281 | }, 282 | ); 283 | } 284 | 285 | Widget _kakaoSignInButton() { 286 | return RaisedButton( 287 | shape: RoundedRectangleBorder( 288 | borderRadius: BorderRadius.circular(8.0), 289 | ), 290 | child: Text("Sign in with Kakao"), 291 | onPressed: () { 292 | _performSignIn(FirebaseKakaoAuthAPI()); 293 | }, 294 | ); 295 | } 296 | 297 | _performSignIn(BaseAuthAPI api) async { 298 | bool succeed = false; 299 | 300 | setState(() { 301 | _isLoading = true; 302 | }); 303 | 304 | try { 305 | await FirebaseAuthProvider.instance.signInWith(api); 306 | succeed = true; 307 | } on PlatformException catch (e) { 308 | print("platform exception: $e"); 309 | final snackBar = SnackBar(content: Text(e.message)); 310 | Scaffold.of(context).showSnackBar(snackBar); 311 | } catch (e) { 312 | print("other exceptions: $e"); 313 | final snackBar = SnackBar(content: Text(e)); 314 | Scaffold.of(context).showSnackBar(snackBar); 315 | } 316 | 317 | if (mounted) { 318 | setState(() { 319 | _isLoading = false; 320 | }); 321 | } 322 | 323 | return succeed; 324 | } 325 | 326 | _createAccount(BaseAuthAPI api) async { 327 | bool succeed = false; 328 | 329 | try { 330 | await FirebaseAuthProvider.instance.signUpWith(api); 331 | succeed = true; 332 | } on PlatformException catch (e) { 333 | print("platform exception: $e"); 334 | } catch (e) { 335 | print("other exceptions: $e"); 336 | } 337 | 338 | return succeed; 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:kakao_flutter_sdk/auth.dart'; 4 | 5 | import 'package:firebase_core/firebase_core.dart'; 6 | import 'package:firebase_auth/firebase_auth.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | import 'login_page.dart'; 10 | import 'landing_page.dart'; 11 | import 'user_credential_provider.dart'; 12 | 13 | void main() async { 14 | WidgetsFlutterBinding.ensureInitialized(); 15 | 16 | KakaoContext.clientId = "YOUR_NATIVE_APP_KEY"; 17 | 18 | await Firebase.initializeApp(); 19 | 20 | runApp(MyApp()); 21 | } 22 | 23 | class MyApp extends StatelessWidget { 24 | @override 25 | Widget build(BuildContext context) { 26 | return MaterialApp( 27 | title: 'Flutter Demo', 28 | theme: ThemeData( 29 | primarySwatch: Colors.blue, 30 | ), 31 | home: AppPage(), 32 | ); 33 | } 34 | } 35 | 36 | class AppPage extends StatelessWidget { 37 | @override 38 | Widget build(BuildContext context) { 39 | print(">>> Build [App] Page"); 40 | 41 | return Scaffold( 42 | appBar: AppBar(title: Text("Firebase Auth Example")), 43 | body: _buildBody(), 44 | ); 45 | } 46 | 47 | Widget _buildBody() { 48 | return StreamBuilder( 49 | stream: FirebaseAuth.instance.authStateChanges(), 50 | builder: (_, snapshot) { 51 | if (snapshot.connectionState == ConnectionState.active) { 52 | if (snapshot.data == null) { 53 | return ChangeNotifierProvider( 54 | create: (_) => UserCredentialProvider(), 55 | child: LoginPage(), 56 | ); 57 | } else { 58 | return ChangeNotifierProvider( 59 | create: (_) => UserCredentialProvider(), 60 | child: LandingPage(), 61 | ); 62 | } 63 | } else { 64 | return _buildLoadingIndicator(); 65 | } 66 | }, 67 | ); 68 | } 69 | 70 | Widget _buildLoadingIndicator() { 71 | return Center( 72 | child: SizedBox( 73 | child: CircularProgressIndicator(), 74 | height: 25, 75 | width: 25, 76 | ), 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /example/lib/user_credential_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | class UserCredentialProvider extends ChangeNotifier { 6 | static UserCredentialProvider of(BuildContext context, 7 | {bool listen = true}) => 8 | Provider.of(context, listen: listen); 9 | 10 | String _email; 11 | String get email => _email; 12 | set email(String email) { 13 | _email = email; 14 | notifyListeners(); 15 | } 16 | 17 | String _password; 18 | String get password => _password; 19 | set password(String pw) { 20 | _password = pw; 21 | notifyListeners(); 22 | } 23 | 24 | String _phoneNumber; 25 | String get phoneNumber => _phoneNumber; 26 | set phoneNumber(String phoneNumber) { 27 | _phoneNumber = phoneNumber; 28 | notifyListeners(); 29 | } 30 | 31 | String _code; 32 | String get code => _code; 33 | set code(String code) { 34 | _code = code; 35 | notifyListeners(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/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.5.0-nullsafety.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0-nullsafety.1" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0-nullsafety.3" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0-nullsafety.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0-nullsafety.1" 39 | cloud_functions: 40 | dependency: transitive 41 | description: 42 | name: cloud_functions 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.9.0" 46 | cloud_functions_platform_interface: 47 | dependency: transitive 48 | description: 49 | name: cloud_functions_platform_interface 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "4.0.1" 53 | cloud_functions_web: 54 | dependency: transitive 55 | description: 56 | name: cloud_functions_web 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "3.1.3" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.15.0-nullsafety.3" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.5" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.1.3" 88 | dio: 89 | dependency: transitive 90 | description: 91 | name: dio 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "3.0.10" 95 | fake_async: 96 | dependency: transitive 97 | description: 98 | name: fake_async 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.2.0-nullsafety.1" 102 | file: 103 | dependency: transitive 104 | description: 105 | name: file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "5.2.1" 109 | firebase_auth: 110 | dependency: transitive 111 | description: 112 | name: firebase_auth 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "0.20.0+1" 116 | firebase_auth_platform_interface: 117 | dependency: transitive 118 | description: 119 | name: firebase_auth_platform_interface 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "3.0.1" 123 | firebase_auth_simplify: 124 | dependency: "direct main" 125 | description: 126 | path: ".." 127 | relative: true 128 | source: path 129 | version: "2.1.1" 130 | firebase_auth_web: 131 | dependency: transitive 132 | description: 133 | name: firebase_auth_web 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "0.3.2+6" 137 | firebase_core: 138 | dependency: transitive 139 | description: 140 | name: firebase_core 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "0.7.0" 144 | firebase_core_platform_interface: 145 | dependency: transitive 146 | description: 147 | name: firebase_core_platform_interface 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "3.0.1" 151 | firebase_core_web: 152 | dependency: transitive 153 | description: 154 | name: firebase_core_web 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "0.2.1+3" 158 | flutter: 159 | dependency: "direct main" 160 | description: flutter 161 | source: sdk 162 | version: "0.0.0" 163 | flutter_facebook_login: 164 | dependency: transitive 165 | description: 166 | name: flutter_facebook_login 167 | url: "https://pub.dartlang.org" 168 | source: hosted 169 | version: "3.0.0" 170 | flutter_test: 171 | dependency: "direct dev" 172 | description: flutter 173 | source: sdk 174 | version: "0.0.0" 175 | flutter_web_plugins: 176 | dependency: transitive 177 | description: flutter 178 | source: sdk 179 | version: "0.0.0" 180 | google_sign_in: 181 | dependency: transitive 182 | description: 183 | name: google_sign_in 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "4.5.1" 187 | google_sign_in_platform_interface: 188 | dependency: transitive 189 | description: 190 | name: google_sign_in_platform_interface 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "1.1.1" 194 | google_sign_in_web: 195 | dependency: transitive 196 | description: 197 | name: google_sign_in_web 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "0.9.1" 201 | http: 202 | dependency: transitive 203 | description: 204 | name: http 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.12.0+4" 208 | http_parser: 209 | dependency: transitive 210 | description: 211 | name: http_parser 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "3.1.3" 215 | intl: 216 | dependency: transitive 217 | description: 218 | name: intl 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "0.16.1" 222 | js: 223 | dependency: transitive 224 | description: 225 | name: js 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.6.1+1" 229 | json_annotation: 230 | dependency: transitive 231 | description: 232 | name: json_annotation 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "3.0.1" 236 | kakao_flutter_sdk: 237 | dependency: transitive 238 | description: 239 | name: kakao_flutter_sdk 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "0.6.0-beta.1" 243 | matcher: 244 | dependency: transitive 245 | description: 246 | name: matcher 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.12.10-nullsafety.1" 250 | meta: 251 | dependency: transitive 252 | description: 253 | name: meta 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.3.0-nullsafety.3" 257 | nested: 258 | dependency: transitive 259 | description: 260 | name: nested 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "0.0.4" 264 | package_info: 265 | dependency: transitive 266 | description: 267 | name: package_info 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.4.1" 271 | path: 272 | dependency: transitive 273 | description: 274 | name: path 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.8.0-nullsafety.1" 278 | path_provider_linux: 279 | dependency: transitive 280 | description: 281 | name: path_provider_linux 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "0.0.1+2" 285 | path_provider_platform_interface: 286 | dependency: transitive 287 | description: 288 | name: path_provider_platform_interface 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.0.4" 292 | pedantic: 293 | dependency: transitive 294 | description: 295 | name: pedantic 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.8.0+1" 299 | platform: 300 | dependency: transitive 301 | description: 302 | name: platform 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "3.0.0-nullsafety.3" 306 | plugin_platform_interface: 307 | dependency: transitive 308 | description: 309 | name: plugin_platform_interface 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "1.0.2" 313 | process: 314 | dependency: transitive 315 | description: 316 | name: process 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "3.0.13" 320 | provider: 321 | dependency: "direct main" 322 | description: 323 | name: provider 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "4.3.1" 327 | quiver: 328 | dependency: transitive 329 | description: 330 | name: quiver 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "2.1.3" 334 | shared_preferences: 335 | dependency: transitive 336 | description: 337 | name: shared_preferences 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.5.8" 341 | shared_preferences_linux: 342 | dependency: transitive 343 | description: 344 | name: shared_preferences_linux 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "0.0.2+1" 348 | shared_preferences_macos: 349 | dependency: transitive 350 | description: 351 | name: shared_preferences_macos 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "0.0.1+10" 355 | shared_preferences_platform_interface: 356 | dependency: transitive 357 | description: 358 | name: shared_preferences_platform_interface 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "1.0.4" 362 | shared_preferences_web: 363 | dependency: transitive 364 | description: 365 | name: shared_preferences_web 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "0.1.2+7" 369 | sign_in_with_apple: 370 | dependency: transitive 371 | description: 372 | name: sign_in_with_apple 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "2.5.4" 376 | sky_engine: 377 | dependency: transitive 378 | description: flutter 379 | source: sdk 380 | version: "0.0.99" 381 | source_span: 382 | dependency: transitive 383 | description: 384 | name: source_span 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "1.8.0-nullsafety.2" 388 | stack_trace: 389 | dependency: transitive 390 | description: 391 | name: stack_trace 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.10.0-nullsafety.1" 395 | stream_channel: 396 | dependency: transitive 397 | description: 398 | name: stream_channel 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "2.1.0-nullsafety.1" 402 | string_scanner: 403 | dependency: transitive 404 | description: 405 | name: string_scanner 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "1.1.0-nullsafety.1" 409 | term_glyph: 410 | dependency: transitive 411 | description: 412 | name: term_glyph 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "1.2.0-nullsafety.1" 416 | test_api: 417 | dependency: transitive 418 | description: 419 | name: test_api 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "0.2.19-nullsafety.2" 423 | typed_data: 424 | dependency: transitive 425 | description: 426 | name: typed_data 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "1.3.0-nullsafety.3" 430 | vector_math: 431 | dependency: transitive 432 | description: 433 | name: vector_math 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "2.1.0-nullsafety.3" 437 | xdg_directories: 438 | dependency: transitive 439 | description: 440 | name: xdg_directories 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "0.1.0" 444 | sdks: 445 | dart: ">=2.10.0-110 <2.11.0" 446 | flutter: ">=1.16.0 <2.0.0" 447 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 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.1.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 | 27 | firebase_auth_simplify: 28 | path: ../ 29 | 30 | provider: ^4.0.2 31 | 32 | dev_dependencies: 33 | flutter_test: 34 | sdk: flutter 35 | 36 | # For information on the generic Dart part of this file, see the 37 | # following page: https://dart.dev/tools/pub/pubspec 38 | 39 | # The following section is specific to Flutter. 40 | flutter: 41 | # The following line ensures that the Material Icons font is 42 | # included with your application, so that you can use the icons in 43 | # the material Icons class. 44 | uses-material-design: true 45 | 46 | assets: 47 | - asset/ 48 | -------------------------------------------------------------------------------- /example/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:example/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 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /functions/index.js: -------------------------------------------------------------------------------- 1 | const functions = require("firebase-functions"); 2 | const kakao = require("./kakao"); 3 | 4 | const admin = require("firebase-admin"); 5 | admin.initializeApp(); 6 | 7 | exports.verifyKakaoToken = functions.https.onCall(async (data, context) => { 8 | const token = data.token; 9 | if (!token) return { error: "There is no token provided." }; 10 | 11 | console.log(`Verifying Kakao token: ${token}`); 12 | 13 | return kakao 14 | .createFirebaseToken(token) 15 | .then(firebaseToken => { 16 | console.log(`Returning firebase token to user: ${firebaseToken}`); 17 | return { token: firebaseToken }; 18 | }) 19 | .catch(e => { 20 | return { error: e.message }; 21 | }); 22 | }); 23 | 24 | exports.linkWithKakao = functions.https.onCall(async (data, context) => { 25 | const token = data.token; 26 | if (!token) return { error: "There is no token provided." }; 27 | 28 | console.log(`Linking with Kakao token: ${token}`); 29 | 30 | return kakao 31 | .linkToCurrentUser(token, context.auth.uid) 32 | .then(userRecord => { 33 | console.log(`Returning user: ${userRecord}`); 34 | return { userRecord: userRecord }; 35 | }) 36 | .catch(e => { 37 | return { error: e.message }; 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /functions/kakao.js: -------------------------------------------------------------------------------- 1 | const admin = require("firebase-admin"); 2 | const functions = require("firebase-functions"); 3 | const request = require("request-promise"); 4 | 5 | const kakao_appId = functions.config().kakao.appid; 6 | 7 | // Kakao API request url to retrieve user profile based on access token 8 | const requestMeUrl = "https://kapi.kakao.com/v2/user/me?secure_resource=true"; 9 | const accessTokenInfoUrl = "https://kapi.kakao.com/v1/user/access_token_info"; 10 | 11 | /** 12 | * requestMe - Returns user profile from Kakao API 13 | * 14 | * @param {String} kakaoAccessToken Access token retrieved by Kakao Login API 15 | * @return {Promise} User profile response in a promise 16 | */ 17 | function requestMe(kakaoAccessToken) { 18 | console.log("Requesting user profile from Kakao API server."); 19 | return request({ 20 | method: "GET", 21 | headers: { Authorization: "Bearer " + kakaoAccessToken }, 22 | url: requestMeUrl 23 | }); 24 | } 25 | 26 | /** 27 | * validateToken - Returns access token info from Kakao API, 28 | * which checks if this token is issued by this application. 29 | * 30 | * @param {String} kakaoAccessToken Access token retrieved by Kakao Login API 31 | * @return {Promise} Access token info response 32 | */ 33 | function validateToken(kakaoAccessToken) { 34 | console.log("Validating access token from Kakao API server."); 35 | return request({ 36 | method: "GET", 37 | headers: { Authorization: "Bearer " + kakaoAccessToken }, 38 | url: accessTokenInfoUrl 39 | }); 40 | } 41 | 42 | /** 43 | * createIfNotExist - If email is not given, 44 | * create a new user since there is no other way to map users. 45 | * If email is not verified, make the user re-authenticate with other means. 46 | * 47 | * @param {String} kakaoUserId user id per app 48 | * @param {String} email user's email address 49 | * @param {Boolean} emailVerified whether this email is verified or not 50 | * @param {String} displayName user 51 | * @param {String} photoURL profile photo url 52 | * @return {Promise} Firebase user record in a promise 53 | */ 54 | function createIfNotExist(kakaoUserId, email, emailVerified, displayName, photoURL) { 55 | return getUser(kakaoUserId, email, emailVerified).catch(error => { 56 | if (error.code == "auth/user-not-found") { 57 | const params = { 58 | uid: `kakao:${kakaoUserId}`, 59 | displayName: displayName 60 | }; 61 | if (email) { 62 | params["email"] = email; 63 | } 64 | if (photoURL) { 65 | params["photoURL"] = photoURL; 66 | } 67 | console.log(`creating a firebase user with email ${email}`); 68 | return admin.auth().createUser(params); 69 | } 70 | throw error; 71 | }); 72 | //.then(userRecord => linkUserWithKakao(kakaoUserId, userRecord)); 73 | // We will not directly link account if there is existing email. Instead, we will throw error, so that we can give an option of signing-in with existing account or linking later. 74 | // This is same behaviour as google and facebook. 75 | } 76 | 77 | /** 78 | * getUser - fetch firebase user with kakao UID first, then with email if 79 | * no user found. If email is not verified, throw an error so that 80 | * the user can re-authenticate. 81 | * 82 | * @param {String} kakaoUserId user id per app 83 | * @param {String} email user's email address 84 | * @param {Boolean} emailVerified whether this email is verified or not 85 | * @return {Promise} 86 | */ 87 | function getUser(kakaoUserId, email, emailVerified) { 88 | console.log(`fetching a firebase user with uid kakao:${kakaoUserId}`); 89 | return admin 90 | .auth() 91 | .getUser(`kakao:${kakaoUserId}`) 92 | .catch(error => { 93 | if (error.code != "auth/user-not-found") { 94 | throw error; 95 | } 96 | if (!email) { 97 | throw error; // cannot find existing accounts since there is no email. 98 | } 99 | console.log(`fetching a firebase user with email ${email}`); 100 | return admin 101 | .auth() 102 | .getUserByEmail(email) 103 | .then(userRecord => { 104 | if (!emailVerified) { 105 | throw new Error("This user should authenticate first with other providers"); 106 | } 107 | 108 | throw new Error("The email address is already in use by another account."); 109 | }); 110 | }); 111 | } 112 | 113 | /** 114 | * linkUserWithKakao - Link current user record with kakao UID 115 | * if not linked yet. 116 | * 117 | * @param {String} kakaoUserId 118 | * @param {admin.auth.UserRecord} userRecord 119 | * @return {Promise} 120 | */ 121 | function linkUserWithKakao(kakaoUserId, userRecord) { 122 | if (userRecord.customClaims && userRecord.customClaims["kakaoUID"] == kakaoUserId) { 123 | console.log(`currently linked with kakao UID ${kakaoUserId}...`); 124 | return Promise.resolve(userRecord); 125 | } 126 | console.log(`linking user with kakao UID ${kakaoUserId}...`); 127 | return admin 128 | .auth() 129 | .setCustomUserClaims(userRecord.uid, { kakaoUID: kakaoUserId, provider: "kakaocorp.com" }) 130 | .then(() => userRecord); 131 | } 132 | 133 | /** 134 | * createFirebaseToken - returns Firebase token using Firebase Admin SDK 135 | * 136 | * @param {String} kakaoAccessToken access token from Kakao Login API 137 | * @return {Promise} Firebase token in a promise 138 | */ 139 | exports.createFirebaseToken = function(kakaoAccessToken) { 140 | return validateToken(kakaoAccessToken) 141 | .then(response => { 142 | const body = JSON.parse(response); 143 | if (body.appId != kakao_appId) { 144 | throw new Error("The given token does not belong to this application."); 145 | } 146 | return requestMe(kakaoAccessToken); 147 | }) 148 | .then(response => { 149 | const body = JSON.parse(response); 150 | const userId = body.id; 151 | if (!userId) { 152 | throw new Error("There was no user with the given access token."); 153 | } 154 | let nickname = null; 155 | let profileImage = null; 156 | let email = null; 157 | let isEmailVerified = null; 158 | if (body.properties) { 159 | nickname = body.properties.nickname; 160 | profileImage = body.properties.profile_image; 161 | } 162 | if (body.kakao_account) { 163 | email = body.kakao_account.email; 164 | isEmailVerified = body.kakao_account.is_email_verified; 165 | } 166 | return createIfNotExist(userId, email, isEmailVerified, nickname, profileImage); 167 | }) 168 | .then(userRecord => { 169 | const userId = userRecord.uid; 170 | console.log(`creating a custom firebase token based on uid ${userId}`); 171 | return admin.auth().createCustomToken(userId, { kakaoUID: userId, provider: "kakaocorp.com" }); 172 | }); 173 | }; 174 | 175 | /** 176 | * linkToCurrentUser - Link kakao account to currently signed-in user. 177 | * 178 | * @param {String} uid uid of current user 179 | */ 180 | exports.linkToCurrentUser = function(kakaoAccessToken, uid) { 181 | return validateToken(kakaoAccessToken) 182 | .then(response => { 183 | const body = JSON.parse(response); 184 | if (body.appId != kakao_appId) { 185 | throw new Error("The given token does not belong to this application."); 186 | } 187 | return requestMe(kakaoAccessToken); 188 | }) 189 | .then(response => { 190 | const body = JSON.parse(response); 191 | console.log(body); 192 | const userId = body.id; 193 | if (!userId) { 194 | throw new Error("There was no user with the given access token."); 195 | } 196 | 197 | return admin 198 | .auth() 199 | .getUser(uid) 200 | .then(userRecord => { 201 | return linkUserWithKakao(userId, userRecord); 202 | }) 203 | .catch(error => { 204 | throw error; 205 | }); 206 | }); 207 | }; 208 | -------------------------------------------------------------------------------- /functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase serve --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "10" 13 | }, 14 | "dependencies": { 15 | "firebase-admin": "^8.6.0", 16 | "firebase-functions": "^3.3.0", 17 | "request": "^2.88.0", 18 | "request-promise": "^4.2.5" 19 | }, 20 | "devDependencies": { 21 | "firebase-functions-test": "^0.1.6" 22 | }, 23 | "private": true 24 | } 25 | -------------------------------------------------------------------------------- /lib/firebase_auth_simplify.dart: -------------------------------------------------------------------------------- 1 | library firebase_auth_simplify; 2 | 3 | export 'src/firebase_auth_provider.dart'; 4 | export 'src/api/base_auth_api.dart'; 5 | 6 | export 'src/api/firebase_email_auth_api.dart'; 7 | export 'src/api/firebase_google_auth_api.dart'; 8 | export 'src/api/firebase_kakao_auth_api.dart'; 9 | export 'src/api/firebase_facebook_auth_api.dart'; 10 | export 'src/api/firebase_apple_auth_api.dart'; 11 | export 'src/api/firebase_phone_auth_api.dart'; 12 | export 'package:firebase_auth/firebase_auth.dart'; 13 | -------------------------------------------------------------------------------- /lib/src/api/base_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | 3 | abstract class BaseAuthAPI { 4 | Future signUp(); 5 | Future signIn(); 6 | Future signOut(); 7 | Future linkWith(User user); 8 | Future unlinkFrom(User user); 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/api/firebase_apple_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'package:flutter/services.dart'; 6 | 7 | import 'package:firebase_auth/firebase_auth.dart'; 8 | import 'package:firebase_auth_simplify/src/api/base_auth_api.dart'; 9 | import 'package:crypto/crypto.dart'; 10 | import 'package:sign_in_with_apple/sign_in_with_apple.dart'; 11 | 12 | class FirebaseAppleAuthAPI implements BaseAuthAPI { 13 | FirebaseAppleAuthAPI({ 14 | this.scopes, 15 | this.webAuthOptions, 16 | }); 17 | 18 | final List scopes; 19 | final WebAuthenticationOptions webAuthOptions; 20 | 21 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 22 | 23 | @override 24 | Future signIn() async { 25 | try { 26 | final authResult = await _firebaseAuth.signInWithCredential(await _getCredential()); 27 | assert(authResult.user.uid == _firebaseAuth.currentUser.uid); 28 | 29 | // When sign in is done, update email info. 30 | await authResult.user.updateEmail(authResult.user.email); 31 | 32 | return authResult; 33 | } catch (e) { 34 | return Future.error(e); 35 | } 36 | } 37 | 38 | Future _getCredential() async { 39 | try { 40 | final _scopes = scopes ?? 41 | [ 42 | AppleIDAuthorizationScopes.email, 43 | AppleIDAuthorizationScopes.fullName, 44 | ]; 45 | 46 | final nonce = _createNonce(32); 47 | final nativeAppleCred = Platform.isIOS 48 | ? await SignInWithApple.getAppleIDCredential( 49 | scopes: _scopes, 50 | nonce: sha256.convert(utf8.encode(nonce)).toString(), 51 | ) 52 | : await SignInWithApple.getAppleIDCredential( 53 | scopes: _scopes, 54 | webAuthenticationOptions: webAuthOptions, 55 | nonce: sha256.convert(utf8.encode(nonce)).toString(), 56 | ); 57 | 58 | final credential = OAuthCredential( 59 | providerId: "apple.com", // MUST be "apple.com" 60 | signInMethod: "oauth", // MUST be "oauth" 61 | accessToken: nativeAppleCred.identityToken, // propagate Apple ID token to BOTH accessToken and idToken parameters 62 | idToken: nativeAppleCred.identityToken, 63 | rawNonce: nonce, 64 | ); 65 | 66 | return credential; 67 | } catch (e) { 68 | return Future.error(e); 69 | } 70 | } 71 | 72 | String _createNonce(int length) { 73 | final random = Random(); 74 | final charCodes = List.generate(length, (_) { 75 | int codeUnit; 76 | 77 | switch (random.nextInt(3)) { 78 | case 0: 79 | codeUnit = random.nextInt(10) + 48; 80 | break; 81 | case 1: 82 | codeUnit = random.nextInt(26) + 65; 83 | break; 84 | case 2: 85 | codeUnit = random.nextInt(26) + 97; 86 | break; 87 | } 88 | 89 | return codeUnit; 90 | }); 91 | 92 | return String.fromCharCodes(charCodes); 93 | } 94 | 95 | /// Apple API does not need sign up. 96 | @override 97 | Future signUp() { 98 | throw PlatformException(code: "UNSUPPORTED_FUNCTION", message: "Apple Signin does not need sign up."); 99 | } 100 | 101 | @override 102 | Future signOut() { 103 | return Future.value(); 104 | } 105 | 106 | @override 107 | Future linkWith(User user) async { 108 | try { 109 | return (await user.linkWithCredential(await _getCredential())).user; 110 | } catch (e) { 111 | return Future.error(e); 112 | } 113 | } 114 | 115 | @override 116 | Future unlinkFrom(User user) async { 117 | try { 118 | await user.unlink("apple.com"); 119 | } catch (e) { 120 | throw Future.error(e); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/src/api/firebase_email_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'base_auth_api.dart'; 5 | 6 | class FirebaseEmailAuthAPI implements BaseAuthAPI { 7 | FirebaseEmailAuthAPI({ 8 | @required this.email, 9 | @required this.password, 10 | }); 11 | 12 | final String email; 13 | final String password; 14 | 15 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 16 | 17 | @override 18 | Future signUp() async { 19 | print("sign up with $email and $password"); 20 | try { 21 | return await _firebaseAuth.createUserWithEmailAndPassword( 22 | email: email, password: password); 23 | } catch (e) { 24 | return Future.error(e); 25 | } 26 | } 27 | 28 | @override 29 | Future signIn() async { 30 | print("sign in with $email and $password"); 31 | try { 32 | final authResult = await _firebaseAuth.signInWithEmailAndPassword( 33 | email: email, password: password); 34 | assert(authResult.user.uid == _firebaseAuth.currentUser.uid); 35 | 36 | return authResult; 37 | } catch (e) { 38 | return Future.error(e); 39 | } 40 | } 41 | 42 | @override 43 | Future signOut() { 44 | return _firebaseAuth.signOut(); 45 | } 46 | 47 | @override 48 | Future linkWith(User user) { 49 | throw PlatformException( 50 | code: "UNSUPPORTED_FUNCTION", 51 | message: "e-mail sign-in does not support linking and unlinking"); 52 | } 53 | 54 | @override 55 | Future unlinkFrom(User user) async { 56 | throw PlatformException( 57 | code: "UNSUPPORTED_FUNCTION", 58 | message: "e-mail sign-in does not support linking and unlinking"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/api/firebase_facebook_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:flutter_facebook_login/flutter_facebook_login.dart'; 6 | import 'package:http/http.dart' as http; 7 | 8 | import 'base_auth_api.dart'; 9 | 10 | class FirebaseFacebookAuthAPI implements BaseAuthAPI { 11 | FirebaseFacebookAuthAPI({ 12 | this.webViewOnly = false, 13 | }); 14 | 15 | final bool webViewOnly; 16 | 17 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 18 | 19 | FacebookLogin _facebookLogin = FacebookLogin(); 20 | 21 | String token; 22 | 23 | @override 24 | Future signIn() async { 25 | try { 26 | final authResult = 27 | await _firebaseAuth.signInWithCredential(await _getCredential()); 28 | assert(authResult.user.uid == _firebaseAuth.currentUser.uid); 29 | 30 | // When sign in is done, update email info. 31 | final graphResponse = await http.get( 32 | 'https://graph.facebook.com/v2.12/me?fields=email&access_token=$token'); 33 | final profile = jsonDecode(graphResponse.body); 34 | 35 | if (profile['email'] == null) { 36 | throw PlatformException( 37 | code: "EMAIL_NOT_PROVIDED", 38 | message: "e-mail must be provided to use the app."); 39 | } 40 | 41 | await authResult.user.updateEmail(profile['email']); 42 | 43 | return authResult; 44 | } catch (e) { 45 | print(e); 46 | return Future.error(e); 47 | } 48 | } 49 | 50 | Future _getCredential() async { 51 | final FacebookLoginResult result = await _signInProvider(); 52 | 53 | if (result.status == FacebookLoginStatus.cancelledByUser) { 54 | return Future.error(PlatformException( 55 | code: "FACEBOOK_CANCELLED_BY_USER", 56 | message: "Facebook sign-in is cancelled by user.")); 57 | } else if (result.status == FacebookLoginStatus.error) { 58 | return Future.error(PlatformException( 59 | code: "FACEBOOK_SIGN_IN_FAILED", message: result.errorMessage)); 60 | } 61 | 62 | token = result.accessToken.token; 63 | 64 | return FacebookAuthProvider.credential(token); 65 | } 66 | 67 | Future _signInProvider() async { 68 | if (webViewOnly) { 69 | _facebookLogin.loginBehavior = FacebookLoginBehavior.webViewOnly; 70 | } 71 | 72 | return await _facebookLogin.logIn(['email']); 73 | } 74 | 75 | @override 76 | Future signOut() { 77 | _facebookLogin ??= FacebookLogin(); 78 | return _facebookLogin.logOut(); 79 | } 80 | 81 | @override 82 | Future linkWith(User user) async { 83 | try { 84 | return (await user.linkWithCredential(await _getCredential())).user; 85 | } catch (e) { 86 | if (_facebookLogin != null) _facebookLogin.logOut(); 87 | return Future.error(e); 88 | } 89 | } 90 | 91 | /// Facebook API does not need sign up. 92 | @override 93 | Future signUp() { 94 | throw PlatformException( 95 | code: "UNSUPPORTED_FUNCTION", 96 | message: "Facebook Signin does not need sign up."); 97 | } 98 | 99 | @override 100 | Future unlinkFrom(User user) async { 101 | try { 102 | await user.unlink("facebook.com"); 103 | } catch (e) { 104 | throw Future.error(e); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/src/api/firebase_google_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:firebase_auth_simplify/src/api/base_auth_api.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:google_sign_in/google_sign_in.dart'; 5 | 6 | class FirebaseGoogleAuthAPI implements BaseAuthAPI { 7 | FirebaseGoogleAuthAPI({this.scopes}); 8 | 9 | final List scopes; 10 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 11 | GoogleSignIn _googleSignIn; 12 | GoogleSignInAccount account; 13 | 14 | @override 15 | Future signIn() async { 16 | try { 17 | final authResult = 18 | await _firebaseAuth.signInWithCredential(await _getCredential()); 19 | assert(authResult.user.uid == _firebaseAuth.currentUser.uid); 20 | 21 | // When sign in is done, update email info. 22 | await authResult.user.updateEmail(account.email); 23 | 24 | return authResult; 25 | } catch (e) { 26 | return Future.error(e); 27 | } 28 | } 29 | 30 | Future _getCredential() async { 31 | try { 32 | _googleSignIn = 33 | scopes == null ? GoogleSignIn() : GoogleSignIn(scopes: scopes); 34 | 35 | // NOTE: signIn() does the work automatically. 36 | // GoogleSignInAccount account = await _googleSignIn.signInSilently(); 37 | 38 | // NOTE: In debug mode, it will throw an exception when user cancel the sign in process, even if it just have to give us 'null'. 39 | // It is a VM debugger issue which doesn't correctly detects it. 40 | // Do not bother for having unhandled exception in debug mode. It will work on release mode. Just check if it is null for user canceled action. 41 | // 42 | // More info: https://github.com/flutter/flutter/issues/26705#issuecomment-507791687 43 | account = await _googleSignIn.signIn(); 44 | 45 | // User canceld. 46 | if (account == null) return null; 47 | 48 | final GoogleSignInAuthentication auth = await account.authentication; 49 | return GoogleAuthProvider.credential( 50 | accessToken: auth.accessToken, 51 | idToken: auth.idToken, 52 | ); 53 | } catch (e) { 54 | return Future.error(e); 55 | } 56 | } 57 | 58 | /// Google API does not need sign up. 59 | @override 60 | Future signUp() { 61 | throw PlatformException( 62 | code: "UNSUPPORTED_FUNCTION", 63 | message: "Google Signin does not need sign up."); 64 | } 65 | 66 | @override 67 | Future signOut() { 68 | _googleSignIn ??= GoogleSignIn(); 69 | return _googleSignIn.signOut(); 70 | } 71 | 72 | @override 73 | Future linkWith(User user) async { 74 | try { 75 | /// NOTE: As mentioned above in _getCredential function, we cannot catch exception here. Need to wait for google_sign package to solve this issue (or dart team). 76 | /// This only happens in Debug mode. 77 | return (await user.linkWithCredential(await _getCredential())).user; 78 | } catch (e) { 79 | if (_googleSignIn != null) _googleSignIn.signOut(); 80 | return Future.error(e); 81 | } 82 | } 83 | 84 | @override 85 | Future unlinkFrom(User user) async { 86 | try { 87 | await user.unlink("google.com"); 88 | } catch (e) { 89 | throw Future.error(e); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/src/api/firebase_kakao_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_functions/cloud_functions.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:kakao_flutter_sdk/auth.dart'; 5 | import 'package:kakao_flutter_sdk/user.dart' as kakao; 6 | import 'base_auth_api.dart'; 7 | 8 | class FirebaseKakaoAuthAPI implements BaseAuthAPI { 9 | FirebaseKakaoAuthAPI({ 10 | this.emailRequired = false, 11 | }); 12 | 13 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 14 | final bool emailRequired; 15 | 16 | static const String providerId = 'kakaocorp.com'; 17 | 18 | @override 19 | Future signIn() async { 20 | try { 21 | final String token = await _retrieveToken(); 22 | final authResult = 23 | await _firebaseAuth.signInWithCustomToken(await _verifyToken(token)); 24 | 25 | final User firebaseUser = authResult.user; 26 | assert(firebaseUser.uid == _firebaseAuth.currentUser.uid); 27 | 28 | if (authResult.user.email == null || authResult.user.email.isEmpty) { 29 | // When sign in is done, update email info. 30 | kakao.User kakaoUser = await kakao.UserApi.instance.me(); 31 | 32 | // Email is required, but kaka account doesn't have email set. 33 | if (emailRequired && 34 | (kakaoUser.kakaoAccount.email == null || 35 | kakaoUser.kakaoAccount.email.isEmpty)) { 36 | throw PlatformException( 37 | code: "KAKAO_EMAIL_REQUIRED", 38 | message: 39 | "Email must be set in Kakao Account in order to sign in."); 40 | } 41 | 42 | // Whether the email is as must or not, update email if exists. 43 | if (kakaoUser.kakaoAccount.email != null && 44 | kakaoUser.kakaoAccount.email.isNotEmpty) { 45 | await authResult.user.updateEmail(kakaoUser.kakaoAccount.email); 46 | } 47 | } 48 | 49 | return authResult; 50 | } on KakaoAuthException catch (e) { 51 | return Future.error(e); 52 | } on KakaoClientException catch (e) { 53 | return Future.error(e); 54 | } catch (e) { 55 | if (e.toString().contains("already in use")) { 56 | return Future.error(PlatformException( 57 | code: "ERROR_EMAIL_ALREADY_IN_USE", 58 | message: "The email address is already in use by another account")); 59 | } 60 | return Future.error(e); 61 | } 62 | } 63 | 64 | Future _retrieveToken() async { 65 | final installed = await isKakaoTalkInstalled(); 66 | final authCode = installed 67 | ? await AuthCodeClient.instance.requestWithTalk() 68 | : await AuthCodeClient.instance.request(); 69 | AccessTokenResponse token = 70 | await AuthApi.instance.issueAccessToken(authCode); 71 | 72 | await AccessTokenStore.instance.toStore( 73 | token); // Store access token in AccessTokenStore for future API requests. 74 | return token.accessToken; 75 | } 76 | 77 | Future _verifyToken(String kakaoToken) async { 78 | try { 79 | final HttpsCallable callable = 80 | FirebaseFunctions.instance.httpsCallable('verifyKakaoToken'); 81 | 82 | final HttpsCallableResult result = await callable.call( 83 | { 84 | 'token': kakaoToken, 85 | }, 86 | ); 87 | 88 | if (result.data['error'] != null) { 89 | return Future.error(result.data['error']); 90 | } else { 91 | return result.data['token']; 92 | } 93 | } catch (e) { 94 | return Future.error(e); 95 | } 96 | } 97 | 98 | /// Kakao API does not need sign up. 99 | @override 100 | Future signUp() { 101 | return Future.error(PlatformException( 102 | code: "UNSUPPORTED_FUNCTION", 103 | message: "Kakao Signin does not need sign up.")); 104 | } 105 | 106 | @override 107 | Future signOut() { 108 | AccessTokenStore.instance.clear(); 109 | return Future.value(""); 110 | } 111 | 112 | @override 113 | Future linkWith(User user) async { 114 | try { 115 | final token = await _retrieveToken(); 116 | 117 | final HttpsCallable callable = 118 | FirebaseFunctions.instance.httpsCallable('linkWithKakao'); 119 | 120 | final HttpsCallableResult result = await callable.call( 121 | { 122 | 'token': token, 123 | }, 124 | ); 125 | 126 | if (result.data['error'] != null) { 127 | return Future.error(result.data['error']); 128 | } else { 129 | return user; 130 | } 131 | } on KakaoAuthException catch (e) { 132 | return Future.error(e); 133 | } on KakaoClientException catch (e) { 134 | return Future.error(e); 135 | } catch (e) { 136 | return Future.error(e); 137 | } 138 | } 139 | 140 | @override 141 | Future unlinkFrom(User user) async { 142 | try { 143 | await user.unlink("kakaocorp.com"); 144 | } catch (e) { 145 | throw Future.error(e); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /lib/src/api/firebase_phone_auth_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'base_auth_api.dart'; 4 | 5 | class FirebasePhoneAuthAPI implements BaseAuthAPI { 6 | FirebasePhoneAuthAPI(); 7 | 8 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 9 | 10 | AuthCredential _credential; 11 | String _verificationId; 12 | 13 | Future verifyNumber(String phoneNumber, 14 | {bool signInOnAutoRetrieval = true, 15 | int timeoutSeconds = 30, 16 | PhoneCodeSent codeSent, 17 | PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout, 18 | PhoneVerificationCompleted verificationCompleted, 19 | PhoneVerificationFailed verificationFailed}) async { 20 | assert(phoneNumber != null && phoneNumber.length > 1); 21 | 22 | _firebaseAuth.verifyPhoneNumber( 23 | phoneNumber: phoneNumber, 24 | timeout: Duration(seconds: timeoutSeconds), 25 | codeSent: (String verificationId, [int forceResendingToken]) { 26 | _verificationId = verificationId; 27 | 28 | codeSent(verificationId, forceResendingToken); 29 | }, 30 | codeAutoRetrievalTimeout: (String verificationId) { 31 | _verificationId = verificationId; 32 | 33 | codeAutoRetrievalTimeout(verificationId); 34 | }, 35 | verificationCompleted: (AuthCredential phoneAuthCredential) { 36 | _credential = phoneAuthCredential; 37 | 38 | verificationCompleted(phoneAuthCredential); 39 | if (signInOnAutoRetrieval) { 40 | signIn(); 41 | } 42 | }, 43 | verificationFailed: (FirebaseAuthException error) { 44 | print(error.code); 45 | print(error.message); 46 | 47 | verificationFailed(error); 48 | }, 49 | ); 50 | } 51 | 52 | AuthCredential submitVerificationCode(String code) { 53 | assert(_verificationId != null); 54 | assert(code != null && code.length == 6); 55 | 56 | _credential = PhoneAuthProvider.credential( 57 | verificationId: _verificationId, 58 | smsCode: code, 59 | ); 60 | 61 | return _credential; 62 | } 63 | 64 | @override 65 | Future signUp() async { 66 | throw PlatformException( 67 | code: "UNSUPPORTED_FUNCTION", 68 | message: "Phone Signin does not need sign up."); 69 | } 70 | 71 | @override 72 | Future signIn() async { 73 | try { 74 | UserCredential result = 75 | await _firebaseAuth.signInWithCredential(_credential); 76 | assert(result.user.uid == _firebaseAuth.currentUser.uid); 77 | return result; 78 | } catch (e) { 79 | return Future.error(e); 80 | } 81 | } 82 | 83 | @override 84 | Future signOut() { 85 | return _firebaseAuth.signOut(); 86 | } 87 | 88 | @override 89 | Future linkWith(User user) async { 90 | try { 91 | return (await user.linkWithCredential(_credential)).user; 92 | } catch (e) { 93 | return Future.error(e); 94 | } 95 | } 96 | 97 | @override 98 | Future unlinkFrom(User user) async { 99 | try { 100 | await user.unlink("phone"); 101 | } catch (e) { 102 | throw Future.error(e); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/src/firebase_auth_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | import 'package:firebase_auth_simplify/firebase_auth_simplify.dart'; 3 | import 'package:firebase_auth_simplify/src/api/base_auth_api.dart'; 4 | 5 | class FirebaseAuthProvider { 6 | /// Private constructor 7 | FirebaseAuthProvider._(); 8 | 9 | /// Provides an instance of this class 10 | static final FirebaseAuthProvider instance = FirebaseAuthProvider._(); 11 | 12 | final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 13 | 14 | Stream get onAuthStateChanged => _firebaseAuth.authStateChanges(); 15 | 16 | User currentUser() { 17 | return _firebaseAuth.currentUser; 18 | } 19 | 20 | Future> getUserClaim() async { 21 | try { 22 | User user = currentUser(); 23 | final IdTokenResult idToken = await user?.getIdTokenResult(true); 24 | return idToken?.claims; 25 | } catch (e) { 26 | return Future.error(e); 27 | } 28 | } 29 | 30 | BaseAuthAPI _primaryAuth; 31 | BaseAuthAPI get primaryAuth => _primaryAuth; 32 | 33 | Future signUpWith(BaseAuthAPI api) async { 34 | _primaryAuth = api; 35 | 36 | return api.signUp(); 37 | } 38 | 39 | Future signInWith(BaseAuthAPI api) async { 40 | _primaryAuth = api; 41 | 42 | return api.signIn(); 43 | } 44 | 45 | Future signOut() async { 46 | try { 47 | // Previously signed-in before re-launching the app. So there is no _primaryAuth set. Need to find out how it is signed-in in order to sign-out properly. 48 | if (_primaryAuth == null) { 49 | _primaryAuth = await getAuthFromClaims(); 50 | } 51 | 52 | await _firebaseAuth.signOut(); 53 | 54 | // If provider is firebase, we don't need to sign-out anymore. 55 | if (_primaryAuth == null || 56 | _primaryAuth is FirebaseEmailAuthAPI || 57 | _primaryAuth is FirebasePhoneAuthAPI) return; 58 | 59 | // If primary sign in provider is not firebase, we should do manually for them. 60 | await _primaryAuth.signOut(); 61 | } catch (e) { 62 | return Future.error(e); 63 | } 64 | } 65 | 66 | Future getAuthFromClaims() async { 67 | try { 68 | BaseAuthAPI api; 69 | var userClaims = await getUserClaim(); 70 | final String providerId = userClaims['firebase']['sign_in_provider']; 71 | 72 | if (providerId == "google.com") { 73 | api = FirebaseGoogleAuthAPI(); 74 | } else if (providerId == "facebook.com") { 75 | api = FirebaseFacebookAuthAPI(); 76 | } 77 | // Custom providers (providerId == "custom") 78 | else { 79 | if (userClaims['provider'] == "kakaocorp.com") { 80 | api = FirebaseKakaoAuthAPI(); 81 | } else { 82 | // TBA. (eg. Link, Apple, etc..) 83 | api = null; 84 | } 85 | } 86 | return api; 87 | } catch (e) { 88 | return Future.error(e); 89 | } 90 | } 91 | 92 | /// This will link the provided auth with currently signed-in user's account. 93 | /// If there is no previously signed-in user, this will throw an exception. 94 | Future linkCurrentUserWith(BaseAuthAPI api) async { 95 | try { 96 | User prevUser = currentUser(); 97 | return await api.linkWith(prevUser); 98 | } catch (e) { 99 | return Future.error(e); 100 | } 101 | } 102 | 103 | /// This will unlink the provided auth with currently signed-in user's account. 104 | /// 105 | /// If there is no previously signed-in user or no linked auth, this will throw an exception. 106 | /// PlatformException(FirebaseException, User was not linked to an account with the given provider.) 107 | Future unlinkCurrentUserFrom(BaseAuthAPI api) async { 108 | try { 109 | User prevUser = currentUser(); 110 | await api.unlinkFrom(prevUser); 111 | } catch (e) { 112 | throw Future.error(e); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/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.5.0-nullsafety.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0-nullsafety.1" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0-nullsafety.3" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0-nullsafety.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0-nullsafety.1" 39 | cloud_functions: 40 | dependency: "direct main" 41 | description: 42 | name: cloud_functions 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.9.0" 46 | cloud_functions_platform_interface: 47 | dependency: transitive 48 | description: 49 | name: cloud_functions_platform_interface 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "4.0.1" 53 | cloud_functions_web: 54 | dependency: transitive 55 | description: 56 | name: cloud_functions_web 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "3.1.3" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.15.0-nullsafety.3" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: "direct main" 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.5" 81 | dio: 82 | dependency: transitive 83 | description: 84 | name: dio 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "3.0.10" 88 | fake_async: 89 | dependency: transitive 90 | description: 91 | name: fake_async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.2.0-nullsafety.1" 95 | file: 96 | dependency: transitive 97 | description: 98 | name: file 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "5.2.1" 102 | firebase_auth: 103 | dependency: "direct main" 104 | description: 105 | name: firebase_auth 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "0.20.0+1" 109 | firebase_auth_platform_interface: 110 | dependency: transitive 111 | description: 112 | name: firebase_auth_platform_interface 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "3.0.1" 116 | firebase_auth_web: 117 | dependency: transitive 118 | description: 119 | name: firebase_auth_web 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "0.3.2+6" 123 | firebase_core: 124 | dependency: "direct main" 125 | description: 126 | name: firebase_core 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "0.7.0" 130 | firebase_core_platform_interface: 131 | dependency: transitive 132 | description: 133 | name: firebase_core_platform_interface 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "3.0.1" 137 | firebase_core_web: 138 | dependency: transitive 139 | description: 140 | name: firebase_core_web 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "0.2.1+3" 144 | flutter: 145 | dependency: "direct main" 146 | description: flutter 147 | source: sdk 148 | version: "0.0.0" 149 | flutter_facebook_login: 150 | dependency: "direct main" 151 | description: 152 | name: flutter_facebook_login 153 | url: "https://pub.dartlang.org" 154 | source: hosted 155 | version: "3.0.0" 156 | flutter_test: 157 | dependency: "direct dev" 158 | description: flutter 159 | source: sdk 160 | version: "0.0.0" 161 | flutter_web_plugins: 162 | dependency: transitive 163 | description: flutter 164 | source: sdk 165 | version: "0.0.0" 166 | google_sign_in: 167 | dependency: "direct main" 168 | description: 169 | name: google_sign_in 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "4.5.1" 173 | google_sign_in_platform_interface: 174 | dependency: transitive 175 | description: 176 | name: google_sign_in_platform_interface 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.1.1" 180 | google_sign_in_web: 181 | dependency: transitive 182 | description: 183 | name: google_sign_in_web 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.9.1" 187 | http: 188 | dependency: "direct main" 189 | description: 190 | name: http 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "0.12.0+4" 194 | http_parser: 195 | dependency: transitive 196 | description: 197 | name: http_parser 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "3.1.3" 201 | intl: 202 | dependency: transitive 203 | description: 204 | name: intl 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.16.1" 208 | js: 209 | dependency: transitive 210 | description: 211 | name: js 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.6.1+1" 215 | json_annotation: 216 | dependency: transitive 217 | description: 218 | name: json_annotation 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "3.0.1" 222 | kakao_flutter_sdk: 223 | dependency: "direct main" 224 | description: 225 | name: kakao_flutter_sdk 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.6.0-beta.1" 229 | matcher: 230 | dependency: transitive 231 | description: 232 | name: matcher 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.12.10-nullsafety.1" 236 | meta: 237 | dependency: transitive 238 | description: 239 | name: meta 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.3.0-nullsafety.3" 243 | nested: 244 | dependency: transitive 245 | description: 246 | name: nested 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.0.4" 250 | package_info: 251 | dependency: transitive 252 | description: 253 | name: package_info 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "0.4.1" 257 | path: 258 | dependency: transitive 259 | description: 260 | name: path 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "1.8.0-nullsafety.1" 264 | path_provider_linux: 265 | dependency: transitive 266 | description: 267 | name: path_provider_linux 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.0.1+2" 271 | path_provider_platform_interface: 272 | dependency: transitive 273 | description: 274 | name: path_provider_platform_interface 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.0.4" 278 | pedantic: 279 | dependency: transitive 280 | description: 281 | name: pedantic 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "1.8.0+1" 285 | platform: 286 | dependency: transitive 287 | description: 288 | name: platform 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "3.0.0-nullsafety.3" 292 | plugin_platform_interface: 293 | dependency: transitive 294 | description: 295 | name: plugin_platform_interface 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.0.2" 299 | process: 300 | dependency: transitive 301 | description: 302 | name: process 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "3.0.13" 306 | provider: 307 | dependency: "direct main" 308 | description: 309 | name: provider 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "4.3.1" 313 | quiver: 314 | dependency: transitive 315 | description: 316 | name: quiver 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "2.1.3" 320 | shared_preferences: 321 | dependency: transitive 322 | description: 323 | name: shared_preferences 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "0.5.8" 327 | shared_preferences_linux: 328 | dependency: transitive 329 | description: 330 | name: shared_preferences_linux 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "0.0.2+1" 334 | shared_preferences_macos: 335 | dependency: transitive 336 | description: 337 | name: shared_preferences_macos 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.0.1+10" 341 | shared_preferences_platform_interface: 342 | dependency: transitive 343 | description: 344 | name: shared_preferences_platform_interface 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "1.0.4" 348 | shared_preferences_web: 349 | dependency: transitive 350 | description: 351 | name: shared_preferences_web 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "0.1.2+7" 355 | sign_in_with_apple: 356 | dependency: "direct main" 357 | description: 358 | name: sign_in_with_apple 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "2.5.4" 362 | sky_engine: 363 | dependency: transitive 364 | description: flutter 365 | source: sdk 366 | version: "0.0.99" 367 | source_span: 368 | dependency: transitive 369 | description: 370 | name: source_span 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "1.8.0-nullsafety.2" 374 | stack_trace: 375 | dependency: transitive 376 | description: 377 | name: stack_trace 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "1.10.0-nullsafety.1" 381 | stream_channel: 382 | dependency: transitive 383 | description: 384 | name: stream_channel 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "2.1.0-nullsafety.1" 388 | string_scanner: 389 | dependency: transitive 390 | description: 391 | name: string_scanner 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.1.0-nullsafety.1" 395 | term_glyph: 396 | dependency: transitive 397 | description: 398 | name: term_glyph 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "1.2.0-nullsafety.1" 402 | test_api: 403 | dependency: transitive 404 | description: 405 | name: test_api 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "0.2.19-nullsafety.2" 409 | typed_data: 410 | dependency: transitive 411 | description: 412 | name: typed_data 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "1.3.0-nullsafety.3" 416 | vector_math: 417 | dependency: transitive 418 | description: 419 | name: vector_math 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "2.1.0-nullsafety.3" 423 | xdg_directories: 424 | dependency: transitive 425 | description: 426 | name: xdg_directories 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "0.1.0" 430 | sdks: 431 | dart: ">=2.10.0-110 <2.11.0" 432 | flutter: ">=1.16.0 <2.0.0" 433 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: firebase_auth_simplify 2 | description: A high-level framework of Firebase Auth package that wraps several lines of codes to one line in order to easily use sign-in and out function. 3 | version: 2.1.1 4 | homepage: https://github.com/fysoul17/firebase_auth_simplify 5 | 6 | environment: 7 | sdk: ">=2.1.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | firebase_core: ^0.7.0 14 | firebase_auth: ^0.20.0 15 | cloud_functions: ^0.9.0 16 | 17 | provider: ^4.3.1 18 | 19 | google_sign_in: ^4.5.1 20 | kakao_flutter_sdk: ^0.6.0-beta.1 21 | flutter_facebook_login: ^3.0.0 22 | http: ^0.12.0+4 # Used for fetching profiles from Facebook GraphAPI 23 | sign_in_with_apple: ^2.5.4 24 | crypto: ^2.1.5 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | 30 | flutter: 31 | -------------------------------------------------------------------------------- /screenshots/link.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/screenshots/link.PNG -------------------------------------------------------------------------------- /screenshots/signin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fysoul17/firebase_auth_simplify/9b19374958be8d6a961fa37e8896ec27b56117b0/screenshots/signin.PNG -------------------------------------------------------------------------------- /test/firebase_auth_simplify_test.dart: -------------------------------------------------------------------------------- 1 | void main() {} 2 | --------------------------------------------------------------------------------