返回键功能说明.md 9.7 KB

🔙 返回键功能说明(Kiosk 模式)

📋 问题描述

原始问题

在 UniApp 离线 Android 项目中,启用 Kiosk 模式后,当用户在登录页面(主页面)按返回键时,会返回到一个黑屏页面,导致:

  • ❌ 显示"无法取消固定屏幕"提示
  • ❌ 卡在黑屏页面
  • ❌ 无法继续使用应用
  • ❌ Kiosk 锁定失效

问题原因

UniApp 使用双 Activity 架构:

PandoraEntry (启动页)
    ↓
  启动
    ↓
PandoraEntryActivity (主页面, LockTask 模式)

当用户按返回键时:

PandoraEntryActivity (主页面)
    ↓
  按返回键
    ↓
PandoraEntry (启动页) ← 此时已经是空白页面,显示黑屏
    ↓
显示"无法取消固定屏幕"

业务需求

  • ✅ Kiosk 模式应该始终锁定,不允许退出应用
  • 只允许进入 WiFi 设置页面配置网络
  • ✅ 从 WiFi 设置返回后,继续保持 Kiosk 模式
  • 完全禁用返回键,防止回到黑屏页面

✅ 解决方案(Kiosk 模式专用)

核心思路

完全禁用返回键,防止任何退出操作:

  1. PandoraEntry(启动页)

    • 按返回键 → 完全禁用,显示 "Kiosk 模式已锁定"
    • 防止进入黑屏
  2. PandoraEntryActivity(主页面)

    • 按返回键 → 完全禁用,显示 "Kiosk 模式已锁定"
    • 防止回到启动页
  3. 系统设置页面(WiFi 设置)

    • 按返回键 → 允许返回
    • 确保可以从 WiFi 设置返回到应用

📁 实现文件

1. BackPressHandler.java

路径: app/src/main/java/com/YuyeTech/HeartRate/BackPressHandler.java

功能:

  • ✅ 统一处理返回键事件
  • ✅ 双击退出逻辑(2 秒间隔)
  • ✅ 显示 Toast 提示
  • ✅ 优雅退出应用

核心方法:

public static boolean handleBackPress(Activity activity) {
    // 处理返回键按下事件
    // 返回 true 表示已处理,false 表示继续默认行为
}

2. MyApplication.java(修改)

路径: app/src/main/java/com/YuyeTech/HeartRate/MyApplication.java

新增功能:

  • ✅ 在 onActivityCreated 中调用 interceptBackPress()
  • ✅ 使用 setOnKeyListener 拦截按键事件
  • ✅ 委托给 BackPressHandler 处理

拦截方法:

private void interceptBackPress(Activity activity) {
    activity.getWindow().getDecorView().setOnKeyListener((v, keyCode, event) -> {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            return BackPressHandler.handleBackPress(activity);
        }
        return false;
    });
}

🔍 工作流程

场景 1:在主页面按返回键(Kiosk 模式)

用户在 PandoraEntryActivity
    ↓
按返回键
    ↓
BackPressHandler.handleBackPress()
    ↓
检测到 PandoraEntryActivity
    ↓
显示 Toast: "Kiosk 模式已锁定"
    ↓
返回 true(拦截事件,禁止返回)
    ↓
应用保持在主页面 ✅

场景 2:在启动页按返回键(Kiosk 模式)

用户在 PandoraEntry
    ↓
按返回键
    ↓
BackPressHandler.handleBackPress()
    ↓
检测到 PandoraEntry
    ↓
显示 Toast: "Kiosk 模式已锁定"
    ↓
返回 true(拦截事件,禁止退出)
    ↓
应用保持锁定 ✅

场景 3:从 WiFi 设置返回

用户在 WiFi 设置页面
    ↓
按返回键
    ↓
BackPressHandler.handleBackPress()
    ↓
检测到系统设置页面
    ↓
返回 false(允许返回)
    ↓
正常返回到应用主页面 ✅

📱 用户体验

修改前(有问题)

主页面 → 按返回键 → 黑屏页面 → "无法取消固定屏幕" → 卡住 ❌

修改后(Kiosk 模式)

主页面 → 按返回键 → Toast: "Kiosk 模式已锁定" → 保持在主页面 ✅

WiFi 设置 → 按返回键 → 正常返回到主页面 ✅

🧪 测试方法

自动化测试脚本

运行 测试返回键功能.bat

.\测试返回键功能.bat

手动测试步骤

测试 1:主页面禁用返回键(Kiosk 模式)

  1. 启动应用,进入主页面
  2. 按返回键
    • ✅ 应显示 Toast: "Kiosk 模式已锁定"
    • ✅ 应用保持在主页面,不退出
    • ❌ 不应该出现黑屏
    • ❌ 不应该显示"无法取消固定屏幕"
  3. 多次按返回键
    • ✅ 每次都显示 "Kiosk 模式已锁定"
    • ✅ 应用始终锁定

测试 2:WiFi 设置返回

  1. 禁用设备 WiFi
  2. 启动应用,会弹出 "WiFi 未连接" 对话框
  3. 点击"去设置",进入系统 WiFi 设置
  4. 按返回键
    • ✅ 应正常返回到应用主页面
    • ✅ 不会被拦截
  5. 再次弹出 WiFi 对话框(因为仍未连接)
    • ✅ 确认 WiFi 检测功能正常

测试 3:启动页禁用返回键

  1. 重新启动应用
  2. 在启动页(白屏或 Logo 页面)按返回键
    • ✅ 应显示 Toast: "Kiosk 模式已锁定"
    • ✅ 应用不退出
    • ❌ 不应该卡在黑屏

📊 日志输出

正常工作日志(Kiosk 模式)

在主页面按返回键

D BackPressHandler: 🔙 检测到返回键按下
D BackPressHandler: ⛔ PandoraEntryActivity 按返回键 → 已禁用(Kiosk 模式)

在启动页按返回键

D BackPressHandler: 🔙 检测到返回键按下
D BackPressHandler: ⛔ PandoraEntry 按返回键 → 已禁用(Kiosk 模式)

从 WiFi 设置返回

D BackPressHandler: 🔙 检测到返回键按下
D BackPressHandler: ✅ 系统设置页面 按返回键 → 允许返回

查看日志命令

adb logcat -s BackPressHandler:D MyApplication:D

⚙️ 配置选项

修改 Toast 提示文本

BackPressHandler.java 中:

showToast(activity, "Kiosk 模式已锁定");  // ← 修改提示文本

允许特定应用返回

如果需要允许其他应用(如浏览器)的返回键,修改 isSettingsActivity() 方法:

private static boolean isSettingsActivity(Activity activity) {
    String className = activity.getClass().getName();
    
    return className.startsWith("com.android.settings") ||
           className.startsWith("android.settings") ||
           className.contains("Settings") ||
           className.contains("Browser");  // ← 添加浏览器
}

启用返回键(退出 Kiosk 模式用于测试)

临时禁用返回键拦截:

// 在 MyApplication.java 中注释掉这行
// interceptBackPress(activity);

🔧 技术细节

拦截方式

使用 View.OnKeyListener 拦截按键事件:

activity.getWindow().getDecorView().setOnKeyListener((v, keyCode, event) -> {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        return BackPressHandler.handleBackPress(activity);
    }
    return false;
});

优点:

  • ✅ 不需要修改 UniApp 框架代码
  • ✅ 不需要重写 onBackPressed() 方法
  • ✅ 在 Application 层面统一处理
  • ✅ 支持所有 Activity

为什么使用 ACTION_UP

event.getAction() == KeyEvent.ACTION_UP
  • ACTION_DOWN: 按键按下时触发
  • ACTION_UP: 按键松开时触发 ← 我们使用这个

原因: 避免长按返回键时重复触发

返回键拦截机制

public static boolean handleBackPress(Activity activity) {
    // 返回 true = 拦截事件,禁止返回
    // 返回 false = 允许默认行为,可以返回
}

Kiosk 模式下的策略

  • 主应用 Activity → 返回 true(禁止返回)
  • 系统设置 Activity → 返回 false(允许返回)

🐛 故障排查

问题 1:按返回键没有反应

可能原因:

  • 拦截器未安装
  • 日志被过滤

排查步骤:

  1. 查看日志是否有 "返回键拦截器已安装" 消息

    adb logcat -s MyApplication:D | findstr "拦截器"
    
  2. 检查是否有 "检测到返回键按下" 日志

    adb logcat -s BackPressHandler:D
    

问题 2:仍然出现黑屏或"无法取消固定屏幕"

可能原因:

  • 拦截器未正确返回 true
  • 其他代码覆盖了返回键行为

排查步骤:

  1. 查看日志,确认看到 "已禁用(Kiosk 模式)"
  2. 确认返回值是 true(拦截成功)
  3. 检查是否有其他 onBackPressed() 重写

问题 3:从 WiFi 设置无法返回

可能原因:

  • 系统设置页面判断失败

排查步骤:

  1. 查看日志中的 Activity 类名

    adb logcat -s BackPressHandler:D | findstr "按返回键"
    
  2. 修改 isSettingsActivity() 方法,添加更多判断条件

问题 4:Toast 不显示

可能原因:

  • 系统通知权限被禁用
  • Toast 被其他 UI 遮挡

解决方案:

  • Toast 不影响功能,只是提示
  • 可以通过日志确认功能正常

📚 相关文件

文件 说明
BackPressHandler.java 返回键处理器
MyApplication.java Application 类(已修改)
测试返回键功能.bat 自动化测试脚本
返回键功能说明.md 本文档

💡 最佳实践

  1. 保持双击退出逻辑

    • 防止用户误触返回键
    • 提供更好的用户体验
  2. 使用 moveTaskToBack()

    • finish() 更优雅
    • 保留应用状态
  3. 记录详细日志

    • 方便调试和排查问题
    • 使用统一的 TAG
  4. 处理异常情况

    • Activity 为 null
    • Activity 已 finishing
    • Toast 显示失败

🎯 总结

问题已解决

  • 不再出现黑屏页面
  • 用户可以正常退出应用
  • 提供友好的双击退出提示

实现方式

  • 使用 OnKeyListener 拦截返回键
  • 在 Application 层面统一处理
  • 不修改 UniApp 框架代码

用户体验

  • 双击退出,防止误触
  • Toast 提示,清晰明了
  • 优雅退出,保留状态