文档管理中心

应用协议弹窗侧滑后关闭导致无法进入应用

问题现象

应用在首次启动后,通过自定义弹窗实现用户隐私协议授权页面,侧滑返回时弹窗直接消失,导致应用无法正常进入主页面,不符合预期。

背景知识

  • Navigation:路由导航的根视图容器,作为page页面的根容器使用,默认包含标题栏、内容区和工具栏。
  • NavDestination:作为子页面的根容器,用于显示Navigation的内容区。
  • NavDestinationMode:NavDestination类型,包含自定义dialog模式。
  • onBackPressed:当点击返回键或侧滑时,触发该回调。返回值为true时,表示重写返回键逻辑,返回值为false时,表示回退到上一个页面。

问题定位

复现问题,抓取Hilog日志,查看进程相关日志进行业务逻辑排查。

  1. 自定义弹窗创建。如下日志,进入主界面page后,基于NavDestination创建dialog并显示。焦点由page切换到dialog也可说明当前弹窗逻辑。
    收起
    自动换行
    深色代码主题
    复制
    1. 07-08 10:45:20.852 29801-29801 C0390F/应用包名/AceDialog 应用包名 I [(100000:100000:scope)] dialog GetContext fontScale : 1.000000
    2. 07-08 10:45:20.852 29801-29801 C03922/应用包名/AceNavigation 应用包名 I [(100000:100000:scope)] fire dialog change to cause navdestination lifecycle: 6
    3. 07-08 10:45:20.852 29801-29801 C03900/应用包名/Ace 应用包名 I [(100000:100000:scope)] Put node level order. nodeId: 17, levelOrder: 0.000000
    4. 07-08 10:45:20.852 29801-29801 C0390F/应用包名/AceDialog 应用包名 I [(100000:100000:scope)] Controller/0 create dialog node/17 successfully.
    5. 07-08 10:45:21.022 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] FocusView: Dialog/17 show
    6. 07-08 10:45:21.022 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] FocusView: page/2 lost focus
    7. 07-08 10:45:21.028 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] Request focus on focusView: Dialog/17.
  2. 侧滑返回后弹窗消失。日志显示侧滑返回后触发NavDestination的onBackPressed回调,之后dialog正常关闭,且页面焦点由dialog切换到page。
    收起
    自动换行
    深色代码主题
    复制
    1. 07-08 10:54:53.122 29801-31911 C03900/应用包名/Ace 应用包名 I [(-1:100000:singleton)] [应用包名][entry][100000]: OnBackPressed called
    2. 07-08 10:54:53.124 29801-29801 C03900/应用包名/Ace 应用包名 I [(100000:100000:scope)] Pop node level order. nodeId: 17, levelOrder: 0.000000
    3. 07-08 10:54:53.124 29801-29801 C0390D/应用包名/AceOverlay 应用包名 I [(100000:100000:scope)] close dialog animation
    4. 07-08 10:54:53.124 29801-29801 C0390D/应用包名/AceOverlay 应用包名 W [(100000:100000:scope)] not find mask dialog 17 in maskNodeIdMap
    5. 07-08 10:54:53.124 29801-29801 C03922/应用包名/AceNavigation 应用包名 I [(100000:100000:scope)] fire dialog change to cause navdestination lifecycle: 4
    6. 07-08 10:54:53.125 29801-29801 C03900/应用包名/Ace 应用包名 I [(100000:100000:scope)] Overlay consumed backpressed event
    7. 07-08 10:54:53.357 29801-29801 C0390F/应用包名/AceDialog 应用包名 I [(100000:100000:scope)] post dialog finish event enter
    8. 07-08 10:54:53.358 29801-29801 C0390F/应用包名/AceDialog 应用包名 I [(100000:100000:scope)] on dialog/17 close event enter
    9. 07-08 10:54:53.358 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] Focus view: Dialog/17 close
    10. 07-08 10:54:53.358 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] FocusView: Dialog/17 lost focus
    11. 07-08 10:54:53.365 29801-29801 C0391C/应用包名/AceFocus 应用包名 I [(100000:100000:scope)] Request focus on focusView: page/2.

分析结论

应用通过NavDestination的dialog模式创建协议弹窗,在页面侧滑时触发NavDestination的onBackPressed回调,由于onBackPressed返回false未进行拦截,弹窗dialog正常退出回到主页面。

修改建议

由于应用是基于Navigation自定义弹窗实现,使用NavDestination的回调函数onBackPressed,当点击物理返回按钮或使用手势滑动时,触发该回调。而当onBackPressed返回值为true时,表示重写返回键逻辑,即可实现拦截,示例如下。

主页面:

收起
自动换行
深色代码主题
复制
  1. @Entry
  2. @Component
  3. export struct DialogDemo {
  4. @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack();
  5. build() {
  6. Navigation(this.pageStack) {
  7. Column() {
  8. Row() {
  9. Button('打开弹窗')
  10. .width('100%')
  11. .onClick(() => {
  12. this.pageStack.pushPathByName('SubDialog', null);
  13. })
  14. }
  15. .width('100%')
  16. .alignItems(VerticalAlign.Center)
  17. .padding({ left: 16, right: 16 })
  18. }
  19. .width('100%')
  20. .height('100%')
  21. .justifyContent(FlexAlign.End)
  22. }
  23. .hideToolBar(true)
  24. }
  25. }

弹窗页面:

收起
自动换行
深色代码主题
复制
  1. @Builder
  2. export function myRouter() {
  3. SubDialog();
  4. }
  5. @Component
  6. export struct SubDialog {
  7. @Consume('NavPathStack') pageStack: NavPathStack;
  8. build() {
  9. NavDestination() {
  10. Stack({ alignContent: Alignment.Center }) {
  11. Column() {
  12. Row() {
  13. Text('隐私协议')
  14. .fontSize(20)
  15. .fontWeight(FontWeight.Bold)
  16. }
  17. .justifyContent(FlexAlign.Center)
  18. .padding({ top: 20 })
  19. Text('协议协议内容...')
  20. .fontSize(14)
  21. .padding({ top: 10 })
  22. .width('80%')
  23. Row() {
  24. Button('取消')
  25. .backgroundColor(Color.White)
  26. .fontColor('rgb(65, 105, 225)')
  27. .fontSize(16)
  28. .onClick(() => {
  29. this.pageStack.pop();
  30. })
  31. Divider()
  32. .vertical(true)
  33. .height(22)
  34. .color('#E5E5EA')
  35. .opacity(0.6)
  36. .margin({ left: 8, right: 8 })
  37. Button('确认')
  38. .backgroundColor(Color.White)
  39. .fontColor('rgb(65, 105, 225)')
  40. .fontSize(16)
  41. .onClick(() => {
  42. this.pageStack.pop();
  43. })
  44. }
  45. .justifyContent(FlexAlign.SpaceAround)
  46. .padding({ top: 60 })
  47. .width('80%')
  48. }
  49. .width('90%')
  50. .height('25%')
  51. .borderRadius(30)
  52. .backgroundColor(Color.White)
  53. }
  54. .height('100%')
  55. .width('100%')
  56. }
  57. .hideTitleBar(true)
  58. .backgroundColor('rgba(0, 0, 0, 0.3)')
  59. .mode(NavDestinationMode.DIALOG)
  60. .onBackPressed(() => { // 拦截侧滑返回
  61. // 阻止默认行为
  62. return true;
  63. })
  64. }
  65. }

route_map.json配置如下:

收起
自动换行
深色代码主题
复制
  1. {
  2. "routerMap": [
  3. {
  4. "name": "SubDialog",
  5. "pageSourceFile": "src/main/ets/pages/SubDialog.ets",
  6. "buildFunction": "myRouter",
  7. "data": {
  8. "description": "this is SubDialog.ets"
  9. }
  10. }
  11. ]
  12. }