feat: deepLink

This commit is contained in:
guozhigq
2024-10-13 23:00:32 +08:00
parent be316f1c69
commit 47ec38b465
12 changed files with 235 additions and 121 deletions

View File

@ -1,3 +1,4 @@
import 'package:app_links/app_links.dart';
import 'package:appscheme/appscheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -10,22 +11,29 @@ import 'url_utils.dart';
import 'utils.dart';
class PiliSchame {
static late AppLinks appLinks;
static AppScheme appScheme = AppSchemeImpl.getInstance()!;
static Future<void> init() async {
///
final SchemeEntity? value = await appScheme.getInitScheme();
if (value != null) {
_routePush(value);
}
appLinks = AppLinks();
appLinks.uriLinkStream.listen((Uri uri) {
final String scheme = uri.scheme;
if (RegExp(r'^pili', caseSensitive: false).hasMatch(scheme)) {
piliScheme(uri);
}
});
appScheme.getInitScheme().then((SchemeEntity? value) {
if (value != null) {
_routePush(value);
}
});
/// 完整链接进入 b23.无效
appScheme.getLatestScheme().then((SchemeEntity? value) {
if (value != null) {
_routePush(value);
}
});
/// 注册从外部打开的Scheme监听信息 #
appScheme.registerSchemeListener().listen((SchemeEntity? event) {
if (event != null) {
_routePush(event);
@ -36,88 +44,11 @@ class PiliSchame {
/// 路由跳转
static void _routePush(value) async {
final String scheme = value.scheme;
final String host = value.host;
final String path = value.path;
if (scheme == 'bilibili') {
switch (host) {
case 'root':
Navigator.popUntil(
Get.context!, (Route<dynamic> route) => route.isFirst);
break;
case 'space':
final String mid = path.split('/').last;
Get.toNamed<dynamic>(
'/member?mid=$mid',
arguments: <String, dynamic>{'face': null},
);
break;
case 'video':
String pathQuery = path.split('/').last;
final numericRegex = RegExp(r'^[0-9]+$');
if (numericRegex.hasMatch(pathQuery)) {
pathQuery = 'AV$pathQuery';
}
Map map = IdUtils.matchAvorBv(input: pathQuery);
if (map.containsKey('AV')) {
_videoPush(map['AV'], null);
} else if (map.containsKey('BV')) {
_videoPush(null, map['BV']);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'live':
final String roomId = path.split('/').last;
Get.toNamed<dynamic>(
'/liveRoom?roomid=$roomId',
arguments: <String, String?>{'liveItem': null, 'heroTag': roomId},
);
break;
case 'bangumi':
if (path.startsWith('/season')) {
final String seasonId = path.split('/').last;
RoutePush.bangumiPush(int.parse(seasonId), null);
}
break;
case 'opus':
if (path.startsWith('/detail')) {
var opusId = path.split('/').last;
Get.toNamed('/opus', parameters: {
'title': '',
'id': opusId,
'articleType': 'opus',
});
}
break;
case 'search':
Get.toNamed('/searchResult', parameters: {'keyword': ''});
break;
case 'article':
final String id = path.split('/').last.split('?').first;
Get.toNamed(
'/read',
parameters: {
'title': 'cv$id',
'id': id,
'dynamicType': 'read',
},
);
break;
case 'pgc':
if (path.contains('ep')) {
final String lastPathSegment = path.split('/').last;
RoutePush.bangumiPush(
null, int.parse(lastPathSegment.split('?').first));
}
break;
default:
SmartDialog.showToast('未匹配地址,请联系开发者');
Clipboard.setData(ClipboardData(text: value.toJson().toString()));
break;
}
biliScheme(value);
}
if (scheme == 'https') {
fullPathPush(value);
httpsScheme(value);
}
}
@ -148,7 +79,7 @@ class PiliSchame {
}
}
static Future<void> fullPathPush(SchemeEntity value) async {
static Future<void> httpsScheme(SchemeEntity value) async {
// https://m.bilibili.com/bangumi/play/ss39708
// https | m.bilibili.com | /bangumi/play/ss39708
// final String scheme = value.scheme!;
@ -281,6 +212,134 @@ class PiliSchame {
}
}
static Future<void> biliScheme(SchemeEntity value) async {
final String host = value.host!;
final String path = value.path!;
switch (host) {
case 'root':
Navigator.popUntil(
Get.context!, (Route<dynamic> route) => route.isFirst);
break;
case 'space':
final String mid = path.split('/').last;
Get.toNamed<dynamic>(
'/member?mid=$mid',
arguments: <String, dynamic>{'face': null},
);
break;
case 'video':
String pathQuery = path.split('/').last;
final numericRegex = RegExp(r'^[0-9]+$');
if (numericRegex.hasMatch(pathQuery)) {
pathQuery = 'AV$pathQuery';
}
Map map = IdUtils.matchAvorBv(input: pathQuery);
if (map.containsKey('AV')) {
_videoPush(map['AV'], null);
} else if (map.containsKey('BV')) {
_videoPush(null, map['BV']);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'live':
final String roomId = path.split('/').last;
Get.toNamed<dynamic>(
'/liveRoom?roomid=$roomId',
arguments: <String, String?>{'liveItem': null, 'heroTag': roomId},
);
break;
case 'bangumi':
if (path.startsWith('/season')) {
final String seasonId = path.split('/').last;
RoutePush.bangumiPush(int.parse(seasonId), null);
}
break;
case 'opus':
if (path.startsWith('/detail')) {
var opusId = path.split('/').last;
Get.toNamed('/opus', parameters: {
'title': '',
'id': opusId,
'articleType': 'opus',
});
}
break;
case 'search':
Get.toNamed('/searchResult', parameters: {'keyword': ''});
break;
case 'article':
final String id = path.split('/').last.split('?').first;
Get.toNamed(
'/read',
parameters: {
'title': 'cv$id',
'id': id,
'dynamicType': 'read',
},
);
break;
case 'pgc':
if (path.contains('ep')) {
final String lastPathSegment = path.split('/').last;
RoutePush.bangumiPush(
null, int.parse(lastPathSegment.split('?').first));
}
break;
default:
SmartDialog.showToast('未匹配地址,请联系开发者');
Clipboard.setData(ClipboardData(text: value.toJson().toString()));
break;
}
}
static Future<void> piliScheme(Uri value) async {
final String host = value.host;
final String path = value.path;
final String arg = path.split('/').last;
switch (host) {
case 'home':
case 'root':
Get.toNamed('/');
break;
case 'member':
if (arg != '') {
Get.toNamed<dynamic>(
'/member?mid=$arg',
arguments: <String, dynamic>{'face': null},
);
} else {
Get.toNamed('/mine');
}
break;
case 'search':
if (arg != '') {
Get.toNamed('/searchResult', parameters: {'keyword': arg});
} else {
Get.toNamed('/search');
}
break;
case 'setting':
Get.toNamed('/setting');
break;
case 'fav':
Get.toNamed('/fav');
break;
case 'history':
Get.toNamed('/history');
break;
case 'later':
Get.toNamed('/later');
break;
case 'msg':
Get.toNamed('/whisper');
break;
default:
Get.toNamed('/');
break;
}
}
static void _handleEpisodePath(String lastPathSegment, String redirectUrl) {
final String seasonId = _extractIdFromPath(lastPathSegment);
RoutePush.bangumiPush(null, Utils.matchNum(seasonId).first);