Flutter数据库管理插件supabase_flutter的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter数据库管理插件supabase_flutter的使用

介绍

supabase_flutter 是一个用于Flutter客户端连接Supabase后端服务的库。它简化了与Supabase API、认证系统、实时数据库等特性的交互。

开始使用

导入包

首先,你需要在你的Dart文件中导入supabase_flutter包:

import 'package:supabase_flutter/supabase_flutter.dart';

初始化Supabase

在使用Supabase之前,必须先初始化它。这通常在应用程序启动时完成:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Supabase.initialize(
    url: SUPABASE_URL,
    anonKey: SUPABASE_ANON_KEY,
  );

  runApp(MyApp());
}

// 提取Supabase客户端以备后续使用
final supabase = Supabase.instance.client;

请确保用你的Supabase项目的URL和匿名密钥替换SUPABASE_URLSUPABASE_ANON_KEY

使用示例

下面是一个完整的示例应用,演示了如何使用supabase_flutter进行用户认证和配置个人资料表单。

import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

Future<void> main() async {
  // 替换为您的Supabase项目URL和匿名密钥
  await Supabase.initialize(url: 'YOUR_SUPABASE_URL', anonKey: 'YOUR_ANON_KEY');
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Supabase Flutter Demo',
      home: MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  User? _user;

  @override
  void initState() {
    _getAuth();
    super.initState();
  }

  Future<void> _getAuth() async {
    setState(() {
      _user = Supabase.instance.client.auth.currentUser;
    });
    Supabase.instance.client.auth.onAuthStateChange.listen((data) {
      setState(() {
        _user = data.session?.user;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile Example'),
      ),
      body: _user == null ? const _LoginForm() : const _ProfileForm(),
    );
  }
}

class _LoginForm extends StatefulWidget {
  const _LoginForm({Key? key}) : super(key: key);

  @override
  State<_LoginForm> createState() => _LoginFormState();
}

class _LoginFormState extends State<_LoginForm> {
  bool _loading = false;
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _loading
        ? const Center(child: CircularProgressIndicator())
        : ListView(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
            children: [
              TextFormField(
                keyboardType: TextInputType.emailAddress,
                controller: _emailController,
                decoration: const InputDecoration(label: Text('Email')),
              ),
              const SizedBox(height: 16),
              TextFormField(
                obscureText: true,
                controller: _passwordController,
                decoration: const InputDecoration(label: Text('Password')),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () async {
                  setState(() {
                    _loading = true;
                  });
                  try {
                    final email = _emailController.text;
                    final password = _passwordController.text;
                    await Supabase.instance.client.auth.signInWithPassword(
                      email: email,
                      password: password,
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                      content: Text('Login failed'),
                      backgroundColor: Colors.red,
                    ));
                    setState(() {
                      _loading = false;
                    });
                  }
                },
                child: const Text('Login'),
              ),
              const SizedBox(height: 16),
              TextButton(
                onPressed: () async {
                  setState(() {
                    _loading = true;
                  });
                  try {
                    final email = _emailController.text;
                    final password = _passwordController.text;
                    await Supabase.instance.client.auth.signUp(
                      email: email,
                      password: password,
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                      content: Text('Signup failed'),
                      backgroundColor: Colors.red,
                    ));
                    setState(() {
                      _loading = false;
                    });
                  }
                },
                child: const Text('Signup'),
              ),
            ],
          );
  }
}

class _ProfileForm extends StatefulWidget {
  const _ProfileForm({Key? key}) : super(key: key);

  @override
  State<_ProfileForm> createState() => _ProfileFormState();
}

class _ProfileFormState extends State<_ProfileForm> {
  var _loading = true;
  final _usernameController = TextEditingController();
  final _websiteController = TextEditingController();

  @override
  void initState() {
    _loadProfile();
    super.initState();
  }

  @override
  void dispose() {
    _usernameController.dispose();
    _websiteController.dispose();
    super.dispose();
  }

  Future<void> _loadProfile() async {
    try {
      final userId = Supabase.instance.client.auth.currentUser!.id;
      final data = (await Supabase.instance.client
          .from('profiles')
          .select()
          .match({'id': userId}).maybeSingle());
      if (data != null) {
        setState(() {
          _usernameController.text = data['username'];
          _websiteController.text = data['website'];
        });
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
        content: Text('Error occurred while getting profile'),
        backgroundColor: Colors.red,
      ));
    }
    setState(() {
      _loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return _loading
        ? const Center(child: CircularProgressIndicator())
        : ListView(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
            children: [
              TextFormField(
                controller: _usernameController,
                decoration: const InputDecoration(
                  label: Text('Username'),
                ),
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _websiteController,
                decoration: const InputDecoration(
                  label: Text('Website'),
                ),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                  onPressed: () async {
                    try {
                      setState(() {
                        _loading = true;
                      });
                      final userId =
                          Supabase.instance.client.auth.currentUser!.id;
                      final username = _usernameController.text;
                      final website = _websiteController.text;
                      await Supabase.instance.client.from('profiles').upsert({
                        'id': userId,
                        'username': username,
                        'website': website,
                      });
                      if (mounted) {
                        ScaffoldMessenger.of(context)
                            .showSnackBar(const SnackBar(
                          content: Text('Saved profile'),
                        ));
                      }
                    } catch (e) {
                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                        content: Text('Error saving profile'),
                        backgroundColor: Colors.red,
                      ));
                    }
                    setState(() {
                      _loading = false;
                    });
                  },
                  child: const Text('Save')),
              const SizedBox(height: 16),
              TextButton(
                  onPressed: () => Supabase.instance.client.auth.signOut(),
                  child: const Text('Sign Out')),
            ],
          );
  }
}

此代码段创建了一个简单的登录/注册页面,并允许已认证用户查看和编辑他们的个人资料信息。通过监听认证状态变化,当用户登录或登出时会自动更新UI。

更多功能

除了上述基本操作外,supabase_flutter还支持多种高级特性,如OAuth登录(Google、Apple等)、实时数据流、文件存储等功能。有关这些特性的详细说明,请参阅官方文档。

希望这段指南能帮助你快速上手并充分利用supabase_flutter!如果你有任何问题或需要进一步的帮助,请随时查阅Supabase官方文档或访问其GitHub仓库获取更多信息。


更多关于Flutter数据库管理插件supabase_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库管理插件supabase_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用supabase_flutter插件来管理数据库的示例代码。这个示例将展示如何连接到Supabase,执行基本的CRUD(创建、读取、更新、删除)操作。

首先,确保你已经在pubspec.yaml文件中添加了supabase_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  supabase_flutter: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你需要初始化Supabase客户端并连接到你的Supabase项目。这里假设你已经有一个Supabase项目,并且知道你的项目URL和匿名密钥(ANON_KEY)。

初始化Supabase客户端

创建一个新的Dart文件(例如supabase_client.dart)来初始化Supabase客户端:

import 'package:supabase_flutter/supabase_flutter.dart';

class SupabaseClient {
  late SupabaseClient supabase;

  SupabaseClient(String supabaseUrl, String supabaseAnonKey) {
    supabase = SupabaseClient.create(supabaseUrl, supabaseAnonKey);
  }

  static SupabaseClient getInstance(String supabaseUrl, String supabaseAnonKey) {
    return SupabaseClient(supabaseUrl, supabaseAnonKey);
  }
}

在你的主应用文件中(例如main.dart),初始化这个客户端:

import 'package:flutter/material.dart';
import 'supabase_client.dart';

void main() {
  final supabaseUrl = 'YOUR_SUPABASE_URL';
  final supabaseAnonKey = 'YOUR_ANON_KEY';
  final supabaseClient = SupabaseClient.getInstance(supabaseUrl, supabaseAnonKey);

  runApp(MyApp(supabaseClient: supabaseClient.supabase));
}

class MyApp extends StatelessWidget {
  final SupabaseClient supabase;

  MyApp({required this.supabase});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Supabase Flutter Demo'),
        ),
        body: Center(
          child: MyHomePage(supabase: supabase),
        ),
      ),
    );
  }
}

执行CRUD操作

现在,让我们在MyHomePage中实现一些基本的CRUD操作。

import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class MyHomePage extends StatefulWidget {
  final SupabaseClient supabase;

  MyHomePage({required this.supabase});

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final RealtimeClient realtime;
  late final Subscription sub;
  late List<Map<String, dynamic>> users = [];

  @override
  void initState() {
    super.initState();
    realtime = widget.supabase.realtime;

    // 订阅表变化
    sub = realtime.from('users').on('*', (payload) {
      setState(() {
        // 根据需要处理数据更新
      });
    }).subscribe();

    // 初始化加载数据
    fetchUsers();
  }

  @override
  void dispose() {
    sub.unsubscribe();
    super.dispose();
  }

  Future<void> fetchUsers() async {
    final response = await widget.supabase.from('users').select().execute();
    if (response.data != null) {
      setState(() {
        users = response.data! as List<Map<String, dynamic>>;
      });
    }
  }

  Future<void> createUser() async {
    final response = await widget.supabase.from('users')
      .insert({'username': 'new_user_${(DateTime.now().millisecondsSinceEpoch / 1000).toInt()}'})
      .execute();
    if (response.error == null) {
      print('User created successfully');
      fetchUsers();
    } else {
      print('Error creating user: ${response.error!.message}');
    }
  }

  Future<void> updateUser(String id, String newUsername) async {
    final response = await widget.supabase.from('users')
      .update({'username': newUsername})
      .eq('id', id)
      .execute();
    if (response.error == null) {
      print('User updated successfully');
      fetchUsers();
    } else {
      print('Error updating user: ${response.error!.message}');
    }
  }

  Future<void> deleteUser(String id) async {
    final response = await widget.supabase.from('users')
      .delete()
      .eq('id', id)
      .execute();
    if (response.error == null) {
      print('User deleted successfully');
      fetchUsers();
    } else {
      print('Error deleting user: ${response.error!.message}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: createUser,
          child: Text('Create User'),
        ),
        // 你可以在这里添加更多的按钮和逻辑来展示、更新和删除用户
        // 例如,遍历users列表,为每个用户显示详细信息并提供更新和删除按钮
        // 由于篇幅限制,这里只展示如何调用函数
        // ...
      ],
    );
  }
}

注意事项

  1. 安全性:不要在客户端代码中硬编码你的Supabase密钥。考虑使用环境变量或安全的密钥管理服务。
  2. 错误处理:示例代码中仅打印了错误消息。在实际应用中,你应该有更健壮的错误处理机制。
  3. UI设计:示例代码中的UI非常简单。在实际应用中,你可能需要设计更复杂的用户界面来展示和管理数据。

这个示例应该为你提供了一个良好的起点,以便在你的Flutter应用中使用supabase_flutter插件来管理数据库。

回到顶部