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 de967f1c
authored
2025-12-29 13:37:26 +0800
by
tanghuan
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
ios手势操作返回
1 parent
6b0f058e
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
248 additions
and
102 deletions
lib/bloc/web_cubit.dart
lib/config/routes.dart
lib/main.dart
lib/ui/pages/link_page.dart
lib/ui/pages/web_page.dart
lib/ui/widgets/ios_edge_swipe_detector.dart
lib/bloc/web_cubit.dart
View file @
de967f1
...
...
@@ -17,7 +17,6 @@ import 'package:dio/dio.dart';
import
'package:equatable/equatable.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:fluwx/fluwx.dart'
;
import
'package:path_provider/path_provider.dart'
;
import
'package:permission_handler/permission_handler.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
...
...
@@ -200,7 +199,6 @@ class WebState extends Equatable {
class
WebCubit
extends
Cubit
<
WebState
>
with
WidgetsBindingObserver
{
late
final
MessageDispatcher
_dispatcher
;
late
final
WebViewController
_controller
;
late
final
Fluwx
_fluwx
;
HttpServer
?
_server
;
PlayerService
?
_playerService
;
RecorderService
?
_recorderService
;
...
...
@@ -255,8 +253,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
}
}
catch
(
e
)
{
emit
(
state
.
copyWith
(
isUpgrading:
false
));
print
(
'升级检测处理失败'
);
print
(
e
);
debugPrint
(
'升级检测处理失败
$e
'
);
}
// 消息处理器
...
...
@@ -275,13 +272,17 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
_readH5ShowVersion
();
// 初始化其它一些属性
_fluwx
=
getIt
.
get
<
Fluwx
>();
_playerService
=
getIt
.
get
<
PlayerService
>();
_playerService
?.
sendResponse
=
_sendResponse
;
_recorderService
=
getIt
.
get
<
RecorderService
>();
// 登录IM
_loginIM
();
// 针对ios系统,处理侧滑返回
if
(
Platform
.
isIOS
)
{
WebCubitHolder
.
register
(
this
);
}
}
Future
<
Map
<
String
,
String
>>
_getVersionConfig
()
async
{
...
...
@@ -361,8 +362,8 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
await
_recorderService
?.
close
();
},
onPageFinished:
(
String
url
)
async
{
p
rint
(
'onPageFinished--------------------------------->'
);
p
rint
(
url
);
debugP
rint
(
'onPageFinished--------------------------------->'
);
debugP
rint
(
url
);
_controller
.
runJavaScript
(
'document.querySelector("meta[name=viewport]").setAttribute("content", "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no")'
,
...
...
@@ -466,7 +467,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
_sendResponse
(
response
);
},
webCubit:
this
);
}
catch
(
e
)
{
p
rint
(
'消息解析错误:
$e
'
);
debugP
rint
(
'消息解析错误:
$e
'
);
}
}
...
...
@@ -1130,7 +1131,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
// 安全起见,执行一次关闭旧的server,
_server
?.
close
();
}
catch
(
e
)
{
p
rint
(
'SocketException:
$e
'
);
debugP
rint
(
'SocketException:
$e
'
);
}
emit
(
state
.
copyWith
(
testMsg:
'A
${DateTime.now()}
'
));
_server
=
await
localServerService
.
restartLocalServer
();
...
...
@@ -1201,11 +1202,14 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
@override
Future
<
void
>
close
()
async
{
_server
?.
close
();
// _fluwx.removeSubscriber(_responseListener);
await
_playerService
?.
close
();
await
_recorderService
?.
close
();
if
(
Platform
.
isIOS
)
{
WebCubitHolder
.
unregister
();
}
// 移除观察者
WidgetsBinding
.
instance
.
removeObserver
(
this
);
...
...
lib/config/routes.dart
View file @
de967f1
import
'dart:io'
;
import
'package:appframe/bloc/web_cubit.dart'
;
import
'package:appframe/ui/pages/adv_page.dart'
;
import
'package:appframe/ui/pages/im_page.dart'
;
import
'package:appframe/ui/pages/link_page.dart'
;
...
...
@@ -9,11 +12,13 @@ import 'package:appframe/ui/pages/scan_code_page.dart';
import
'package:appframe/ui/pages/setting/account_page.dart'
;
import
'package:appframe/ui/pages/setting/account_phone_page.dart'
;
import
'package:appframe/ui/pages/web_page.dart'
;
import
'package:appframe/ui/widgets/ios_edge_swipe_detector.dart'
;
import
'package:flutter/material.dart'
;
import
'package:go_router/go_router.dart'
;
final
GoRouter
router
=
GoRouter
(
initialLocation:
'/web'
,
observers:
Platform
.
isIOS
?
[
AppRouteObserver
()]
:
[],
routes:
<
RouteBase
>[
GoRoute
(
path:
'/web'
,
...
...
@@ -83,3 +88,72 @@ final GoRouter router = GoRouter(
),
],
);
///
/// 只针对iOS使用
///
class
AppRouteObserver
extends
NavigatorObserver
{
@override
void
didPush
(
Route
route
,
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
();
}
}
}
///
/// 只针对iOS使用
///
class
WebCubitHolder
{
static
WebCubit
?
instance
;
static
void
register
(
WebCubit
cubit
)
{
instance
=
cubit
;
}
static
void
unregister
()
{
instance
=
null
;
}
}
lib/main.dart
View file @
de967f1
import
'dart:convert'
;
import
'dart:io'
;
import
'package:appframe/config/constant.dart'
;
import
'package:appframe/config/env_config.dart'
;
import
'package:appframe/config/locator.dart'
;
import
'package:appframe/services/im_service.dart'
;
import
'package:appframe/ui/widgets/ios_edge_swipe_detector.dart'
;
import
'package:archive/archive.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
...
...
@@ -17,6 +19,7 @@ void main() async {
await
setupLocator
();
await
_initH5Version
();
await
_initImSdk
();
await
_initIOSGesture
();
runApp
(
const
App
());
}
...
...
@@ -60,3 +63,10 @@ Future<void> _initImSdk() async {
await
getIt
.
get
<
ImService
>().
initSdk
();
}
}
Future
<
void
>
_initIOSGesture
()
async
{
if
(
Platform
.
isIOS
)
{
// ios边缘滑动检测
await
IosEdgeSwipeDetector
.
init
();
}
}
lib/ui/pages/link_page.dart
View file @
de967f1
import
'dart:io'
;
import
'package:appframe/bloc/link_cubit.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
...
...
@@ -17,27 +19,36 @@ class LinkPage extends StatelessWidget {
create:
(
context
)
=>
LinkCubit
(
LinkState
(
loaded:
false
,
url:
url
!,
title:
title
??
''
)),
child:
BlocConsumer
<
LinkCubit
,
LinkState
>(
builder:
(
ctx
,
state
)
{
final
scaffold
=
Scaffold
(
appBar:
AppBar
(
title:
Text
(
state
.
title
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
18
)),
centerTitle:
true
,
backgroundColor:
Color
(
0xFF7691FA
),
iconTheme:
IconThemeData
(
color:
Colors
.
white
),
),
body:
state
.
loaded
?
SizedBox
(
height:
MediaQuery
.
of
(
ctx
).
size
.
height
-
120
,
// 减去100像素留空
child:
WebViewWidget
(
controller:
ctx
.
read
<
LinkCubit
>().
controller
,
),
)
:
const
Center
(
child:
CircularProgressIndicator
(
color:
Color
(
0xFF7691fa
))),
);
if
(
Platform
.
isIOS
)
{
return
scaffold
;
}
return
PopScope
(
canPop:
false
,
onPopInvokedWithResult:
(
didPop
,
result
)
{
if
(
didPop
)
{
return
;
}
ctx
.
read
<
LinkCubit
>().
handleBack
(
ctx
);
},
child:
Scaffold
(
appBar:
AppBar
(
title:
Text
(
state
.
title
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
18
)),
centerTitle:
true
,
backgroundColor:
Color
(
0xFF7691FA
),
iconTheme:
IconThemeData
(
color:
Colors
.
white
),
),
body:
state
.
loaded
?
SizedBox
(
height:
MediaQuery
.
of
(
ctx
).
size
.
height
-
120
,
// 减去100像素留空
child:
WebViewWidget
(
controller:
ctx
.
read
<
LinkCubit
>().
controller
,
),
)
:
const
Center
(
child:
CircularProgressIndicator
(
color:
Color
(
0xFF7691fa
))),
),
child:
scaffold
,
);
},
listener:
(
context
,
state
)
{},
...
...
lib/ui/pages/web_page.dart
View file @
de967f1
import
'dart:io'
;
import
'package:appframe/bloc/web_cubit.dart'
;
import
'package:appframe/config/constant.dart'
;
import
'package:appframe/config/env_config.dart'
;
import
'package:appframe/config/locator.dart'
;
import
'package:appframe/config/routes.dart'
;
import
'package:appframe/ui/widgets/tip_overlay_widget.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:go_router/go_router.dart'
;
...
...
@@ -39,92 +39,105 @@ class WebPage extends StatelessWidget {
}
return
BlocProvider
(
create:
(
context
)
=>
WebCubit
(
WebState
(
loginOpFlag:
loginOpFlag
,
sessionCode:
sessionCode
,
userCode:
userCode
,
classCode:
classCode
,
userType:
userType
,
stuId:
stuId
,
),
),
create:
(
context
)
{
final
webCubit
=
WebCubit
(
WebState
(
loginOpFlag:
loginOpFlag
,
sessionCode:
sessionCode
,
userCode:
userCode
,
classCode:
classCode
,
userType:
userType
,
stuId:
stuId
,
),
);
return
webCubit
;
},
child:
BlocConsumer
<
WebCubit
,
WebState
>(
builder:
(
ctx
,
state
)
{
return
PopScope
(
canPop:
false
,
onPopInvokedWithResult:
(
didPop
,
result
)
{
ctx
.
read
<
WebCubit
>().
handleBack
();
},
child:
Scaffold
(
appBar:
_buildAppBar
(
ctx
,
state
),
endDrawer:
_buildDrawer
(
ctx
,
state
),
body:
Stack
(
children:
[
state
.
loaded
?
SizedBox
(
height:
MediaQuery
.
of
(
ctx
).
size
.
height
-
60
,
// 减去100像素留空
child:
WebViewWidget
(
controller:
ctx
.
read
<
WebCubit
>().
controller
),
)
:
const
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
CircularProgressIndicator
(
color:
Color
(
0xFF7691fa
)),
SizedBox
(
height:
16
),
Text
(
'加载中...'
),
],
),
),
// 添加升级遮罩层
if
(
state
.
isUpgrading
)
Container
(
color:
Colors
.
black54
,
child:
const
Center
(
final
scaffold
=
Scaffold
(
appBar:
_buildAppBar
(
ctx
,
state
),
endDrawer:
_buildDrawer
(
ctx
,
state
),
body:
Stack
(
children:
[
state
.
loaded
?
SizedBox
(
height:
MediaQuery
.
of
(
ctx
).
size
.
height
-
60
,
// 减去100像素留空
child:
WebViewWidget
(
controller:
ctx
.
read
<
WebCubit
>().
controller
),
)
:
const
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
CircularProgressIndicator
(
color:
Color
(
0xFF7691fa
)),
SizedBox
(
height:
16
),
Text
(
'
资源更新中...'
,
style:
TextStyle
(
color:
Colors
.
white
)
),
Text
(
'
加载中...'
),
],
),
),
// 添加升级遮罩层
if
(
state
.
isUpgrading
)
Container
(
color:
Colors
.
black54
,
child:
const
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
CircularProgressIndicator
(
color:
Color
(
0xFF7691fa
)),
SizedBox
(
height:
16
),
Text
(
'资源更新中...'
,
style:
TextStyle
(
color:
Colors
.
white
)),
],
),
),
],
),
bottomNavigationBar:
state
.
showBottomNavBar
?
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
currentIndex:
state
.
selectedIndex
,
selectedItemColor:
Color
(
0xFF7691fa
),
unselectedItemColor:
Color
(
0xFF969799
),
onTap:
(
index
)
{
// 更新选中索引
ctx
.
read
<
WebCubit
>().
updateSelectedIndex
(
index
);
// 根据 index 执行相应的操作
},
items:
const
[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
home
,
size:
32
),
label:
'我的班级'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
contact_page
,
size:
32
),
label:
'通讯录'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
find_in_page
,
size:
32
),
label:
'发现'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
person
,
size:
32
),
label:
'我的'
,
),
],
)
:
null
,
),
],
),
bottomNavigationBar:
state
.
showBottomNavBar
?
BottomNavigationBar
(
type:
BottomNavigationBarType
.
fixed
,
currentIndex:
state
.
selectedIndex
,
selectedItemColor:
Color
(
0xFF7691fa
),
unselectedItemColor:
Color
(
0xFF969799
),
onTap:
(
index
)
{
// 更新选中索引
ctx
.
read
<
WebCubit
>().
updateSelectedIndex
(
index
);
// 根据 index 执行相应的操作
},
items:
const
[
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
home
,
size:
32
),
label:
'我的班级'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
contact_page
,
size:
32
),
label:
'通讯录'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
find_in_page
,
size:
32
),
label:
'发现'
,
),
BottomNavigationBarItem
(
icon:
Icon
(
Icons
.
person
,
size:
32
),
label:
'我的'
,
),
],
)
:
null
,
);
// ios 不使用 PopScope
if
(
Platform
.
isIOS
)
{
return
scaffold
;
}
return
PopScope
(
canPop:
false
,
onPopInvokedWithResult:
(
didPop
,
result
)
{
if
(
didPop
)
{
return
;
}
ctx
.
read
<
WebCubit
>().
handleBack
();
},
child:
scaffold
,
);
},
listener:
(
context
,
state
)
{
...
...
lib/ui/widgets/ios_edge_swipe_detector.dart
0 → 100644
View file @
de967f1
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
class
IosEdgeSwipeDetector
{
static
const
MethodChannel
_channel
=
MethodChannel
(
'ios_edge_swipe'
);
/// 初始化边缘滑动检测器
/// 调用原生iOS代码注册边缘滑动监听
static
Future
<
void
>
init
()
async
{
try
{
await
_channel
.
invokeMethod
(
'initSwipeListener'
);
}
catch
(
e
)
{
debugPrint
(
'初始化边缘滑动监听失败:
$e
'
);
}
}
/// 注册边缘滑动事件回调
/// [onSwipeDetected] 当检测到边缘滑动时的回调函数
static
void
onEdgeSwipe
(
VoidCallback
onSwipeDetected
)
{
_channel
.
setMethodCallHandler
((
call
)
async
{
if
(
call
.
method
==
'onEdgeSwipe'
)
{
onSwipeDetected
();
}
else
{
debugPrint
(
'方法
${call.method}
未实现'
);
}
});
}
/// 清理边缘滑动监听器
/// 在组件销毁时调用,防止内存泄漏
static
void
dispose
()
{
_channel
.
setMethodCallHandler
(
null
);
}
}
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