创建一个隐式的控制器, 解决无法给客服发消息的bug

2023-11-18  本文已影响0人  小冰山口

不得不吐槽一下网易七鱼SDK的设计

给客服发消息的会话, 和控制器, 竟然没有分开
你见过拿一个viewController去发起会话的吗? 讲道理, 我是没有见过的
好的, 那你今天就见到了!

/**
 *  获取客服聊天ViewController,非单例,每次调用新建会话页面
 *
 *  @return 会话ViewController
 *  @discussion 为保证功能完整性,必须嵌入至UINavigationController中使用;保证全局仅有一个VC实例,退出后可正常释放
 */
- (QYSessionViewController *)sessionViewController;

这是七鱼的代码文档
发消息一定要创建会话, 这可以理解. 但会话和控制器其实是两个概念
会话可以理解为一个模型, 用模型去处理调用发消息的接口, 可以做到很好的解耦
而控制器, 尤其是iOS的控制器, 其实是一个view的容器, 相当于, 你在view层去调用网络请求的接口, 是可以这么做, 但是, 耦合性就非常高了. 这样你调用接口必须创建控制器, 并且控制器要处于控制器栈中.

现在产品有一个需求, 就是用户现在处于商品的退款界面, 我这时候就想给客服发一条要退款商品的信息. 七鱼iOS端的做法是, 你必须拉起sessionViewController界面, 才可以调用发消息的接口

 QYSDK.shared().sessionViewController().sendText("test")

直接这样写是不行的. 因为此时sessionViewController并没有在栈中, 意思是: 其实真正的会话并没有创建成功, 那发送消息肯定就不行了. 会提示

错误提示

这就很坑, 我想给客服发消息就不能隐式地发了, 就必须创建一个控制器, 还必须push或者present出来. 还不能停留时间太短, 还要等真正的会话(虽然我也不知道是怎么创建出来的)创建出来才能发消息

此时, 我采取了以下的方法:

        if let productDict = dict["productDetail"] as? Dictionary<String, Any>,
           let product = JSONDeserializer<CustomServiceProduct>.deserializeFrom(dict: productDict)
        {
            let commodityInfo = QYCommodityInfo()
            commodityInfo.show = product.show
            commodityInfo.cardType = product.cardType
            commodityInfo.title = product.title
            commodityInfo.desc = product.desc
            commodityInfo.note = product.note
            commodityInfo.pictureUrlString = product.picture
            commodityInfo.urlString = product.url
            commodityInfo.actionText = product.actionText
            commodityInfo.goodsId = product.goodsId
            commodityInfo.goodsCId = product.goodsCId
            commodityInfo.orderId = product.orderId
            commodityInfo.actionTextColor = UIColor.cp_text()
            // TODO: - 这里的逻辑很奇葩, 这个会话是和控制器耦连的, 所以控制器如果没有push或者present出来, 会话是无法真正连接的
            // TODO: - 所以思路就是创建会话, 并present出来, 但用户感知不到, 给客服发消息, 然后dissmiss掉会话
            // 创建一个与客服的回话
            let session = QYSDK.shared().sessionViewController()
            // 文档上说要包在nav中使用, 那就勉强包一下吧
            // 不知道包含了什么骚操作
            // 创建一个空的控制器, 他的view在屏幕之外, 就是不让用户看到
            let vc = UIViewController()
            vc.view.frame = CGRectMake(0, UIScreen.main.bounds.size.height + 100, 1, 1)
            // 然后把这个控制器的view, 添加在当前控制器的view上
            view.addSubview(vc.view)
            guard let session = session else { return }
            let nav = UINavigationController(rootViewController: session)
            // 设置模态的类型, 如果按照默认, 会有动画效果, 就会被看出来
            nav.modalPresentationStyle = .overCurrentContext
            // 空的控制器, 将nav模态出来
            vc.present(nav, animated: false) {
                // 模态出来之后, 延时1.5秒操作, 这里的时间无法把控, 之前设置过1s, 但是, 仍有可能会话没有连接成功
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) {
                    // 延时1.5s后, 会话连接成功(其实也不一定)后, 发送消息给客服
                    session.sendCommodityInfo(commodityInfo)
                    // 然后再过0.25秒, 将会话控制器dismiss掉, 全程不让用户感知
                    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) {
                        session.dismiss(animated: false)
                    }
                }
            }
        }

我创建了一个viewsize{1,1}的控制器, 并且y值为屏幕高度下面100的位置, 这样就可以保证这个view其实是不在用户的视野内的. 然后用这个控制器去present出来奇葩的sessionViewController, 这还没完, 不知道里面有什么异步操作, 我延时一秒后, 竟然还有一定的概率真实的会话没有创建成功, 所以延迟1.5秒, 虽然这不是什么好的操作, 但目前也只能这么玩了. 测试了一段时间, 是可以在用户无法感知的情况下, 去发送给客服消息的.

上一篇 下一篇

猜你喜欢

热点阅读