Flutter三方库适配OpenHarmony【flutter_web_auth】— 示例应用开发与 OAuth2 实战接入
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net前面 15 篇讲了原理和源码,这篇来点实际的——从零搭建一个示例应用,接入 GitHub OAuth 登录,在 OpenHarmony 真机上跑通完整流程。代码可以直接复制到项目里用。项目结构:Dart 代码 + 宿主配置 + EntryAbility 集成OAuth2 URL 构造宿主配
·
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
前面 15 篇讲了原理和源码,这篇来点实际的——从零搭建一个示例应用,接入 GitHub OAuth 登录,在 OpenHarmony 真机上跑通完整流程。代码可以直接复制到项目里用。
一、example 项目结构
1.1 目录结构
example/
├── lib/
│ └── main.dart # 示例应用主文件
├── ohos/
│ └── entry/
│ └── src/
│ └── main/
│ ├── ets/
│ │ └── entryability/
│ │ └── EntryAbility.ets # 宿主 Ability
│ └── module.json5 # 宿主配置
├── android/
│ └── app/
│ └── src/
│ └── main/
│ └── AndroidManifest.xml
└── pubspec.yaml
1.2 关键文件
| 文件 | 作用 | 需要修改 |
|---|---|---|
| main.dart | 示例 UI 和认证逻辑 | ✅ |
| EntryAbility.ets | 深度链接回调转发 | ✅ |
| module.json5 | skills 和权限配置 | ✅ |
| AndroidManifest.xml | Intent Filter 配置 | ✅ |
二、构造 OAuth2 授权 URL
2.1 GitHub OAuth 参数
| 参数 | 值 | 说明 |
|---|---|---|
| client_id | 在 GitHub 注册获取 | 应用标识 |
| redirect_uri | myapp://callback |
回调地址 |
| scope | read:user |
请求的权限 |
| state | 随机字符串 | 防 CSRF |
2.2 构造 URL
import 'dart:math';
String _generateState() {
final random = Random.secure();
return List.generate(32, (_) => random.nextInt(16).toRadixString(16)).join();
}
final state = _generateState();
final authUrl = Uri.https('github.com', '/login/oauth/authorize', {
'client_id': 'your_github_client_id',
'redirect_uri': 'myapp://callback',
'scope': 'read:user',
'state': state,
});
2.3 Google OAuth 参数
final googleAuthUrl = Uri.https('accounts.google.com', '/o/oauth2/v2/auth', {
'response_type': 'code',
'client_id': 'your_google_client_id.apps.googleusercontent.com',
'redirect_uri': 'com.googleusercontent.apps.your-client-id:/',
'scope': 'email profile',
'state': state,
});
📌 Google OAuth 的 callbackUrlScheme 格式比较特殊:
com.googleusercontent.apps.{client_id}。注意这个 Scheme 全是小写字母和点号,符合 RFC 3986。
三、callbackUrlScheme 在宿主应用中的配置
3.1 OpenHarmony module.json5
{
"module": {
"name": "entry",
"type": "entry",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"launchType": "singleton",
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
},
{
"entities": ["entity.system.browsable"],
"actions": ["ohos.want.action.viewData"],
"uris": [{ "scheme": "myapp" }]
}
]
}
],
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
}
}
3.2 Android AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity"
android:exported="true">
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>
</application>
</manifest>
3.3 配置检查清单
- OpenHarmony: skills 中 uris.scheme = “myapp”
- OpenHarmony: launchType = “singleton”
- OpenHarmony: requestPermissions 包含 INTERNET
- Android: CallbackActivity 的 data.scheme = “myapp”
- 两端的 Scheme 与 Dart 代码中的 callbackUrlScheme 一致
四、EntryAbility.ets 集成代码
4.1 完整代码
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import { AbilityConstant, Want } from '@kit.AbilityKit';
import FlutterWebAuthPlugin from 'flutter_web_auth';
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine);
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam);
FlutterWebAuthPlugin.onNewWant(want);
}
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam);
FlutterWebAuthPlugin.onNewWant(want);
}
}
4.2 关键点
| 要点 | 说明 |
|---|---|
| import FlutterWebAuthPlugin | 从包名导入,不是文件路径 |
| super.onNewWant | 必须调用,不能遗漏 |
| onCreate 也处理 | 覆盖冷启动场景 |
五、完整示例应用代码
5.1 main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_auth/flutter_web_auth.dart';
import 'dart:math';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Web Auth Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const AuthPage(),
);
}
}
class AuthPage extends StatefulWidget {
const AuthPage({super.key});
State<AuthPage> createState() => _AuthPageState();
}
class _AuthPageState extends State<AuthPage> {
String _status = '未登录';
String _userInfo = '';
bool _isLoading = false;
String _generateState() {
final random = Random.secure();
return List.generate(32, (_) => random.nextInt(16).toRadixString(16)).join();
}
Future<void> _loginWithGitHub() async {
setState(() {
_isLoading = true;
_status = '正在认证...';
});
final state = _generateState();
const clientId = 'your_github_client_id';
const callbackScheme = 'myapp';
final authUrl = Uri.https('github.com', '/login/oauth/authorize', {
'client_id': clientId,
'redirect_uri': '$callbackScheme://callback',
'scope': 'read:user',
'state': state,
});
try {
final result = await FlutterWebAuth.authenticate(
url: authUrl.toString(),
callbackUrlScheme: callbackScheme,
);
final returnedState = Uri.parse(result).queryParameters['state'];
if (returnedState != state) {
throw Exception('State 不匹配,可能存在 CSRF 攻击');
}
final code = Uri.parse(result).queryParameters['code'];
setState(() {
_status = '获取到授权码';
_userInfo = 'code: ${code?.substring(0, 10)}...';
});
} on PlatformException catch (e) {
setState(() {
if (e.code == 'CANCELED') {
_status = '用户取消了登录';
} else {
_status = '登录失败: ${e.code}';
_userInfo = e.message ?? '';
}
});
} catch (e) {
setState(() {
_status = '错误: $e';
});
} finally {
setState(() => _isLoading = false);
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter Web Auth Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_status, style: const TextStyle(fontSize: 18)),
if (_userInfo.isNotEmpty)
Padding(
padding: const EdgeInsets.all(16),
child: Text(_userInfo, style: const TextStyle(fontSize: 14, color: Colors.grey)),
),
const SizedBox(height: 32),
ElevatedButton(
onPressed: _isLoading ? null : _loginWithGitHub,
child: _isLoading
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Text('使用 GitHub 登录'),
),
],
),
),
);
}
}
5.2 UI 状态流转
| 状态 | 显示 | 按钮 |
|---|---|---|
| 初始 | “未登录” | 可点击 |
| 认证中 | “正在认证…” | 禁用 + loading |
| 成功 | “获取到授权码” + code | 可点击 |
| 取消 | “用户取消了登录” | 可点击 |
| 失败 | “登录失败: {code}” | 可点击 |
六、GitHub OAuth 完整接入
6.1 注册 GitHub OAuth App
- 打开 https://github.com/settings/developers
- 点击 “New OAuth App”
- 填写信息:
| 字段 | 值 |
|---|---|
| Application name | My Flutter App |
| Homepage URL | https://example.com |
| Authorization callback URL | myapp://callback |
- 获取 Client ID 和 Client Secret
6.2 用 code 换 token
Future<String> _exchangeCodeForToken(String code) async {
final response = await http.post(
Uri.https('github.com', '/login/oauth/access_token'),
headers: {'Accept': 'application/json'},
body: {
'client_id': 'your_client_id',
'client_secret': 'your_client_secret', // ⚠️ 不应在客户端
'code': code,
},
);
final data = jsonDecode(response.body);
return data['access_token'] as String;
}
⚠️ client_secret 不应该放在客户端代码中。生产环境应该通过后端服务器来换取 token。这里只是演示用途。
6.3 获取用户信息
Future<Map<String, dynamic>> _getUserInfo(String token) async {
final response = await http.get(
Uri.https('api.github.com', '/user'),
headers: {'Authorization': 'Bearer $token'},
);
return jsonDecode(response.body);
}
七、在 OpenHarmony 真机上运行
7.1 环境要求
| 要求 | 版本 |
|---|---|
| Flutter-OHOS SDK | 3.35.7-dev |
| DevEco Studio | 6.0.2 Release |
| OpenHarmony SDK | API 20 |
| 设备 ROM | 6.0.0.130 SP8 |
7.2 运行步骤
# 1. 获取依赖
flutter pub get
# 2. 连接设备
hdc list targets
# 3. 运行
flutter run -d <device_id>
7.3 验证流程
- 点击"使用 GitHub 登录"按钮
- 系统浏览器打开 GitHub 登录页面
- 输入 GitHub 账号密码(或使用已登录的会话)
- 点击"Authorize"授权
- 浏览器重定向到
myapp://callback?code=xxx&state=xxx - App 自动回到前台,显示授权码
7.4 常见运行问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 浏览器不打开 | INTERNET 权限未声明 | 检查 module.json5 |
| 回调不触发 | skills 配置错误 | 检查 Scheme 拼写 |
| App 没有回到前台 | launchType 不是 singleton | 修改为 singleton |
| onNewWant 不调用 | EntryAbility 未集成 | 添加 onNewWant 方法 |
总结
本文完成了 flutter_web_auth 的示例应用开发:
- 项目结构:Dart 代码 + 宿主配置 + EntryAbility 集成
- OAuth2 URL 构造:client_id + redirect_uri + scope + state
- 宿主配置:module.json5 的 skills + INTERNET 权限
- 完整 UI:状态管理 + loading + 错误处理
- 真机运行:环境要求 + 运行步骤 + 常见问题
下一篇我们做四平台认证机制的横向对比。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- GitHub OAuth 文档
- Google OAuth2 文档
- flutter_web_auth Gitcode
- flutter_web_auth README
- http 包
- OpenHarmony 开发环境
- Flutter-OHOS 项目
- 开源鸿蒙跨平台社区

flutter_web_auth 示例应用认证流程
更多推荐


所有评论(0)