【2026版 OpenHarmony】GitCode 口袋工具 v1.0.4:Flutter + OpenHarmony 下基于 shared_preferences 持久化实现本地登录注册
🔐 版本亮点:新增本地账号注册/登录/退出 + 启动鉴权(未登录先登录)+ OpenHarmony 端可持久化(解决
MissingPluginException),并整理了 Windows/DevEco 构建过程中的关键踩坑与修复手段。
一、版本信息
-
版本号:v1.0.4
-
发布日期:2026 年
-
核心更新:本地登录注册、登录态持久化、启动鉴权入口(AuthGate)、OpenHarmony 插件适配(shared_preferences_ohos)、Windows 路径与 DevEco 缓存问题处理
-

二、页面展示
为了方便大家学习,做了一个登录注册的小案例:



本文以一个实际 Flutter 项目为例,完整记录如何在 OpenHarmony 设备上实现一个本地账号登录/注册功能(离线可用),并做到:
-
注册/登录/退出
-
密码不明文保存(salt + sha256)
-
登录态持久化(重启仍保持登录)
-
启动时强制登录(未登录先进入登录页)
-
解决 OpenHarmony 上常见的
shared_preferences MissingPluginException -
解决 Windows 下拉取 OpenHarmony 插件仓库引发的
Filename too long
本文偏“工程实践”,适合:Flutter + OpenHarmony 开发者、需要离线账号体系/本地存储的 App。
三、需求与目标
我们希望实现一个简单、可用、可落地的本地账号体系:
-
注册:输入用户名/密码,创建本地用户,并自动登录。
-
登录:输入用户名/密码,校验成功后写入登录态。
-
退出:清除登录态。
-
启动鉴权:进入应用先检查是否已登录;未登录则只能进入登录/注册页面。
-
数据持久化:用户表/登录态落盘保存。
为什么需要本地数据持久化?
在 OpenHarmony 上,持久化常见用途包括:
-
用户偏好设置(主题/语言等)
-
应用状态(登录态、阅读进度)
-
离线缓存(接口响应、列表数据)
如果不做持久化,登录态会随进程退出而丢失,用户体验较差。
四、核心实现概览
本次功能拆分为 4 个模块:
-
依赖与 OpenHarmony 适配:通过
dependency_overrides让 OpenHarmony 端拥有shared_preferences的 OHOS 实现 -
LocalAuthService:本地用户表/会话的读写与校验
-
Login/Register UI:表单校验 + 错误提示 + 注册后自动登录
-
AuthGate:启动入口页,未登录先进入登录页,已登录进入主导航
五、方案选型
5.1 账号数据存储
本例选择“最轻量”的键值存储,存两类数据:
-
local_auth_users_v1:用户表(JSON) -
local_auth_current_user_v1:当前登录用户(会话)
数据量很小(<= 几 KB),键值存储即可满足。

5.2 密码安全
密码不保存明文,使用:
-
salt:随机 16 字节 -
hash:sha256(salt + '::' + password)
这样即使本地数据被读取也不会直接泄露密码。
六、OpenHarmony 的关键坑:shared_preferences MissingPluginException
在 OpenHarmony 环境中,直接使用 Flutter 生态常见插件(如 shared_preferences)可能遇到:
MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)
这通常意味着:当前 OpenHarmony 运行时没有该插件的平台实现。
6.1 正确做法:使用 OpenHarmony-SIG 的 ohos 实现(推荐)
OpenHarmony 社区通常会维护一套 flutter_packages 仓库,提供插件的 OHOS 适配实现。
本文做法是(重点):
-
代码层继续使用标准
shared_preferencesAPI(Dart 代码不写平台分支) -
通过
dependency_overrides将shared_preferences/shared_preferences_ohos指向 OpenHarmony-SIG 的 OHOS 实现目录
这样 Dart 代码无需写平台判断,OpenHarmony 上会自动使用 OHOS 平台实现。
GitCode对应仓库连接:flutter_packages - AtomGit | GitCode

Gitee仓库对应链接:flutter_packages

七、Windows 的关键坑:Filename too long
如果直接用:
dependency_overrides:
shared_preferences:
git:
url: https://gitee.com/openharmony-sig/flutter_packages.git
ref: xxx
path: ...
在 Windows 下,pub 会把大仓库拉到 .pub-cache 深层目录,容易触发:
Filename too long
7.1 解决方案:本地路径 clone + path 覆盖
推荐两种方式(按稳定性排序):
-
克隆到短路径(最稳,避免 Windows
Filename too long) -
克隆到项目当前目录(更方便,但项目路径很长时可能触发
Filename too long)
如果你使用“项目当前目录”方案并遇到
Filename too long:
方案 A:改用短路径(例如
E:\fp\flutter_packages)方案 B:启用 Windows 长路径支持,并设置:
git config --global core.longpaths true
八、实现本地登录/注册(代码结构)
本文实现分为四块:
-
依赖配置
-
Auth Service(本地认证与持久化)
-
登录/注册 UI
-
启动鉴权 AuthGate
8.1 添加依赖
8.1.1 密码哈希依赖

在 pubspec.yaml 增加:
dependencies:
crypto: ^3.0.3
shared_preferences: ^2.3.2
8.1.2 OpenHarmony 持久化:dependency_overrides(关键)
在项目 pubspec.yaml 底部加入(示例:克隆到项目当前目录 ./flutter_packages):

dependency_overrides:
shared_preferences:
path: ./flutter_packages/packages/shared_preferences/shared_preferences
shared_preferences_ohos:
path: ./flutter_packages/packages/shared_preferences/shared_preferences_ohos
然后在本机执行:
重要:以下命令都需要在「项目根目录」执行,也就是看到类似提示符:
E:\FlutterOpenHarmony\gitcode_pocket_tool>
8.1.2.1 Windows CMD(一行复制版)推荐

git clone -b br_shared_preferences-v2.3.2_ohos https://gitee.com/openharmony-sig/flutter_packages.git flutter_packages
flutter pub get
flutter analyze
8.1.2.2 Windows PowerShell(一行复制版)
git clone -b br_shared_preferences-v2.3.2_ohos https://gitee.com/openharmony-sig/flutter_packages.git .\flutter_packages
flutter pub get
flutter analyze
8.1.2.3 Bash / Git-Bash(支持 \ 续行)
git clone -b br_shared_preferences-v2.3.2_ohos \
https://gitee.com/openharmony-sig/flutter_packages.git \
./flutter_packages
flutter pub get
flutter analyze
如果你在 Windows 上遇到
Filename too long:
方案 A:把仓库克隆到短路径(例如
E:\fp\flutter_packages),然后把dependency_overrides的path:改成短路径方案 B:启用 Windows 长路径支持,并设置
git config --global core.longpaths true
8.1.3 快速自检:确认 overrides 生效
执行 flutter pub get 后,终端应该出现类似输出(关键是 overridden):
! shared_preferences ... (overridden)
! shared_preferences_ohos ... (overridden)
如果你使用的是别的分支名,请先
git branch -a查看。
8.2 实现 LocalAuthService(注册/登录/退出/持久化)
新建文件:
-
lib/core/local_auth_service.dart
核心要点:
-
用户表以 JSON 存在
shared_preferences -
当前用户(会话)以 JSON 存在
shared_preferences -
密码使用 salt + sha256
数据结构示例:
{
"yixuan": {
"salt": "...",
"hash": "...",
"createdAt": "2026-01-26T..."
}
}
关键 API 设计:
-
Future<LocalUser?> currentUser() -
Future<LocalUser> register({username, password}) -
Future<LocalUser> login({username, password}) -
Future<void> logout()
8.2.1 关键代码(可直接复用)
下面给出最关键的实现片段(完整实现见 lib/core/local_auth_service.dart)。
8.2.1.1 数据 Key
static const _usersKey = 'local_auth_users_v1';
static const _currentUserKey = 'local_auth_current_user_v1';
8.2.1.2 密码 hash:salt + sha256
String _generateSalt() {
final random = Random.secure();
final bytes = List<int>.generate(16, (_) => random.nextInt(256));
return base64UrlEncode(bytes);
}
String _hashPassword({required String password, required String salt}) {
final bytes = utf8.encode('$salt::$password');
return sha256.convert(bytes).toString();
}
8.2.1.3 注册(写入 users + currentUser)
Future<LocalUser> register({required String username, required String password}) async {
final normalized = username.trim();
if (normalized.length < 3) throw const LocalAuthException('用户名至少 3 位');
if (password.length < 6) throw const LocalAuthException('密码至少 6 位');
final users = await _loadUsers();
if (users.containsKey(normalized)) throw const LocalAuthException('该用户名已存在');
final salt = _generateSalt();
final hash = _hashPassword(password: password, salt: salt);
users[normalized] = {
'salt': salt,
'hash': hash,
'createdAt': DateTime.now().toIso8601String(),
};
await _saveUsers(users);
final user = LocalUser(username: normalized);
await _setString(_currentUserKey, jsonEncode(user.toJson()));
return user;
}
8.2.1.4 登录(校验 hash + 写入 currentUser)
Future<LocalUser> login({required String username, required String password}) async {
final normalized = username.trim();
if (normalized.isEmpty) throw const LocalAuthException('用户名不能为空');
if (password.isEmpty) throw const LocalAuthException('密码不能为空');
final users = await _loadUsers();
final record = users[normalized];
if (record is! Map<String, dynamic>) throw const LocalAuthException('用户名或密码错误');
final salt = record['salt'];
final hash = record['hash'];
if (salt is! String || hash is! String) throw const LocalAuthException('用户数据损坏,请重新注册');
final inputHash = _hashPassword(password: password, salt: salt);
if (inputHash != hash) throw const LocalAuthException('用户名或密码错误');
final user = LocalUser(username: normalized);
await _setString(_currentUserKey, jsonEncode(user.toJson()));
return user;
}
8.2.1.5 读取当前登录用户(启动鉴权依赖它)
Future<LocalUser?> currentUser() async {
final raw = await _getString(_currentUserKey);
if (raw == null || raw.isEmpty) return null;
try {
final map = jsonDecode(raw);
if (map is! Map<String, dynamic>) return null;
return LocalUser.fromJson(map);
} catch (_) {
return null;
}
}
8.3 实现登录/注册页面
新增文件:
-
lib/pages/login_page.dart -
lib/pages/register_page.dart
实现点:
-
表单校验:用户名、密码长度
-
Loading 状态
-
错误展示(
LocalAuthException.message) -
注册成功后自动登录
8.3.1 让 LoginPage 既能“push/pop”也能当“应用入口”
为了实现“启动必须登录”,我们给 LoginPage 增加可选回调:
-
ValueChanged<LocalUser>? onLoggedIn
行为规则:
-
如果
onLoggedIn != null:登录/注册成功时调用回调,不执行Navigator.pop() -
否则:保持原逻辑
Navigator.pop(user)
8.3.1.1 关键代码:onLoggedIn 回调
class LoginPage extends StatefulWidget {
const LoginPage({super.key, this.onLoggedIn});
final ValueChanged<LocalUser>? onLoggedIn;
// ...
}
void _complete(LocalUser user) {
final callback = widget.onLoggedIn;
if (callback != null) {
callback(user);
return;
}
Navigator.of(context).pop<LocalUser>(user);
}
8.4 实现启动鉴权 AuthGate(启动必须登录)
在 lib/main.dart 里实现:
-
AuthGatePage
逻辑:
-
App 启动时进入
AuthGatePage -
AuthGatePage调用LocalAuthService.currentUser() -
若返回
null:展示LoginPage(onLoggedIn: ...) -
若返回用户:进入
MainNavigationPage
并将 MaterialApp(home: ...) 改为:
-
home: const AuthGatePage()
这样用户无法绕过登录页。
8.4.1 关键代码:AuthGatePage(启动检查 currentUser)
以下为核心逻辑片段(完整实现见 lib/main.dart):
class AuthGatePage extends StatefulWidget {
const AuthGatePage({super.key});
@override
State<AuthGatePage> createState() => _AuthGatePageState();
}
class _AuthGatePageState extends State<AuthGatePage> {
final _auth = LocalAuthService();
bool _checking = true;
LocalUser? _user;
String? _error;
@override
void initState() {
super.initState();
_check();
}
Future<void> _check() async {
setState(() {
_checking = true;
_error = null;
});
try {
final user = await _auth.currentUser();
if (!mounted) return;
setState(() {
_user = user;
_checking = false;
});
} catch (e) {
if (!mounted) return;
setState(() {
_error = '$e';
_checking = false;
});
}
}
void _handleLoggedIn(LocalUser user) {
setState(() {
_user = user;
});
}
@override
Widget build(BuildContext context) {
if (_checking) return const Scaffold(body: Center(child: CircularProgressIndicator()));
if (_error != null) return Scaffold(body: Center(child: Text(_error!)));
if (_user == null) return LoginPage(onLoggedIn: _handleLoggedIn);
return const MainNavigationPage();
}
}
九、验证与测试清单
9.1 功能验证
-
首次启动:进入登录页
-
注册:创建用户并自动登录
-
登录:校验成功进入主页面
-
退出:清除登录态
-
重启:若未退出,仍保持登录态
9.2 OpenHarmony 持久化验证
9.2.1 执行指令:依赖与静态检查
flutter pub get
flutter analyze
9.2.2 运行与验证步骤
-
安装并启动 App
-
由于启用了启动鉴权(AuthGate),未登录会直接进入登录页
-
注册或登录成功后进入主页面
-
完全退出 App(从后台划掉)
-
再次启动 App
-
预期:直接进入主页面(登录态已持久化)
-
在 OHOS 设备上注册并登录
-
杀进程 / 重启 App
-
应用应直接进入主页面(AuthGate 检测到 currentUser 不为空)
十、验证与工具
-
flutter pub get:拉取依赖并生成插件映射 -
flutter analyze:确保 0 issue -
DevEco Studio:
Clean Project+Rebuild Project用于清理 hvigor 缓存路径
十一、常见问题(FAQ)
11.1 仍然出现 MissingPluginException?
-
检查
dependency_overrides是否生效(flutter pub get输出中应看到 overridden) -
确认本地
flutter_packages的路径是否正确 -
确认 OHOS 分支是否与你 Flutter/OHOS 版本匹配
11.2 Windows 还是 Filename too long?
-
不要用
git:覆盖(会进入.pub-cache深目录) -
一定使用本地短路径 clone +
path:覆盖
11.3 登录态没保持?
-
检查
LocalAuthService是否在登录/注册成功后写入_currentUserKey -
在 OHOS 上优先确保 shared_preferences 插件实现已正确接入
十二、总结
通过以上步骤,我们在 Flutter(OpenHarmony) 项目里实现了:
-
本地注册/登录/退出
-
密码安全存储(salt + sha256)
-
OpenHarmony 可用的 shared_preferences 持久化
-
启动鉴权(未登录先登录)
-
Windows/镜像/插件适配的工程踩坑与解决方案
你可以在此基础上继续扩展:
-
账号删除/修改密码
-
更严格的密码策略
-
敏感数据加密(结合 OHOS 安全组件)
-
本地缓存(Hive/SQLite)
十三、关键改动一览
| 模块/文件 | 主要工作 |
|---|---|
pubspec.yaml |
增加 dependency_overrides 指向 ./flutter_packages/...,让 OpenHarmony 使用 OHOS 实现;并补充 Windows/CMD/PowerShell 命令说明 |
lib/core/local_auth_service.dart |
本地用户表/会话存储,密码 salt + sha256,提供 register/login/logout/currentUser |
lib/pages/login_page.dart |
增加 onLoggedIn 回调,既支持“页面 pop 返回”也支持“作为启动入口” |
lib/pages/register_page.dart |
注册后自动登录返回用户 |
lib/main.dart |
新增 AuthGatePage 作为 home,启动检查登录态 |
lib/pages/main_navigation/profile_page.dart |
“我的”页展示本地账号模块,并调整到个人信息卡片上方 |
| DevEco/hvigor | 增加清理策略:Clean/Rebuild + flutter clean 解决旧路径缓存 |
十四、升级指南(从旧版本升级到 v1.0.4)
-
git pull获取最新代码 -
在项目根目录执行(Windows CMD 一行版):
git clone -b br_shared_preferences-v2.3.2_ohos https://gitee.com/openharmony-sig/flutter_packages.git flutter_packages
flutter pub get
flutter analyze
DevEco Studio:
-
Build->Clean Project -
Build->Rebuild Project
运行验证:
-
首次启动进入登录页
-
注册/登录后进入主页面
-
杀进程重启仍保持登录态
十五、下一站
- 退出登录后全局回到登录页(并清理主页面堆栈)
- 支持修改密码/删除账号
- 敏感信息加密存储(结合 OpenHarmony 安全组件)
- 本地缓存(Hive/SQLite)与离线模式
欢迎加入开源鸿蒙跨平台社区:开源鸿蒙跨平台开发者社区!
更多推荐




所有评论(0)