You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter开发中使用SQFLite存储API返回用户数据实现免登录功能失败求助

Hey there! Let's work through getting your Flutter app set up to save user data locally with sqflite and enable auto-login. I'll break this down step by step with concrete code examples, and we can troubleshoot specific issues if you hit snags.


Step 1: Add Required Dependencies

First, make sure your pubspec.yaml includes these packages—sqflite for local database, path_provider to find the storage path, and shared_preferences to track login state:

dependencies:
  flutter:
    sdk: flutter
  sqflite: ^2.3.0
  path_provider: ^2.1.1
  shared_preferences: ^2.2.2

Run flutter pub get to install them.

Step 2: Create a Database Helper Class

This class will handle database initialization, table creation, and all user data operations. It uses a singleton pattern to ensure we only have one database instance:

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

class DatabaseHelper {
  static final _databaseName = "UserDatabase.db";
  static final _databaseVersion = 1;

  // Table and column names
  static final table = 'users';
  static final columnId = 'id';
  static final columnName = 'name';
  static final columnAge = 'age';
  static final columnEmail = 'email'; // Adjust to your login identifier (e.g., username)
  static final columnToken = 'auth_token'; // Use this instead of storing plain text passwords!

  // Singleton instance
  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database? _database;
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }

  // Initialize database
  _initDatabase() async {
    final documentsDir = await getApplicationDocumentsDirectory();
    final path = join(documentsDir.path, _databaseName);
    return await openDatabase(
      path,
      version: _databaseVersion,
      onCreate: _onCreate,
    );
  }

  // Create users table on first run
  Future _onCreate(Database db, int version) async {
    await db.execute('''
      CREATE TABLE $table (
        $columnId INTEGER PRIMARY KEY,
        $columnName TEXT NOT NULL,
        $columnAge INTEGER,
        $columnEmail TEXT UNIQUE NOT NULL,
        $columnToken TEXT NOT NULL
      )
    ''');
  }

  // Insert user data after login/register success
  Future<int> insertUser(Map<String, dynamic> user) async {
    final db = await instance.database;
    // Replace existing user if email matches (for updates)
    return await db.insert(table, user, conflictAlgorithm: ConflictAlgorithm.replace);
  }

  // Fetch user by email (for auto-login)
  Future<Map<String, dynamic>?> getUserByEmail(String email) async {
    final db = await instance.database;
    final results = await db.query(
      table,
      where: '$columnEmail = ?',
      whereArgs: [email],
    );
    return results.isNotEmpty ? results.first : null;
  }

  // Delete user data on logout
  Future<int> deleteUser(int userId) async {
    final db = await instance.database;
    return await db.delete(table, where: '$columnId = ?', whereArgs: [userId]);
  }
}

⚠️ Critical Note: Never store plain-text passwords locally. Use an auth token from your API instead (like JWT)—that's what columnToken is for.

Step 3: Handle Login & Save User Data

After your API returns a successful login response, parse the JSON and save it to the local database, then set the login state:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';

// Example API login call
Future<Map<String, dynamic>> login(String email, String password) async {
  final response = await http.post(
    Uri.parse('https://your-api-endpoint/login'),
    body: {'email': email, 'password': password},
  );

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  } else {
    throw Exception('Login failed: ${response.body}');
  }
}

// Process login success
void handleLoginSuccess(Map<String, dynamic> apiResponse, BuildContext context) async {
  // Map API data to match our database table
  final userMap = {
    DatabaseHelper.columnId: apiResponse['user_id'],
    DatabaseHelper.columnName: apiResponse['name'],
    DatabaseHelper.columnAge: apiResponse['age'],
    DatabaseHelper.columnEmail: apiResponse['email'],
    DatabaseHelper.columnToken: apiResponse['auth_token'], // From your API
  };

  // Save to local database
  await DatabaseHelper.instance.insertUser(userMap);

  // Set login state with shared_preferences
  final prefs = await SharedPreferences.getInstance();
  await prefs.setBool('is_logged_in', true);
  await prefs.setString('current_user_email', apiResponse['email']);

  // Navigate to home screen
  Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeScreen()));
}

Step 4: Implement Auto-Login

Check the login state when the app starts, and skip the login screen if the user is already logged in:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  final prefs = await SharedPreferences.getInstance();
  final isLoggedIn = prefs.getBool('is_logged_in') ?? false;
  final userEmail = prefs.getString('current_user_email');

  runApp(MyApp(
    initialRoute: isLoggedIn && userEmail != null ? '/home' : '/login',
    currentUserEmail: userEmail,
  ));
}

// In your home screen, load the saved user data
class HomeScreen extends StatefulWidget {
  final String? currentUserEmail;
  const HomeScreen({super.key, this.currentUserEmail});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Map<String, dynamic>? userData;

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

  Future<void> _loadUserData() async {
    if (widget.currentUserEmail != null) {
      userData = await DatabaseHelper.instance.getUserByEmail(widget.currentUserEmail!);
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: userData != null
          ? Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Welcome back, ${userData![DatabaseHelper.columnName]}!'),
                Text('User ID: ${userData![DatabaseHelper.columnId]}'),
                Text('Age: ${userData![DatabaseHelper.columnAge]}'),
                ElevatedButton(
                  onPressed: _handleLogout,
                  child: const Text('Logout'),
                ),
              ],
            )
          : const Center(child: CircularProgressIndicator()),
    );
  }

  Future<void> _handleLogout() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool('is_logged_in', false);
    await prefs.remove('current_user_email');
    await DatabaseHelper.instance.deleteUser(userData![DatabaseHelper.columnId]);
    
    Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => LoginScreen()));
  }
}

Common Troubleshooting Tips

If you're still having issues, check these:

  • Database initialization errors: Ensure path_provider is correctly accessing the documents directory (no special permissions needed for Android/iOS).
  • Insert failures: Verify all required fields are populated, and that the email field is unique (your API should return a unique user identifier).
  • Auto-login not working: Double-check that shared_preferences is saving the is_logged_in flag correctly, and that the email stored matches what's in the database.
  • Async issues: Make sure all database and shared_preferences calls use await—forgetting this is a common pitfall.

If you share specific error messages or code snippets that are failing, I can help narrow it down further!

内容的提问来源于stack exchange,提问作者Rishabh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:07:29