So, i've setup up a project on Firebase and followed many tutorials on how to connect firebase to my flutter application. I started by reading FlutterFire docs, step by step, and i managed to install the FlutterFire CLI. After that, i went straight into reading the Realtime Database section and whenever i try to write into the db, nothing happens.
The database is in test mode, firebase is correctly initialised inside the project and i get no errors while trying to write inside it, so i think that even the URL is correct (but i might be wrong)
Here's the code i used:
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'firebase_options.dart'; //generated with FlutterFire CLI
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await Firebase.initializeApp(
options: Platform.isWindows ? null : DefaultFirebaseOptions.currentPlatform, //not working on windows
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final FirebaseDatabase database = FirebaseDatabase.instance;
final DatabaseReference ref = FirebaseDatabase.instance.ref("/");
void writeToFirebase() async {
print('wrote to database');
await ref.set({
'title': 'Hello World',
'body': 'This is my first post',
'userId': '123',
});
await ref.child('title').set('Hello World');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: writeToFirebase,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
I noticed that when the print() statement is above ref.set() , i see the output in the console. But, if i put it beneath the ref.set() statement, i see no output. So, this makes me think that the ref.set() does never end its execution or something like that.
I'm 2 weeks in learning flutter and i really can't make Firebase work
Since you're using await, did you consider using try-catch too so that you can catch and log any errors?
So:
void writeToFirebase() async {
print('Start writing to database');
try {
await ref.set({
'title': 'Hello World',
'body': 'This is my first post',
'userId': '123',
});
await ref.child('title').set('Hello World');
}
catch (error) {
print(error);
}
finally {
print('Done writing to database');
}
}
Related
When I Sign-in with one of my Google accounts the sign-in works perfectly. but after signing out, when I try to sign in with a different account, instead of popping up the google accounts list the app directly sign-ins to the previous account I signed in to.
This is the Code Snippet for Main.dart
main.dart ->>
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:social_media_app/widget/auth_gate.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(375, 667),
minTextAdapt: true,
builder: () {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AuthGate(),
);
},
);
}
}
This is the code snippet of the AuthGate.
auth_gate.dart -->
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutterfire_ui/auth.dart';
class AuthGate extends StatelessWidget {
const AuthGate({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
// showAuthActionSwitch: false,
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
action == AuthAction.signIn
? 'Welcome to FlutterFire UI! Please sign in to continue.'
: 'Welcome to FlutterFire UI! Please create an account to continue',
),
);
},
footerBuilder: (context, _) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, constraints) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://firebase.flutter.dev/img/flutterfire_300x.png'),
),
);
},
headerBuilder: (context, constraints, _) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://firebase.flutter.dev/img/flutterfire_300x.png',
),
),
);
},
providerConfigs: const [
EmailProviderConfiguration(),
PhoneProviderConfiguration(),
GoogleProviderConfiguration(
clientId: '1:778935804680:android:d2da33128b67cdc68c42bd',
),
FacebookProviderConfiguration(
clientId: '...',
),
],
);
}
return const ProfileScreen(
providerConfigs: [
EmailProviderConfiguration(),
GoogleProviderConfiguration(
clientId: '1:778935804680:android:d2da33128b67cdc68c42bd',
),
FacebookProviderConfiguration(
clientId: '...',
),
],
avatarSize: 200,
);
},
);
}
}
I take it you did first sign-out of google in any open browsers right? I believe the idea is to speed up login by using often already established Google logins. So if you have more, log off in other windows.
You should add an extra line of code where you explicitly diconnect from googleSignIn.
final googleSignIn = GoogleSignIn();
.
.
.
Future logout() async {
await googleSignIn.disconnect();
FirebaseAuth.instance.signOut();
}
Also, be sure to add the google_sign_in package :)
I'm currently learning Flutter and I wanted to try out Network Requests and working with Futures.
I want to show a random image from unsplash.com using their API and I want to change the image every time I press a certain button.
I tried implementing a function to change the image, but it doesn't work.
My code looks like this:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: RandomImage(),
);
}
}
class RandomImage extends StatefulWidget {
#override
_RandomImageState createState() => _RandomImageState();
}
class _RandomImageState extends State<RandomImage> {
static String imageUrl = 'https://source.unsplash.com/random/300x200';
Future _imgFuture = http.get(imageUrl);
void _changeImage() async {
_imgFuture = http.put(imageUrl);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: (Text('Hello')),
),
body: Center(
child: Column(
children: [
Spacer(),
FutureBuilder(
future: _imgFuture,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Oops, there was an error');
} else if (snapshot.hasData) {
return Image.network(imageUrl);
} else {
return Text('No value yet');
}
},
),
RaisedButton(
child: Text('Change Image!'),
onPressed: () => setState(() {
_changeImage();
}),
),
Spacer(),
],
),
),
);
}
}
Actually, Image.network is keeping your image, for more detail to see It here. The solution for this issue is make a simple useless query to api, so the image will be identical differently in flutter.
RaisedButton(
child: Text('Change Image!'),
onPressed: () => setState(() {
// _changeImage();
imageUrl="https://source.unsplash.com/random/300x200?v=${DateTime.now().millisecondsSinceEpoch}";
}),
),
The image won't change If you call the api too frequently, you might want to add a timer to prevent user from clicking too often.
I think the problem is in the _changeImage() method, try replace http.put with http.get.
I'm doing some tests with web_socket_channel Flutter plugin and I've noticed a very strange behavior. I've implemented flutter-dev's example, just changing the socket kind to HtmlWebSocketChannel in order to make it work in web builds.
If I compile my app with flutter build web --release and later I expose it with a local webserver, it works perfectly fine. Same happens if I execute it in debug mode.
However, if I deploy the release version to Firebase hosting (firebase deploy), the widgets where a HtmlWebSocketChannel is present are rendered as a grey box. If I remove those instances, all widgets are rendered as usual.
I thought Firebase hosting was nothing more that a very simple web server, I can't see how can it interfere with specific widgets in a Flutter app. Maybe the cause is related to the fact I'm accesing a remote URL?
Any help will be appreciated!
Here's the code of the app I'm deploying:
import 'package:flutter/foundation.dart';
import 'package:web_socket_channel/html.dart';
import 'package:flutter/material.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'WebSocket Demo';
return MaterialApp(
title: title,
home: MyHomePage(
title: title,
channel: HtmlWebSocketChannel.connect('ws://echo.websocket.org'),
),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
final WebSocketChannel channel;
MyHomePage({Key key, #required this.title, #required this.channel})
: super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Form(
child: TextFormField(
controller: _controller,
decoration: InputDecoration(labelText: 'Send a message'),
),
),
StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Text(snapshot.hasData ? '${snapshot.data}' : ''),
);
},
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _sendMessage,
tooltip: 'Send message',
child: Icon(Icons.send),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void _sendMessage() {
if (_controller.text.isNotEmpty) {
widget.channel.sink.add(_controller.text);
}
}
#override
void dispose() {
widget.channel.sink.close();
super.dispose();
}
}
As mentioned above in my comments this seems to be an issue with trying to access insecure resource from a secure environment as https. Here is a working demo of the same code you used.
https://stackoverlfow-demos.web.app/#/
I just replaced it with wss and deployed it to the firebase hosting.
channel: HtmlWebSocketChannel.connect('wss://echo.websocket.org'),
This was working initially and it just stopped and I cannot figure out where the problem lies.
I am working with streams on my flutter project in provider package. Streams are being emitted from services files and listening is happening on the widgets file. Firebase onAuthStateChanged stream is working but mine are not working.
I have alot of code in my files so am not going to post everything here.
I have a problem with AuthStatus stream
I tried subscribing to the stream on the widget class but it seems like no streams are getting emitted
MyApp(){
auth.authStateStream.listen((d){print("$d is data");});
}
This how firebase streams are getting emiited from services file
Stream<UserModel> get onAuthStateChanged{
return _firebaseAuth.onAuthStateChanged.map(_userFromFirebase);
}
I have a problem with AuthStatus stream. This was working initially
This is how AuthStatus stream is getting emmited from services file
//Services file
final StreamController<AuthStatus> _currentAuthStateController =
StreamController<AuthStatus>.broadcast();
Stream<AuthStatus> get authStateStream{
return _currentAuthStateController.stream;
}
void testStremas() {
//Stoast.setMessage("Test Message");
_currentAuthStateController.add(AuthStatus.ACTIVE);
}
This is how provider is litening to streams as a parent of the MaterialAPP widget
class MyApp extends StatelessWidget {
//I was trying if i my widget could subscribe to the stream
MyApp (){
auth.authStateStream.listen((d){print("$d is data");});
}
final ToastHelper toast = ToastHelper();
final ThemeHelper theme = ThemeHelper();
final AuthService auth = AuthService();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<UserModel>.value(value: auth.onAuthStateChanged),
StreamProvider<ToastMessage>.value(value: toast.onNewMessage),
StreamProvider<AuthStatus>.value(
value: auth.authStateStream, initialData: AuthStatus.NONE),
],
child: MaterialApp(
title: Strings.appName,
theme: theme.darkThemeData(),
home: Loader(),
routes: {
'home': (context) => Home(),
},
debugShowCheckedModeBanner: false,
),
);
}
}
This is how the above method is getting called on a the widget on a click of a button
//Widgets file
onTap: () => auth.testStremas(),
The expected result should be when the AuthStatus change from the services file, The widgets should be notified via the provider package. Thanks in advance
Widget _body(BuildContext context) {
final AuthStatus _authStatus = Provider.of<AuthStatus>(context);
return Center(
child: Container(
constraints: BoxConstraints(maxWidth: 300),
child: SingleChildScrollView(
child: Center(
child: _authStatus == AuthStatus.ACTIVE
? Padding(
padding: const EdgeInsets.all(8.0),
child:CircularProgressIndicator(strokeWidth: 2,)
)
: _buildScreen(context),
)),
),
);
}
I'm not sure - try to change
final StreamController<AuthStatus> _currentAuthStateController =
StreamController<AuthStatus>.broadcast();
to
final StreamController<AuthStatus> _currentAuthStateController =
BehaviorSubject<AuthStatus>();
This BehaviorSubject from rxdart library https://pub.dev/packages/rxdart, so, you should import it. BehaviorSubject is keep last state of stream. You can read more here https://pub.dev/documentation/rxdart/latest/rx/BehaviorSubject-class.html
import 'package:rxdart/rxdart.dart';
I am just getting into Flutter, Dart and Redux. Have followed a YouTube video to modify the default Flutter example to use Redux but its failing for me and I still have a hard time understanding exceptions and reacting to them effectively. Here is the code:
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
// following this youtube video: https://youtu.be/X8B-UzqEaWc
void main() => runApp(new MyApp());
#immutable
class AppState {
final int counter;
AppState(this.counter);
}
// actions
enum Actions { increment }
// pure function
AppState reducer(AppState prev, action) {
if(action == Actions.increment) {
return new AppState(prev.counter + 1);
}
return prev;
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData.dark(),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final store = new Store(reducer, initialState: new AppState(0));
//print(store.state.counter); <----- Undefined class 'counter'.
#override
Widget build(BuildContext context) {
return new StoreProvider(
store: store,
child: new Scaffold(
appBar: new AppBar(
title: new Text("Flutter Redux"),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new StoreConnector(
converter: (store) => store.state.counter,
builder: (context, counter) => new Text(
"$counter",
style: Theme.of(context).textTheme.display1,
)
)
],
),
),
floatingActionButton: new StoreConnector<int, VoidCallback>(
converter: (store) {
return () => store.dispatch(Actions.increment);
},
builder: (context, callback) => new FloatingActionButton(
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
)
),
);
}
}
So first of all, when I try to run this, I am getting an exception that states that "The following NoSuchMethodError was thrown building StoreConnector(dirty):
I/flutter (20662): The getter 'store' was called on null.". Secondary question is why the print method highlighted in the code is not recognizing counter getter? Thanks.
The problem was that I had "dart.previewDart2" set to true and I guess something might be screwed up in the latest preview build. Once I set the option to false, all worked good.
Details:
Got to File -> Preferences -> Settings.
Type 'dart" in the search box.
Once you find the setting dart.previewDart2, click on the pencil icon to the left of it and select "Copy to Settings".
On the right hand side in user settings, set the setting to true.