Maison > interface Web > tutoriel CSS > Comment créer une application mobile complète avec Flutter, Faune et GraphQL

Comment créer une application mobile complète avec Flutter, Faune et GraphQL

Lisa Kudrow
Libérer: 2025-03-21 10:34:13
original
314 Les gens l'ont consulté

Comment créer une application mobile complète avec Flutter, Faune et GraphQL

Flutter est le cadre de l'interface utilisateur de Google pour créer des applications mobiles multiplateforme flexibles et expressives. Il s'agit de l'un des cadres à la croissance la plus rapide pour le développement d'applications mobiles. La faune, en revanche, est une base de données transactionnelle sans serveur conviviale pour les développeurs qui prend en charge le graphique natif. Flutter Fauna est un match parfait fait par le ciel. Si vous souhaitez créer et publier des applications complètes riches en fonctionnalités en temps record, Flutter et Fauna sont les bons outils. Dans cet article, nous vous guiderons à travers la construction de votre première application Flutter à l'aide de backends Fauna et GraphQL.

Vous pouvez trouver le code complet de cet article sur GitHub.

Objectifs d'apprentissage

Après avoir lu cet article, vous devez savoir comment:

  1. Configurez l'instance de faune,
  2. Écrivez le modèle GraphQL pour la faune,
  3. Configurez le client GraphQL dans l'application Flutter, et
  4. Effectuez des requêtes et des mutations sur le backend GraphQL de la faune.

Faune vs AWS Amplify vs Firebase : Quels problèmes résolvent la faune? En quoi est-ce différent des autres solutions sans serveur? Si vous n'êtes pas familier avec la faune et que vous souhaitez en savoir plus sur la comparaison de Fauna avec d'autres solutions, je vous suggère de lire cet article.

Que construisons-nous?

Nous créerons une application mobile simple qui permet aux utilisateurs d'ajouter, de supprimer et de mettre à jour leurs personnages de séries de films et de télévision préférés.

Mettre en place la faune

Allez sur fauna.com et créez un nouveau compte. Après vous être connecté, vous devriez être en mesure de créer une nouvelle base de données.

Nommez votre base de données. J'ai nommé le mien Flutter_demo. Ensuite, nous pouvons sélectionner un groupe régional. Pour cette démo, nous sélectionnerons le classique. La faune est une base de données sans serveur distribuée à l'échelle mondiale. Il s'agit de la seule base de données qui prend en charge l'accès à la lecture et à l'écriture à faible latence de n'importe où. Considérez-le comme un CDN (réseau de distribution de contenu), mais c'est pour votre base de données. Pour en savoir plus sur le groupe régional, suivez ce guide.

Générer une clé administratrice

Une fois la base de données créée, accédez à l'onglet de sécurité. Cliquez sur le bouton de la nouvelle clé et créez une nouvelle clé pour votre base de données. Veuillez garder cette clé correctement car nous en avons besoin pour les opérations GraphQL.

Nous créerons une clé administratrice pour notre base de données. Une clé avec un rôle d'administrateur est utilisée pour gérer ses bases de données associées, y compris les fournisseurs d'accès aux bases de données, les sous-databases, les documents, les fonctions, les index, les clés, les jetons et les rôles définis par l'utilisateur. Vous pouvez en savoir plus sur les différentes clés de sécurité de Fauna et les rôles d'accès dans les liens ci-dessous.

Écriture du modèle GraphQL

Nous créerons une application simple qui permet aux utilisateurs d'ajouter, de mettre à jour et de supprimer leurs personnages de télévision préférés.

Créer un nouveau projet Flutter

Créons un nouveau projet Flutter en exécutant la commande suivante.

 <code>flutter create my_app</code>
Copier après la connexion

Dans le répertoire du projet, nous créerons un nouveau fichier nommé GraphQL / Schema.graphql.

Dans le fichier de schéma, nous définirons la structure de la collection. Les collections dans la faune sont similaires aux tableaux de SQL. Nous n'avons besoin qu'un seul ensemble maintenant. Nous le nommez le caractère.

 <code>### schema.graphql type Character { name: String! description: String! picture: String } type Query { listAllCharacters: [Character] }</code>
Copier après la connexion

Comme indiqué ci-dessus, nous définissons un type appelé caractère qui a plusieurs propriétés (c'est-à-dire le nom, la description, l'image, etc.). Une propriété peut être traitée comme une colonne d'une base de données SQL ou une paire de valeurs clés d'une base de données NOSQL. Nous définissons également une requête. Cette requête renvoie la liste des rôles.

Revenons maintenant au tableau de bord de la faune. Cliquez sur GraphQL et cliquez sur Mode d'importation pour télécharger notre mode sur Fauna.

Une fois l'importation terminée, nous verrons la faune générer des requêtes et des mutations GraphQL.

Vous n'aimez pas la génération automatique de GraphQL? Vous voulez avoir un meilleur contrôle sur votre logique commerciale? Dans ce cas, la faune vous permet de définir un analyseur GraphQL personnalisé. Pour en savoir plus, cliquez sur ce lien.

Configuration du client GraphQL dans l'application Flutter

Ouvrez le fichier pubspe.yaml et ajoutons les dépendances requises.

 <code>... dependencies: graphql_flutter: ^4.0.0-beta hive: ^1.3.0 flutter: sdk: flutter ...</code>
Copier après la connexion

Nous avons ajouté deux dépendances ici. GraphQL_Flumber est la bibliothèque client GraphQL de Flutter. Il intègre toutes les fonctionnalités modernes du client GraphQL dans un package facile à utiliser. Nous avons également ajouté le package Hive comme dépendance. Hive est une base de données de valeur clé légère écrite en fléchette pure pour le stockage local. Nous utilisons Hive pour mettre en cache nos requêtes GraphQL.

Ensuite, nous créerons un nouveau fichier lib / client_provider.dart. Nous créerons une classe de fournisseur dans ce fichier qui contiendra notre configuration de faune.

Pour nous connecter à l'API GraphQL de Fauna, nous devons d'abord créer un GraphQlClient. GraphQlClient nécessite un cache et un lien à initialiser. Jetons un coup d'œil au code ci-dessous.

 <code>// lib/client_provider.dart import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:flutter/material.dart'; ValueNotifier<graphqlclient> clientFor({ @required String uri, String subscriptionUri, }) { final HttpLink httpLink = HttpLink( uri, ); final AuthLink authLink = AuthLink( getToken: () async => 'Bearer fnAEPAjy8QACRJssawcwuywad2DbB6ssrsgZ2-2', ); Link link = authLink.concat(httpLink); return ValueNotifier<graphqlclient> ( GraphQLClient( cache: GraphQLCache(store: HiveStore()), link: link, ), ); }</graphqlclient></graphqlclient></code>
Copier après la connexion

Dans le code ci-dessus, nous créons un ValueNotifier pour envelopper le GraphQlClient. Notez que nous avons configuré AuthLink sur les lignes 13-15 (en surbrillance). À la ligne 14, nous avons ajouté la clé administratrice de la faune dans le cadre du jeton. Ici, j'ai codé en dur la clé d'administration. Cependant, dans les applications de production, nous devons éviter les clés de sécurité à code dur de la faune.

Il existe plusieurs façons de stocker des clés dans une application Flutter. Veuillez consulter ce blog pour référence.

Nous voulons pouvoir appeler la requête et la mutation à partir de n'importe quel widget de l'application. Pour ce faire, nous devons envelopper notre widget en utilisant le widget GraphQlProvider.

 <code>// lib/client_provider.dart .... /// 使用`graphql_flutter`客户端包装根应用程序。 /// 我们使用缓存进行所有状态管理。 class ClientProvider extends StatelessWidget { ClientProvider({ @required this.child, @required String uri, }) : client = clientFor( uri: uri, ); final Widget child; final ValueNotifier<graphqlclient> client; @override Widget build(BuildContext context) { return GraphQLProvider( client: client, child: child, ); } }</graphqlclient></code>
Copier après la connexion

Ensuite, nous allons dans le fichier main.dart et enroulons notre widget principal avec le widget ClientProvider. Jetons un coup d'œil au code ci-dessous.

 <code>// lib/main.dart ... void main() async { await initHiveForFlutter(); runApp(MyApp()); } final graphqlEndpoint = 'https://graphql.fauna.com/graphql'; class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ClientProvider( uri: graphqlEndpoint, child: MaterialApp( title: 'My Character App', debugShowCheckedModeBanner: false, initialRoute: '/', routes: { '/': (_) => AllCharacters(), '/new': (_) => NewCharacter(), } ), ); } }</code>
Copier après la connexion

À ce stade, tous nos widgets en aval pourront exécuter des requêtes et des fonctions de mutations et peuvent interagir avec l'API GraphQL.

Page de demande

L'application de démonstration doit être simple et facile à comprendre. Allons-y et créons un widget de liste simple qui affichera une liste de tous les rôles. Créons un nouveau fichier lib / écrans / caractères-list.dart. Dans ce fichier, nous rédigerons un nouveau widget appelé AllCharacters.

 <code>// lib/screens/character-list.dart.dart class AllCharacters extends StatelessWidget { const AllCharacters({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( pinned: true, snap: false, floating: true, expandedHeight: 160.0, title: Text( 'Characters', style: TextStyle( fontWeight: FontWeight.w400, fontSize: 36, ), ), actions:<widget> [ IconButton( padding: EdgeInsets.all(5), icon: const Icon(Icons.add_circle), tooltip: 'Add new entry', onPressed: () { Navigator.pushNamed(context, '/new'); }, ), ], ), SliverList( delegate: SliverChildListDelegate([ Column( children: [ for (var i = 0; i _CharacterTileeState(); } class _CharacterTileState extends State<charactertile> { @override Widget build(BuildContext context) { return Container( child: Text("Character Tile"), ); } }</charactertile></widget></code>
Copier après la connexion

Comme indiqué dans le code ci-dessus, [ligne 37] Nous avons une boucle pour la liste qui remplit la liste avec de fausses données. Enfin, nous ferons des requêtes GraphQL sur le backend de la faune et obtiendrons tous les rôles de la base de données. Avant de le faire, essayons d'exécuter notre application. Nous pouvons exécuter notre application en utilisant la commande suivante

 <code>flutter run</code>
Copier après la connexion

À ce stade, nous devrions pouvoir voir l'écran suivant.

Exécuter des requêtes et des mutations

Nous avons maintenant des widgets de base que nous pouvons continuer à nous connecter aux requêtes GraphQL. Nous voulons obtenir tous les rôles de la base de données au lieu de chaînes codées en dur et les visualiser dans le widget AllCharacters.

Revenons au terrain de jeu GraphQL de Fauna. Notez que nous pouvons exécuter la requête suivante pour répertorier tous les rôles.

 <code>query ListAllCharacters { listAllCharacters(_size: 100) { data { _id name description picture } after } }</code>
Copier après la connexion

Pour effectuer cette requête de notre widget, nous devons y apporter quelques modifications.

 <code>import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:todo_app/screens/Character-tile.dart'; String readCharacters = ";";"; query ListAllCharacters { listAllCharacters(_size: 100) { data { _id name description picture } after } } ";";";; class AllCharacters extends StatelessWidget { const AllCharacters({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( pinned: true, snap: false, floating: true, expandedHeight: 160.0, title: Text( 'Characters', style: TextStyle( fontWeight: FontWeight.w400, fontSize: 36, ), ), actions:<widget> [ IconButton( padding: EdgeInsets.all(5), icon: const Icon(Icons.add_circle), tooltip: 'Add new entry', onPressed: () { Navigator.pushNamed(context, '/new'); }, ), ], ), SliverList( delegate: SliverChildListDelegate([ Query(options: QueryOptions( document: gql(readCharacters), // 我们要执行的graphql查询pollInterval: Duration(seconds: 120), // 重新获取间隔), builder: (QueryResult result, { VoidCallback refetch, FetchMore fetchMore }) { if (result.isLoading) { return Text('Loading'); } return Column( children: [ for (var item in result.data\['listAllCharacters'\]['data']) CharacterTile(Character: item, refetch: refetch), ], ); }) ]) ) ], ), ); } }</widget></code>
Copier après la connexion

Tout d'abord, nous définissons la chaîne de requête pour obtenir tous les rôles de la base de données [lignes 5 à 17]. Nous enroulons le widget de liste à l'aide du widget de requête dans flutter_graphql.

N'hésitez pas à consulter la documentation officielle de la bibliothèque Flutter_GraphQL.

Dans le paramètre Options de requête, nous fournissons la chaîne de requête GraphQL elle-même. Nous pouvons passer n'importe quel numéro de point flottant pour le paramètre Polterval. L'intervalle de sondage définit combien de temps nous souhaitons réapparaître les données du backend. Le widget a également une fonction de constructeur standard. Nous pouvons utiliser la fonction Builder pour transmettre les résultats de la requête, recueillir les fonctions de rappel et obtenir plus de fonctions de rappel dans l'arborescence du widget.

Ensuite, je mettrai à jour le widget de caractères pour afficher les données des caractères à l'écran.

 <code>// lib/screens/character-tile.dart ... class CharacterTile extends StatelessWidget { final Character; final VoidCallback refetch; final VoidCallback updateParent; const CharacterTile({ Key key, @required this.Character, @required this.refetch, this.updateParent, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { }, child: Padding( padding: const EdgeInsets.all(10), child: Row( children: [ Container( height: 90, width: 90, decoration: BoxDecoration( color: Colors.amber, borderRadius: BorderRadius.circular(15), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage(Character['picture']) ) ), ), SizedBox(width: 10), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( Character['name'], style: TextStyle( color: Colors.black87, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), Text( Character['description'], style: TextStyle( color: Colors.black87, ), maxLines: 2, ), ], ) ) ], ), ), ); } }</code>
Copier après la connexion

Ajouter de nouvelles données

Nous pouvons ajouter de nouveaux rôles à notre base de données en exécutant la mutation suivante.

 <code>mutation CreateNewCharacter($data: CharacterInput!) { createCharacter(data: $data) { _id name description picture } }</code>
Copier après la connexion

Pour exécuter cette mutation à partir de notre widget, nous devons utiliser le widget de mutation de la bibliothèque FLUTTER_GRAPHQL. Créons un nouveau widget avec un formulaire simple pour les utilisateurs pour interagir et entrer des données. Après avoir soumis le formulaire, la mutation CreateCaraCter sera appelée.

 <code>// lib/screens/new.dart ... String addCharacter = ";";"; mutation CreateNewCharacter(\$data: CharacterInput!) { createCharacter(data: \$data) { _id name description picture } } ";";";; class NewCharacter extends StatelessWidget { const NewCharacter({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Add New Character'), ), body: AddCharacterForm() ); } } class AddCharacterForm extends StatefulWidget { AddCharacterForm({Key key}) : super(key: key); @override _AddCharacterFormState createState() => _AddCharacterFormState(); } class _AddCharacterFormState extends State<addcharacterform> { String name; String description; String imgUrl; @override Widget build(BuildContext context) { return Form( child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Name *', ), onChanged: (text) { name = text; }, ), TextField( decoration: const InputDecoration( icon: Icon(Icons.post_add), labelText: 'Description', ), minLines: 4, maxLines: 4, onChanged: (text) { description = text; }, ), TextField( decoration: const InputDecoration( icon: Icon(Icons.image), labelText: 'Image Url', ), onChanged: (text) { imgUrl = text; }, ), SizedBox(height: 20), Mutation( options: MutationOptions( document: gql(addCharacter), onCompleted: (dynamic resultData) { print(resultData); name = ''; description = ''; imgUrl = ''; Navigator.of(context).push( MaterialPageRoute(builder: (context) => AllCharacters()) ); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { return Center( child: ElevatedButton( child: const Text('Submit'), onPressed: () { runMutation({ 'data': { ";picture";: imgUrl, ";name";: name, ";description";: description, } }); }, ), ); } ) ], ), ), ); } }</addcharacterform></code>
Copier après la connexion

Comme le montre le code ci-dessus, le widget de mutation fonctionne de manière très similaire au widget de requête. De plus, le widget de mutation nous fournit une fonction oncomplete. Cette fonction renvoie le résultat de mise à jour dans la base de données une fois la mutation terminée.

Supprimer les données

Nous pouvons supprimer des rôles de la base de données en exécutant la mutation DeleteCharacter. Nous pouvons ajouter ce mutant à notre caractères et le déclencher lorsque le bouton est enfoncé.

 <code>// lib/screens/character-tile.dart ... String deleteCharacter = ";";"; mutation DeleteCharacter(\$id: ID!) { deleteCharacter(id: \$id) { _id name } } ";";";; class CharacterTile extends StatelessWidget { final Character; final VoidCallback refetch; final VoidCallback updateParent; const CharacterTile({ Key key, @required this.Character, @required this.refetch, this.updateParent, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { showModalBottomSheet( context: context, builder: (BuildContext context) { print(Character['picture']); return Mutation( options: MutationOptions( document: gql(deleteCharacter), onCompleted: (dynamic resultData) { print(resultData); this.refetch(); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { return Container( height: 400, padding: EdgeInsets.all(30), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children:<widget> [ Text(Character['description']), ElevatedButton( child: Text('Delete Character'), onPressed: () { runMutation({ 'id': Character['_id'], }); Navigator.pop(context); }, ), ], ), ), ); } ); } ); }, child: Padding( padding: const EdgeInsets.all(10), child: Row( children: [ Container( height: 90, width: 90, decoration: BoxDecoration( color: Colors.amber, borderRadius: BorderRadius.circular(15), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage(Character['picture']) ) ), ), SizedBox(width: 10), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( Character['name'], style: TextStyle( color: Colors.black87, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), Text( Character['description'], style: TextStyle( color: Colors.black87, ), maxLines: 2, ), ], ) ) ], ), ), ); } }</widget></code>
Copier après la connexion

Modifier les données

Les données d'édition sont les mêmes que l'ajout et la suppression. C'est juste une autre mutation de l'API GraphQL. Nous pouvons créer un widget de formulaire de rôle d'édition similaire au nouveau widget de formulaire de rôle. La seule différence est que l'édition du formulaire exécutera la mutation UpdateCharacter. Pour l'édition, j'ai créé un nouveau widget lib / écran / edit.dart. Voici le code de ce widget.

 <code>// lib/screens/edit.dart String editCharacter = """ mutation EditCharacter(\$name: String!, \$id: ID!, \$description: String!, \$picture: String!) { updateCharacter(data: { name: \$name description: \$description picture: \$picture }, id: \$id) { _id name description picture } } """; class EditCharacter extends StatelessWidget { final Character; const EditCharacter({Key key, this.Character}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Edit Character'), ), body: EditFormBody(Character: this.Character), ); } } class EditFormBody extends StatefulWidget { final Character; EditFormBody({Key key, this.Character}) : super(key: key); @override _EditFormBodyState createState() => _EditFormBodyState(); } class _EditFormBodyState extends State<editformbody> { String name; String description; String picture; @override Widget build(BuildContext context) { return Container( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( initialValue: widget.Character['name'], decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Name *', ), onChanged: (text) { name = text; } ), TextFormField( initialValue: widget.Character['description'], decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Description', ), minLines: 4, maxLines: 4, onChanged: (text) { description = text; } ), TextFormField( initialValue: widget.Character['picture'], decoration: const InputDecoration( icon: Icon(Icons.image), labelText: 'Image Url', ), onChanged: (text) { picture = text; }, ), SizedBox(height: 20), Mutation( options: MutationOptions( document: gql(editCharacter), onCompleted: (dynamic resultData) { print(resultData); Navigator.of(context).push( MaterialPageRoute(builder: (context) => AllCharacters()) ); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { print(result); return Center( child: ElevatedButton( child: const Text('Submit'), onPressed: () { runMutation({ 'id': widget.Character['_id'], 'name': name != null ? name : widget.Character['name'], 'description': description != null ? description : widget.Character['description'], 'picture': picture != null ? picture : widget.Character['picture'], }); }, ), ); } ), ] ) ), ); } }</editformbody></code>
Copier après la connexion

Vous pouvez afficher le code complet de cet article comme suit.

Vous avez des questions sur la faune ou le flottement? Vous pouvez me contacter sur twitter @haqueshadid

Github ### Étapes suivantes

Le but principal de cet article est de vous aider à démarrer avec Flutter et Fauna. Nous ne touchons que la surface ici. L'écosystème de la faune fournit à votre application mobile un backend complet, à l'échelle automatique et adapté aux développeurs en tant que service. Si votre objectif est de publier une application mobile multiplateforme qui peut être utilisée pour la production en temps record, essayez la faune et le flutter .

Je vous recommande fortement de consulter le site officiel de la documentation de Fauna. Si vous êtes intéressé à en savoir plus sur le client GraphQL de Dart / Flutter, consultez le référentiel GitHub officiel de GraphQL_Flumber.

Je vous souhaite une bonne programmation, à la prochaine fois.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal