Flutter用户管理插件easyuser的使用

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

Flutter用户管理插件easyuser的使用

Easy User 是一个基于 Firebase Realtime Database 的用户管理包。本文将详细介绍如何使用该插件进行用户管理。

安全规则

安装数据库安全规则文件:

安装来自 <a href="https://github.com/thruthesky/easy_packages/blob/main/docs/database_security_rules.json" rel="ugc">database security rules</a> 文件的安全规则。

数据库结构

数据库结构如下:

  • users: 是数据库的根节点。
    • users/<uid>: 是用户的节点。
      • users/<uid>/name: 用户的名字。
      • users/<uid>/photoUrl: 用户的照片URL。
      • users/<uid>/role: 用户的角色。
      • users/<uid>/status: 用户的状态。
      • users/<uid>/createdAt: 用户的创建日期。
      • users/<uid>/updatedAt: 用户的最后更新日期。
      • users/<uid>/deletedAt: 用户的删除日期。
      • users/<uid>/deleted: 用户的删除状态。
      • users/<uid>/password: 用户的密码。
      • users/<uid>/phone: 用户的电话号码。
      • users/<uid>/address: 用户的地址。
      • users/<uid>/gender: 用户的性别。可以是"M"或"F"。
      • users/<uid>/birthYear: 用户的出生年份。
      • users/<uid>/birthMonth: 用户的出生月份。
      • users/<uid>/birthDay: 用户的出生日期。
  • user-phone-sign-in-numbers: 是存储用户用于登录的电话号码的列表。
    • user-phone-sign-in-numbers/<phoneNumber>: 用户用于登录的电话号码。
      • user-phone-sign-in-numbers/<phoneNumber>/lastSignedInAt: 用户使用电话号码登录的时间(毫秒)。

小部件

UserField

UserField 小部件仅获取并显示用户数据的一个字段。

UserField<int?>(
  uid: user.uid, // 用户ID
  field: 'birthDay', // 字段名
  builder: (v) { // 构建函数
    return ElevatedButton(
      onPressed: () async {
        final easyUser = await User.get(user.uid);
        easyUser?.ref.child(User.field.birthDay).set((v ?? 0) + 1);
      },
      child: Text('UserField(birthDay): $v'),
    );
  },
)

UserModel

UserModel 小部件通过构建方法传递用户模型对象。这意味着此小部件可以显示所有用户数据。

UserModel(
  uid: user.uid, // 用户ID
  builder: (userData) { // 构建函数
    return Text('User ID: ${userData.uid}');
  },
)

UserAvtar

UserAvtar 小部件用于显示用户头像。

UserBuildAvatar(
  photoUrl: null, // 用户照片URL
  initials: null // 用户初始字母
)

UI 和 UX 自定义

自定义公共个人资料屏幕前缀操作构建器:

自定义公共个人资料屏幕前缀操作构建器。

逻辑

账号关联

  • /registered-phone-number: 检查电话号码是否已注册的节点。
    • 为什么?
      • 为了将电话号码与现有用户账户关联。
      • 用户可能使用其他登录方式(如匿名、邮箱、Google、Apple、Facebook等)。
      • 如果电话号码已经注册(或之前登录过),意味着该电话号码属于一个账户。
        • 不能将电话号码与另一个账户关联。
      • 一旦电话号码凭证被使用,就不能再次使用(凭证可能在其他方式下重复使用)。
      • 可以尝试将电话号码凭证关联,并且如果成功,则已关联。
        • 但如果失败,不能重新使用凭证。这意味着用户必须通过其他方式获得新凭证。
flowchart TB
  node_1(["Anonymous User Login"])
  node_2{"Phone Sign-In with Anonymous Account Link?"}
  node_3["Provide if the phone number is registered already"]
  node_1 --&gt; node_2
  node_2 --"Yes"--&gt; node_3

电话号码登录

  • 如果用户使用电话号码登录,则电话号码会保存在 user-phone-sign-in-numbers/<phoneNumber> 节点。
    • 这仅用于检查电话号码是否已注册。
    • 如果电话号码未注册,则用户可以将账户与电话号码关联。
    • 如果电话号码已注册,则用户不能将电话号码与账户关联。相反,用户可以使用电话号码登录。
  • 如果系统需要重置用户的电话号码,则在 easy-engine/tools 目录下运行 tsx reset-phone-sign-in-numbers 命令。

示例代码

以下是一个完整的示例代码,展示了如何使用 easyuser 插件进行用户管理。

import 'dart:developer';
import 'dart:math' hide log;

import 'package:easy_locale/easy_locale.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_auth/firebase_auth.dart' hide User;
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:easyuser/easyuser.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  lo.init();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String firebaseAppName = '[DEFAULT]';
  [@override](/user/override)
  void initState() {
    super.initState();
    UserService.instance.init();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            AuthStateChanges(
              builder: (user) {
                return user == null
                    ? const EmailPasswordLogin()
                    : Column(
                        children: [
                          Text('User UID: ${user.uid}'),
                          ElevatedButton(
                            onPressed: () => UserService.instance.showProfileUpdateScreen(context),
                            child: const Text('Profile update'),
                          ),
                          ElevatedButton(
                            onPressed: () => i.signOut(),
                            child: const Text('Sign out'),
                          ),
                          UserField<int?>(
                            uid: user.uid,
                            field: 'birthDay',
                            builder: (v) {
                              return ElevatedButton(
                                onPressed: () async {
                                  final easyUser = await User.get(user.uid);
                                  easyUser?.ref.child(User.field.birthDay).set((v ?? 0) + 1);
                                },
                                child: Text('UserField(birthDay): $v'),
                              );
                            },
                          ),
                          const UserUpdateAvatar(),
                          ElevatedButton(
                            onPressed: () async {
                              await UserService.instance.showBlockListScreen(context);
                            },
                            child: const Text("Show Block list"),
                          ),
                        ],
                      );
              },
            ),
            ElevatedButton(
              onPressed: () async {
                final user = await UserService.instance.showSearchDialog(
                  context,
                  exactSearch: true,
                );
                if (user == null) return;
                if (!context.mounted) return;
                UserService.instance.showPublicProfileScreen(context, user: user);
              },
              child: const Text('User Search Dialog'),
            ),
            const Divider(),
            ElevatedButton(
              onPressed: () async {
                await UserService.instance.showProfileUpdateScreen(context);
              },
              child: const Text("Update Profile"),
            ),
            const Divider(),
            const Text('TESTS'),
            ElevatedButton(
                onPressed: () async {
                  log("Begin Test", name: '❗️');
                  final errors = await UserTestService.instance.test([
                    getDataTest,
                    recordPhoneSignInNumberTest,
                    alreadyRegisteredPhoneNumberTest,
                    anonymousSignInTest,
                    displayNameUpdateTest,
                    nameUpdateTest,
                    yearUpdate,
                    birthMonthUpdate,
                    birthDayUpdate,
                    genderUpdate,
                    photoUrlUpdate,
                    stateMessageUpdate,
                    statePhotoUrlUpdate,
                    userDeletetest,
                    userResigntest,
                  ]);

                  debugPrint(
                    "Errors: ${errors.length}",
                  );
                  for (String e in errors) {
                    log(
                      "Error: $e",
                      name: '❌',
                    );
                  }
                },
                child: const Text('TEST ALL')),
            const Divider(),
            ElevatedButton(
              onPressed: () async {
                final refTest = FirebaseDatabase.instance.ref().child("test").child(myUid!);
                await refTest.set({
                  "field1": "val1",
                  "field2": "val2",
                  "field3": "val3",
                });

                debugPrint("==============");
                debugPrint("==============");
                debugPrint("Getting using Get: ");
                final getValue = await refTest.child("field1").get();
                debugPrint("Get Value: ${getValue.value}");
                debugPrint("Getting using Once: ");
                final onceValue = await refTest.child("field1").once();
                debugPrint("Once Value: ${onceValue.snapshot.value}");
                debugPrint("==============");
                debugPrint("Getting null using Get: ");
                final getNullValue = await refTest.child("nullField").get();
                debugPrint("Get Null Value: ${getNullValue.value}");
                debugPrint("Getting null using Once: ");
                final onceNullValue = await refTest.child("nullField").once();
                debugPrint("Once Null Value: ${onceNullValue.snapshot.value}");
              },
              child: const Text("Firebase Get vs Once"),
            ),
            const Divider(),
            ElevatedButton(
              onPressed: recordPhoneSignInNumberTest,
              child: const Text("Record Phone Number Test"),
            ),
            ElevatedButton(
              onPressed: alreadyRegisteredPhoneNumberTest,
              child: const Text("Already Registered Phone Number Test"),
            ),
            const Divider(),
            ElevatedButton(
              onPressed: () async {
                await UserService.instance.signOut();
                await UserTestService.instance.createTestUser();
              },
              child: const Text('Create a user'),
            ),
            ElevatedButton(
              onPressed: deleteFieldTest,
              child: const Text('Delete Field Test'),
            ),
            ElevatedButton(
              onPressed: anonymousSignInTest,
              child: const Text('Anonymous sign in test'),
            ),
            ElevatedButton(
              onPressed: blockUserTest,
              child: const Text('Block user test'),
            ),
            ElevatedButton(
              onPressed: getDataTest,
              child: const Text('Get data'),
            ),
            ElevatedButton(
              onPressed: getFieldTest,
              child: const Text('Get field'),
            ),
            ElevatedButton(
              onPressed: displayNameUpdateTest,
              child: const Text('Update display name'),
            ),
            ElevatedButton(
              onPressed: displayNameUpdateTest,
              child: const Text('Update name'),
            ),
            ElevatedButton(
              onPressed: yearUpdate,
              child: const Text('Update birthYear'),
            ),
            ElevatedButton(
              onPressed: birthMonthUpdate,
              child: const Text('Update birthMonth'),
            ),
            ElevatedButton(
              onPressed: birthDayUpdate,
              child: const Text('Update birthDay'),
            ),
            ElevatedButton(
              onPressed: genderUpdate,
              child: const Text('Update gender'),
            ),
            ElevatedButton(
              onPressed: photoUrlUpdate,
              child: const Text('Update photoUrl'),
            ),
            ElevatedButton(
              onPressed: stateMessageUpdate,
              child: const Text('Update stateMessage'),
            ),
            ElevatedButton(
              onPressed: statePhotoUrlUpdate,
              child: const Text('Update statePhotoUrl'),
            ),
            ElevatedButton(
              onPressed: statePhotoUrlUpdate,
              child: const Text('Update statePhotoUrl'),
            ),
            ElevatedButton(
              onPressed: userDeletetest,
              child: const Text("Delete user"),
            ),
            ElevatedButton(
              onPressed: userResigntest,
              child: const Text("Resign user"),
            ),
            const SafeArea(
              child: SizedBox(
                height: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }

  static const phoneNumber = "+11111111111";
  PhoneAuthCredential? _phoneAuthCredential;

  _logInAs11111111111() async {
    const verificationCode = "111111";

    // Step 1: Sign out any previous session
    await UserService.instance.signOut();

    // Step 2: Start phone number verification
    await FirebaseAuth.instance.verifyPhoneNumber(
      autoRetrievedSmsCodeForTesting: verificationCode,
      phoneNumber: phoneNumber,
      verificationCompleted: (PhoneAuthCredential credential) async {
        await FirebaseAuth.instance.signInWithCredential(credential);
        debugPrint('Auto-sign in completed');
      },
      verificationFailed: (FirebaseAuthException error) {
        debugPrint('Verification failed: ${error.message}');
      },
      codeSent: (String verificationId, int? resendToken) async {
        debugPrint('Code sent. Please enter the verification code.');

        // Wait for the code to be sent and verificationId to be set
        // Step 3: Manually sign in using the verification code and verificationId
        PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: verificationCode,
        );

        // Sign in with the credential
        await FirebaseAuth.instance.signInWithCredential(phoneAuthCredential);

        debugPrint('Phone number successfully verified and signed in.');

        _phoneAuthCredential = phoneAuthCredential;
      },
      codeAutoRetrievalTimeout: (String verificationId) async {
        debugPrint('Auto retrieval timeout. Manual sign-in required.');
        // Wait for the code to be sent and verificationId to be set
        // Step 3: Manually sign in using the verification code and verificationId
        PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.credential(
          verificationId: verificationId,
          smsCode: verificationCode,
        );

        // Sign in with the credential
        await FirebaseAuth.instance.signInWithCredential(phoneAuthCredential);

        _phoneAuthCredential = phoneAuthCredential;
      },
      timeout: const Duration(seconds: 120), // Set the timeout duration
    );
  }

  bool checkTimeWithin30Seconds(int timestamp, int timestamp2) {
    final difference = (timestamp - timestamp2).abs();
    // 30 seconds = 30 * 1000 milliseconds
    if (difference <= 30 * 1000) {
      debugPrint("The timestamp is within 30 seconds of the current time.");
      return true;
    } else {
      debugPrint("The timestamp is not within 30 seconds of the current time.");
      return false;
    }
  }

  recordPhoneSignInNumberTest() async {
    await UserService.instance.signOut();

    // To clear the user-phone-sign-in-numbers node
    await UserService.instance.database.ref('user-phone-sign-in-numbers').set(null);

    await _logInAs11111111111();

    await waitUntil(() async => UserService.instance.user != null);
    final timeNow = DateTime.now().millisecondsSinceEpoch;

    debugPrint("Is it recorded? ${await UserService.instance.isPhoneNumberRegistered(phoneNumber)}");

    final checkRecord = await UserService.instance.database
        .ref()
        .child('user-phone-sign-in-numbers')
        .child(phoneNumber)
        .child("lastSignedInAt")
        .get();

    debugPrint("Last Signed in at: ${checkRecord.value}");

    assert(checkRecord.value != null, "recordPhoneSignInNumberTest: The phone sign in was not recorded.");

    final lastSignedInAt = checkRecord.value as int;

    debugPrint("lastSignedInAt $lastSignedInAt");

    assert(
      checkTimeWithin30Seconds(lastSignedInAt, timeNow),
      "recordPhoneSignInNumberTest: It's either delayed, or not recorded with correct time. Difference: ${(lastSignedInAt - timeNow).abs()}",
    );
  }

  alreadyRegisteredPhoneNumberTest() async {
    // There is no linkingAuthToAnonymous in User Service dart.

    Object? error;
    try {
      // SignOut
      await UserService.instance.signOut();

      // Login anonymously
      await UserService.instance.initAnonymousSignIn();

      // Login as 111 and link
      await _logInAs11111111111();

      await waitUntil(() async => UserService.instance.user != null);
      await FirebaseAuth.instance.currentUser?.linkWithCredential(_phoneAuthCredential!);

      // Sign Out
      await UserService.instance.signOut();

      // Login anonymously
      await UserService.instance.initAnonymousSignIn();

      // Login as 111 and link
      await _logInAs11111111111();

      // Login as 111 and link
      await waitUntil(() async => UserService.instance.user != null);
      await FirebaseAuth.instance.currentUser?.linkWithCredential(_phoneAuthCredential!);
    } catch (e) {
      error = e;
    }
    assert(error == null, "alreadyRegisteredPhoneNumberTest: There is an error: $error");

    if (error == null) {
      log("No error", name: '🟢');
    } else {
      log("ERROR", name: '🔴');
      debugPrint(error.toString());
    }
  }

  deleteFieldTest() async {
    await UserService.instance.signOut();
    final uid1 = await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await Future.delayed(const Duration(milliseconds: 500));

    const testDisplayNameVal = "Test Display Name";
    const testNameVal = "Test Name";

    await my.update(
      displayName: testDisplayNameVal,
      name: testNameVal,
    );

    final myDataUpdate = await User.get(uid1, cache: false);

    assert(
      myDataUpdate?.displayName == testDisplayNameVal,
      "deleteFieldTest: Something went wrong in the middle of testing",
    );
    assert(
      myDataUpdate?.name == testNameVal,
      "deleteFieldTest: Something went wrong in the middle of testing",
    );

    await my.deleteFields([User.field.displayName]);

    await Future.delayed(const Duration(milliseconds: 500));

    final displayNameUpdate = await User.getField(uid: uid1, field: User.field.displayName, cache: false);
    debugPrint("displayNameUpdate: $displayNameUpdate");
    final nameUpdate = await User.getField(uid: uid1, field: User.field.name, cache: false);

    assert(
      displayNameUpdate == null,
      "deleteFieldTest: Display name SHOULD be deleted",
    );

    assert(
      nameUpdate == testNameVal,
      "deleteFieldTest: Name field should NOT be deleted",
    );
  }

  anonymousSignInTest() async {
    await UserService.instance.signOut();
    final originalSetup = UserService.instance.enableAnonymousSignIn;
    UserService.instance.enableAnonymousSignIn = true;
    await UserService.instance.initAnonymousSignIn();

    await waitUntil(() async => UserService.instance.user != null);

    UserService.instance.enableAnonymousSignIn = originalSetup;

    assert(
      i.anonymous,
      "anonymousSignInTest: Unable to login as anonymous",
    );
  }

  blockUserTest() async {
    UnimplementedError("Unable to Unit test because of confirmation");

    // User 1
    await UserService.instance.signOut();
    final uid1 = await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);

    // User 2
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    if (!context.mounted || !mounted) return;

    // Block user 1
    await UserService.instance.block(context: context, otherUid: uid1);

    assert(
      UserService.instance.blocks.containsKey(uid1),
      "blockUserTest: Unable to block user 1, uid: $uid1, myUid: ${my.uid}",
    );
  }

  getDataTest() async {
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);

    final getMy = await User.get(my.uid, cache: false);
    assert(
      getMy != null,
      "getDataTest: User.get failed to get my User",
    );
  }

  getFieldTest() async {
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);

    await Future.delayed(const Duration(milliseconds: 500));

    await UserService.instance.usersRef.child(myUid!).child("testField").set("testing");

    final testField = await User.getField(uid: myUid!, field: "testField");

    debugPrint("testField: $testField");

    final testfield2Once =
        await FirebaseDatabase.instance.ref("users").child(myUid!).child("testField").once();

    debugPrint("testField2: ${testfield2Once.snapshot.value}");

    final testfield2Get =
        await FirebaseDatabase.instance.ref("users").child(myUid!).child("testField").get();

    debugPrint("testField2: ${testfield2Get.value}");
  }

  displayNameUpdateTest() async {
    final displayName = 'newDisplayName:${DateTime.now().millisecond}';
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      displayName: displayName,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.displayName == displayName,
      "uid: ${my.uid}, updated displayName from Database: ${updated.displayName} vs displayName: $displayName",
    );
  }

  nameUpdateTest() async {
    final name = 'newName:${DateTime.now().millisecond}';
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      name: name,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.name == name,
      "nameUpdateTest: uid: ${my.uid}, updated name from Database: ${updated.name} vs name: $name",
    );
  }

  yearUpdate() async {
    final newBirthYear = DateTime.now().millisecond;
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      birthYear: newBirthYear,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.birthYear == newBirthYear,
      "yearUpdate: uid: ${my.uid}, updated birthYear from Database: ${updated.birthYear} vs newBirthYear: $newBirthYear",
    );
  }

  birthMonthUpdate() async {
    final newBirthMonth = DateTime.now().millisecond;
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      birthMonth: newBirthMonth,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.birthMonth == newBirthMonth,
      "birthMonthUpdate: uid: ${my.uid}, updated birthMonth from Database: ${updated.birthMonth} vs newBirthMonth: $newBirthMonth",
    );
  }

  birthDayUpdate() async {
    final newBirthDay = DateTime.now().millisecond;
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      birthDay: newBirthDay,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.birthDay == newBirthDay,
      "birthDayUpdate: uid: ${my.uid}, updated birthDay from Database: ${updated.birthDay} vs newBirthDay: $newBirthDay",
    );
  }

  genderUpdate() async {
    final newGender = ['M', 'F'][Random().nextInt(2)];
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      gender: newGender,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.gender == newGender,
      "genderUpdate: uid: ${my.uid}, updated gender from Database: ${updated.gender} vs newGender: $newGender",
    );
  }

  photoUrlUpdate() async {
    final photoUrl = 'photoUrl:${DateTime.now().millisecond}';
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      photoUrl: photoUrl,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.photoUrl == photoUrl,
      "photoUrlUpdate: uid: ${my.uid}, updated photoUrl from Database: ${updated.photoUrl} vs newGender: $photoUrl",
    );
  }

  stateMessageUpdate() async {
    final stateMessage = 'stateMessage:${DateTime.now().millisecond}';
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      stateMessage: stateMessage,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.stateMessage == stateMessage,
      "stateMessageUpdate: uid: ${my.uid}, updated stateMessage from Database: ${updated.stateMessage} vs stateMessage: $stateMessage",
    );
  }

  statePhotoUrlUpdate() async {
    final statePhotoUrl = 'statePhotoUrl:${DateTime.now().millisecond}';
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    await UserService.instance.user!.update(
      statePhotoUrl: statePhotoUrl,
    );
    final updated = await User.get(my.uid, cache: false);
    assert(
      updated!.statePhotoUrl == statePhotoUrl,
      "statePhotoUrlUpdate: uid: ${my.uid}, updated statePhotoUrl from Database: ${updated.statePhotoUrl} vs statePhotoUrl: $statePhotoUrl",
    );
  }

  userDeletetest() async {
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    final myUid = my.uid;

    await UserService.instance.user!.update(
      name: "test name",
    );
    final checkUpdate = await User.get(myUid, cache: false);
    debugPrint("Check if Updated: ${checkUpdate?.name ?? 'null'}");
    await UserService.instance.user!.delete();
    final deleted = await User.get(myUid, cache: false);
    debugPrint("Check if nulled: ${deleted?.name ?? 'null'}");
    assert(
      deleted == null,
      "userDeletetest: uid: $myUid, deleted from Database: $deleted",
    );
  }

  userResigntest() async {
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);

    await UserService.instance.user!.update(
      name: "test name",
    );

    final oldUid = my.uid;
    final checkUpdate = await User.get(oldUid, cache: false);
    debugPrint("Check if Updated: ${checkUpdate?.name ?? 'null'}");

    debugPrint("Resigning user: ${i.auth.currentUser?.uid}");
    await UserService.instance.resign();

    // Check if deleted
    await UserService.instance.signOut();
    await UserTestService.instance.createTestUser();
    await waitUntil(() async => UserService.instance.user != null);
    final deleted = await User.get(oldUid, cache: false);
    assert(
      deleted == null,
      "userResignTest: uid: $oldUid, deleted from Database: $deleted",
    );
  }
}

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

1 回复

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


当然,作为一个IT专家,我可以为你提供一个关于如何在Flutter项目中使用easy_user插件进行用户管理的代码示例。easy_user是一个假设的插件名称,因为实际上并没有一个广泛知名的名为easy_user的官方Flutter插件。不过,我会根据常见的用户管理功能(如注册、登录、用户信息存储等)给出一个示例代码,你可以根据实际需要和插件的API进行调整。

假设我们有一个名为easy_user的插件,它提供了以下功能:

  • 用户注册(register
  • 用户登录(login
  • 获取当前用户信息(getCurrentUser
  • 登出(logout

以下是一个示例代码,展示了如何使用这个假设的easy_user插件:

import 'package:flutter/material.dart';
import 'package:easy_user/easy_user.dart'; // 假设的插件导入

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Easy User Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: UserManagementScreen(),
    );
  }
}

class UserManagementScreen extends StatefulWidget {
  @override
  _UserManagementScreenState createState() => _UserManagementScreenState();
}

class _UserManagementScreenState extends State<UserManagementScreen> {
  final EasyUser _easyUser = EasyUser(); // 初始化插件实例
  String _userStatus = 'Not Logged In';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('User Management'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'User Status: $_userStatus',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                await _registerUser();
              },
              child: Text('Register'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () async {
                await _loginUser();
              },
              child: Text('Login'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () async {
                await _logoutUser();
              },
              child: Text('Logout'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () async {
                await _getCurrentUser();
              },
              child: Text('Get Current User'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _registerUser() async {
    try {
      // 假设注册需要email和password
      String email = 'test@example.com';
      String password = 'password123';
      await _easyUser.register(email: email, password: password);
      setState(() {
        _userStatus = 'Registered Successfully';
      });
    } catch (e) {
      print('Registration Error: $e');
      setState(() {
        _userStatus = 'Registration Failed';
      });
    }
  }

  Future<void> _loginUser() async {
    try {
      String email = 'test@example.com';
      String password = 'password123';
      await _easyUser.login(email: email, password: password);
      User? user = await _easyUser.getCurrentUser();
      setState(() {
        _userStatus = 'Logged In as ${user?.email ?? 'Unknown'}';
      });
    } catch (e) {
      print('Login Error: $e');
      setState(() {
        _userStatus = 'Login Failed';
      });
    }
  }

  Future<void> _logoutUser() async {
    try {
      await _easyUser.logout();
      setState(() {
        _userStatus = 'Not Logged In';
      });
    } catch (e) {
      print('Logout Error: $e');
      setState(() {
        _userStatus = 'Logout Failed';
      });
    }
  }

  Future<void> _getCurrentUser() async {
    try {
      User? user = await _easyUser.getCurrentUser();
      setState(() {
        _userStatus = 'Current User: ${user?.email ?? 'Not Logged In'}';
      });
    } catch (e) {
      print('Get Current User Error: $e');
      setState(() {
        _userStatus = 'Failed to Get Current User';
      });
    }
  }
}

// 假设的用户模型
class User {
  String? email;
  String? name;
  // 其他用户属性...

  User({this.email, this.name});

  @override
  String toString() {
    return 'User{email: $email, name: $name}';
  }
}

请注意,上述代码是基于假设的easy_user插件API编写的。在实际使用中,你需要根据具体插件的文档来调整代码。例如,实际的插件可能会有不同的方法名称、参数或返回类型。务必参考插件的官方文档来获取正确的API信息。

此外,如果你正在寻找一个实际的Flutter用户管理插件,可以考虑使用如firebase_auth这样的插件,它提供了强大的用户认证功能,并且与Flutter生态系统紧密集成。

回到顶部