Cet article donne une solution entièrement fonctionnelle pour soutenir le flux de connexion Facebook Oauth avec Flutter.

Difficulté: Débutant

Contexte

J’ai éprouvé beaucoup de mal à trouver une solution qui répondait à un besoin de base de la plupart des applications Flutter: intégration de l’authentification Facebook

Après des heures de recherches, d’essais et d’erreurs sur Google, je suis finalement arrivé avec une solution qui fonctionne pour moi et je voulais simplement partager cette solution avec vous.

Crédits

Cette solution n’est pas initialement la mienne. Comme je l’ai dit, après de nombreuses heures de recherche sur Google, j’ai finalement trouvé cet article, écrit par Kevin Segaud, qui explique en détails le processus et donne un code source.

Cependant, cette solution ne m’a pas entièrement satisfait sous 2 aspects:

  • il ne donne pas de solution complète pour totalement intégrer la page d’authentification HTML Facebook dans l’application Flutter
  • cela n’explique pas un paramètre très critique à mettre en place sur la page des développeurs de Facebook.

Cet article complète simplement la solution de Kevin et explique comment l’utiliser.

Solution

Comment intégrer la page de connexion HTML de Facebook?

Afin d’intégrer complètement la page HTML d’authentification de Facebook dans votre application Flutter, plutôt que d’utiliser le plugin url_launcher, utilisez plutôt le plugin flutter_webview_plugin.

Pour l’utiliser, ajoutez la ligne suivante à vos dépendances:

dependencies:
  flutter:
    sdk: flutter

  flutter_localizations:
    sdk: flutter
    
  flutter_webview_plugin: ^0.1.4

Valid OAuth Redirect URIs

Pour que l’application Flutter fonctionne avec Facebook, vous devez indiquer à Facebook où retourner le résultat de l’authentification de l’utilisateur.

Comme cette solution lie (binds) la réponse à l’URI suivante: “http://localhost:8080”, nous devons le configurer au niveau de Facebook dans Facebook for developers. Dans le panneau “Products > Facebook Login > Settings”, ajoutez “http://localhost:8080/” à la liste des “Valid OAuth Redirect URIs”.

Le code source final

Ci-dessous, vous trouverez le code source final. Pour l’explication principale sur le flux Facebook, veuillez vous référer à la page de Kevin. Je vais seulement me concentrer sur les changements que j’ai faits (voir en surbrillance). Créez un nouveau fichier, nommé: facebook.dart et copiez le code suivant.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:http/http.dart' as http;

Future<Stream<String>> _server() async {
  final StreamController<String> onCode = new StreamController();
  HttpServer server =
  await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 8080);
  server.listen((HttpRequest request) async {
    final String code = request.uri.queryParameters["code"];
    request.response
      ..statusCode = 200
      ..headers.set("Content-Type", ContentType.HTML.mimeType)
      ..write("<html>You can now close this window</html>");
    await request.response.close();
    await server.close(force: true);
    onCode.add(code);
    await onCode.close();
  });
  return onCode.stream;
}

Future<Token> getToken(String appId, String appSecret) async {
  Stream<String> onCode = await _server();
  String url = "https://www.facebook.com/dialog/oauth?client_id=$appId&redirect_uri=http://localhost:8080/&scope=public_profile";

  ///
  /// Implementation using a webviewFlugin (full page)
  ///
  final FlutterWebviewPlugin webviewPlugin = new FlutterWebviewPlugin();
  webviewPlugin.launch(url /*, clearCache: true, clearCookies: true*/);           // Uncomment to force new login via Facebook
  final String code = await onCode.first;
  webviewPlugin.close();

  final http.Response response = await http.get(
      "https://graph.facebook.com/v2.2/oauth/access_token?client_id=$appId&redirect_uri=http://localhost:8080/&client_secret=$appSecret&code=$code");
  return new Token.fromMap(json.decode(response.body));
}

class Token {
  final String access;
  final String type;
  final num expiresIn;

  Token(this.access, this.type, this.expiresIn);

  Token.fromMap(Map<String, dynamic> json)
      : access = json['access_token'],
        type = json['token_type'],
        expiresIn = json['expires_in'];
}

class Id {
  final String id;

  Id(this.id);
}

class Cover {
  final String id;
  final int offsetY;
  final String source;

  Cover(this.id, this.offsetY, this.source);

  Cover.fromMap(Map<String, dynamic> json)
      : id = json['id'],
        offsetY = json['offset_y'],
        source = json['source'];
}

class PublicProfile extends Id {
  final Cover cover;
  final String name;

  PublicProfile.fromMap(Map<String, dynamic> json)
      : cover =
  json.containsKey('cover') ? new Cover.fromMap(json['cover']) : null,
        name = json['name'],
        super(json['id']);
}

class FacebookGraph {
  final String _baseGraphUrl = "https://graph.facebook.com/v2.8/";
  final Token token;

  FacebookGraph(this.token);

  Future<PublicProfile> me(List<String> fields) async {
    String _fields = fields.join(",");
    final http.Response response = await http
        .get("$_baseGraphUrl/me?fields=$_fields&access_token=${token.access}");
    return new PublicProfile.fromMap(json.decode(response.body));
  }
}
  • Lignes #25-40: Comme vous pouvez le constater, les seules modifications à appliquer pour que la page de connexion HTML soit entièrement intégrée à votre application sont appliquées à la méthode getToken. J’utilise le FlutterWebviewPlugin plutôt que le _launchURL dans le code original.
  • Ligne #33: lors de vos tests, si vous devez forcer une nouvelle connexion avec Facebook, supprimez la partie commentée de la ligne.

Intégration

Le code suivant vous montre comment intégrer l’authentification Facebook dans votre application.

import 'facebook.dart' as fb;

Future<Null> onLoginWithFacebook() async {
	String facebookAppId = "put your facebook app_id here";
	String facebookAppSecret = "put your facebook app_secret here";
	
    fb.Token token;
    fb.FacebookGraph graph;
    fb.PublicProfile profile;

    final fb.Token _token = await fb.getToken(facebookAppId, facebookAppSecret);
    fb.FacebookGraph _graph = new fb.FacebookGraph(_token);
    fb.PublicProfile _profile = await _graph.me(["name", "email"]);

///print(_profile);

    ///
    /// If a Facebook ProfileId is returned, the authentication went OK
    /// 
    if (_profile.id != null){
      ///
	  /// Proceed with further activities linked to the _profile.id
	  ///
    }
}

C’est un code très basique pour illustrer l’utilisation de la solution facebook.dart.

Remplacez facebookAppId et facebookAppSecret avec vos données personnelles Facebook. Pour retrouver ces 2 paramètres, allez sur la page Facebook for developers et, sous Settings > Basic”.

Conclusion

En essayant de collecter et de partager autant de trucs et astuces, je ne pouvais pas laisser ce sujet de côté…

J’espère que cela aidera quelqu’un.

En attendant, restez à l’écoute pour d’autres articles et bon codage.