iOS家人共享-屏幕时间之WKWebView问题

18 阅读3分钟

背景

如何玩转“屏幕时间”

  1. “屏幕时间”是什么?

第一性原理:行为数据 + 干扰抑制 + 家长监管

促进“意图性使用”,减少“无意识沉迷”,将数字设备的使用权和控制权交还给用户及其监护人。 其核心是 “知情”与“选择”。

- 知情(Awareness): 通过数据可视化(图表、报告),客观反映设备使用模式,打破“时间黑洞”。
- 选择(Choice): 提供工具(App限额、停用时间、通信限制、内容与隐私限制),让用户有能力基于“知情”做出符合自身价值观的调整。
- 尊重(Respect): 设计上平衡控制与自主。例如,限额到期时可申请“更多时间”,系统会向家长发送请求,而非粗暴切断。

2. WKWebView有什么问题?

  • WKWebView通用报错ErrorView遮挡问题
  • 授权二次Present不能正常弹出问题

使用教程

  1. 家人共享-创建儿童账号:
  • 准备邮箱、手机号(可以使用家长账号对应的手机号)

  • 设置年龄(实际年龄,不然更改年龄特麻烦)

  1. 配置-屏幕使用时间
  • 家长账号

    • 统计:行为数据

    • 限制:添加使用限制(“达到限额时阻止使用”打开时,才能使用“授权更多时间”)

    • 监管

      • 限制App安装、删除

      • 屏幕距离-提醒:提醒儿童保持推荐距离,降低儿童近视风险

  1. 请求/授权,更多时间
  • 儿童账号:请求更多时间

  • 家长-授权更多时间

  1. 关闭-屏幕使用时间
  • 家长账号

设置-屏幕时间-找到儿童账号(小孩名)-管理屏幕时间-停止管理“小孩名”的屏幕时间

  1. 退出儿童账号

设备上,儿童账号,“退出登录”显示“由于访问限制,无法退出登录”

此处限制条件比较多,逐个检查

  • 儿童设备:设置-屏幕使用时间-内容和隐私访问限制-关闭“内容和隐私访问限制”
  • 家长设备:关闭儿童账号-屏幕使用时间(见上4.关闭-屏幕使用时间)
  • 儿童设备:设置-屏幕使用时间-内容和隐私访问限制-查看描述文件(如果以下不能解决,尝试删除设备的描述文件)

WKWebView适配

  1. 去除ErrorView的遮挡
  • 定义错误码
    // error code

    **static** **var** webKitErrorDomainCode = 105

    **static** **var** webKitErrorDomain = "WebKitErrorDomain"
  • url加载和跳转回调
private func onWebViewLoadFinish(success: Bool, error: NSError?) {
    if success {
        hideLoadingView()
    } else if Self.checkIsAccessRestrictedError(error: error) {
        // 展示出 允许 用户设置配额
        hideLoadingView()
        // wakeupAccessAuthWebController 展示域名对应的“访问限制”授权页
        if !isAccessRestrictedIgnore && wakeupAccessAuthWebController(by: self) {
            return
        }
    } else {
        showErrorView()
    }            
}

// 检查是否为,访问限制错误
static func checkIsAccessRestrictedError(error: NSError?) -> Bool {
    guard let error = error else {
        return false
    }
    return error.domain == Self.webKitErrorDomain && error.code == Self.webKitErrorDomainCode
}

  1. 解决二次present不能弹出问题
private func wakeupAccessAuthWebController(by webView: JDWebView) -> Bool {
    guard !webView.isAccessRestrictedIgnore else {
        // 跳转来的,返回,断开循环调用
        return false
    }

    guard !isCheckingAccess else {
        // 仅有一个在授权
        return false
    }
    
    // 找到webview对应的controller
    guard let controller = webView.findViewController() else {
        return false
    }

    let urlString = webView.currentUrl ?? ""
    // 找到controller唤起的present controller
    if let topController = controller.topPresentingViewController() {
        // 二次弹出
        // 1.topPresentController dismiss
        isCheckingAccess = true
        topController.dismiss(animated: true) {
            // 2. 跳转到新的 授权页
            let accessAuthWebController = AccessAuthWebViewController.createBy(url: urlString)
            let rootShowController = UIApplication.getTopViewController(master: false)
            rootShowController?.showDetailViewController(accessAuthWebController, sender: nil)
        }
    } else {
        // 没有presentingViewController, 不是二次弹出,无需处理
        return false
    }
    return true
}

private extension UIView {
    /// 返回承载当前视图的 UIViewController
    func findViewController() -> UIViewController? {
        var nextResponder: UIResponder? = self

        while nextResponder != nil {
            nextResponder = nextResponder?.next

            if let viewController = nextResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

private extension UIViewController {
  func topPresentingViewController() -> UIViewController? {
        var topVC = presentingViewController
        while let parent = topVC?.presentingViewController {
            topVC = parent
        }
        return topVC
    }
}


展望

结合福格行为模型,设计儿童(14-)学习奖惩制度