Adoird build migration and update

This commit is contained in:
Yasien Mac Mini 2026-07-01 14:01:25 +02:00
parent 04f034971f
commit 7a5c8721dd
1062 changed files with 143083 additions and 221 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,26 @@
[<img src="https://raw.githubusercontent.com/firebase/flutterfire/main/.github/images/flutter_favorite.png" width="200" />](https://flutter.dev/docs/development/packages-and-plugins/favorites)
# Firebase Auth for Flutter
[![pub package](https://img.shields.io/pub/v/firebase_auth.svg)](https://pub.dev/packages/firebase_auth)
A Flutter plugin to use the [Firebase Authentication API](https://firebase.google.com/products/auth/).
To learn more about Firebase Auth, please visit the [Firebase website](https://firebase.google.com/products/auth)
## Getting Started
To get started with Firebase Auth for Flutter, please [see the documentation](https://firebase.google.com/docs/auth/flutter/start).
## Usage
To use this plugin, please visit the [Authentication Usage documentation](https://firebase.google.com/docs/auth/flutter/manage-users)
## Issues and feedback
Please file FlutterFire specific issues, bugs, or feature requests in our [issue tracker](https://github.com/firebase/flutterfire/issues/new).
Plugin issues that are not specific to FlutterFire can be filed in the [Flutter issue tracker](https://github.com/flutter/flutter/issues/new).
To contribute a change to this plugin,
please review our [contribution guide](https://github.com/firebase/flutterfire/blob/main/CONTRIBUTING.md)
and open a [pull request](https://github.com/firebase/flutterfire/pulls).

View file

@ -0,0 +1,66 @@
group 'io.flutter.plugins.firebase.auth'
version '1.0-SNAPSHOT'
apply plugin: 'com.android.library'
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
def firebaseCoreProject = findProject(':firebase_core')
if (firebaseCoreProject == null) {
throw new GradleException('Could not find the firebase_core FlutterFire plugin, have you added it as a dependency in your pubspec?')
} else if (!firebaseCoreProject.properties['FirebaseSDKVersion']) {
throw new GradleException('A newer version of the firebase_core FlutterFire plugin is required, please update your firebase_core pubspec dependency.')
}
def getRootProjectExtOrCoreProperty(name, firebaseCoreProject) {
if (!rootProject.ext.has('FlutterFire')) return firebaseCoreProject.properties[name]
if (!rootProject.ext.get('FlutterFire')[name]) return firebaseCoreProject.properties[name]
return rootProject.ext.get('FlutterFire').get(name)
}
android {
// Conditional for compatibility with AGP <4.2.
if (project.android.hasProperty("namespace")) {
namespace 'io.flutter.plugins.firebase.auth'
}
compileSdkVersion 34
defaultConfig {
minSdkVersion 23
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility JavaVersion.toVersion(17)
targetCompatibility JavaVersion.toVersion(17)
}
buildFeatures {
buildConfig true
}
lintOptions {
disable 'InvalidPackage'
}
dependencies {
api firebaseCoreProject
implementation platform("com.google.firebase:firebase-bom:${getRootProjectExtOrCoreProperty("FirebaseSDKVersion", firebaseCoreProject)}")
implementation 'com.google.firebase:firebase-auth'
implementation 'androidx.annotation:annotation:1.7.0'
}
}
apply from: file("./user-agent.gradle")

View file

@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,8 @@
rootProject.name = 'firebase_auth'
pluginManagement {
plugins {
id "com.android.application" version "8.3.0"
id "com.android.library" version "8.3.0"
}
}

View file

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.flutter.plugins.firebase.auth">
<application>
<service android:name="com.google.firebase.components.ComponentDiscoveryService">
<meta-data android:name="com.google.firebase.components:io.flutter.plugins.firebase.auth.FlutterFirebaseAuthRegistrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
</service>
</application>
</manifest>

View file

@ -0,0 +1,63 @@
/*
* Copyright 2022, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuth.AuthStateListener;
import com.google.firebase.auth.FirebaseUser;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class AuthStateChannelStreamHandler implements StreamHandler {
private final FirebaseAuth firebaseAuth;
private AuthStateListener authStateListener;
public AuthStateChannelStreamHandler(FirebaseAuth firebaseAuth) {
this.firebaseAuth = firebaseAuth;
}
@Override
public void onListen(Object arguments, EventSink events) {
Map<String, Object> event = new HashMap<>();
event.put(Constants.APP_NAME, firebaseAuth.getApp().getName());
final AtomicBoolean initialAuthState = new AtomicBoolean(true);
authStateListener =
auth -> {
if (initialAuthState.get()) {
initialAuthState.set(false);
return;
}
FirebaseUser user = auth.getCurrentUser();
if (user == null) {
event.put(Constants.USER, null);
} else {
event.put(
Constants.USER, PigeonParser.manuallyToList(PigeonParser.parseFirebaseUser(user)));
}
events.success(event);
};
firebaseAuth.addAuthStateListener(authStateListener);
}
@Override
public void onCancel(Object arguments) {
if (authStateListener != null) {
firebaseAuth.removeAuthStateListener(authStateListener);
authStateListener = null;
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2022, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
public class Constants {
public static final String APP_NAME = "appName";
// Providers
public static final String SIGN_IN_METHOD_PASSWORD = "password";
public static final String SIGN_IN_METHOD_EMAIL_LINK = "emailLink";
public static final String SIGN_IN_METHOD_FACEBOOK = "facebook.com";
public static final String SIGN_IN_METHOD_GOOGLE = "google.com";
public static final String SIGN_IN_METHOD_TWITTER = "twitter.com";
public static final String SIGN_IN_METHOD_GITHUB = "github.com";
public static final String SIGN_IN_METHOD_PHONE = "phone";
public static final String SIGN_IN_METHOD_OAUTH = "oauth";
public static final String SIGN_IN_METHOD_PLAY_GAMES = "playgames.google.com";
// User
public static final String USER = "user";
public static final String EMAIL = "email";
public static final String PROVIDER_ID = "providerId";
public static final String CREDENTIAL = "credential";
public static final String SECRET = "secret";
public static final String ID_TOKEN = "idToken";
public static final String TOKEN = "token";
public static final String ACCESS_TOKEN = "accessToken";
public static final String RAW_NONCE = "rawNonce";
public static final String EMAIL_LINK = "emailLink";
public static final String VERIFICATION_ID = "verificationId";
public static final String SMS_CODE = "smsCode";
public static final String SIGN_IN_METHOD = "signInMethod";
public static final String FORCE_RESENDING_TOKEN = "forceResendingToken";
public static final String NAME = "name";
public static final String SERVER_AUTH_CODE = "serverAuthCode";
// MultiFactor
public static final String MULTI_FACTOR_HINTS = "multiFactorHints";
public static final String MULTI_FACTOR_SESSION_ID = "multiFactorSessionId";
public static final String MULTI_FACTOR_RESOLVER_ID = "multiFactorResolverId";
}

View file

@ -0,0 +1,782 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.firebase.auth;
import static io.flutter.plugins.firebase.auth.FlutterFirebaseMultiFactor.multiFactorUserMap;
import static io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry.registerPlugin;
import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.ActionCodeResult;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.MultiFactor;
import com.google.firebase.auth.MultiFactorInfo;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.OAuthProvider;
import com.google.firebase.auth.PhoneMultiFactorInfo;
import com.google.firebase.auth.SignInMethodQueryResult;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin;
import io.flutter.plugins.firebase.core.FlutterFirebasePlugin;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/** Flutter plugin for Firebase Auth. */
public class FlutterFirebaseAuthPlugin
implements FlutterFirebasePlugin,
FlutterPlugin,
ActivityAware,
GeneratedAndroidFirebaseAuth.FirebaseAuthHostApi {
private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_auth";
// Stores the instances of native AuthCredentials by their hashCode
static final HashMap<Integer, AuthCredential> authCredentials = new HashMap<>();
@Nullable private BinaryMessenger messenger;
private MethodChannel channel;
private Activity activity;
private final Map<EventChannel, StreamHandler> streamHandlers = new HashMap<>();
private final FlutterFirebaseAuthUser firebaseAuthUser = new FlutterFirebaseAuthUser();
private final FlutterFirebaseMultiFactor firebaseMultiFactor = new FlutterFirebaseMultiFactor();
private final FlutterFirebaseTotpMultiFactor firebaseTotpMultiFactor =
new FlutterFirebaseTotpMultiFactor();
private final FlutterFirebaseTotpSecret firebaseTotpSecret = new FlutterFirebaseTotpSecret();
private void initInstance(BinaryMessenger messenger) {
registerPlugin(METHOD_CHANNEL_NAME, this);
channel = new MethodChannel(messenger, METHOD_CHANNEL_NAME);
GeneratedAndroidFirebaseAuth.FirebaseAuthHostApi.setUp(messenger, this);
GeneratedAndroidFirebaseAuth.FirebaseAuthUserHostApi.setUp(messenger, firebaseAuthUser);
GeneratedAndroidFirebaseAuth.MultiFactorUserHostApi.setUp(messenger, firebaseMultiFactor);
GeneratedAndroidFirebaseAuth.MultiFactoResolverHostApi.setUp(messenger, firebaseMultiFactor);
GeneratedAndroidFirebaseAuth.MultiFactorTotpHostApi.setUp(messenger, firebaseTotpMultiFactor);
GeneratedAndroidFirebaseAuth.MultiFactorTotpSecretHostApi.setUp(messenger, firebaseTotpSecret);
this.messenger = messenger;
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
initInstance(binding.getBinaryMessenger());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
assert messenger != null;
GeneratedAndroidFirebaseAuth.FirebaseAuthHostApi.setUp(messenger, null);
GeneratedAndroidFirebaseAuth.FirebaseAuthUserHostApi.setUp(messenger, null);
GeneratedAndroidFirebaseAuth.MultiFactorUserHostApi.setUp(messenger, null);
GeneratedAndroidFirebaseAuth.MultiFactoResolverHostApi.setUp(messenger, null);
GeneratedAndroidFirebaseAuth.MultiFactorTotpHostApi.setUp(messenger, null);
GeneratedAndroidFirebaseAuth.MultiFactorTotpSecretHostApi.setUp(messenger, null);
channel = null;
messenger = null;
removeEventListeners();
}
@Override
public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) {
activity = activityPluginBinding.getActivity();
firebaseAuthUser.setActivity(activity);
}
@Override
public void onDetachedFromActivityForConfigChanges() {
activity = null;
firebaseAuthUser.setActivity(null);
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) {
activity = activityPluginBinding.getActivity();
firebaseAuthUser.setActivity(activity);
}
@Override
public void onDetachedFromActivity() {
activity = null;
firebaseAuthUser.setActivity(null);
}
// Only access activity with this method.
@Nullable
private Activity getActivity() {
return activity;
}
static FirebaseAuth getAuthFromPigeon(
GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp pigeonApp) {
FirebaseApp app = FirebaseApp.getInstance(pigeonApp.getAppName());
FirebaseAuth auth = FirebaseAuth.getInstance(app);
if (pigeonApp.getTenantId() != null) {
auth.setTenantId(pigeonApp.getTenantId());
}
String customDomain = FlutterFirebaseCorePlugin.customAuthDomain.get(pigeonApp.getAppName());
if (customDomain != null) {
auth.setCustomAuthDomain(customDomain);
}
// Auth's `getCustomAuthDomain` supersedes value from `customAuthDomain` map set by
// `initializeApp`
if (pigeonApp.getCustomAuthDomain() != null) {
auth.setCustomAuthDomain(pigeonApp.getCustomAuthDomain());
}
return auth;
}
@Override
public void registerIdTokenListener(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
try {
final FirebaseAuth auth = getAuthFromPigeon(app);
final IdTokenChannelStreamHandler handler = new IdTokenChannelStreamHandler(auth);
final String name = METHOD_CHANNEL_NAME + "/id-token/" + auth.getApp().getName();
final EventChannel channel = new EventChannel(messenger, name);
channel.setStreamHandler(handler);
streamHandlers.put(channel, handler);
result.success(name);
} catch (Exception e) {
result.error(e);
}
}
@Override
public void registerAuthStateListener(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
try {
final FirebaseAuth auth = getAuthFromPigeon(app);
final AuthStateChannelStreamHandler handler = new AuthStateChannelStreamHandler(auth);
final String name = METHOD_CHANNEL_NAME + "/auth-state/" + auth.getApp().getName();
final EventChannel channel = new EventChannel(messenger, name);
channel.setStreamHandler(handler);
streamHandlers.put(channel, handler);
result.success(name);
} catch (Exception e) {
result.error(e);
}
}
@Override
public void useEmulator(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String host,
@NonNull Long port,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
try {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth.useEmulator(host, port.intValue());
result.success();
} catch (Exception e) {
result.error(e);
}
}
@Override
public void applyActionCode(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String code,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.applyActionCode(code)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void checkActionCode(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String code,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalActionCodeInfo>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.checkActionCode(code)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
ActionCodeResult actionCodeInfo = task.getResult();
result.success(PigeonParser.parseActionCodeResult(actionCodeInfo));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void confirmPasswordReset(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String code,
@NonNull String newPassword,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.confirmPasswordReset(code, newPassword)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void createUserWithEmailAndPassword(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@NonNull String password,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInAnonymously(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.signInAnonymously()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInWithCredential(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull Map<String, Object> input,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
AuthCredential credential = PigeonParser.getCredential(input);
if (credential == null) {
throw FlutterFirebaseAuthPluginException.invalidCredential();
}
firebaseAuth
.signInWithCredential(credential)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInWithCustomToken(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String token,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.signInWithCustomToken(token)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInWithEmailAndPassword(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@NonNull String password,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInWithEmailLink(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@NonNull String emailLink,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.signInWithEmailLink(email, emailLink)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signInWithProvider(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalSignInProvider signInProvider,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
OAuthProvider.Builder provider =
OAuthProvider.newBuilder(signInProvider.getProviderId(), firebaseAuth);
if (signInProvider.getScopes() != null) {
provider.setScopes(signInProvider.getScopes());
}
if (signInProvider.getCustomParameters() != null) {
provider.addCustomParameters(signInProvider.getCustomParameters());
}
firebaseAuth
.startActivityForSignInWithProvider(getActivity(), provider.build())
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void signOut(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
try {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
if (firebaseAuth.getCurrentUser() != null) {
final Map<String, MultiFactor> appMultiFactorUser =
multiFactorUserMap.get(app.getAppName());
if (appMultiFactorUser != null) {
appMultiFactorUser.remove(firebaseAuth.getCurrentUser().getUid());
}
}
firebaseAuth.signOut();
result.success();
} catch (Exception e) {
result.error(e);
}
}
@Override
public void fetchSignInMethodsForEmail(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@NonNull GeneratedAndroidFirebaseAuth.Result<List<String>> result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.fetchSignInMethodsForEmail(email)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
SignInMethodQueryResult signInMethodQueryResult = task.getResult();
result.success(signInMethodQueryResult.getSignInMethods());
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void sendPasswordResetEmail(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@Nullable GeneratedAndroidFirebaseAuth.InternalActionCodeSettings actionCodeSettings,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
if (actionCodeSettings == null) {
firebaseAuth
.sendPasswordResetEmail(email)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
return;
}
firebaseAuth
.sendPasswordResetEmail(email, PigeonParser.getActionCodeSettings(actionCodeSettings))
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void sendSignInLinkToEmail(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String email,
@NonNull GeneratedAndroidFirebaseAuth.InternalActionCodeSettings actionCodeSettings,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.sendSignInLinkToEmail(email, PigeonParser.getActionCodeSettings(actionCodeSettings))
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void setLanguageCode(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@Nullable String languageCode,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
try {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
if (languageCode == null) {
firebaseAuth.useAppLanguage();
} else {
firebaseAuth.setLanguageCode(languageCode);
}
result.success(firebaseAuth.getLanguageCode());
} catch (Exception e) {
result.error(e);
}
}
@Override
public void setSettings(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalFirebaseAuthSettings settings,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
try {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.getFirebaseAuthSettings()
.setAppVerificationDisabledForTesting(settings.getAppVerificationDisabledForTesting());
if (settings.getForceRecaptchaFlow() != null) {
firebaseAuth
.getFirebaseAuthSettings()
.forceRecaptchaFlowForTesting(settings.getForceRecaptchaFlow());
}
if (settings.getPhoneNumber() != null && settings.getSmsCode() != null) {
firebaseAuth
.getFirebaseAuthSettings()
.setAutoRetrievedSmsCodeForPhoneNumber(
settings.getPhoneNumber(), settings.getSmsCode());
}
result.success();
} catch (Exception e) {
result.error(e);
}
}
@Override
public void verifyPasswordResetCode(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String code,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.verifyPasswordResetCode(code)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(task.getResult());
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void verifyPhoneNumber(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalVerifyPhoneNumberRequest request,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
try {
String eventChannelName = METHOD_CHANNEL_NAME + "/phone/" + UUID.randomUUID().toString();
EventChannel channel = new EventChannel(messenger, eventChannelName);
MultiFactorSession multiFactorSession = null;
if (request.getMultiFactorSessionId() != null) {
multiFactorSession =
FlutterFirebaseMultiFactor.multiFactorSessionMap.get(request.getMultiFactorSessionId());
}
final String multiFactorInfoId = request.getMultiFactorInfoId();
PhoneMultiFactorInfo multiFactorInfo = null;
if (multiFactorInfoId != null) {
for (String resolverId : FlutterFirebaseMultiFactor.multiFactorResolverMap.keySet()) {
for (MultiFactorInfo info :
FlutterFirebaseMultiFactor.multiFactorResolverMap.get(resolverId).getHints()) {
if (info.getUid().equals(multiFactorInfoId) && info instanceof PhoneMultiFactorInfo) {
multiFactorInfo = (PhoneMultiFactorInfo) info;
break;
}
}
}
}
PhoneNumberVerificationStreamHandler handler =
new PhoneNumberVerificationStreamHandler(
getActivity(),
app,
request,
multiFactorSession,
multiFactorInfo,
credential -> {
int hashCode = credential.hashCode();
authCredentials.put(hashCode, credential);
});
channel.setStreamHandler(handler);
streamHandlers.put(channel, handler);
result.success(eventChannelName);
} catch (Exception e) {
result.error(e);
}
}
@Override
public void revokeTokenWithAuthorizationCode(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String authorizationCode,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
// Should never get here as we throw Exception on Dart side.
result.success();
}
@Override
public void revokeAccessToken(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String accessToken,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.revokeAccessToken(accessToken)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void initializeRecaptchaConfig(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseAuth firebaseAuth = getAuthFromPigeon(app);
firebaseAuth
.initializeRecaptchaConfig()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public Task<Map<String, Object>> getPluginConstantsForFirebaseApp(FirebaseApp firebaseApp) {
TaskCompletionSource<Map<String, Object>> taskCompletionSource = new TaskCompletionSource<>();
cachedThreadPool.execute(
() -> {
try {
Map<String, Object> constants = new HashMap<>();
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
String languageCode = firebaseAuth.getLanguageCode();
GeneratedAndroidFirebaseAuth.InternalUserDetails user =
firebaseUser == null ? null : PigeonParser.parseFirebaseUser(firebaseUser);
if (languageCode != null) {
constants.put("APP_LANGUAGE_CODE", languageCode);
}
if (user != null) {
constants.put("APP_CURRENT_USER", PigeonParser.manuallyToList(user));
}
taskCompletionSource.setResult(constants);
} catch (Exception e) {
taskCompletionSource.setException(e);
}
});
return taskCompletionSource.getTask();
}
@Override
public Task<Void> didReinitializeFirebaseCore() {
TaskCompletionSource<Void> taskCompletionSource = new TaskCompletionSource<>();
cachedThreadPool.execute(
() -> {
try {
removeEventListeners();
authCredentials.clear();
taskCompletionSource.setResult(null);
} catch (Exception e) {
taskCompletionSource.setException(e);
}
});
return taskCompletionSource.getTask();
}
private void removeEventListeners() {
for (EventChannel eventChannel : streamHandlers.keySet()) {
StreamHandler streamHandler = streamHandlers.get(eventChannel);
if (streamHandler != null) {
streamHandler.onCancel(null);
}
eventChannel.setStreamHandler(null);
}
streamHandlers.clear();
}
}

View file

@ -0,0 +1,157 @@
/*
* Copyright 2022, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import androidx.annotation.Nullable;
import com.google.firebase.FirebaseApiNotAvailableException;
import com.google.firebase.FirebaseNetworkException;
import com.google.firebase.FirebaseTooManyRequestsException;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.FirebaseAuthException;
import com.google.firebase.auth.FirebaseAuthMultiFactorException;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
import com.google.firebase.auth.FirebaseAuthWeakPasswordException;
import com.google.firebase.auth.MultiFactorInfo;
import com.google.firebase.auth.MultiFactorResolver;
import com.google.firebase.auth.MultiFactorSession;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class FlutterFirebaseAuthPluginException {
static GeneratedAndroidFirebaseAuth.FlutterError parserExceptionToFlutter(
@Nullable Exception nativeException) {
if (nativeException == null) {
return new GeneratedAndroidFirebaseAuth.FlutterError("UNKNOWN", null, null);
}
String code = "UNKNOWN";
String message = nativeException.getMessage();
Map<String, Object> additionalData = new HashMap<>();
if (nativeException instanceof FirebaseAuthMultiFactorException) {
final FirebaseAuthMultiFactorException multiFactorException =
(FirebaseAuthMultiFactorException) nativeException;
Map<String, Object> output = new HashMap<>();
MultiFactorResolver multiFactorResolver = multiFactorException.getResolver();
final List<MultiFactorInfo> hints = multiFactorResolver.getHints();
final MultiFactorSession session = multiFactorResolver.getSession();
final String sessionId = UUID.randomUUID().toString();
FlutterFirebaseMultiFactor.multiFactorSessionMap.put(sessionId, session);
final String resolverId = UUID.randomUUID().toString();
FlutterFirebaseMultiFactor.multiFactorResolverMap.put(resolverId, multiFactorResolver);
final List<List<Object>> pigeonHints = PigeonParser.multiFactorInfoToMap(hints);
output.put(
Constants.APP_NAME,
multiFactorException.getResolver().getFirebaseAuth().getApp().getName());
output.put(Constants.MULTI_FACTOR_HINTS, pigeonHints);
output.put(Constants.MULTI_FACTOR_SESSION_ID, sessionId);
output.put(Constants.MULTI_FACTOR_RESOLVER_ID, resolverId);
return new GeneratedAndroidFirebaseAuth.FlutterError(
multiFactorException.getErrorCode(), multiFactorException.getLocalizedMessage(), output);
}
if (nativeException instanceof FirebaseNetworkException
|| (nativeException.getCause() != null
&& nativeException.getCause() instanceof FirebaseNetworkException)) {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"network-request-failed",
"A network error (such as timeout, interrupted connection or unreachable host) has"
+ " occurred.",
null);
}
if (nativeException instanceof FirebaseApiNotAvailableException
|| (nativeException.getCause() != null
&& nativeException.getCause() instanceof FirebaseApiNotAvailableException)) {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"api-not-available", "The requested API is not available.", null);
}
if (nativeException instanceof FirebaseTooManyRequestsException
|| (nativeException.getCause() != null
&& nativeException.getCause() instanceof FirebaseTooManyRequestsException)) {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"too-many-requests",
"We have blocked all requests from this device due to unusual activity. Try again later.",
null);
}
// Manual message overrides to match other platforms.
if (nativeException.getMessage() != null
&& nativeException
.getMessage()
.startsWith("Cannot create PhoneAuthCredential without either verificationProof")) {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"invalid-verification-code",
"The verification ID used to create the phone auth credential is invalid.",
null);
}
if (message != null
&& message.contains("User has already been linked to the given provider.")) {
return FlutterFirebaseAuthPluginException.alreadyLinkedProvider();
}
if (nativeException instanceof FirebaseAuthException) {
code = ((FirebaseAuthException) nativeException).getErrorCode();
}
if (nativeException instanceof FirebaseAuthWeakPasswordException) {
message = ((FirebaseAuthWeakPasswordException) nativeException).getReason();
}
if (nativeException instanceof FirebaseAuthUserCollisionException) {
String email = ((FirebaseAuthUserCollisionException) nativeException).getEmail();
if (email != null) {
additionalData.put("email", email);
}
AuthCredential authCredential =
((FirebaseAuthUserCollisionException) nativeException).getUpdatedCredential();
if (authCredential != null) {
additionalData.put("authCredential", PigeonParser.parseAuthCredential(authCredential));
}
}
return new GeneratedAndroidFirebaseAuth.FlutterError(code, message, additionalData);
}
static GeneratedAndroidFirebaseAuth.FlutterError noUser() {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"NO_CURRENT_USER", "No user currently signed in.", null);
}
static GeneratedAndroidFirebaseAuth.FlutterError invalidCredential() {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"INVALID_CREDENTIAL",
"The supplied auth credential is malformed, has expired or is not currently supported.",
null);
}
static GeneratedAndroidFirebaseAuth.FlutterError noSuchProvider() {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"NO_SUCH_PROVIDER", "User was not linked to an account with the given provider.", null);
}
static GeneratedAndroidFirebaseAuth.FlutterError alreadyLinkedProvider() {
return new GeneratedAndroidFirebaseAuth.FlutterError(
"PROVIDER_ALREADY_LINKED", "User has already been linked to the given provider.", null);
}
}

View file

@ -0,0 +1,21 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.firebase.auth;
import androidx.annotation.Keep;
import com.google.firebase.components.Component;
import com.google.firebase.components.ComponentRegistrar;
import com.google.firebase.platforminfo.LibraryVersionComponent;
import java.util.Collections;
import java.util.List;
@Keep
public class FlutterFirebaseAuthRegistrar implements ComponentRegistrar {
@Override
public List<Component<?>> getComponents() {
return Collections.<Component<?>>singletonList(
LibraryVersionComponent.create(BuildConfig.LIBRARY_NAME, BuildConfig.LIBRARY_VERSION));
}
}

View file

@ -0,0 +1,548 @@
/*
* Copyright 2023, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import static io.flutter.plugins.firebase.core.FlutterFirebasePlugin.cachedThreadPool;
import android.app.Activity;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GetTokenResult;
import com.google.firebase.auth.OAuthProvider;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.UserProfileChangeRequest;
import java.util.Map;
public class FlutterFirebaseAuthUser
implements GeneratedAndroidFirebaseAuth.FirebaseAuthUserHostApi {
private Activity activity;
public void setActivity(Activity activity) {
this.activity = activity;
}
public static FirebaseUser getCurrentUserFromPigeon(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp pigeonApp) {
FirebaseApp app = FirebaseApp.getInstance(pigeonApp.getAppName());
FirebaseAuth auth = FirebaseAuth.getInstance(app);
if (pigeonApp.getTenantId() != null) {
auth.setTenantId(pigeonApp.getTenantId());
}
return auth.getCurrentUser();
}
@Override
public void delete(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
firebaseUser
.delete()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void getIdToken(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull Boolean forceRefresh,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalIdTokenResult>
result) {
cachedThreadPool.execute(
() -> {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
try {
GetTokenResult response = Tasks.await(firebaseUser.getIdToken(forceRefresh));
result.success(PigeonParser.parseTokenResult(response));
} catch (Exception exception) {
result.error(FlutterFirebaseAuthPluginException.parserExceptionToFlutter(exception));
}
});
}
@Override
public void linkWithCredential(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull Map<String, Object> input,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
AuthCredential credential = PigeonParser.getCredential(input);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
if (credential == null) {
result.error(FlutterFirebaseAuthPluginException.invalidCredential());
return;
}
firebaseUser
.linkWithCredential(credential)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void linkWithProvider(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalSignInProvider signInProvider,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
OAuthProvider.Builder provider = OAuthProvider.newBuilder(signInProvider.getProviderId());
if (signInProvider.getScopes() != null) {
provider.setScopes(signInProvider.getScopes());
}
if (signInProvider.getCustomParameters() != null) {
provider.addCustomParameters(signInProvider.getCustomParameters());
}
firebaseUser
.startActivityForLinkWithProvider(activity, provider.build())
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void reauthenticateWithCredential(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull Map<String, Object> input,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
AuthCredential credential = PigeonParser.getCredential(input);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
if (credential == null) {
result.error(FlutterFirebaseAuthPluginException.invalidCredential());
return;
}
firebaseUser
.reauthenticateAndRetrieveData(credential)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void reauthenticateWithProvider(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalSignInProvider signInProvider,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
OAuthProvider.Builder provider = OAuthProvider.newBuilder(signInProvider.getProviderId());
if (signInProvider.getScopes() != null) {
provider.setScopes(signInProvider.getScopes());
}
if (signInProvider.getCustomParameters() != null) {
provider.addCustomParameters(signInProvider.getCustomParameters());
}
firebaseUser
.startActivityForReauthenticateWithProvider(activity, provider.build())
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void reload(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserDetails>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
firebaseUser
.reload()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseFirebaseUser(firebaseUser));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void sendEmailVerification(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@Nullable GeneratedAndroidFirebaseAuth.InternalActionCodeSettings actionCodeSettings,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
if (actionCodeSettings == null) {
firebaseUser
.sendEmailVerification()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
return;
}
firebaseUser
.sendEmailVerification(PigeonParser.getActionCodeSettings(actionCodeSettings))
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void unlink(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String providerId,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
firebaseUser
.unlink(providerId)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success(PigeonParser.parseAuthResult(task.getResult()));
} else {
Exception exception = task.getException();
if (exception
.getMessage()
.contains("User was not linked to an account with the given provider.")) {
result.error(FlutterFirebaseAuthPluginException.noSuchProvider());
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(exception));
}
}
});
}
@Override
public void updateEmail(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String newEmail,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserDetails>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
firebaseUser
.updateEmail(newEmail)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
firebaseUser
.reload()
.addOnCompleteListener(
reloadTask -> {
if (reloadTask.isSuccessful()) {
result.success(PigeonParser.parseFirebaseUser(firebaseUser));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
reloadTask.getException()));
}
});
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void updatePassword(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String newPassword,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserDetails>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
firebaseUser
.updatePassword(newPassword)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
firebaseUser
.reload()
.addOnCompleteListener(
reloadTask -> {
if (reloadTask.isSuccessful()) {
result.success(PigeonParser.parseFirebaseUser(firebaseUser));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
reloadTask.getException()));
}
});
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void updatePhoneNumber(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull Map<String, Object> input,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserDetails>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
PhoneAuthCredential phoneAuthCredential =
(PhoneAuthCredential) PigeonParser.getCredential(input);
if (phoneAuthCredential == null) {
result.error(FlutterFirebaseAuthPluginException.invalidCredential());
return;
}
firebaseUser
.updatePhoneNumber(phoneAuthCredential)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
firebaseUser
.reload()
.addOnCompleteListener(
reloadTask -> {
if (reloadTask.isSuccessful()) {
result.success(PigeonParser.parseFirebaseUser(firebaseUser));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
reloadTask.getException()));
}
});
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void updateProfile(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalUserProfile profile,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserDetails>
result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
UserProfileChangeRequest.Builder builder = new UserProfileChangeRequest.Builder();
if (profile.getDisplayNameChanged()) {
builder.setDisplayName(profile.getDisplayName());
}
if (profile.getPhotoUrlChanged()) {
if (profile.getPhotoUrl() != null) {
builder.setPhotoUri(Uri.parse(profile.getPhotoUrl()));
} else {
builder.setPhotoUri(null);
}
}
firebaseUser
.updateProfile(builder.build())
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
firebaseUser
.reload()
.addOnCompleteListener(
reloadTask -> {
if (reloadTask.isSuccessful()) {
result.success(PigeonParser.parseFirebaseUser(firebaseUser));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
reloadTask.getException()));
}
});
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void verifyBeforeUpdateEmail(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String newEmail,
@Nullable GeneratedAndroidFirebaseAuth.InternalActionCodeSettings actionCodeSettings,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
FirebaseUser firebaseUser = getCurrentUserFromPigeon(app);
if (firebaseUser == null) {
result.error(FlutterFirebaseAuthPluginException.noUser());
return;
}
if (actionCodeSettings == null) {
firebaseUser
.verifyBeforeUpdateEmail(newEmail)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
return;
}
firebaseUser
.verifyBeforeUpdateEmail(newEmail, PigeonParser.getActionCodeSettings(actionCodeSettings))
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
}

View file

@ -0,0 +1,252 @@
/*
* Copyright 2023, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.MultiFactor;
import com.google.firebase.auth.MultiFactorAssertion;
import com.google.firebase.auth.MultiFactorInfo;
import com.google.firebase.auth.MultiFactorResolver;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.PhoneMultiFactorGenerator;
import com.google.firebase.internal.api.FirebaseNoSignedInUserException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class FlutterFirebaseMultiFactor
implements GeneratedAndroidFirebaseAuth.MultiFactorUserHostApi,
GeneratedAndroidFirebaseAuth.MultiFactoResolverHostApi {
// Map an app id to a map of user id to a MultiFactorUser object.
static final Map<String, Map<String, MultiFactor>> multiFactorUserMap = new HashMap<>();
// Map an id to a MultiFactorSession object.
static final Map<String, MultiFactorSession> multiFactorSessionMap = new HashMap<>();
// Map an id to a MultiFactorResolver object.
static final Map<String, MultiFactorResolver> multiFactorResolverMap = new HashMap<>();
static final Map<String, MultiFactorAssertion> multiFactorAssertionMap = new HashMap<>();
MultiFactor getAppMultiFactor(@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app)
throws FirebaseNoSignedInUserException {
final FirebaseUser currentUser = FlutterFirebaseAuthUser.getCurrentUserFromPigeon(app);
if (currentUser == null) {
throw new FirebaseNoSignedInUserException("No user is signed in");
}
if (multiFactorUserMap.get(app.getAppName()) == null) {
multiFactorUserMap.put(app.getAppName(), new HashMap<>());
}
final Map<String, MultiFactor> appMultiFactorUser = multiFactorUserMap.get(app.getAppName());
if (appMultiFactorUser.get(currentUser.getUid()) == null) {
appMultiFactorUser.put(currentUser.getUid(), currentUser.getMultiFactor());
}
return appMultiFactorUser.get(currentUser.getUid());
}
@Override
public void enrollPhone(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalPhoneMultiFactorAssertion assertion,
@Nullable String displayName,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
final MultiFactor multiFactor;
try {
multiFactor = getAppMultiFactor(app);
} catch (FirebaseNoSignedInUserException e) {
result.error(e);
return;
}
PhoneAuthCredential credential =
PhoneAuthProvider.getCredential(
assertion.getVerificationId(), assertion.getVerificationCode());
MultiFactorAssertion multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
multiFactor
.enroll(multiFactorAssertion, displayName)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void enrollTotp(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String assertionId,
@Nullable String displayName,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
final MultiFactor multiFactor;
try {
multiFactor = getAppMultiFactor(app);
} catch (FirebaseNoSignedInUserException e) {
result.error(e);
return;
}
final MultiFactorAssertion multiFactorAssertion = multiFactorAssertionMap.get(assertionId);
assert multiFactorAssertion != null;
multiFactor
.enroll(multiFactorAssertion, displayName)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void getSession(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull
GeneratedAndroidFirebaseAuth.Result<
GeneratedAndroidFirebaseAuth.InternalMultiFactorSession>
result) {
final MultiFactor multiFactor;
try {
multiFactor = getAppMultiFactor(app);
} catch (FirebaseNoSignedInUserException e) {
result.error(e);
return;
}
multiFactor
.getSession()
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
final MultiFactorSession sessionResult = task.getResult();
final String id = UUID.randomUUID().toString();
multiFactorSessionMap.put(id, sessionResult);
result.success(
new GeneratedAndroidFirebaseAuth.InternalMultiFactorSession.Builder()
.setId(id)
.build());
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void unenroll(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull String factorUid,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
final MultiFactor multiFactor;
try {
multiFactor = getAppMultiFactor(app);
} catch (FirebaseNoSignedInUserException e) {
result.error(FlutterFirebaseAuthPluginException.parserExceptionToFlutter(e));
return;
}
multiFactor
.unenroll(factorUid)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
result.success();
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void getEnrolledFactors(
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull
GeneratedAndroidFirebaseAuth.Result<
List<GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo>>
result) {
final MultiFactor multiFactor;
try {
multiFactor = getAppMultiFactor(app);
} catch (FirebaseNoSignedInUserException e) {
result.error(e);
return;
}
final List<MultiFactorInfo> factors = multiFactor.getEnrolledFactors();
final List<GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo> resultFactors =
PigeonParser.multiFactorInfoToPigeon(factors);
result.success(resultFactors);
}
@Override
public void resolveSignIn(
@NonNull String resolverId,
@Nullable GeneratedAndroidFirebaseAuth.InternalPhoneMultiFactorAssertion assertion,
@Nullable String totpAssertionId,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalUserCredential>
result) {
final MultiFactorResolver resolver = multiFactorResolverMap.get(resolverId);
if (resolver == null) {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
new Exception("Resolver not found")));
return;
}
MultiFactorAssertion multiFactorAssertion;
if (assertion != null) {
PhoneAuthCredential credential =
PhoneAuthProvider.getCredential(
assertion.getVerificationId(), assertion.getVerificationCode());
multiFactorAssertion = PhoneMultiFactorGenerator.getAssertion(credential);
} else {
multiFactorAssertion = multiFactorAssertionMap.get(totpAssertionId);
}
resolver
.resolveSignIn(multiFactorAssertion)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
final AuthResult authResult = task.getResult();
result.success(PigeonParser.parseAuthResult(authResult));
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright 2023, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import androidx.annotation.NonNull;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.TotpMultiFactorAssertion;
import com.google.firebase.auth.TotpMultiFactorGenerator;
import com.google.firebase.auth.TotpSecret;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class FlutterFirebaseTotpMultiFactor
implements GeneratedAndroidFirebaseAuth.MultiFactorTotpHostApi {
// Map an app id to a map of user id to a TotpSecret object.
static final Map<String, TotpSecret> multiFactorSecret = new HashMap<>();
@Override
public void generateSecret(
@NonNull String sessionId,
@NonNull
GeneratedAndroidFirebaseAuth.Result<GeneratedAndroidFirebaseAuth.InternalTotpSecret>
result) {
MultiFactorSession multiFactorSession =
FlutterFirebaseMultiFactor.multiFactorSessionMap.get(sessionId);
assert multiFactorSession != null;
TotpMultiFactorGenerator.generateSecret(multiFactorSession)
.addOnCompleteListener(
task -> {
if (task.isSuccessful()) {
TotpSecret secret = task.getResult();
multiFactorSecret.put(secret.getSharedSecretKey(), secret);
result.success(
new GeneratedAndroidFirebaseAuth.InternalTotpSecret.Builder()
.setCodeIntervalSeconds((long) secret.getCodeIntervalSeconds())
.setCodeLength((long) secret.getCodeLength())
.setSecretKey(secret.getSharedSecretKey())
.setHashingAlgorithm(secret.getHashAlgorithm())
.setEnrollmentCompletionDeadline(secret.getEnrollmentCompletionDeadline())
.build());
} else {
result.error(
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(
task.getException()));
}
});
}
@Override
public void getAssertionForEnrollment(
@NonNull String secretKey,
@NonNull String oneTimePassword,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
final TotpSecret secret = multiFactorSecret.get(secretKey);
assert secret != null;
TotpMultiFactorAssertion assertion =
TotpMultiFactorGenerator.getAssertionForEnrollment(secret, oneTimePassword);
String assertionId = UUID.randomUUID().toString();
FlutterFirebaseMultiFactor.multiFactorAssertionMap.put(assertionId, assertion);
result.success(assertionId);
}
@Override
public void getAssertionForSignIn(
@NonNull String enrollmentId,
@NonNull String oneTimePassword,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
TotpMultiFactorAssertion assertion =
TotpMultiFactorGenerator.getAssertionForSignIn(enrollmentId, oneTimePassword);
String assertionId = UUID.randomUUID().toString();
FlutterFirebaseMultiFactor.multiFactorAssertionMap.put(assertionId, assertion);
result.success(assertionId);
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2023, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.firebase.auth.TotpSecret;
public class FlutterFirebaseTotpSecret
implements GeneratedAndroidFirebaseAuth.MultiFactorTotpSecretHostApi {
@Override
public void generateQrCodeUrl(
@NonNull String secretKey,
@Nullable String accountName,
@Nullable String issuer,
@NonNull GeneratedAndroidFirebaseAuth.Result<String> result) {
final TotpSecret secret = FlutterFirebaseTotpMultiFactor.multiFactorSecret.get(secretKey);
assert secret != null;
if (accountName == null || issuer == null) {
result.success(secret.generateQrCodeUrl());
return;
}
result.success(secret.generateQrCodeUrl(accountName, issuer));
}
@Override
public void openInOtpApp(
@NonNull String secretKey,
@NonNull String qrCodeUrl,
@NonNull GeneratedAndroidFirebaseAuth.VoidResult result) {
final TotpSecret secret = FlutterFirebaseTotpMultiFactor.multiFactorSecret.get(secretKey);
assert secret != null;
secret.openInOtpApp(qrCodeUrl);
result.success();
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright 2022, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuth.IdTokenListener;
import com.google.firebase.auth.FirebaseUser;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class IdTokenChannelStreamHandler implements StreamHandler {
private final FirebaseAuth firebaseAuth;
private IdTokenListener idTokenListener;
public IdTokenChannelStreamHandler(FirebaseAuth firebaseAuth) {
this.firebaseAuth = firebaseAuth;
}
@Override
public void onListen(Object arguments, EventSink events) {
Map<String, Object> event = new HashMap<>();
event.put(Constants.APP_NAME, firebaseAuth.getApp().getName());
final AtomicBoolean initialAuthState = new AtomicBoolean(true);
idTokenListener =
auth -> {
if (initialAuthState.get()) {
initialAuthState.set(false);
return;
}
FirebaseUser user = auth.getCurrentUser();
if (user == null) {
event.put(Constants.USER, null);
} else {
event.put(
Constants.USER, PigeonParser.manuallyToList(PigeonParser.parseFirebaseUser(user)));
}
events.success(event);
};
firebaseAuth.addIdTokenListener(idTokenListener);
}
@Override
public void onCancel(Object arguments) {
if (idTokenListener != null) {
firebaseAuth.removeIdTokenListener(idTokenListener);
idTokenListener = null;
}
}
}

View file

@ -0,0 +1,197 @@
/*
* Copyright 2022, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.firebase.FirebaseException;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthOptions;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider.ForceResendingToken;
import com.google.firebase.auth.PhoneMultiFactorInfo;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class PhoneNumberVerificationStreamHandler implements StreamHandler {
interface OnCredentialsListener {
void onCredentialsReceived(PhoneAuthCredential credential);
}
final AtomicReference<Activity> activityRef = new AtomicReference<>(null);
final FirebaseAuth firebaseAuth;
final String phoneNumber;
final PhoneMultiFactorInfo multiFactorInfo;
final int timeout;
final OnCredentialsListener onCredentialsListener;
final MultiFactorSession multiFactorSession;
String autoRetrievedSmsCodeForTesting;
Integer forceResendingToken;
private static final HashMap<Integer, ForceResendingToken> forceResendingTokens = new HashMap<>();
@Nullable private EventSink eventSink;
public PhoneNumberVerificationStreamHandler(
Activity activity,
@NonNull GeneratedAndroidFirebaseAuth.AuthPigeonFirebaseApp app,
@NonNull GeneratedAndroidFirebaseAuth.InternalVerifyPhoneNumberRequest request,
@Nullable MultiFactorSession multiFactorSession,
@Nullable PhoneMultiFactorInfo multiFactorInfo,
OnCredentialsListener onCredentialsListener) {
this.activityRef.set(activity);
this.multiFactorSession = multiFactorSession;
this.multiFactorInfo = multiFactorInfo;
firebaseAuth = FlutterFirebaseAuthPlugin.getAuthFromPigeon(app);
phoneNumber = request.getPhoneNumber();
timeout = Math.toIntExact(request.getTimeout());
if (request.getAutoRetrievedSmsCodeForTesting() != null) {
autoRetrievedSmsCodeForTesting = request.getAutoRetrievedSmsCodeForTesting();
}
if (request.getForceResendingToken() != null) {
forceResendingToken = Math.toIntExact(request.getForceResendingToken());
}
this.onCredentialsListener = onCredentialsListener;
}
@Override
public void onListen(Object arguments, EventSink events) {
eventSink = events;
PhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks =
new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
@Override
public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
int phoneAuthCredentialHashCode = phoneAuthCredential.hashCode();
onCredentialsListener.onCredentialsReceived(phoneAuthCredential);
Map<String, Object> event = new HashMap<>();
event.put(Constants.TOKEN, phoneAuthCredentialHashCode);
if (phoneAuthCredential.getSmsCode() != null) {
event.put(Constants.SMS_CODE, phoneAuthCredential.getSmsCode());
}
event.put(Constants.NAME, "Auth#phoneVerificationCompleted");
if (eventSink != null) {
eventSink.success(event);
}
}
@Override
public void onVerificationFailed(@NonNull FirebaseException e) {
Map<String, Object> event = new HashMap<>();
Map<String, Object> error = new HashMap<>();
GeneratedAndroidFirebaseAuth.FlutterError flutterError =
FlutterFirebaseAuthPluginException.parserExceptionToFlutter(e);
error.put(
"code",
flutterError
.code
.replaceAll("ERROR_", "")
.toLowerCase(Locale.ROOT)
.replaceAll("_", "-"));
error.put("message", flutterError.getMessage());
error.put("details", flutterError.details);
event.put("error", error);
event.put(Constants.NAME, "Auth#phoneVerificationFailed");
if (eventSink != null) {
eventSink.success(event);
}
}
@Override
public void onCodeSent(
@NonNull String verificationId,
@NonNull PhoneAuthProvider.ForceResendingToken token) {
int forceResendingTokenHashCode = token.hashCode();
forceResendingTokens.put(forceResendingTokenHashCode, token);
Map<String, Object> event = new HashMap<>();
event.put(Constants.VERIFICATION_ID, verificationId);
event.put(Constants.FORCE_RESENDING_TOKEN, forceResendingTokenHashCode);
event.put(Constants.NAME, "Auth#phoneCodeSent");
if (eventSink != null) {
eventSink.success(event);
}
}
@Override
public void onCodeAutoRetrievalTimeOut(@NonNull String verificationId) {
Map<String, Object> event = new HashMap<>();
event.put(Constants.VERIFICATION_ID, verificationId);
event.put(Constants.NAME, "Auth#phoneCodeAutoRetrievalTimeout");
if (eventSink != null) {
eventSink.success(event);
}
}
};
// Allows the auto-retrieval flow to be tested.
// See https://firebase.google.com/docs/auth/android/phone-auth#integration-testing
if (autoRetrievedSmsCodeForTesting != null) {
firebaseAuth
.getFirebaseAuthSettings()
.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, autoRetrievedSmsCodeForTesting);
}
PhoneAuthOptions.Builder phoneAuthOptionsBuilder = new PhoneAuthOptions.Builder(firebaseAuth);
phoneAuthOptionsBuilder.setActivity(activityRef.get());
phoneAuthOptionsBuilder.setCallbacks(callbacks);
if (phoneNumber != null) {
phoneAuthOptionsBuilder.setPhoneNumber(phoneNumber);
}
if (multiFactorSession != null) {
phoneAuthOptionsBuilder.setMultiFactorSession(multiFactorSession);
}
if (multiFactorInfo != null) {
phoneAuthOptionsBuilder.setMultiFactorHint(multiFactorInfo);
}
phoneAuthOptionsBuilder.setTimeout((long) timeout, TimeUnit.MILLISECONDS);
if (forceResendingToken != null) {
PhoneAuthProvider.ForceResendingToken forceResendingToken =
forceResendingTokens.get(this.forceResendingToken);
if (forceResendingToken != null) {
phoneAuthOptionsBuilder.setForceResendingToken(forceResendingToken);
}
}
PhoneAuthProvider.verifyPhoneNumber(phoneAuthOptionsBuilder.build());
}
@Override
public void onCancel(Object arguments) {
eventSink = null;
activityRef.set(null);
}
}

View file

@ -0,0 +1,382 @@
/*
* Copyright 2023, the Chromium project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
package io.flutter.plugins.firebase.auth;
import android.net.Uri;
import androidx.annotation.NonNull;
import com.google.firebase.auth.ActionCodeEmailInfo;
import com.google.firebase.auth.ActionCodeInfo;
import com.google.firebase.auth.ActionCodeResult;
import com.google.firebase.auth.ActionCodeSettings;
import com.google.firebase.auth.AdditionalUserInfo;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.EmailAuthProvider;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuthProvider;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.FirebaseUserMetadata;
import com.google.firebase.auth.GetTokenResult;
import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.auth.MultiFactorInfo;
import com.google.firebase.auth.OAuthCredential;
import com.google.firebase.auth.OAuthProvider;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.PhoneMultiFactorInfo;
import com.google.firebase.auth.PlayGamesAuthProvider;
import com.google.firebase.auth.TwitterAuthProvider;
import com.google.firebase.auth.UserInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class PigeonParser {
static List<Object> manuallyToList(
GeneratedAndroidFirebaseAuth.InternalUserDetails pigeonUserDetails) {
List<Object> output = new ArrayList<>();
output.add(pigeonUserDetails.getUserInfo().toList());
output.add(pigeonUserDetails.getProviderData());
return output;
}
static GeneratedAndroidFirebaseAuth.InternalUserCredential parseAuthResult(
@NonNull AuthResult authResult) {
GeneratedAndroidFirebaseAuth.InternalUserCredential.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalUserCredential.Builder();
builder.setAdditionalUserInfo(parseAdditionalUserInfo(authResult.getAdditionalUserInfo()));
builder.setCredential(parseAuthCredential(authResult.getCredential()));
builder.setUser(parseFirebaseUser(authResult.getUser()));
return builder.build();
}
private static GeneratedAndroidFirebaseAuth.InternalAdditionalUserInfo parseAdditionalUserInfo(
AdditionalUserInfo additionalUserInfo) {
if (additionalUserInfo == null) {
return null;
}
GeneratedAndroidFirebaseAuth.InternalAdditionalUserInfo.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalAdditionalUserInfo.Builder();
builder.setIsNewUser(additionalUserInfo.isNewUser());
builder.setProfile(additionalUserInfo.getProfile());
builder.setProviderId(additionalUserInfo.getProviderId());
builder.setUsername(additionalUserInfo.getUsername());
return builder.build();
}
static GeneratedAndroidFirebaseAuth.InternalAuthCredential parseAuthCredential(
AuthCredential authCredential) {
if (authCredential == null) {
return null;
}
int authCredentialHashCode = authCredential.hashCode();
FlutterFirebaseAuthPlugin.authCredentials.put(authCredentialHashCode, authCredential);
GeneratedAndroidFirebaseAuth.InternalAuthCredential.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalAuthCredential.Builder();
builder.setProviderId(authCredential.getProvider());
builder.setSignInMethod(authCredential.getSignInMethod());
builder.setNativeId((long) authCredentialHashCode);
if (authCredential instanceof OAuthCredential) {
builder.setAccessToken(((OAuthCredential) authCredential).getAccessToken());
}
return builder.build();
}
static GeneratedAndroidFirebaseAuth.InternalUserDetails parseFirebaseUser(
FirebaseUser firebaseUser) {
if (firebaseUser == null) {
return null;
}
GeneratedAndroidFirebaseAuth.InternalUserDetails.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalUserDetails.Builder();
GeneratedAndroidFirebaseAuth.InternalUserInfo.Builder builderInfo =
new GeneratedAndroidFirebaseAuth.InternalUserInfo.Builder();
builderInfo.setDisplayName(firebaseUser.getDisplayName());
builderInfo.setEmail(firebaseUser.getEmail());
builderInfo.setIsEmailVerified(firebaseUser.isEmailVerified());
builderInfo.setIsAnonymous(firebaseUser.isAnonymous());
final FirebaseUserMetadata userMetadata = firebaseUser.getMetadata();
if (userMetadata != null) {
builderInfo.setCreationTimestamp(firebaseUser.getMetadata().getCreationTimestamp());
builderInfo.setLastSignInTimestamp(firebaseUser.getMetadata().getLastSignInTimestamp());
}
builderInfo.setPhoneNumber(firebaseUser.getPhoneNumber());
builderInfo.setPhotoUrl(parsePhotoUrl(firebaseUser.getPhotoUrl()));
builderInfo.setUid(firebaseUser.getUid());
builderInfo.setTenantId(firebaseUser.getTenantId());
builder.setUserInfo(builderInfo.build());
builder.setProviderData(parseUserInfoList(firebaseUser.getProviderData()));
return builder.build();
}
private static List<Map<Object, Object>> parseUserInfoList(
List<? extends UserInfo> userInfoList) {
List<Map<Object, Object>> output = new ArrayList<>();
if (userInfoList == null) {
return null;
}
for (UserInfo userInfo : new ArrayList<UserInfo>(userInfoList)) {
if (userInfo == null) {
continue;
}
if (!FirebaseAuthProvider.PROVIDER_ID.equals(userInfo.getProviderId())) {
output.add(parseUserInfoToMap(userInfo));
}
}
return output;
}
private static Map<Object, Object> parseUserInfoToMap(UserInfo userInfo) {
Map<Object, Object> output = new HashMap<>();
output.put("displayName", userInfo.getDisplayName());
output.put("email", userInfo.getEmail());
output.put("isEmailVerified", userInfo.isEmailVerified());
output.put("phoneNumber", userInfo.getPhoneNumber());
output.put("photoUrl", parsePhotoUrl(userInfo.getPhotoUrl()));
// Can be null on Emulator
output.put("uid", userInfo.getUid() == null ? "" : userInfo.getUid());
output.put("providerId", userInfo.getProviderId());
output.put("isAnonymous", false);
return output;
}
private static String parsePhotoUrl(Uri photoUri) {
if (photoUri == null) {
return null;
}
String photoUrl = photoUri.toString();
// Return null if the URL is an empty string
return "".equals(photoUrl) ? null : photoUrl;
}
@SuppressWarnings("ConstantConditions")
static AuthCredential getCredential(Map<String, Object> credentialMap) {
// If the credential map contains a token, it means a native one has been stored
if (credentialMap.get(Constants.TOKEN) != null) {
int token = ((Number) credentialMap.get(Constants.TOKEN)).intValue();
AuthCredential credential = FlutterFirebaseAuthPlugin.authCredentials.get(token);
if (credential == null) {
throw FlutterFirebaseAuthPluginException.invalidCredential();
}
return credential;
}
String signInMethod =
(String) Objects.requireNonNull(credentialMap.get(Constants.SIGN_IN_METHOD));
String secret = (String) credentialMap.get(Constants.SECRET);
String idToken = (String) credentialMap.get(Constants.ID_TOKEN);
String accessToken = (String) credentialMap.get(Constants.ACCESS_TOKEN);
String rawNonce = (String) credentialMap.get(Constants.RAW_NONCE);
switch (signInMethod) {
case Constants.SIGN_IN_METHOD_PASSWORD:
return EmailAuthProvider.getCredential(
(String) Objects.requireNonNull(credentialMap.get(Constants.EMAIL)),
Objects.requireNonNull(secret));
case Constants.SIGN_IN_METHOD_EMAIL_LINK:
return EmailAuthProvider.getCredentialWithLink(
(String) Objects.requireNonNull(credentialMap.get(Constants.EMAIL)),
(String) Objects.requireNonNull(credentialMap.get(Constants.EMAIL_LINK)));
case Constants.SIGN_IN_METHOD_FACEBOOK:
return FacebookAuthProvider.getCredential(Objects.requireNonNull(accessToken));
case Constants.SIGN_IN_METHOD_GOOGLE:
return GoogleAuthProvider.getCredential(idToken, accessToken);
case Constants.SIGN_IN_METHOD_TWITTER:
return TwitterAuthProvider.getCredential(
Objects.requireNonNull(accessToken), Objects.requireNonNull(secret));
case Constants.SIGN_IN_METHOD_GITHUB:
return GithubAuthProvider.getCredential(Objects.requireNonNull(accessToken));
case Constants.SIGN_IN_METHOD_PHONE:
{
String verificationId =
(String) Objects.requireNonNull(credentialMap.get(Constants.VERIFICATION_ID));
String smsCode = (String) Objects.requireNonNull(credentialMap.get(Constants.SMS_CODE));
return PhoneAuthProvider.getCredential(verificationId, smsCode);
}
case Constants.SIGN_IN_METHOD_OAUTH:
{
String providerId =
(String) Objects.requireNonNull(credentialMap.get(Constants.PROVIDER_ID));
OAuthProvider.CredentialBuilder builder = OAuthProvider.newCredentialBuilder(providerId);
if (accessToken != null) {
builder.setAccessToken(accessToken);
}
if (rawNonce == null) {
builder.setIdToken(Objects.requireNonNull(idToken));
} else {
builder.setIdTokenWithRawNonce(Objects.requireNonNull(idToken), rawNonce);
}
return builder.build();
}
case Constants.SIGN_IN_METHOD_PLAY_GAMES:
{
String serverAuthCode =
(String) Objects.requireNonNull(credentialMap.get(Constants.SERVER_AUTH_CODE));
return PlayGamesAuthProvider.getCredential(serverAuthCode);
}
default:
return null;
}
}
static ActionCodeSettings getActionCodeSettings(
@NonNull GeneratedAndroidFirebaseAuth.InternalActionCodeSettings pigeonActionCodeSettings) {
ActionCodeSettings.Builder builder = ActionCodeSettings.newBuilder();
builder.setUrl(pigeonActionCodeSettings.getUrl());
if (pigeonActionCodeSettings.getDynamicLinkDomain() != null) {
builder.setDynamicLinkDomain(pigeonActionCodeSettings.getDynamicLinkDomain());
}
if (pigeonActionCodeSettings.getLinkDomain() != null) {
builder.setLinkDomain(pigeonActionCodeSettings.getLinkDomain());
}
builder.setHandleCodeInApp(pigeonActionCodeSettings.getHandleCodeInApp());
if (pigeonActionCodeSettings.getAndroidPackageName() != null) {
builder.setAndroidPackageName(
pigeonActionCodeSettings.getAndroidPackageName(),
pigeonActionCodeSettings.getAndroidInstallApp(),
pigeonActionCodeSettings.getAndroidMinimumVersion());
}
if (pigeonActionCodeSettings.getIOSBundleId() != null) {
builder.setIOSBundleId(pigeonActionCodeSettings.getIOSBundleId());
}
return builder.build();
}
static List<GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo> multiFactorInfoToPigeon(
List<MultiFactorInfo> hints) {
List<GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo> pigeonHints = new ArrayList<>();
for (MultiFactorInfo info : hints) {
if (info instanceof PhoneMultiFactorInfo) {
pigeonHints.add(
new GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo.Builder()
.setPhoneNumber(((PhoneMultiFactorInfo) info).getPhoneNumber())
.setDisplayName(info.getDisplayName())
.setEnrollmentTimestamp((double) info.getEnrollmentTimestamp())
.setUid(info.getUid())
.setFactorId(info.getFactorId())
.build());
} else {
pigeonHints.add(
new GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo.Builder()
.setDisplayName(info.getDisplayName())
.setEnrollmentTimestamp((double) info.getEnrollmentTimestamp())
.setUid(info.getUid())
.setFactorId(info.getFactorId())
.build());
}
}
return pigeonHints;
}
static List<List<Object>> multiFactorInfoToMap(List<MultiFactorInfo> hints) {
List<List<Object>> pigeonHints = new ArrayList<>();
for (GeneratedAndroidFirebaseAuth.InternalMultiFactorInfo info :
multiFactorInfoToPigeon(hints)) {
pigeonHints.add(info.toList());
}
return pigeonHints;
}
static GeneratedAndroidFirebaseAuth.InternalActionCodeInfo parseActionCodeResult(
@NonNull ActionCodeResult actionCodeResult) {
GeneratedAndroidFirebaseAuth.InternalActionCodeInfo.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalActionCodeInfo.Builder();
GeneratedAndroidFirebaseAuth.InternalActionCodeInfoData.Builder builderData =
new GeneratedAndroidFirebaseAuth.InternalActionCodeInfoData.Builder();
int operation = actionCodeResult.getOperation();
switch (operation) {
case ActionCodeResult.PASSWORD_RESET:
builder.setOperation(GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.PASSWORD_RESET);
break;
case ActionCodeResult.VERIFY_EMAIL:
builder.setOperation(GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.VERIFY_EMAIL);
break;
case ActionCodeResult.RECOVER_EMAIL:
builder.setOperation(GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.RECOVER_EMAIL);
break;
case ActionCodeResult.SIGN_IN_WITH_EMAIL_LINK:
builder.setOperation(GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.EMAIL_SIGN_IN);
break;
case ActionCodeResult.VERIFY_BEFORE_CHANGE_EMAIL:
builder.setOperation(
GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.VERIFY_AND_CHANGE_EMAIL);
break;
case ActionCodeResult.REVERT_SECOND_FACTOR_ADDITION:
builder.setOperation(
GeneratedAndroidFirebaseAuth.ActionCodeInfoOperation.REVERT_SECOND_FACTOR_ADDITION);
break;
}
ActionCodeInfo actionCodeInfo = actionCodeResult.getInfo();
if (actionCodeInfo != null && operation == ActionCodeResult.VERIFY_EMAIL
|| operation == ActionCodeResult.PASSWORD_RESET) {
builderData.setEmail(actionCodeInfo.getEmail());
} else if (operation == ActionCodeResult.RECOVER_EMAIL
|| operation == ActionCodeResult.VERIFY_BEFORE_CHANGE_EMAIL) {
ActionCodeEmailInfo actionCodeEmailInfo =
(ActionCodeEmailInfo) Objects.requireNonNull(actionCodeInfo);
builderData.setEmail(actionCodeEmailInfo.getEmail());
builderData.setPreviousEmail(actionCodeEmailInfo.getPreviousEmail());
}
builder.setData(builderData.build());
return builder.build();
}
static GeneratedAndroidFirebaseAuth.InternalIdTokenResult parseTokenResult(
@NonNull GetTokenResult tokenResult) {
final GeneratedAndroidFirebaseAuth.InternalIdTokenResult.Builder builder =
new GeneratedAndroidFirebaseAuth.InternalIdTokenResult.Builder();
builder.setToken(tokenResult.getToken());
builder.setSignInProvider(tokenResult.getSignInProvider());
builder.setAuthTimestamp(tokenResult.getAuthTimestamp() * 1000);
builder.setExpirationTimestamp(tokenResult.getExpirationTimestamp() * 1000);
builder.setIssuedAtTimestamp(tokenResult.getIssuedAtTimestamp() * 1000);
builder.setClaims(tokenResult.getClaims());
builder.setSignInSecondFactor(tokenResult.getSignInSecondFactor());
return builder.build();
}
}

View file

@ -0,0 +1,22 @@
import java.util.regex.Matcher
import java.util.regex.Pattern
String libraryVersionName = "UNKNOWN"
String libraryName = "flutter-fire-auth"
File pubspec = new File(project.projectDir.parentFile, 'pubspec.yaml')
if (pubspec.exists()) {
String yaml = pubspec.text
// Using \s*['|"]?([^\n|'|"]*)['|"]? to extract version number.
Matcher versionMatcher = Pattern.compile("^version:\\s*['|\"]?([^\\n|'|\"]*)['|\"]?\$", Pattern.MULTILINE).matcher(yaml)
if (versionMatcher.find()) libraryVersionName = versionMatcher.group(1).replaceAll("\\+", "-")
}
android {
defaultConfig {
// BuildConfig.VERSION_NAME
buildConfigField 'String', 'LIBRARY_VERSION', "\"${libraryVersionName}\""
// BuildConfig.LIBRARY_NAME
buildConfigField 'String', 'LIBRARY_NAME', "\"${libraryName}\""
}
}

View file

@ -0,0 +1,58 @@
# Firebase Auth Example
[![pub package](https://img.shields.io/pub/v/firebase_auth.svg)](https://pub.dev/packages/firebase_auth)
Demonstrates how to use the `firebase_auth` plugin and enable multiple auth providers.
## Phone Auth
1. Enable phone authentication in the [Firebase console]((https://console.firebase.google.com/u/0/project/_/authentication/providers)).
2. Add test phone number and verification code to the Firebase console.
- For this sample the number `+1 408-555-6969` and verification code `888888` are used.
3. For iOS set the `URL Schemes` to the `REVERSE_CLIENT_ID` from the `GoogleServices-Info.plist` file.
4. Enter the phone number `+1 408-555-6969` and press the `Verify phone number` button.
5. Once the phone number is verified the app displays the test
verification code.
6. Enter the verficication code `888888` and press "Sign in with phone number"
7. Signed in user ID is now displayed in the UI.
## Google Sign-In
1. Enable Google authentication in the [Firebase console](https://console.firebase.google.com/u/0/project/_/authentication/providers).
2. For Android, add your app's package name and SHA-1 fingerprint to the [Settings page](https://console.firebase.google.com/project/_/settings/general) of the Firebase console. Refer to [Authenticating Your Client]('https://developers.google.com/android/guides/client-auth') for details on how to get your app's SHA-1 fingerprint.
3. For iOS set the `URL Schemes` to the `REVERSE_CLIENT_ID` from the `GoogleServices-Info.plist` file (same step for `Phone Auth` above).
4. Select `Google` under `Social Authentication` and click the `Sign In With Google` button.
5. Signed in user's details are displayed in the UI.
### Running on Web
Make sure you run the example app on port 5000, since `localhost:5000` is
whitelisted for Google authentication. To do so, run:
```
flutter run -d web-server --web-port 5000
```
## GitHub Sign-In
To get your `clientId` and `clientSecret`:
1. Visit https://github.com/settings/developers.
2. Create a new OAuth application.
3. Set **Home Page URL** to `https://react-native-firebase-testing.firebaseapp.com`.
4. Set **Authorization callback URL** to `https://react-native-firebase-testing.firebaseapp.com/__/auth/handler`.
5. After you register your app, add the `clientId` and `clientSecret` to the example app config in [`lib/config.dart`](./lib/config.dart).
## Twitter Sign-In
Twitter sign in requires you to add keys from Twitter Developer API to Firebase Console, which means you cannot use the provided configurations with the example app, instead, **please create a new Firebase project**, then enable Twitter as an Auth provider (*optionally you can enable the rest of providers supported in this example*).
To get your `apiKey` and `apiSecretKey` for Twitter:
1. Sign up for a developer account on [Twitter Developer](https://developer.twitter.com).
2. Create a new app and copy your keys.
3. From the dashboard, go to your app settings, then go to OAuth settings and turn on OAuth 1.0a, then add 2 callback URLs:
1. `flutterfireauth://`
2. `https://react-native-firebase-testing.firebaseapp.com/__/auth/handler`
4. Add your keys to the example app config in [`lib/config.dart`](./lib/config.dart).
## Getting Started
For help getting started with Flutter, view the online
[documentation](https://flutter.dev/).

View file

@ -0,0 +1,7 @@
include: ../../../../analysis_options.yaml
linter:
rules:
avoid_print: false
depend_on_referenced_packages: false
library_private_types_in_public_api: false

View file

@ -0,0 +1,62 @@
plugins {
id "com.android.application"
// START: FlutterFire Configuration
id 'com.google.gms.google-services'
// END: FlutterFire Configuration
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader("UTF-8") { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "1"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0"
}
android {
namespace = "io.flutter.plugins.firebase.auth.example"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17
}
defaultConfig {
applicationId = "io.flutter.plugins.firebase.auth.example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
}
}
flutter {
source = "../.."
}

View file

@ -0,0 +1,615 @@
{
"project_info": {
"project_number": "406099696497",
"firebase_url": "https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app",
"project_id": "flutterfire-e2e-tests",
"storage_bucket": "flutterfire-e2e-tests.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:d86a91cc7b338b233574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.analytics.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:a241c4b471513a203574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.appcheck.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-7bvmqp0fffe24vm2arng0dtdeh2tvkgl.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.appcheck.example",
"certificate_hash": "909ca1482ef022bbae45a2db6b6d05d807a4c4aa"
}
},
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:21d5142deea38dda3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.auth.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-emmujnd7g2ammh5uu9ni6v04p4ateqac.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.auth.example",
"certificate_hash": "5ad0d6d5cbe577ca185b8df246656bebc3957128"
}
},
{
"client_id": "406099696497-in8bfp0nali85oul1o98huoar6eo1vv1.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.auth.example",
"certificate_hash": "909ca1482ef022bbae45a2db6b6d05d807a4c4aa"
}
},
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:3ef965ff044efc0b3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.dataconnect.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:40da41183cb3d3ff3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.dynamiclinksexample"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:175ea7a64b2faf5e3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.firestore.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:7ca3394493cc601a3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.functions.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.functions.example",
"certificate_hash": "a4256c0612686b336af6d138a5479b7dc1ee1af6"
}
},
{
"client_id": "406099696497-tvtvuiqogct1gs1s6lh114jeps7hpjm5.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.functions.example",
"certificate_hash": "909ca1482ef022bbae45a2db6b6d05d807a4c4aa"
}
},
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:6d1c1fbf4688f39c3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.installations.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:74ebb073d7727cd43574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.messaging.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:f54b85cfa36a39f73574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.remoteconfig.example"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:0d4ed619c031c0ac3574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase.tests"
}
},
"oauth_client": [
{
"client_id": "406099696497-ib9hj9281l3343cm3nfvvdotaojrthdc.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.tests",
"certificate_hash": "5ad0d6d5cbe577ca185b8df246656bebc3957128"
}
},
{
"client_id": "406099696497-lc54d5l8sp90k39r0bb39ovsgo1s9bek.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase.tests",
"certificate_hash": "909ca1482ef022bbae45a2db6b6d05d807a4c4aa"
}
},
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:899c6485cfce26c13574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebase_ui_example"
}
},
"oauth_client": [
{
"client_id": "406099696497-ltgvphphcckosvqhituel5km2k3aecg8.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.flutter.plugins.firebase_ui_example",
"certificate_hash": "a4256c0612686b336af6d138a5479b7dc1ee1af6"
}
},
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:bc0b12b0605df8633574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebasecoreexample"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:0f3f7bfe78b8b7103574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebasecrashlyticsexample"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:406099696497:android:2751af6868a69f073574d0",
"android_client_info": {
"package_name": "io.flutter.plugins.firebasestorageexample"
}
},
"oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "406099696497-0mofiof3ofcgmpmirb6q0fllvb372sme.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.flutter.plugins.firebase.example"
}
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View file

@ -0,0 +1,45 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="example"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View file

@ -0,0 +1,5 @@
package io.flutter.plugins.firebase.auth.example
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View file

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View file

@ -0,0 +1,18 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View file

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,28 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.3.0" apply false
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.3.15" apply false
// END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "1.9.22" apply false
}
include ":app"

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

View file

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -0,0 +1,3 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View file

@ -0,0 +1,48 @@
# Uncomment this line to define a global platform for your project
platform :ios, '15.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
end
end
end
end

View file

@ -0,0 +1,700 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
081BFEF7D2871CF6AC71DD05 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7B49E087B951778510D20936 /* GoogleService-Info.plist */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
25A01FAE278D905100D1E790 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 25A01FAD278D905100D1E790 /* GoogleService-Info.plist */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3DBDE9876E1D48FC8ED096A3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E010D242A20C21968D02B7C9 /* Pods_Runner.framework */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
253804AE278DB662003BA2E2 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
25A01FAD278D905100D1E790 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
2FB2202774601424C6393E3D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
7B49E087B951778510D20936 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E010D242A20C21968D02B7C9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ED172FD60C3CC14CD005C328 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
FD585EE39F3F8D58CFCE5419 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
3DBDE9876E1D48FC8ED096A3 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
9C7F99B73919EAB4FA657D9E /* Pods */,
7B49E087B951778510D20936 /* GoogleService-Info.plist */,
DE500BC6E74EB524103D00CE /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
253804AE278DB662003BA2E2 /* Runner.entitlements */,
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
25A01FAD278D905100D1E790 /* GoogleService-Info.plist */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
9C7F99B73919EAB4FA657D9E /* Pods */ = {
isa = PBXGroup;
children = (
2FB2202774601424C6393E3D /* Pods-Runner.debug.xcconfig */,
ED172FD60C3CC14CD005C328 /* Pods-Runner.release.xcconfig */,
FD585EE39F3F8D58CFCE5419 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
DE500BC6E74EB524103D00CE /* Frameworks */ = {
isa = PBXGroup;
children = (
E010D242A20C21968D02B7C9 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
AC2BD8C60F3AA720CEA78FA3 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
3E42446041C78F434168F902 /* [CP] Embed Pods Frameworks */,
7A855ADEADAAB6F658B535DB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
25A01FAE278D905100D1E790 /* GoogleService-Info.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
081BFEF7D2871CF6AC71DD05 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
3E42446041C78F434168F902 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/AppAuth/AppAuth.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAppCheckInterop/FirebaseAppCheckInterop.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAuth/FirebaseAuth.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseAuthInterop/FirebaseAuthInterop.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
"${BUILT_PRODUCTS_DIR}/GTMAppAuth/GTMAppAuth.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
"${BUILT_PRODUCTS_DIR}/GoogleSignIn/GoogleSignIn.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
"${BUILT_PRODUCTS_DIR}/RecaptchaInterop/RecaptchaInterop.framework",
"${BUILT_PRODUCTS_DIR}/flutter_facebook_auth/flutter_facebook_auth.framework",
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBAEMKit/FBAEMKit.framework/FBAEMKit",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework/FBSDKCoreKit",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit_Basics/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKLoginKit/FBSDKLoginKit.framework/FBSDKLoginKit",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAppCheckInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseAuthInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMAppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleSignIn.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RecaptchaInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_facebook_auth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBAEMKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit_Basics.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKLoginKit.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
7A855ADEADAAB6F658B535DB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/google_sign_in_ios/google_sign_in_ios_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_sign_in_ios_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AC2BD8C60F3AA720CEA78FA3 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "\\\"${PODS_ROOT}/Headers\\\"";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = YYX2P3XVJ7;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "\\\"${PODS_ROOT}/Headers\\\"";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "\\\"${PODS_ROOT}/Headers\\\"";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = YYX2P3XVJ7;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = YYX2P3XVJ7;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View file

@ -0,0 +1,6 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end

View file

@ -0,0 +1,13 @@
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

View file

@ -0,0 +1,13 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View file

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
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.

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>406099696497-134k3722m01rtrsklhf3b7k8sqa5r7in.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.406099696497-134k3722m01rtrsklhf3b7k8sqa5r7in</string>
<key>ANDROID_CLIENT_ID</key>
<string>406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com</string>
<key>API_KEY</key>
<string>AIzaSyDooSUGSf63Ghq02_iIhtnmwMDs4HlWS6c</string>
<key>GCM_SENDER_ID</key>
<string>406099696497</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>io.flutter.plugins.firebase.auth.example</string>
<key>PROJECT_ID</key>
<string>flutterfire-e2e-tests</string>
<key>STORAGE_BUCKET</key>
<string>flutterfire-e2e-tests.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:406099696497:ios:58cbc26aca8e5cf83574d0</string>
<key>DATABASE_URL</key>
<string>https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app</string>
</dict>
</plist>

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Firebase Auth Example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>firebase_auth_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>FacebookAppID</key>
<string>128693022464535</string>
<!-- The Facebook client token should not be made public but this is a developer mode app with whitelisted user access -->
<key>FacebookClientToken</key>
<string>16dbbdf0cfb309034a6ad98ac2a21688</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.406099696497-134k3722m01rtrsklhf3b7k8sqa5r7in</string>
<string>fb128693022464535</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>

View file

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.developer.game-center</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,9 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View file

@ -0,0 +1,7 @@
{
"file_generated_by": "FlutterFire CLI",
"purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
"GOOGLE_APP_ID": "1:406099696497:ios:58cbc26aca8e5cf83574d0",
"FIREBASE_PROJECT_ID": "flutterfire-e2e-tests",
"GCM_SENDER_ID": "406099696497"
}

View file

@ -0,0 +1,748 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'package:barcode_widget/barcode_widget.dart';
import 'package:collection/collection.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_example/main.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
import 'package:google_sign_in/google_sign_in.dart';
typedef OAuthSignIn = void Function();
// If set to true, the app will request notification permissions to use
// silent verification for SMS MFA instead of Recaptcha.
const withSilentVerificationSMSMFA = true;
/// Helper class to show a snackbar using the passed context.
class ScaffoldSnackbar {
// ignore: public_member_api_docs
ScaffoldSnackbar(this._context);
/// The scaffold of current context.
factory ScaffoldSnackbar.of(BuildContext context) {
return ScaffoldSnackbar(context);
}
final BuildContext _context;
/// Helper method to show a SnackBar.
void show(String message) {
ScaffoldMessenger.of(_context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(
content: Text(message),
behavior: SnackBarBehavior.floating,
),
);
}
}
/// The mode of the current auth session, either [AuthMode.login] or [AuthMode.register].
// ignore: public_member_api_docs
enum AuthMode { login, register, phone }
extension on AuthMode {
String get label => this == AuthMode.login
? 'Sign in'
: this == AuthMode.phone
? 'Sign in'
: 'Register';
}
/// Entrypoint example for various sign-in flows with Firebase.
class AuthGate extends StatefulWidget {
// ignore: public_member_api_docs
const AuthGate({Key? key}) : super(key: key);
static String? appleAuthorizationCode;
@override
State<StatefulWidget> createState() => _AuthGateState();
}
class _AuthGateState extends State<AuthGate> {
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
TextEditingController phoneController = TextEditingController();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
String error = '';
String verificationId = '';
AuthMode mode = AuthMode.login;
bool isLoading = false;
void setIsLoading() {
setState(() {
isLoading = !isLoading;
});
}
late Map<Buttons, OAuthSignIn> authButtons;
@override
void initState() {
super.initState();
if (withSilentVerificationSMSMFA && !kIsWeb) {
FirebaseMessaging messaging = FirebaseMessaging.instance;
messaging.requestPermission();
}
if (!kIsWeb && Platform.isMacOS) {
authButtons = {
Buttons.Apple: () => _handleMultiFactorException(
_signInWithApple,
),
};
} else {
authButtons = {
Buttons.Apple: () => _handleMultiFactorException(
_signInWithApple,
),
Buttons.Google: () => _handleMultiFactorException(
_signInWithGoogle,
),
Buttons.GitHub: () => _handleMultiFactorException(
_signInWithGitHub,
),
Buttons.Microsoft: () => _handleMultiFactorException(
_signInWithMicrosoft,
),
Buttons.Twitter: () => _handleMultiFactorException(
_signInWithTwitter,
),
Buttons.Yahoo: () => _handleMultiFactorException(
_signInWithYahoo,
),
Buttons.Facebook: () => _handleMultiFactorException(
_signInWithFacebook,
),
};
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: Scaffold(
body: Center(
child: SingleChildScrollView(
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: SafeArea(
child: Form(
key: formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 400),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Visibility(
visible: error.isNotEmpty,
child: MaterialBanner(
backgroundColor:
Theme.of(context).colorScheme.error,
content: SelectableText(error),
actions: [
TextButton(
onPressed: () {
setState(() {
error = '';
});
},
child: const Text(
'dismiss',
style: TextStyle(color: Colors.white),
),
),
],
contentTextStyle:
const TextStyle(color: Colors.white),
padding: const EdgeInsets.all(10),
),
),
const SizedBox(height: 20),
if (mode != AuthMode.phone)
Column(
children: [
TextFormField(
controller: emailController,
decoration: const InputDecoration(
hintText: 'Email',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
autofillHints: const [AutofillHints.email],
validator: (value) =>
value != null && value.isNotEmpty
? null
: 'Required',
),
const SizedBox(height: 20),
TextFormField(
controller: passwordController,
obscureText: true,
decoration: const InputDecoration(
hintText: 'Password',
border: OutlineInputBorder(),
),
validator: (value) =>
value != null && value.isNotEmpty
? null
: 'Required',
),
],
),
if (mode == AuthMode.phone)
TextFormField(
controller: phoneController,
decoration: const InputDecoration(
hintText: '+12345678910',
labelText: 'Phone number',
border: OutlineInputBorder(),
),
validator: (value) =>
value != null && value.isNotEmpty
? null
: 'Required',
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: isLoading
? null
: () => _handleMultiFactorException(
_emailAndPassword,
),
child: isLoading
? const CircularProgressIndicator.adaptive()
: Text(mode.label),
),
),
TextButton(
onPressed: _resetPassword,
child: const Text('Forgot password?'),
),
...authButtons.keys
.map(
(button) => Padding(
padding:
const EdgeInsets.symmetric(vertical: 5),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: isLoading
? Container(
color: Colors.grey[200],
height: 50,
width: double.infinity,
)
: SizedBox(
width: double.infinity,
height: 50,
child: SignInButton(
button,
onPressed: authButtons[button],
),
),
),
),
)
.toList(),
SizedBox(
width: double.infinity,
height: 50,
child: OutlinedButton(
onPressed: isLoading
? null
: () {
if (mode != AuthMode.phone) {
setState(() {
mode = AuthMode.phone;
});
} else {
setState(() {
mode = AuthMode.login;
});
}
},
child: isLoading
? const CircularProgressIndicator.adaptive()
: Text(
mode != AuthMode.phone
? 'Sign in with Phone Number'
: 'Sign in with Email and Password',
),
),
),
const SizedBox(height: 20),
if (mode != AuthMode.phone)
RichText(
text: TextSpan(
style: Theme.of(context).textTheme.bodyLarge,
children: [
TextSpan(
text: mode == AuthMode.login
? "Don't have an account? "
: 'You have an account? ',
),
TextSpan(
text: mode == AuthMode.login
? 'Register now'
: 'Click to login',
style: const TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
mode = mode == AuthMode.login
? AuthMode.register
: AuthMode.login;
});
},
),
],
),
),
const SizedBox(height: 10),
RichText(
text: TextSpan(
style: Theme.of(context).textTheme.bodyLarge,
children: [
const TextSpan(text: 'Or '),
TextSpan(
text: 'continue as guest',
style: const TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = _anonymousAuth,
),
],
),
),
],
),
),
),
),
),
),
),
),
),
);
}
Future _resetPassword() async {
String? email;
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Send'),
),
],
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text('Enter your email'),
const SizedBox(height: 20),
TextFormField(
onChanged: (value) {
email = value;
},
),
],
),
);
},
);
if (email != null) {
try {
await auth.sendPasswordResetEmail(email: email!);
ScaffoldSnackbar.of(context).show('Password reset email is sent');
} catch (e) {
ScaffoldSnackbar.of(context).show('Error resetting');
}
}
}
Future<void> _anonymousAuth() async {
setIsLoading();
try {
await auth.signInAnonymously();
} on FirebaseAuthException catch (e) {
setState(() {
error = '${e.message}';
});
} catch (e) {
setState(() {
error = '$e';
});
} finally {
setIsLoading();
}
}
Future<void> _handleMultiFactorException(
Future<void> Function() authFunction,
) async {
setIsLoading();
try {
await authFunction();
} on FirebaseAuthMultiFactorException catch (e) {
setState(() {
error = '${e.message}';
});
final firstTotpHint = e.resolver.hints
.firstWhereOrNull((element) => element is TotpMultiFactorInfo);
if (firstTotpHint != null) {
final code = await getSmsCodeFromUser(context);
final assertion = await TotpMultiFactorGenerator.getAssertionForSignIn(
firstTotpHint.uid,
code!,
);
await e.resolver.resolveSignIn(assertion);
return;
}
final firstPhoneHint = e.resolver.hints
.firstWhereOrNull((element) => element is PhoneMultiFactorInfo);
if (firstPhoneHint is! PhoneMultiFactorInfo) {
return;
}
await auth.verifyPhoneNumber(
multiFactorSession: e.resolver.session,
multiFactorInfo: firstPhoneHint,
verificationCompleted: (_) {},
verificationFailed: print,
codeSent: (String verificationId, int? resendToken) async {
final smsCode = await getSmsCodeFromUser(context);
if (smsCode != null) {
// Create a PhoneAuthCredential with the code
final credential = PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: smsCode,
);
try {
await e.resolver.resolveSignIn(
PhoneMultiFactorGenerator.getAssertion(
credential,
),
);
} on FirebaseAuthException catch (e) {
print(e.message);
}
}
},
codeAutoRetrievalTimeout: print,
);
} on FirebaseAuthException catch (e) {
setState(() {
error = '${e.message}';
});
} catch (e) {
setState(() {
error = '$e';
});
}
setIsLoading();
}
Future<void> _emailAndPassword() async {
if (formKey.currentState?.validate() ?? false) {
if (mode == AuthMode.login) {
await auth.signInWithEmailAndPassword(
email: emailController.text,
password: passwordController.text,
);
} else if (mode == AuthMode.register) {
await auth.createUserWithEmailAndPassword(
email: emailController.text,
password: passwordController.text,
);
} else {
await _phoneAuth();
}
}
}
Future<void> _phoneAuth() async {
if (mode != AuthMode.phone) {
setState(() {
mode = AuthMode.phone;
});
} else {
if (kIsWeb) {
final confirmationResult =
await auth.signInWithPhoneNumber(phoneController.text);
final smsCode = await getSmsCodeFromUser(context);
if (smsCode != null) {
await confirmationResult.confirm(smsCode);
}
} else {
await auth.verifyPhoneNumber(
phoneNumber: phoneController.text,
verificationCompleted: (_) {},
verificationFailed: (e) {
setState(() {
error = '${e.message}';
});
},
codeSent: (String verificationId, int? resendToken) async {
final smsCode = await getSmsCodeFromUser(context);
if (smsCode != null) {
// Create a PhoneAuthCredential with the code
final credential = PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: smsCode,
);
try {
// Sign the user in (or link) with the credential
await auth.signInWithCredential(credential);
} on FirebaseAuthException catch (e) {
setState(() {
error = e.message ?? '';
});
}
}
},
codeAutoRetrievalTimeout: (e) {
setState(() {
error = e;
});
},
);
}
}
}
Future<void> _signInWithGoogle() async {
// Trigger the authentication flow
final googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final googleAuth = await googleUser?.authentication;
if (googleAuth != null) {
// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Once signed in, return the UserCredential
await auth.signInWithCredential(credential);
}
}
Future<void> _signInWithFacebook() async {
// Trigger the authentication flow
// by default we request the email and the public profile
final LoginResult result = await FacebookAuth.instance.login();
if (result.status == LoginStatus.success) {
// Get access token
final AccessToken accessToken = result.accessToken!;
// Login with token
await auth.signInWithCredential(
FacebookAuthProvider.credential(accessToken.tokenString),
);
} else {
print('Facebook login did not succeed');
print(result.status);
print(result.message);
}
}
}
Future<void> _signInWithTwitter() async {
TwitterAuthProvider twitterProvider = TwitterAuthProvider();
if (kIsWeb) {
await auth.signInWithPopup(twitterProvider);
} else {
await auth.signInWithProvider(twitterProvider);
}
}
Future<void> _signInWithApple() async {
final appleProvider = AppleAuthProvider();
appleProvider.addScope('email');
if (kIsWeb) {
// Once signed in, return the UserCredential
await auth.signInWithPopup(appleProvider);
} else {
final userCred = await auth.signInWithProvider(appleProvider);
AuthGate.appleAuthorizationCode =
userCred.additionalUserInfo?.authorizationCode;
}
}
Future<void> _signInWithYahoo() async {
final yahooProvider = YahooAuthProvider();
if (kIsWeb) {
// Once signed in, return the UserCredential
await auth.signInWithPopup(yahooProvider);
} else {
await auth.signInWithProvider(yahooProvider);
}
}
Future<void> _signInWithGitHub() async {
final githubProvider = GithubAuthProvider();
if (kIsWeb) {
await auth.signInWithPopup(githubProvider);
} else {
await auth.signInWithProvider(githubProvider);
}
}
Future<void> _signInWithMicrosoft() async {
final microsoftProvider = MicrosoftAuthProvider();
if (kIsWeb) {
await auth.signInWithPopup(microsoftProvider);
} else {
await auth.signInWithProvider(microsoftProvider);
}
}
Future<String?> getSmsCodeFromUser(BuildContext context) async {
String? smsCode;
// Update the UI - wait for the user to enter the SMS code
await showDialog<String>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('SMS code:'),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Sign in'),
),
OutlinedButton(
onPressed: () {
smsCode = null;
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
],
content: Container(
padding: const EdgeInsets.all(20),
child: TextField(
onChanged: (value) {
smsCode = value;
},
textAlign: TextAlign.center,
autofocus: true,
),
),
);
},
);
return smsCode;
}
Future<String?> getTotpFromUser(
BuildContext context,
TotpSecret totpSecret,
) async {
String? smsCode;
final qrCodeUrl = await totpSecret.generateQrCodeUrl(
accountName: FirebaseAuth.instance.currentUser!.email,
issuer: 'Firebase',
);
// Update the UI - wait for the user to enter the SMS code
await showDialog<String>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('TOTP code:'),
content: Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
BarcodeWidget(
barcode: Barcode.qrCode(),
data: qrCodeUrl,
width: 150,
height: 150,
),
TextField(
onChanged: (value) {
smsCode = value;
},
textAlign: TextAlign.center,
autofocus: true,
),
ElevatedButton(
onPressed: () {
totpSecret.openInOtpApp(qrCodeUrl);
},
child: const Text('Open in OTP App'),
),
],
),
),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Sign in'),
),
OutlinedButton(
onPressed: () {
smsCode = null;
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
],
);
},
);
return smsCode;
}

View file

@ -0,0 +1,98 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
return macos;
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyB7wZb2tO1-Fs6GbDADUSTs2Qs3w08Hovw',
appId: '1:406099696497:web:87e25e51afe982cd3574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
authDomain: 'flutterfire-e2e-tests.firebaseapp.com',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
measurementId: 'G-JN95N1JV2E',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw',
appId: '1:406099696497:android:21d5142deea38dda3574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDooSUGSf63Ghq02_iIhtnmwMDs4HlWS6c',
appId: '1:406099696497:ios:58cbc26aca8e5cf83574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
androidClientId:
'406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com',
iosClientId:
'406099696497-134k3722m01rtrsklhf3b7k8sqa5r7in.apps.googleusercontent.com',
iosBundleId: 'io.flutter.plugins.firebase.auth.example',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyDooSUGSf63Ghq02_iIhtnmwMDs4HlWS6c',
appId: '1:406099696497:ios:58cbc26aca8e5cf83574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
androidClientId:
'406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com',
iosClientId:
'406099696497-134k3722m01rtrsklhf3b7k8sqa5r7in.apps.googleusercontent.com',
iosBundleId: 'io.flutter.plugins.firebase.auth.example',
);
}

View file

@ -0,0 +1,108 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in_dartio/google_sign_in_dartio.dart';
import 'auth.dart';
import 'firebase_options.dart';
import 'profile.dart';
/// Requires that a Firebase local emulator is running locally.
/// See https://firebase.google.com/docs/auth/flutter/start#optional_prototype_and_test_with_firebase_local_emulator_suite
bool shouldUseFirebaseEmulator = false;
late final FirebaseApp app;
late final FirebaseAuth auth;
// Requires that the Firebase Auth emulator is running locally
// e.g via `melos run firebase:emulator`.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// We're using the manual installation on non-web platforms since Google sign in plugin doesn't yet support Dart initialization.
// See related issue: https://github.com/flutter/flutter/issues/96391
// We store the app and auth to make testing with a named instance easier.
app = await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
auth = FirebaseAuth.instanceFor(app: app);
if (shouldUseFirebaseEmulator) {
await auth.useAuthEmulator('localhost', 9099);
}
if (!kIsWeb && Platform.isWindows) {
await GoogleSignInDart.register(
clientId:
'406099696497-g5o9l0blii9970bgmfcfv14pioj90djd.apps.googleusercontent.com',
);
}
runApp(const AuthExampleApp());
}
/// The entry point of the application.
///
/// Returns a [MaterialApp].
class AuthExampleApp extends StatelessWidget {
const AuthExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase Example App',
theme: ThemeData(primarySwatch: Colors.amber),
home: Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return Row(
children: [
Visibility(
visible: constraints.maxWidth >= 1200,
child: Expanded(
child: Container(
height: double.infinity,
color: Theme.of(context).colorScheme.primary,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Firebase Auth Desktop',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
),
),
),
SizedBox(
width: constraints.maxWidth >= 1200
? constraints.maxWidth / 2
: constraints.maxWidth,
child: StreamBuilder<User?>(
stream: auth.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return const ProfilePage();
}
return const AuthGate();
},
),
),
],
);
},
),
),
);
}
}

View file

@ -0,0 +1,391 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:developer';
import 'package:collection/collection.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_example/main.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'auth.dart';
/// Displayed as a profile image if the user doesn't have one.
const placeholderImage =
'https://upload.wikimedia.org/wikipedia/commons/c/cd/Portrait_Placeholder_Square.png';
/// Profile page shows after sign in or registration.
class ProfilePage extends StatefulWidget {
// ignore: public_member_api_docs
const ProfilePage({Key? key}) : super(key: key);
@override
// ignore: library_private_types_in_public_api
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
late User user;
late TextEditingController controller;
final phoneController = TextEditingController();
String? photoURL;
bool showSaveButton = false;
bool isLoading = false;
@override
void initState() {
user = auth.currentUser!;
controller = TextEditingController(text: user.displayName);
controller.addListener(_onNameChanged);
auth.userChanges().listen((event) {
if (event != null && mounted) {
setState(() {
user = event;
});
}
});
log(user.toString());
super.initState();
}
@override
void dispose() {
controller.removeListener(_onNameChanged);
super.dispose();
}
void setIsLoading() {
setState(() {
isLoading = !isLoading;
});
}
void _onNameChanged() {
setState(() {
if (controller.text == user.displayName || controller.text.isEmpty) {
showSaveButton = false;
} else {
showSaveButton = true;
}
});
}
/// Map User provider data into a list of Provider Ids.
List get userProviders => user.providerData.map((e) => e.providerId).toList();
Future updateDisplayName() async {
await user.updateDisplayName(controller.text);
setState(() {
showSaveButton = false;
});
// ignore: use_build_context_synchronously
ScaffoldSnackbar.of(context).show('Name updated');
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: Scaffold(
body: Stack(
children: [
Center(
child: SizedBox(
width: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Stack(
children: [
CircleAvatar(
maxRadius: 60,
backgroundImage: NetworkImage(
user.photoURL ?? placeholderImage,
),
),
Positioned.directional(
textDirection: Directionality.of(context),
end: 0,
bottom: 0,
child: Material(
clipBehavior: Clip.antiAlias,
color: Theme.of(context).colorScheme.secondary,
borderRadius: BorderRadius.circular(40),
child: InkWell(
onTap: () async {
final photoURL = await getPhotoURLFromUser();
if (photoURL != null) {
await user.updatePhotoURL(photoURL);
}
},
radius: 50,
child: const SizedBox(
width: 35,
height: 35,
child: Icon(Icons.edit),
),
),
),
),
],
),
const SizedBox(height: 10),
TextField(
textAlign: TextAlign.center,
controller: controller,
decoration: const InputDecoration(
border: InputBorder.none,
floatingLabelBehavior: FloatingLabelBehavior.never,
alignLabelWithHint: true,
label: Center(
child: Text(
'Click to add a display name',
),
),
),
),
Text(user.email ?? user.phoneNumber ?? 'User'),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (userProviders.contains('phone'))
const Icon(Icons.phone),
if (userProviders.contains('password'))
const Icon(Icons.mail),
if (userProviders.contains('google.com'))
SizedBox(
width: 24,
child: Image.network(
'https://upload.wikimedia.org/wikipedia/commons/0/09/IOS_Google_icon.png',
),
),
],
),
const SizedBox(height: 20),
TextButton(
onPressed: () {
user.sendEmailVerification();
},
child: const Text('Verify Email'),
),
TextButton(
onPressed: () async {
final a = await user.multiFactor.getEnrolledFactors();
print(a);
},
child: const Text('Get enrolled factors'),
),
TextButton(
onPressed: () async {
if (AuthGate.appleAuthorizationCode != null) {
// The `authorizationCode` is on the user credential.
// e.g. final authorizationCode = userCredential.additionalUserInfo?.authorizationCode;
await FirebaseAuth.instance
.revokeTokenWithAuthorizationCode(
AuthGate.appleAuthorizationCode!,
);
// You may wish to delete the user at this point
AuthGate.appleAuthorizationCode = null;
} else {
print(
'Apple `authorizationCode` is null, cannot revoke token.',
);
}
},
child: const Text('Revoke Apple auth token'),
),
TextFormField(
controller: phoneController,
decoration: const InputDecoration(
icon: Icon(Icons.phone),
hintText: '+33612345678',
labelText: 'Phone number',
),
),
const SizedBox(height: 20),
TextButton(
onPressed: () async {
final session = await user.multiFactor.getSession();
await auth.verifyPhoneNumber(
multiFactorSession: session,
phoneNumber: phoneController.text,
verificationCompleted: (_) {},
verificationFailed: print,
codeSent: (
String verificationId,
int? resendToken,
) async {
final smsCode = await getSmsCodeFromUser(context);
if (smsCode != null) {
// Create a PhoneAuthCredential with the code
final credential = PhoneAuthProvider.credential(
verificationId: verificationId,
smsCode: smsCode,
);
try {
await user.multiFactor.enroll(
PhoneMultiFactorGenerator.getAssertion(
credential,
),
);
} on FirebaseAuthException catch (e) {
print(e.message);
}
}
},
codeAutoRetrievalTimeout: print,
);
},
child: const Text('Verify Number For MFA'),
),
TextButton(
onPressed: () async {
final totp =
(await user.multiFactor.getEnrolledFactors())
.firstWhereOrNull(
(element) => element.factorId == 'totp',
);
if (totp != null) {
await user.multiFactor.unenroll(
factorUid:
(await user.multiFactor.getEnrolledFactors())
.firstWhere(
(element) => element.factorId == 'totp',
)
.uid,
);
}
final session = await user.multiFactor.getSession();
final totpSecret =
await TotpMultiFactorGenerator.generateSecret(
session,
);
print(totpSecret);
final code =
await getTotpFromUser(context, totpSecret);
print('code: $code');
if (code == null) {
return;
}
await user.multiFactor.enroll(
await TotpMultiFactorGenerator
.getAssertionForEnrollment(
totpSecret,
code,
),
displayName: 'TOTP',
);
},
child: const Text('Enroll TOTP'),
),
TextButton(
onPressed: () async {
try {
final enrolledFactors =
await user.multiFactor.getEnrolledFactors();
await user.multiFactor.unenroll(
factorUid: enrolledFactors.first.uid,
);
// Show snackbar
ScaffoldSnackbar.of(context).show('MFA unenrolled');
} catch (e) {
print(e);
}
},
child: const Text('Unenroll MFA'),
),
const Divider(),
TextButton(
onPressed: _signOut,
child: const Text('Sign out'),
),
],
),
),
),
),
Positioned.directional(
textDirection: Directionality.of(context),
end: 40,
top: 40,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: !showSaveButton
? SizedBox(key: UniqueKey())
: TextButton(
onPressed: isLoading ? null : updateDisplayName,
child: const Text('Save changes'),
),
),
),
],
),
),
);
}
Future<String?> getPhotoURLFromUser() async {
String? photoURL;
// Update the UI - wait for the user to enter the SMS code
await showDialog<String>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('New image Url:'),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Update'),
),
OutlinedButton(
onPressed: () {
photoURL = null;
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
],
content: Container(
padding: const EdgeInsets.all(20),
child: TextField(
onChanged: (value) {
photoURL = value;
},
textAlign: TextAlign.center,
autofocus: true,
),
),
);
},
);
return photoURL;
}
/// Example code for sign out.
Future<void> _signOut() async {
await auth.signOut();
await GoogleSignIn().signOut();
}
}

View file

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -0,0 +1,40 @@
platform :osx, '10.15'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

View file

@ -0,0 +1,718 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
25A01FB0278D938300D1E790 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 25A01FAF278D938300D1E790 /* GoogleService-Info.plist */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
B6036D992F5B77F0D48D7883 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1026236A547BC5196614E954 /* Pods_Runner.framework */; };
C0151CEAF69E3751D6A8FA78 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F30ED8EF0A1349EA81AEE1A /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0B4CF9B1CA3F6E07FE2F953C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
1026236A547BC5196614E954 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1E5E064344044E24673A33BD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
25A01FAF278D938300D1E790 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
2F30ED8EF0A1349EA81AEE1A /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
3D7BD4B06D0869EA1407E048 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
B6036D992F5B77F0D48D7883 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
286E7513A68DD39907D77423 /* Pods */ = {
isa = PBXGroup;
children = (
3D7BD4B06D0869EA1407E048 /* Pods-Runner.debug.xcconfig */,
1E5E064344044E24673A33BD /* Pods-Runner.release.xcconfig */,
0B4CF9B1CA3F6E07FE2F953C /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
286E7513A68DD39907D77423 /* Pods */,
2F30ED8EF0A1349EA81AEE1A /* GoogleService-Info.plist */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* example.app */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
25A01FAF278D938300D1E790 /* GoogleService-Info.plist */,
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
1026236A547BC5196614E954 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9C4FABD4FD7B8936CFFEAF31 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
E033F9E34514FF7F419D8FF5 /* [CP] Embed Pods Frameworks */,
91D69FDB92A2BAB6493D7E50 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
25A01FB0278D938300D1E790 /* GoogleService-Info.plist in Resources */,
C0151CEAF69E3751D6A8FA78 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
};
91D69FDB92A2BAB6493D7E50 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/google_sign_in_ios/google_sign_in_ios_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_sign_in_ios_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9C4FABD4FD7B8936CFFEAF31 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E033F9E34514FF7F419D8FF5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/AppAuth/AppAuth.framework",
"${BUILT_PRODUCTS_DIR}/GTMAppAuth/GTMAppAuth.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleSignIn/GoogleSignIn.framework",
"${BUILT_PRODUCTS_DIR}/facebook_auth_desktop/facebook_auth_desktop.framework",
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage_macos/flutter_secure_storage_macos.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMAppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleSignIn.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/facebook_auth_desktop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage_macos.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = YYX2P3XVJ7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = YYX2P3XVJ7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = YYX2P3XVJ7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.firebase.auth.example;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/stuartmorgan/src/embedder-opensource/flutter-desktop-embedding/example/macos/Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "&quot;$FLUTTER_ROOT&quot;/packages/flutter_tools/bin/macos_assemble.sh prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00380F9121DF178D00097171"
BuildableName = "RunnerUITests.xctest"
BlueprintName = "RunnerUITests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show more