# 🔙 返回键功能说明(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 提示 - ✅ 优雅退出应用 **核心方法**: ```java public static boolean handleBackPress(Activity activity) { // 处理返回键按下事件 // 返回 true 表示已处理,false 表示继续默认行为 } ``` ### 2. MyApplication.java(修改) **路径**: `app/src/main/java/com/YuyeTech/HeartRate/MyApplication.java` **新增功能**: - ✅ 在 `onActivityCreated` 中调用 `interceptBackPress()` - ✅ 使用 `setOnKeyListener` 拦截按键事件 - ✅ 委托给 `BackPressHandler` 处理 **拦截方法**: ```java 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`: ```bash .\测试返回键功能.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: ✅ 系统设置页面 按返回键 → 允许返回 ``` ### 查看日志命令 ```bash adb logcat -s BackPressHandler:D MyApplication:D ``` --- ## ⚙️ 配置选项 ### 修改 Toast 提示文本 在 `BackPressHandler.java` 中: ```java showToast(activity, "Kiosk 模式已锁定"); // ← 修改提示文本 ``` ### 允许特定应用返回 如果需要允许其他应用(如浏览器)的返回键,修改 `isSettingsActivity()` 方法: ```java 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 模式用于测试) 临时禁用返回键拦截: ```java // 在 MyApplication.java 中注释掉这行 // interceptBackPress(activity); ``` --- ## 🔧 技术细节 ### 拦截方式 使用 `View.OnKeyListener` 拦截按键事件: ```java 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`? ```java event.getAction() == KeyEvent.ACTION_UP ``` - `ACTION_DOWN`: 按键按下时触发 - `ACTION_UP`: 按键松开时触发 ← **我们使用这个** **原因**: 避免长按返回键时重复触发 ### 返回键拦截机制 ```java public static boolean handleBackPress(Activity activity) { // 返回 true = 拦截事件,禁止返回 // 返回 false = 允许默认行为,可以返回 } ``` **Kiosk 模式下的策略**: - 主应用 Activity → 返回 `true`(禁止返回) - 系统设置 Activity → 返回 `false`(允许返回) --- ## 🐛 故障排查 ### 问题 1:按返回键没有反应 **可能原因**: - 拦截器未安装 - 日志被过滤 **排查步骤**: 1. 查看日志是否有 "返回键拦截器已安装" 消息 ```bash adb logcat -s MyApplication:D | findstr "拦截器" ``` 2. 检查是否有 "检测到返回键按下" 日志 ```bash adb logcat -s BackPressHandler:D ``` ### 问题 2:仍然出现黑屏或"无法取消固定屏幕" **可能原因**: - 拦截器未正确返回 `true` - 其他代码覆盖了返回键行为 **排查步骤**: 1. 查看日志,确认看到 "已禁用(Kiosk 模式)" 2. 确认返回值是 `true`(拦截成功) 3. 检查是否有其他 `onBackPressed()` 重写 ### 问题 3:从 WiFi 设置无法返回 **可能原因**: - 系统设置页面判断失败 **排查步骤**: 1. 查看日志中的 Activity 类名 ```bash 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 提示,清晰明了 - 优雅退出,保留状态