Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
ethan
/
appframe
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit 2a473bd2
authored
2026-02-05 16:45:19 +0800
by
Administrator
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge branch 'feature-2601-inst' into feature-2601-testing
2 parents
62cba1b0
3f77682b
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
225 additions
and
42 deletions
lib/bloc/link_cubit.dart
lib/bloc/web_cubit.dart
lib/config/locator.dart
lib/config/routes.dart
lib/data/repositories/message/open_link_handler.dart
lib/data/repositories/message/screen_handler.dart
lib/services/dispatcher.dart
lib/ui/pages/link_page.dart
lib/bloc/link_cubit.dart
View file @
2a473bd
import
'dart:convert'
;
import
'package:appframe/config/routes.dart'
;
import
'package:appframe/config/routes.dart'
;
import
'package:equatable/equatable.dart'
;
import
'package:equatable/equatable.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:webview_flutter/webview_flutter.dart'
;
import
'package:webview_flutter/webview_flutter.dart'
;
...
@@ -8,22 +11,26 @@ class LinkState extends Equatable {
...
@@ -8,22 +11,26 @@ class LinkState extends Equatable {
final
bool
loaded
;
final
bool
loaded
;
final
String
url
;
final
String
url
;
final
String
title
;
final
String
title
;
final
int
screenType
;
// 1: 竖屏, 2: 横屏
const
LinkState
({
const
LinkState
({
this
.
loaded
=
false
,
this
.
loaded
=
false
,
this
.
url
=
''
,
this
.
url
=
''
,
this
.
title
=
''
,
this
.
title
=
''
,
this
.
screenType
=
1
,
});
});
LinkState
copyWith
({
LinkState
copyWith
({
bool
?
loaded
,
bool
?
loaded
,
String
?
url
,
String
?
url
,
String
?
title
,
String
?
title
,
int
?
screenType
,
})
{
})
{
return
LinkState
(
return
LinkState
(
loaded:
loaded
??
this
.
loaded
,
loaded:
loaded
??
this
.
loaded
,
url:
url
??
this
.
url
,
url:
url
??
this
.
url
,
title:
title
??
this
.
title
,
title:
title
??
this
.
title
,
screenType:
screenType
??
this
.
screenType
,
);
);
}
}
...
@@ -32,15 +39,21 @@ class LinkState extends Equatable {
...
@@ -32,15 +39,21 @@ class LinkState extends Equatable {
loaded
,
loaded
,
url
,
url
,
title
,
title
,
screenType
,
];
];
}
}
class
LinkCubit
extends
Cubit
<
LinkState
>
{
class
LinkCubit
extends
Cubit
<
LinkState
>
{
late
final
WebViewController
_controller
;
late
final
WebViewController
_controller
;
String
?
msg
;
WebViewController
get
controller
=>
_controller
;
WebViewController
get
controller
=>
_controller
;
LinkCubit
(
super
.
initialState
)
{
LinkCubit
(
super
.
initialState
)
{
if
(
state
.
screenType
!=
1
)
{
_setOrientation
(
2
);
}
_controller
=
WebViewController
()
_controller
=
WebViewController
()
..
setJavaScriptMode
(
JavaScriptMode
.
unrestricted
)
..
setJavaScriptMode
(
JavaScriptMode
.
unrestricted
)
..
setNavigationDelegate
(
..
setNavigationDelegate
(
...
@@ -64,19 +77,68 @@ class LinkCubit extends Cubit<LinkState> {
...
@@ -64,19 +77,68 @@ class LinkCubit extends Cubit<LinkState> {
},
},
),
),
)
)
..
addJavaScriptChannel
(
"xeJsBridge"
,
onMessageReceived:
(
JavaScriptMessage
message
)
{})
..
loadRequest
(
Uri
.
parse
(
state
.
url
));
..
loadRequest
(
Uri
.
parse
(
state
.
url
));
}
}
void
_onMessageReceived
(
JavaScriptMessage
message
)
async
{
// try {
// _dispatcher.dispatch(message.message, (response) {
// _sendResponse(response);
// }, webCubit: this);
// } catch (e) {
// debugPrint('消息解析错误: $e');
// }
}
// 向H5发送响应
void
_sendResponse
(
Map
<
String
,
dynamic
>
response
)
{
String
jsonString
=
jsonEncode
(
response
);
String
escapedJson
=
jsonString
.
replaceAll
(
'"'
,
'
\\
"'
);
final
String
script
=
'xeJsBridgeCallback("
$escapedJson
");'
;
_controller
.
runJavaScript
(
script
);
}
void
_finishLoading
()
{
void
_finishLoading
()
{
emit
(
state
.
copyWith
(
loaded:
true
));
emit
(
state
.
copyWith
(
loaded:
true
));
}
}
Future
<
void
>
handleBack
(
BuildContext
context
)
async
{
// 设置屏幕方向
void
_setOrientation
(
int
screenType
)
{
if
(
screenType
==
2
)
{
// 横屏模式
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
landscapeLeft
,
DeviceOrientation
.
landscapeRight
,
]);
// 隐藏状态栏
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
}
else
{
// 竖屏模式(默认)
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
portraitUp
,
DeviceOrientation
.
portraitDown
,
]);
// 显示状态栏
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
edgeToEdge
);
}
}
Future
<
void
>
handleBack
()
async
{
if
(
await
_controller
.
canGoBack
())
{
if
(
await
_controller
.
canGoBack
())
{
_controller
.
goBack
();
_controller
.
goBack
();
}
else
{
}
else
{
// context.pop(true);
router
.
pop
(
msg
);
router
.
pop
(
'ok'
);
}
}
@override
Future
<
void
>
close
()
{
// 恢复为竖屏模式
if
(
state
.
screenType
!=
1
)
{
_setOrientation
(
1
);
}
}
return
super
.
close
();
}
}
}
}
lib/bloc/web_cubit.dart
View file @
2a473bd
...
@@ -515,6 +515,36 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
...
@@ -515,6 +515,36 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
_sendResponse
(
resp
);
_sendResponse
(
resp
);
}
}
///
/// 设置主Web状态
/// active: 1-激活状态 2-隐藏状态
///
void
handleWebStatus
(
int
active
,
{
String
extData
=
''
})
{
// setWebStatus指令
var
resp
=
{
'unique'
:
''
,
'cmd'
:
'setWebStatus'
,
'data'
:
{
'active'
:
active
,
'extData'
:
extData
},
'errMsg'
:
''
};
_sendResponse
(
resp
);
}
Future
<
void
>
handleToggleDebug
()
async
{
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
var
debug
=
sharedPreferences
.
getInt
(
'debug'
)
??
0
;
debug
=
(
debug
==
0
?
1
:
0
);
sharedPreferences
.
setInt
(
'debug'
,
debug
);
var
resp
=
{
'unique'
:
''
,
'cmd'
:
'toggleDebug'
,
'data'
:
{
'debug'
:
debug
},
'errMsg'
:
''
};
_sendResponse
(
resp
);
}
bool
setTitleBar
(
String
title
,
String
color
,
String
bgColor
,
String
icon
)
{
bool
setTitleBar
(
String
title
,
String
color
,
String
bgColor
,
String
icon
)
{
int
parsedTitleColor
=
_hexStringToInt
(
color
);
int
parsedTitleColor
=
_hexStringToInt
(
color
);
int
parsedBgColor
=
_hexStringToInt
(
bgColor
);
int
parsedBgColor
=
_hexStringToInt
(
bgColor
);
...
...
lib/config/locator.dart
View file @
2a473bd
...
@@ -24,6 +24,7 @@ import 'package:appframe/data/repositories/message/role_info_handler.dart';
...
@@ -24,6 +24,7 @@ import 'package:appframe/data/repositories/message/role_info_handler.dart';
import
'package:appframe/data/repositories/message/save_file_to_disk_handler.dart'
;
import
'package:appframe/data/repositories/message/save_file_to_disk_handler.dart'
;
import
'package:appframe/data/repositories/message/save_to_album_handler.dart'
;
import
'package:appframe/data/repositories/message/save_to_album_handler.dart'
;
import
'package:appframe/data/repositories/message/scan_code_handler.dart'
;
import
'package:appframe/data/repositories/message/scan_code_handler.dart'
;
import
'package:appframe/data/repositories/message/screen_handler.dart'
;
import
'package:appframe/data/repositories/message/share_handler.dart'
;
import
'package:appframe/data/repositories/message/share_handler.dart'
;
import
'package:appframe/data/repositories/message/share_to_wx_handler.dart'
;
import
'package:appframe/data/repositories/message/share_to_wx_handler.dart'
;
import
'package:appframe/data/repositories/message/storage_handler.dart'
;
import
'package:appframe/data/repositories/message/storage_handler.dart'
;
...
@@ -193,6 +194,9 @@ Future<void> setupLocator() async {
...
@@ -193,6 +194,9 @@ Future<void> setupLocator() async {
/// 设置用户角色信息
/// 设置用户角色信息
getIt
.
registerLazySingleton
<
MessageHandler
>(()
=>
RoleInfoHandler
(),
instanceName:
'setRoleInfo'
);
getIt
.
registerLazySingleton
<
MessageHandler
>(()
=>
RoleInfoHandler
(),
instanceName:
'setRoleInfo'
);
/// 设置屏幕模式
getIt
.
registerLazySingleton
<
MessageHandler
>(()
=>
ScreenHandler
(),
instanceName:
'setScreen'
);
/// service
/// service
///
///
/// local server
/// local server
...
...
lib/config/routes.dart
View file @
2a473bd
...
@@ -21,7 +21,7 @@ import 'package:go_router/go_router.dart';
...
@@ -21,7 +21,7 @@ import 'package:go_router/go_router.dart';
final
GoRouter
router
=
GoRouter
(
final
GoRouter
router
=
GoRouter
(
initialLocation:
'/web'
,
initialLocation:
'/web'
,
observers:
Platform
.
isIOS
?
[
AppRouteObserver
()]
:
[
],
observers:
Platform
.
isIOS
?
[
LinkPageObserver
(),
IosGestureObserver
()]
:
[
LinkPageObserver
()
],
routes:
<
RouteBase
>[
routes:
<
RouteBase
>[
GoRoute
(
GoRoute
(
path:
'/web'
,
path:
'/web'
,
...
@@ -113,53 +113,98 @@ final GoRouter router = GoRouter(
...
@@ -113,53 +113,98 @@ final GoRouter router = GoRouter(
///
///
/// 只针对iOS使用
/// 只针对iOS使用
///
///
class
AppRouteObserver
extends
NavigatorObserver
{
class
IosGestureObserver
extends
NavigatorObserver
{
@override
// @override
void
didPush
(
Route
route
,
Route
?
previousRoute
)
{
// void didPush(Route route, Route? previousRoute) {
super
.
didPush
(
route
,
previousRoute
);
// super.didPush(route, previousRoute);
//
// if (route.settings.name == '/web') {
// // push时,当前路由为 /web,代表 /web 路由被push进栈,展示web页面
// // 设置手势监听回调
// debugPrint("设置监听--------");
// IosEdgeSwipeDetector.onEdgeSwipe(
// () {
// WebCubitHolder.instance?.handleBack();
// },
// );
// } else if (previousRoute?.settings.name == '/web') {
// // push时,前一个路由是 /web,代表是从web页进入此页面
// // 将手势监听回调取消
// debugPrint("取消监听--------");
// IosEdgeSwipeDetector.dispose();
// }
// }
//
// @override
// void didPop(Route route, Route? previousRoute) {
// super.didPop(route, previousRoute);
//
// if (previousRoute?.settings.name == '/web') {
// // Pop时, 前一个路由是/web,代表回到web页面
// // 设置手势监听回调
// debugPrint("设置监听--------");
// IosEdgeSwipeDetector.onEdgeSwipe(
// () {
// WebCubitHolder.instance?.handleBack();
// },
// );
// }
// }
//
// @override
// void didRemove(Route route, Route? previousRoute) {
// super.didRemove(route, previousRoute);
//
// if (route.settings.name == '/web') {
// // remove时, 当前路由为 /web, 代表 /web 路由被删除,展示的不是web页面
// // 将手势监听回调取消
// debugPrint("取消监听--------");
// IosEdgeSwipeDetector.dispose();
// }
// }
if
(
route
.
settings
.
name
==
'/web'
)
{
@override
// push时,当前路由为 /web,代表 /web 路由被push进栈,展示web页面
void
didChangeTop
(
Route
<
dynamic
>
topRoute
,
Route
<
dynamic
>?
previousTopRoute
)
{
// 设置手势监听回调
if
(
topRoute
.
settings
.
name
==
'/web'
)
{
debugPrint
(
"设置监听--------"
);
debugPrint
(
"设置监听--------"
);
IosEdgeSwipeDetector
.
onEdgeSwipe
(
IosEdgeSwipeDetector
.
onEdgeSwipe
(
()
{
()
{
WebCubitHolder
.
instance
?.
handleBack
();
WebCubitHolder
.
instance
?.
handleBack
();
},
},
);
);
}
else
if
(
previousRoute
?.
settings
.
name
==
'/web'
)
{
}
else
{
// push时,前一个路由是 /web,代表是从web页进入此页面
// 将手势监听回调取消
debugPrint
(
"取消监听--------"
);
debugPrint
(
"取消监听--------"
);
IosEdgeSwipeDetector
.
dispose
();
IosEdgeSwipeDetector
.
dispose
();
}
}
}
}
}
///
/// 监控 /link 路由,作相应处理
///
class
LinkPageObserver
extends
NavigatorObserver
{
@override
@override
void
didP
op
(
Route
route
,
Route
?
previousRoute
)
{
void
didP
ush
(
Route
route
,
Route
?
previousRoute
)
{
super
.
didP
op
(
route
,
previousRoute
);
super
.
didP
ush
(
route
,
previousRoute
);
if
(
previousRoute
?.
settings
.
name
==
'/web'
)
{
if
(
route
.
settings
.
name
==
'/link'
&&
previousRoute
?.
settings
.
name
==
'/web'
)
{
// Pop时, 前一个路由是/web,代表回到web页面
debugPrint
(
'---didPush--- route:
${route.settings.name}
, previousRoute
${previousRoute?.settings.name}
'
);
// 设置手势监听回调
debugPrint
(
'设置 WebStatus 为 2'
);
debugPrint
(
"设置监听--------"
);
WebCubitHolder
.
instance
?.
handleWebStatus
(
2
);
IosEdgeSwipeDetector
.
onEdgeSwipe
(
()
{
// 在 push 时就设置 pop 返回值的监听
WebCubitHolder
.
instance
?.
handleBack
();
route
.
popped
.
then
((
result
)
{
},
debugPrint
(
'-------------路由
${route.settings.name}
被 pop,返回值:
$result
'
);
);
debugPrint
(
'设置 WebStatus 为 1'
);
WebCubitHolder
.
instance
?.
handleWebStatus
(
1
,
extData:
result
??
''
);
});
}
}
}
}
@override
@override
void
didRemove
(
Route
route
,
Route
?
previousRoute
)
{
void
didPop
(
Route
route
,
Route
?
previousRoute
)
{
super
.
didRemove
(
route
,
previousRoute
);
if
(
previousRoute
?.
settings
.
name
==
'/web'
&&
route
.
settings
.
name
==
'/link'
)
{
debugPrint
(
'---didPop--- route:
${route.settings.name}
, previousRoute:
${previousRoute?.settings.name}
'
);
if
(
route
.
settings
.
name
==
'/web'
)
{
// remove时, 当前路由为 /web, 代表 /web 路由被删除,展示的不是web页面
// 将手势监听回调取消
debugPrint
(
"取消监听--------"
);
IosEdgeSwipeDetector
.
dispose
();
}
}
}
}
}
}
...
...
lib/data/repositories/message/open_link_handler.dart
View file @
2a473bd
...
@@ -3,7 +3,7 @@ import 'package:appframe/services/dispatcher.dart';
...
@@ -3,7 +3,7 @@ import 'package:appframe/services/dispatcher.dart';
class
OpenLinkHandler
extends
MessageHandler
{
class
OpenLinkHandler
extends
MessageHandler
{
@override
@override
Future
<
bool
>
handleMessage
(
params
)
async
{
Future
<
dynamic
>
handleMessage
(
params
)
async
{
if
(
params
is
!
Map
<
String
,
dynamic
>)
{
if
(
params
is
!
Map
<
String
,
dynamic
>)
{
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
}
}
...
@@ -12,12 +12,10 @@ class OpenLinkHandler extends MessageHandler {
...
@@ -12,12 +12,10 @@ class OpenLinkHandler extends MessageHandler {
if
(
url
.
isEmpty
)
{
if
(
url
.
isEmpty
)
{
throw
Exception
(
'参数错误'
);
throw
Exception
(
'参数错误'
);
}
}
int
screenType
=
params
[
'screenType'
]
??
1
;
return
_openLink
(
url
);
router
.
push
(
'/link'
,
extra:
{
'url'
:
url
,
'screenType'
:
screenType
});
}
bool
_openLink
(
String
url
)
{
router
.
push
(
'/link'
,
extra:
{
'url'
:
url
});
return
true
;
return
true
;
}
}
}
}
lib/data/repositories/message/screen_handler.dart
0 → 100644
View file @
2a473bd
import
'package:appframe/services/dispatcher.dart'
;
import
'package:flutter/services.dart'
hide
MessageHandler
;
class
ScreenHandler
extends
MessageHandler
{
@override
Future
<
dynamic
>
handleMessage
(
dynamic
params
)
async
{
if
(
params
is
!
Map
<
String
,
dynamic
>)
{
throw
Exception
(
'参数错误'
);
}
int
type
=
params
[
'type'
];
await
_setOrientation
(
type
);
return
true
;
}
Future
<
void
>
_setOrientation
(
int
screenType
)
async
{
if
(
screenType
==
2
)
{
// 横屏模式
await
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
landscapeLeft
,
DeviceOrientation
.
landscapeRight
,
]);
// 隐藏状态栏
await
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
}
else
{
// 竖屏模式(默认)
await
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
portraitUp
,
DeviceOrientation
.
portraitDown
,
]);
// 显示状态栏
await
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
edgeToEdge
);
}
}
}
lib/services/dispatcher.dart
View file @
2a473bd
...
@@ -55,7 +55,8 @@ class MessageDispatcher {
...
@@ -55,7 +55,8 @@ class MessageDispatcher {
h5Message
.
cmd
==
"chooseVideo"
||
h5Message
.
cmd
==
"chooseVideo"
||
h5Message
.
cmd
==
"goLogin"
||
h5Message
.
cmd
==
"goLogin"
||
h5Message
.
cmd
.
startsWith
(
"setTitlebar"
)
||
h5Message
.
cmd
.
startsWith
(
"setTitlebar"
)
||
h5Message
.
cmd
==
"audioPlay"
)
{
h5Message
.
cmd
==
"audioPlay"
||
h5Message
.
cmd
==
"openLink"
)
{
handler
.
setCubit
(
webCubit
!);
handler
.
setCubit
(
webCubit
!);
handler
.
setMessage
(
message
);
handler
.
setMessage
(
message
);
}
}
...
...
lib/ui/pages/link_page.dart
View file @
2a473bd
...
@@ -12,11 +12,12 @@ class LinkPage extends StatelessWidget {
...
@@ -12,11 +12,12 @@ class LinkPage extends StatelessWidget {
@override
@override
Widget
build
(
BuildContext
buildContext
)
{
Widget
build
(
BuildContext
buildContext
)
{
final
Map
<
String
,
dynamic
>?
extraData
=
GoRouterState
.
of
(
buildContext
).
extra
as
Map
<
String
,
dynamic
>?;
final
Map
<
String
,
dynamic
>?
extraData
=
GoRouterState
.
of
(
buildContext
).
extra
as
Map
<
String
,
dynamic
>?;
final
String
?
url
=
extraData
?[
'url'
];
final
String
url
=
extraData
?[
'url'
];
final
String
?
title
=
extraData
?[
'title'
];
final
String
?
title
=
extraData
?[
'title'
];
final
int
screenType
=
extraData
?[
'screenType'
]
??
1
;
// 1: 竖屏, 2: 横屏
return
BlocProvider
(
return
BlocProvider
(
create:
(
context
)
=>
LinkCubit
(
LinkState
(
loaded:
false
,
url:
url
!,
title:
title
??
''
)),
create:
(
context
)
=>
LinkCubit
(
LinkState
(
url:
url
,
title:
title
??
''
,
screenType:
screenType
)),
child:
BlocConsumer
<
LinkCubit
,
LinkState
>(
child:
BlocConsumer
<
LinkCubit
,
LinkState
>(
builder:
(
ctx
,
state
)
{
builder:
(
ctx
,
state
)
{
final
scaffold
=
Scaffold
(
final
scaffold
=
Scaffold
(
...
@@ -25,6 +26,12 @@ class LinkPage extends StatelessWidget {
...
@@ -25,6 +26,12 @@ class LinkPage extends StatelessWidget {
centerTitle:
true
,
centerTitle:
true
,
backgroundColor:
Color
(
0xFF7691FA
),
backgroundColor:
Color
(
0xFF7691FA
),
iconTheme:
IconThemeData
(
color:
Colors
.
white
),
iconTheme:
IconThemeData
(
color:
Colors
.
white
),
leading:
IconButton
(
icon:
const
Icon
(
Icons
.
arrow_back
,
color:
Colors
.
white
),
onPressed:
()
{
ctx
.
read
<
LinkCubit
>().
handleBack
();
},
),
),
),
body:
state
.
loaded
body:
state
.
loaded
?
SizedBox
(
?
SizedBox
(
...
@@ -46,7 +53,7 @@ class LinkPage extends StatelessWidget {
...
@@ -46,7 +53,7 @@ class LinkPage extends StatelessWidget {
if
(
didPop
)
{
if
(
didPop
)
{
return
;
return
;
}
}
ctx
.
read
<
LinkCubit
>().
handleBack
(
ctx
);
ctx
.
read
<
LinkCubit
>().
handleBack
();
},
},
child:
scaffold
,
child:
scaffold
,
);
);
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment