I am creating a SignIn Page, but when I try to login this error appears:
W/System (17313): Ignoring header X-Firebase-Locale because its value was null.
D/FirebaseAuth(17313): Notifying id token listeners about user ( userId ).
This is my main.dart code:
import 'package:app_mypocket/telas/login/telalogin.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
//initilization of Firebase app
// other Firebase service initialization
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Pocket',
debugShowCheckedModeBanner: false,
theme: ThemeData(
),
home: TelaLogin(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) => Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData){
return HomePage();
} else{
return TelaLogin();
}
})
);
}
Additional information:
The phone is connected to internet properly;
I wrote this line on manifest.xml inside application tag:
android:usesCleartextTraffic="true";
The password has 6 characters in length;
Email/Password Sign-in method on firebase console is enabled.
Related
I've written a Flutter App that use the Bloc Pattern and the GetIt package. It's really weird that the app works fine on Android device but on an iOS Simulator, it only shows a black screen...
Here my code:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
AppInitializer.init();
runApp(App());
}
app_initializer.dart
import 'package:authentication_repository/authentication_repository.dart';
import 'package:get_it/get_it.dart';
import 'package:techniciens/blocs/blocs.dart';
import 'package:user_repository/user_repository.dart';
class AppInitializer {
static final getIt = GetIt.instance;
static void init() {
_registerSingletons();
_registerBlocSingletons();
}
static void _registerSingletons() {
getIt.registerSingleton(AuthenticationRepository()..user.first);
getIt.registerLazySingleton<UserRepository>(() => UserRepository());
}
static void _registerBlocSingletons() {
getIt.registerLazySingleton<AuthenticationBloc>(() => AuthenticationBloc(
authenticationRepository:
GetIt.instance.get<AuthenticationRepository>()));
getIt.registerLazySingleton<SettingsFormCubit>(() => SettingsFormCubit());
getIt.registerLazySingleton<UserInfoCubit>(() => UserInfoCubit());
}
}
app.dart
import 'package:authentication_repository/authentication_repository.dart';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:techniciens/blocs/blocs.dart';
import 'package:techniciens/core/constants/constants.dart';
import 'package:techniciens/screens/screens.dart';
import 'package:get_it/get_it.dart';
import 'package:user_repository/user_repository.dart';
import 'core/theme/app_theme.dart';
class App extends StatelessWidget {
final AuthenticationRepository _authenticationRepository =
GetIt.instance.get<AuthenticationRepository>();
final UserRepository _userRepository = GetIt.instance.get<UserRepository>();
final AuthenticationBloc _authenticationBloc =
GetIt.instance.get<AuthenticationBloc>();
App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiRepositoryProvider(
providers: [
RepositoryProvider.value(value: _authenticationRepository),
RepositoryProvider.value(value: _userRepository),
],
child: BlocProvider<AuthenticationBloc>.value(
value: _authenticationBloc,
child: const AppView(),
),
);
}
}
class AppView extends StatefulWidget {
const AppView({Key? key}) : super(key: key);
#override
State<AppView> createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final _navigatorKey = GlobalKey<NavigatorState>();
NavigatorState get _navigator => _navigatorKey.currentState!;
#override
Widget build(BuildContext context) {
return DynamicColorBuilder(
builder: (ColorScheme? lightColorScheme, ColorScheme? darkColorScheme) {
return OverlaySupport.global(
child: MaterialApp(
title: kLoginAppbarTitle,
theme: AppTheme.lightTheme(lightColorScheme),
darkTheme: AppTheme.darkTheme(darkColorScheme),
themeMode: ThemeMode.system,
debugShowCheckedModeBanner: false,
navigatorKey: _navigatorKey,
builder: (context, child) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (_, state) {
switch (state.authStatus) {
case AuthenticationStatus.unauthenticated:
_navigator.pushAndRemoveUntil<void>(
LoginPage.route(), (route) => false);
break;
case AuthenticationStatus.authenticated:
_navigator.pushAndRemoveUntil<void>(
HomePage.route(), (route) => false);
break;
default:
break;
}
},
child: child,
);
},
onGenerateRoute: (_) => SplashPage.route(),
),
);
},
);
}
}
splash_page.dart
import 'package:flutter/material.dart';
class SplashPage extends StatelessWidget {
static Route<void> route() {
return MaterialPageRoute<void>(builder: (_) => const SplashPage());
}
const SplashPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator.adaptive(strokeWidth: 5),
),
);
}
}
As I could see in the Flutter Inspector and with some print commands, the apps runs normally until the BlocListener and falls on the onGenerateRoute.
The black screen
It gives me this
Launching lib/main.dart on iPhone 14 Pro in debug mode...
Running Xcode build...
Xcode build done. 13,8s
GrMtlCommandBuffer: WARNING: Creating MTLCommandBuffer while in background.
GrMtlCommandBuffer: WARNING: Creating MTLCommandBuffer while in background.
Debug service listening on ws://127.0.0.1:52638/_tIC8TChUyE=/ws
Syncing files to device iPhone 14 Pro...
flutter: dynamic_color: Dynamic color not detected on this device.
I've erased all data on the iOS Simulator, it doesn't give anything...
On Android Simulator, the code works super fine, but here, it fails every time on the Splash Screen.
Thank you for your help!
Error: Could not find the correct Provider above this AuthenticationWrapper Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that AuthenticationWrapper is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:park_app/app_styles.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './views/pages.dart';
import 'views/authentication/authentication_service.dart';
import 'Home_Page.dart';
bool? seenOnboard;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// to show status bar
SystemChrome.setEnabledSystemUIOverlays(
[SystemUiOverlay.bottom, SystemUiOverlay.top]);
// to load onboard for the first time only
SharedPreferences pref = await SharedPreferences.getInstance();
seenOnboard = pref.getBool('seenOnboard') ?? false; //if null set to false
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<AuthenticationService>(
create: (_) => AuthenticationService(FirebaseAuth.instance),
),
StreamProvider(
initialData: null,
create: (context) =>
context.read<AuthenticationService>().authStateChanges),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Park App',
theme: ThemeData(
textTheme: GoogleFonts.manropeTextTheme(
Theme.of(context).textTheme,
),
primarySwatch: Colors.blue,
scaffoldBackgroundColor: kScaffoldBackground,
),
home: seenOnboard == true ? AuthenticationWrapper() : OnBoardingPage(),
),
);
}
}
class AuthenticationWrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseUser = context.watch<User>();
if (firebaseUser != null) {
return HomePage();
}
return LoginPage();
}
}
install provider by running the command below:
flutter pub add provider and then in your main.dart file, import it import 'package:provider/provider.dart';
Make sure to specify the generic type on StreamProvider:
StreamProvider<User?>(
...
)
Note that you have set null as initialData, so your widget likely needs to handle null users. Meaning you need to do:
final user = context.watch<User?>()
I am trying to fix this error
Error: Could not find the correct Provider above this AuthWrapper Widget.
Following this tutorial but it doesnt seem to work for me.https://www.youtube.com/watch?v=yyD_VqSrKd8
here is the code:
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:untitled2/firbaseauth.dart';
import 'package:untitled2/homescreen.dart';
import 'package:untitled2/startpage.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<Authservis>(
create: (_) => Authservis(FirebaseAuth.instance),
),
StreamProvider(create: (context) => context.read<Authservis>().authStateChanges,
initialData: null,),
],
child: MaterialApp(
title: "APP",
home: AuthWrapper(),
),
);
}
}
class AuthWrapper extends StatelessWidget{
#override
Widget build(BuildContext context) {
final user = context.watch<User>();
if(user != null){
return Homescreen();
}
return Startpage();
}
}
The error exactly tells you that there is no Provider named User above the widget that calls such provider.
Your MultiProvider at the top of your tree includes just a Auhtservis provider, but in order to use your User provider, the list should include the User provider, too.
Also, youtube tutorials aren't perfect, if you lecturer uses this precise code you might want to notify them.
I can't see any Provider with User type above your AuthWrapper. I think the correct code should be this:
final authService = context.watch<AuthService>();
// check if user is logged in
try giving your StreamProvider a type of User
StreamProvider<User>(create: (context) => context.read<Authservis>().authStateChanges,
initialData: null,),
I'm trying to understand RiverPod by migrating my simple FireStore auth Provider example to RiverPod.
This is my AuthenticationService:
import 'package:firebase_auth/firebase_auth.dart';
class AuthenticationService {
final FirebaseAuth _firebaseAuth;
AuthenticationService(this._firebaseAuth);
// with StreamProvider we listen to these changes
Stream<User> get authStateChanges => _firebaseAuth.authStateChanges();
Future<String> signIn({String email, String password}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return 'Signed in';
} on FirebaseAuthException catch (e) {
return e.message;
}
}
Future<String> signUp({String email, String password}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return 'Signed up ';
} on FirebaseAuthException catch (e) {
return e.message;
}
}
Future<void> signOut() async {
await _firebaseAuth.signOut();
}
}
In main.dart I made 2 providers so I can use the service and listen to the property inside of the AuthenticationService
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:meditatie_app/authentication_service.dart';
import 'package:meditatie_app/home_page.dart';
import 'package:meditatie_app/signin_page.dart';
import 'package:provider/provider.dart';
Future<void> main() async {
// initalize Firebase and before that we need to initialize the widgets.
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// Normal provider to serve the AuthenticationService in the widgettree
// so the login form can use this provider to use .singIn()
Provider<AuthenticationService>(
create: (_) => AuthenticationService(FirebaseAuth.instance),
),
// also a StreamProvider that serves the AuthenticationSerivce authStateChanges
// this stream is updated by the FirebaseAuth package when users signin or out
// this provider use context.read<AuthenticationService> to find the
// provider dived here above
StreamProvider(
create: (context) =>
context.read<AuthenticationService>().authStateChanges,
)
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AuthenticationWrapper(),
),
);
}
}
class AuthenticationWrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseUser = context.watch<User>();
if (firebaseUser != null) {
return HomePage();
}
return SignInPage();
}
}
Here the SingIn page:
import 'package:flutter/material.dart';
import 'package:meditatie_app/authentication_service.dart';
import 'package:provider/provider.dart';
class SignInPage extends StatelessWidget {
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
...
RaisedButton(
onPressed: () {
// Sign in code
context.read<AuthenticationService>().signIn(
email: emailController.text.trim(),
password: passwordController.text.trim(),
);
},
...
This works fine with normal Provider, but I can't get it to work with RiverPod
What I did was:
These providers I made global in providers.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_riverpod/all.dart';
import 'authentication_service.dart';
final authenticationSeriviceProvider =
Provider((ref) => AuthenticationService(FirebaseAuth.instance));
final authStateChangeProvider = StreamProvider.autoDispose<User>((ref) {
return ref
.watch(authenticationSeriviceProvider)
.authStateChanges;
});
Is this correct? The authStateChangeProvider is using the authenticationSeriviceProvider
When is use it like:
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:meditatie_app/home_page.dart';
import 'package:meditatie_app/signin_page.dart';
import 'package:flutter_riverpod/all.dart';
import 'providers.dart';
Future<void> main() async {
// initialize Firebase and before that we need to initialize the widgets.
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
// riverpod needs at toplevel a Provider container
// for storing state of different providers.
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AuthenticationWrapper(),
);
}
}
// Riverpods ConsumerWidget
// which can consume a provider
// rebuild if the value of the provider changes
class AuthenticationWrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final firebaseUser = watch(authStateChangeProvider);
if (firebaseUser != null) {
return HomePage();
}
return SignInPage();
}
}
My 'firebaseUser' is not a User anymore, but an AsyncValue
When I change it to:
class AuthenticationWrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final User firebaseUser = watch(authStateChangeProvider).data?.value;
if (firebaseUser != null) {
return HomePage();
}
return SignInPage();
}
}
It is working, but what am I doing wrong that I now work with AsyncValue
Expanding the previous answer AsyncValue<T> is a sealed class, think of it as StreamBuilder in Flutter having AsyncSnapshot<T> which wraps the value returned from the stream and gives you options to check if its connecting, waiting, withError or withData. In your case
class AuthenticationWrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
return watch(authStateChangeProvider).when(
data: (user) => user == null ? SignInPage() : HomePage(),
loading: () => CircularProgressIndicator(),
error: (err, stack) => SignInPage(),
);
}
}
should handle all the options, now when loading it will show a progress indicator, if there is an error (connection, bad result, etc) it will display the SignInPage, and finally when there is a value you still will need to check if the value returned from the Stream is null (As far as I understand Firebase returns null when there is no user signed in, it doesn't mean the stream is empty) and display the right widget if its null or not.
Just like Provider, after retrieving the user you still have to do the logic with that
See the documentation.
You should use AsyncValue's exposed states to decide what to render. Your code could look something like the following:
class AuthenticationWrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
return watch(authStateChangeProvider).when(
data: (user) => user == null ? SignInPage() : HomePage(),
loading: () => CircularProgressIndicator(),
error: (err, stack) => SignInPage(),
);
}
}
So adjust your return logic to what you'd like for the data, loading, and error states, but this should give you a general idea on how to use AsyncValue.
Another way I found was to use it the way this tutorial did, but with the new riverpod changes:
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_shopping_list/repositories/auth_repository.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
final authControllerProvider = StateNotifierProvider<AuthController, User?>(
(ref) => AuthController(ref.read)..appStarted(),
);
class AuthController extends StateNotifier<User?> {
final Reader _read;
StreamSubscription<User?>? _authStateChangesSubscription;
AuthController(this._read) : super(null) {
_authStateChangesSubscription?.cancel();
_authStateChangesSubscription = _read(authRepositoryProvider)
.authStateChanges
.listen((user) => state = user);
}
#override
void dispose() {
_authStateChangesSubscription?.cancel();
super.dispose();
}
void appStarted() async {
final user = _read(authRepositoryProvider).getCurrentUser();
if (user == null) {
await _read(authRepositoryProvider).signInAnonymously();
}
}
}
And then I used it like this:
#override
Widget build(BuildContext context, WidgetRef ref) {
User? user = ref.watch<User?>(authControllerProvider);
return user != null
? MaterialApp(
title: 'My App',
builder: (context, child) => _Unfocus(child: child!),
home: MainNavigation(),
debugShowCheckedModeBanner: false,
)
: const MaterialApp(
title: 'My App,
home: LoginPage(),
debugShowCheckedModeBanner: false,
);
}
I have tired to stream user authentication state changes using StreamProvider.value to MaterialApp. But i got this Error: A value of type 'MultiProvider' can't be returned from method 'build' because it has a return type of 'Widget'.
This are my the dependency in pubspec.yaml
firebase_core: ^0.5.0 firebase_auth: ^0.18.0+1 cloud_firestore: ^0.14.0+2 provider: ^4.3.2+2
And couldn't be able to figure it out. I'm stuck please help. Thank you for your help in advance.
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
class MyAwesomeApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [StreamProvider<Usr>.value(value: Authenticate().userStream)],
builder: (context, child) {
return MaterialApp(
home: Wrapper(),
);
},
);
}
}
//This is Authenticate class which holds the stream
import 'package:firebase_auth/firebase_auth.dart';
class Authenticate {
//create an instance of firebase auth
FirebaseAuth _auth = FirebaseAuth.instance;
// Create a new user instance from my user model
Usr _userFromFirebaseUser(User user) {
return user != null ? Usr(uid: user.uid) : null;
}
// set up auth stream to listen to user auth status
Stream<Usr> get userStream {
return _auth.authStateChanges().map(
_userFromFirebaseUser); // shorter way of mapping to user custom user object
// .map((User user) => _userFromFirebaseUser(user)); //longer one
}
// sign in anon
Future signInAnon() async {
try {
UserCredential response = await _auth.signInAnonymously();
User user = response.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
}
Try this
import 'package:flutter/material.dart';
import 'package:provider/provider.dart' as statemanagement;
import 'models/model_provider.dart';
import 'modules/screen_root.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return statemanagement.MultiProvider(
providers: [
statemanagement.Provider<ModelProvider>(
create: ((_) => ModelProvider())),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Multi Provider',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ScreenRoot(),
),
);
}
}