I am trying to include Facebook and Google Authentication in my app which I am creating using Flutter. Is there a tutorial where I can utilize to implement as it is bit uncertain on how to include html elements and Javascript in Flutter to enable such authentication. Or is there a complete different way of authentication for Flutter?
You can use the google_sign_in plugin. Check out the documentation in the plugins repo and on pub.
There isn't a Facebook plugin yet, but you could write one.
I'd recommend leveraging Firebase.
Here is a codelab: https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html#0
Adding this late answer since now there is a package, flutter_facebook_login that replaces flutter_facebook_connect. Here is a functioning main.dart example that should work. Just keep in mind you must have followed all configuration as described in the repository and must have a facebook app configured:
import 'package:flutter/material.dart';
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'dart:async';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Facebook Login',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Login Facebook'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
login() async {
final facebookLogin = new FacebookLogin();
final result = await facebookLogin.logInWithReadPermissions(['email']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
print(result.accessToken.token);
break;
case FacebookLoginStatus.cancelledByUser:
print('CANCELED BY USER');
break;
case FacebookLoginStatus.error:
print(result.errorMessage);
break;
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
floatingActionButton: new FloatingActionButton(
onPressed: login,
tooltip: 'Login With Facebook',
child: new Icon(Icons.add),
),
);
}
}
You should see the login screen when clicking bottom right button, and check the printed response on your debug console:
This is the way to go right now since the package actually uses native Facebook Login SDKs on Android and iOS. So no excuse to use Firebase or having to interface yourself!
Hope it helps others who are having troubles with facebook login. And credits go to the package creator roughike
For google signin use google_sign_in, this package is actually quite mature and easier to get going.
Like the others mentioned for google use google_sign_in plugin and for Facebook you can use this one.
https://github.com/lejard-h/flutter_facebook_connect
But to connect to Facebook you have to register your app by Facebook. They provide an documentation for this.
Note: don‘t forget the redirection to localhost like the README of the github project explains.
The Facebook plugin will open an webview (you need to install the webview_plugin too) where the user can authenticate and accept the permission your app needs.
Looks like oauth2_client is a library that will do what's needed:
Simple Flutter library for interacting with OAuth2 servers. It provides convenience classes for interacting with the "usual suspects" (Google, Facebook, LinkedIn, GitHub), but it's particularly suited for implementing clients for custom OAuth2 servers.
Related
I have an app that requires users to log in. I have the website for the login page and everything.
So I've been using the "flutter_webview_plugin", "openid_client" "flutter_appauth" packages. At the moment I have a webview that opens the login page. So the home page is just a button that routes to a class called "LoginScreen()", which then shows the web page. That's what you see in the code. I am fairly new to flutter and programming as a whole, so please explain as if I have no idea what I'm doing.
Another note is that I am unsure where to apply the logic for the authentication and token retrieval. i.e. in the home page or login page where the webview is
import 'dart:async';
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:flutter/services.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final flutterWebviewPlugin = new FlutterWebviewPlugin();
StreamSubscription _onDestroy;
StreamSubscription<String> _onUrlChanged;
StreamSubscription<WebViewStateChanged> _onStateChanged;
String token;
#override
void dispose() {
// Every listener should be canceled, the same should be done with this stream.
_onDestroy.cancel();
_onUrlChanged.cancel();
_onStateChanged.cancel();
flutterWebviewPlugin.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
//flutterWebviewPlugin.close();
// Add a listener to on destroy WebView, so you can make came actions.
_onDestroy = flutterWebviewPlugin.onDestroy.listen((_) {
print("destroy");
});
_onStateChanged =
flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state) {
print("onStateChanged: ${state.type} ${state.url}");
});
// Add a listener to on url changed
_onUrlChanged = flutterWebviewPlugin.onUrlChanged.listen((String url) {
if (mounted) {
setState(() {
print("URL changed: $url");
//flutterWebviewPlugin.close();
});
}
});
}
#override
Widget build(BuildContext context) {
String url = "http://login/page";
return WebviewScaffold(
appBar: AppBar(
title: Text("Login"),
),
url: url,
withZoom: false,
);
}
}
The webview works, but I have no idea how implement the logic
You're going about this the complete wrong way. Flutter is meant to provide an easier to build native experience. You're using a more advance technology than native programming and making it depend on a lesser technology which is wrapping webviews in a native app. I would suggest the following. If you can implement them.
Expose your API for your login publicly so that you can access it from the mobile app directly.
Build your own login screen on Flutter and don't wrap a website using Flutter.
Once your API is exposed, return your token as a normal json object and use it in the application as you wish.
If you can't change the api and really want to wrap your application (which I don't recommend) then don't use Flutter. Flutter's webview is very limited (It's still in developers preview as it depends on adding Native views into the Element tree, which is an upcoming feature). Use a technology that's catered towards wrapping websites and that provides built in support. If you're new to programming this will be very confusing so use something that's catered towards what you want to do.
I'd recommend looking at the following technologies:
Cordova (which is going out of fashion Very quick)
Ionic More popular and is kind of still growing amongst the native hybrids even though it's completely web based.
I know it's not the answer you were probably looking for but based on your question you're going to have a much harder time with solving this problem. Please try and follow the first points I laid out, your development experience will be much better and your solution will benefit as well in terms of simplicity.
I'm looking for a way to enable the autofill for a password textfield in a login form
As a backup solution, I was thinking to save the password in the secure storage, and then, with the biometrics, recovering the same password when a new login is performing.
But this won't cover all the autofill password experiences from iOS 12.
For example the password won't be saved across multiple devices.
Any tips?
Flutter supports now autofill (password, email, username, etc.) ☑️ The merged pull request with an example: https://github.com/flutter/flutter/pull/52126
Example:
#override
Widget build(BuildContext context) {
return AutofillGroup(
child: Column(
children: <Widget>[
TextField(controller: username, autofillHints: [AutofillHints.username]),
Checkbox(
value: isNewUser,
onChanged: (bool newValue) {
setState(() { isNewUser = newValue; });
},
),
if (isNewUser) TextField(controller: newPassword, autofillHints: [AutofillHints.newPassword]),
if (isNewUser) TextField(controller: repeatNewPassword, autofillHints: [AutofillHints.newPassword]),
if (!isNewUser) TextField(controller: password, autofillHints: [AutofillHints.password]),
],
),
);
}
Auto-Fill is not yet supported in flutter out of the box. There are two issues i know of which are tracking this issue (although android related). You might want to subscribe/vote on those:
https://github.com/flutter/flutter/issues/13015
https://github.com/flutter/flutter/issues/14047
I fear it won't be easy to trigger this functionality via a 3rd party plugin though.
As for your question regarding secure storage: If you are using the flutter secure storage plugin which uses the keychain on iOS, it should be synced across devices via iCloud.
I had an autofill on both an email input and password input on the same page. The autofill was only showing on the password field.
I had to wrap the TextFields in an AutoFillGroup for them to show on both!
To preface this i am new to all of this and don't need step by step information, just seeing what is possible.
I've been toying around with connecting my flutter/dart app to a mysql backend
Im connecting to it using sqljocky and was wondering if there is anyway users can download data from it for offline use. I read about NSUserDefaults (for ios) and Shared_Preferences (for android) for storage of persistent and simple data on the app and wanted to know if this is the correct route to continue on.
I think this answer is required here:
Few days ago I had to dealt with a existing MySQL database and there was no way to do it with Dart except over network requests(there is a sqljocky package which is Dart 2 incompatible). Read best options here.
Here Im going to show an example for a simple fetch data using Flutter http request with simple PHP & MySQL.
Note: This is may not 100% secure.
If you are doing in local server, you need to have server(ex: apache) running and MySQL(you can use XAMPP to get both).
Step 1: create a database.
Step 2: create a folder in htdocs(in XAMP). Next, inside that file create file called conn.php. Then, add below snippet and change
with your db credentials to connect to database.
<?php
$connection = new mysqli("localhost", "username", "password", "db_name");
if (!$connection) {
echo "connection failed!";
exit();
}
?>
Note: above snippet is a simple example and you can customize as you want.
Step 3: Create php file called fetch_data.php and copy paste below code snippet:
<?php
include("conn.php");
$queryResult = $connection->
query("SELECT * FROM your_table");//change your_table with your database table that you want to fetch values
$result = array();
while ($fetchdata=$queryResult->fetch_assoc()) {
$result[] = $fetchdata;
}
echo json_encode($result);
?>
Above code snippet will fetch the data from db table and display it after json_encode.
Step 4: Open up your Flutter project or create one. Below is a code snippet that requesting for fetched data and display them using a ListView.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Login",
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List data = [];
#override
void initState() {
fetchData();
super.initState();
}
void fetchData() async {
final response = await http.get('http://10.0.2.2/fluttertest/fetch_data.php');
if (response.statusCode == 200) {
setState(() {
data = json.decode(response.body);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text(data[index]['title']),
)),
);
}
}
There is an important thing, you should keep in mind: 10.0.2.2 or your machine IP address(type ipconfig in cmd to get your IP address) have to use because emulator itself localhost(127.0.0.1).
Note: I didn't use any model or advanced things to show you bare minimum example. If you want a great CRUD example, check my github repo and you can also do some pull requests because it's can extended.
If you want to insert or update data, you can use http.post() and in php use INSERT, UPDATE sql statements(It's better using Prepared Statement to prevent sql injections).
Also you can read my article. There I have explained everything using a CRUD application.
For Android we can use SQLite and for Flutter, we have equivalent SQFlite that support both IOS and Android.
And there are other best solutions like Firebase database, Firestore and you can also create API and access through HTTP. Also you can store data in a JSON file.
For you to continue on these may help:
Using mysql in flutter.
Flutter connecting to a database in server.
I want to use Google Cloud Natural Language in my Flutter app,I got Google API package
This works for flutter and theGoogle API_AUTH dependence is working for 0.2.1.
How do I implement them ?
This worked for me:
Logging in using package google_sign_in and then get auth headers from it:
import 'package:google_sign_in/google_sign_in.dart'
show GoogleSignIn, GoogleSignInAccount;
import 'package:googleapis/people/v1.dart'
show ListConnectionsResponse, PeopleApi;
useGoogleApi() async {
final _googleSignIn = new GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
await _googleSignIn.signIn();
final authHeaders = _googleSignIn.currentUser.authHeaders;
// custom IOClient from below
final httpClient = GoogleHttpClient(authHeaders);
data = await PeopleApi(httpClient).people.connections.list(
'people/me',
personFields: 'names,addresses',
pageToken: nextPageToken,
pageSize: 100,
);
}
This is a custom IOClient implementation that automatically adds the auth headers to each request. The googleapis call support passing a custom HTTP client to be used instead of the default (see above)
import 'package:http/io_client.dart';
import 'package:http/http.dart';
class GoogleHttpClient extends IOClient {
Map<String, String> _headers;
GoogleHttpClient(this._headers) : super();
#override
Future<StreamedResponse> send(BaseRequest request) =>
super.send(request..headers.addAll(_headers));
#override
Future<Response> head(Object url, {Map<String, String> headers}) =>
super.head(url, headers: headers..addAll(_headers));
}
I can't add comments yet, so I'll just post it as an answer.
I kept trying to make a GoogleHttpClient as per the top answer, but on the import, it says "The library 'package:http/http.dart' doesn't export a member with the shown name 'IOClient'."
I found the answer here https://pub.dartlang.org/packages/http#-changelog-tab-, which says you should import IOClient separately as such: import 'package:http/io_client.dart';
I thought this might help out others who are new to flutter and its implementation of Google APIs.
The accepted answer is most likely written towards an older version of the SDK I just couldn't get it to work. This is what works for me as of now.
As an example, the following allow us to access files in Google Drive which is part of googleapis.
Dependencies
pubspec.yaml:
dependencies:
google_sign_in: any
googleapis: any
(I just put any here as a example, but you should specific the version(s) for you actual app.)
How it works
Necessary imports:
import 'package:googleapis/drive/v3.dart' as drive;
import 'package:google_sign_in/google_sign_in.dart' as signIn;
Step 1, sign in the user and ask for access permission (scope) to google drive:
final googleSignIn = signIn.GoogleSignIn.standard(scopes: [drive.DriveApi.DriveScope]);
final sign.GoogleSignInAccount account = await googleSignIn.signIn();
Step 2, build a AuthenticateClient:
class AuthenticateClient extends http.BaseClient {
final Map<String, String> headers;
final http.Client client;
AuthenticateClient(this.headers, this.client);
Future<http.StreamedResponse> send(http.BaseRequest request) {
return client.send(request..headers.addAll(headers));
}
}
As suggested in http, this is using the BaseClient with extra authentication headers (being composable).
Step 3, create a authenticated http client with from step 1 and 2 and access google drive API.
final baseClient = new Client();
final authenticateClient = AuthenticateClient(authHeader, baseClient);
final driveApi = drive.DriveApi(authenticateClient);
Checkout How to Use the Google Drive API With Flutter Apps for details.
Update to the accepted answer
Along with google_sign_in and googleapis packages, now you can use extension_google_sign_in_as_googleapis_auth package (provided by flutter.dev) to get configured http client. So the accepted answer can be simplified to below. No implementation of GoogleHttpClient is necessary.
import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/people/v1.dart';
useGoogleApi() async {
final _googleSignIn = new GoogleSignIn(
scopes: [
'email',
PeopleServiceApi.contactsReadonlyScope,
],
);
await _googleSignIn.signIn();
// custom IOClient
final httpClient = await _googleSignIn.authenticatedClient();
data = await PeopleApi(httpClient!).people.connections.list(
'people/me',
personFields: 'names,addresses',
pageToken: nextPageToken,
pageSize: 100,
);
}
I'm a Rails web back & front dev, and I want to build a Mobile app. A simple app, with products, users, geolocalisation and maybe payment (with a third-part like Stripe).
I think Flutter framework is a good choice, looks verry simple.
But I don't know how a thing of the Dart language (or mobile native dev), and don't know where to start.
I thought of a system like :
Rails back-end for products and users
Flutter framework app for actions and geolocalisation
API between them to receive and send data
Do you have some advices for me ? Where to start, and alternatives ?
Many thanks !
Your question should should definitely not be so broad since there's no right answer to this but I'll try. I learned flutter in a a few days using the documentation only.
I learned the setup, installation and wrote my first app following this which is in the docs.
I learned architecture through looking at this website and just reading more about the particular architecture that's being implemented.
To get better at the layouts itself, which is super easy and nice to deal with, I had this old design challenge of mine on instagram and I implemented one UI every day for a few days using flutter. After about a week I could build any layout I wanted too.
I've settled on using scoped model as described here and redux in larger apps. It's pretty awesome.
This is all I used, then weekly I would watch the widget of the week on google's developer youtube page and that's it. Flutter's medium community is very active and should be a good source of info, but I almost never read blogs on there unless I need to learn something new.
It's pretty simple to connect a Rails API to a Flutter UI, there are a couple of considerations around state management but Google recommend using the BLoC pattern and it works really well with Rails.
Now I'm not going to go into the details around implementing the BLoC pattern but I will leave some links at the bottom around this topic.
First step is to check the flutter docs, they have some decent Cookbooks and I will adapt one below using Rails generators. https://flutter.dev/docs/cookbook/networking/fetch-data
Create a Post resource:
rails g resource post title:string body:string
Run rails db:migrate.
Create a post using a rails console
In your flutter app (main.dart) I'm assuming it's a brand new app here:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Post> fetchPost() async {
final response =
await http.get('http://10.0.2.2:3000/posts/1');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON.
return Post.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
class Post {
final int id;
final String title;
final String body;
Post({this.id, this.title, this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
void main() => runApp(MyApp(post: fetchPost()));
class MyApp extends StatelessWidget {
final Future<Post> post;
MyApp({Key key, this.post}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Post>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
start a rails server running on port 3000
start the flutter app
That's about it really. Rails and Flutter are absolutely wonderful together and with Flutter Web coming out... at some point... I'm really excited.
Some other resources:
Flutter and Rails CLI (Still very much a WIP but getting there) https://rubygems.org/gems/frap
State management:
https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
https://medium.com/flutterpub/architecting-your-flutter-project-bd04e144a8f1
A bunch of examples
https://github.com/flutter/samples/blob/master/INDEX.md