8.7 KiB
8.7 KiB
Flutter H5 排行榜对接文档
本文说明 Flutter App 如何打开 H5 排行榜、向 H5 传递登录态,以及接收 H5 通过 JSBridge 发回的导航事件。
入口地址
本地开发:
http://127.0.0.1:30000/rank/index.html?env=local&token={access_token}&app_code=lalu
测试环境:
https://{h5-test-domain}/rank/index.html?env=test&token={access_token}&app_code=lalu
线上环境:
https://{h5-domain}/rank/index.html?token={access_token}&app_code=lalu
env 规则:
| 参数 | 说明 |
|---|---|
| 不传 | H5 请求 https://api.global-interaction.com/ |
env=test |
H5 请求 https://api-test.global-interaction.com/ |
env=local |
H5 请求 http://localhost:13000/,用于本机 gateway 联调 |
URL 参数
| 参数 | 必填 | 说明 |
|---|---|---|
token |
是 | App 登录后拿到的 access token。H5 会作为 Authorization: Bearer <token> 调后端。 |
access_token |
否 | token 的兼容别名。 |
accessToken |
否 | token 的兼容别名。 |
app_code |
是 | App 编码,当前传 lalu。H5 会作为 X-App-Code 请求头。 |
appCode |
否 | app_code 的兼容别名。 |
env |
否 | API 环境切换,见上表。 |
H5 启动后会调用:
GET /api/v1/users/me/overview
Authorization: Bearer <token>
X-App-Code: lalu
这个接口用于确认登录态并缓存当前用户信息。排行榜数据使用同一个 token 和 app code 请求。
H5 页面能力
排行榜页面地址:
/rank/index.html
页面内包含三个榜单,通过 tab 切换:
| H5 Tab | 后端 board_type |
说明 |
|---|---|---|
Wealth |
sent |
财富榜,按用户送礼总金币排行 |
Room |
room |
房间榜,按房间收礼总金币排行 |
Charm |
received |
魅力榜,按用户收礼总金币排行 |
时间维度:
| H5 Tab | 后端 period |
|---|---|
Daily |
today |
Weekly |
week |
Monthly |
month |
排行榜接口:
GET /api/v1/activities/user-leaderboards?board_type=sent&period=today&page=1&page_size=20
Authorization: Bearer <token>
X-App-Code: lalu
H5 会分页加载,page_size=20。如果无 token 或接口失败,页面会展示 Figma 默认占位数据,不阻塞页面打开。
Flutter JSBridge
H5 会按以下优先级尝试发送消息:
window.flutter_inappwebview.callHandler("HyAppBridge", action, payload)window.HyAppBridgeChannel.postMessage(jsonString)window.FlutterBridge.postMessage(jsonString)window.webkit.messageHandlers.HyAppBridge.postMessage({ action, payload })
Flutter 只需要实现其中一种即可。推荐统一注册 HyAppBridge。
消息格式
除 flutter_inappwebview.callHandler 外,postMessage 的消息是 JSON 字符串:
{
"action": "openUser",
"payload": {
"user_id": "10001"
}
}
H5 发出的 action
| action | payload | 触发场景 | Flutter 行为 |
|---|---|---|---|
ready |
{ "page": "rank" } |
H5 初始化完成 | 可关闭加载态 |
back |
{} |
用户点击左上角返回 | 关闭 WebView 或返回上一页 |
openUser |
{ "user_id": "10001" } |
点击财富榜/魅力榜用户头像、榜单项 | 打开用户详情页 |
openRoom |
{ "room_id": "room_id" } |
点击房间榜房间头像、榜单项 | 进入或打开房间详情 |
openRankNote |
{ "board_type": "sent" } |
点击右上角问号 | 当前 H5 已内置说明页;Flutter 可只打点,不需要跳转 |
board_type 取值:
| 值 | 说明 |
|---|---|
sent |
财富榜 |
room |
房间榜 |
received |
魅力榜 |
Flutter 示例
flutter_inappwebview
final url = Uri.parse(
'http://127.0.0.1:30000/rank/index.html'
'?env=local'
'&token=${Uri.encodeComponent(accessToken)}'
'&app_code=lalu',
);
InAppWebView(
initialUrlRequest: URLRequest(url: WebUri(url.toString())),
onWebViewCreated: (controller) {
controller.addJavaScriptHandler(
handlerName: 'HyAppBridge',
callback: (args) async {
final action = args.isNotEmpty ? args[0] as String : '';
final payload = args.length > 1 && args[1] is Map
? Map<String, dynamic>.from(args[1] as Map)
: <String, dynamic>{};
switch (action) {
case 'ready':
// 关闭 loading
break;
case 'back':
Navigator.of(context).maybePop();
break;
case 'openUser':
final userId = payload['user_id']?.toString() ?? '';
if (userId.isNotEmpty) {
// TODO: 打开用户详情页
}
break;
case 'openRoom':
final roomId = payload['room_id']?.toString() ?? '';
if (roomId.isNotEmpty) {
// TODO: 打开房间或房间详情页
}
break;
case 'openRankNote':
// H5 内部已展示说明页,这里可做埋点
break;
}
return {'ok': true};
},
);
},
)
webview_flutter JavaScriptChannel
如果使用 webview_flutter,可以注入 HyAppBridgeChannel:
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'HyAppBridgeChannel',
onMessageReceived: (message) {
final data = jsonDecode(message.message) as Map<String, dynamic>;
final action = data['action']?.toString() ?? '';
final payload = data['payload'] is Map
? Map<String, dynamic>.from(data['payload'] as Map)
: <String, dynamic>{};
switch (action) {
case 'ready':
break;
case 'back':
Navigator.of(context).maybePop();
break;
case 'openUser':
final userId = payload['user_id']?.toString() ?? '';
break;
case 'openRoom':
final roomId = payload['room_id']?.toString() ?? '';
break;
}
},
)
..loadRequest(Uri.parse(rankUrl));
后端依赖
H5 依赖以下 Gateway HTTP 接口:
| 接口 | 说明 |
|---|---|
GET /api/v1/users/me/overview |
解析 token 后获取当前用户信息 |
GET /api/v1/activities/user-leaderboards |
获取排行榜 |
业务接口返回 envelope:
{
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {}
}
H5 也兼容旧的 code: 0 成功格式。
本地联调
在 hyapp-h5 目录运行:
make run
默认打开:
http://127.0.0.1:30000/rank/index.html?env=local
Flutter 真机调本机服务时,env=local 对 H5 来说会请求 http://localhost:13000/。如果 WebView 运行在真机上,localhost 指向手机自身,不是开发机。真机联调建议:
- 使用测试环境
env=test。 - 或把 H5/API 部署到同一局域网可访问地址。
- 或后续给 H5 增加可配置
api_base参数。
验收点
- Flutter 打开 H5 时带上
token和app_code。 - H5 首次加载后发出
ready。 - 点击左上角返回,Flutter 收到
back并关闭 WebView。 - 点击财富榜/魅力榜用户,Flutter 收到
openUser。 - 点击房间榜房间,Flutter 收到
openRoom。 - 切换
Wealth / Room / Charm和Daily / Weekly / Monthly时,H5 正确请求排行榜接口。 - 点击右上角问号,H5 展示说明页,返回后仍停留在排行榜页。