不得不吐槽一下网易七鱼SDK
的设计
给客服发消息的会话, 和控制器, 竟然没有分开
你见过拿一个viewController
去发起会话的吗? 讲道理, 我是没有见过的
好的, 那你今天就见到了!
/**
* 获取客服聊天ViewController,非单例,每次调用新建会话页面
*
* @return 会话ViewController
* @discussion 为保证功能完整性,必须嵌入至UINavigationController中使用;保证全局仅有一个VC实例,退出后可正常释放
*/
- (QYSessionViewController *)sessionViewController;
这是七鱼的代码文档
发消息一定要创建会话, 这可以理解. 但会话和控制器其实是两个概念
会话可以理解为一个模型, 用模型去处理调用发消息的接口, 可以做到很好的解耦
而控制器, 尤其是iOS
的控制器, 其实是一个view
的容器, 相当于, 你在view
层去调用网络请求的接口, 是可以这么做, 但是, 耦合性就非常高了. 这样你调用接口必须创建控制器, 并且控制器要处于控制器栈中.
现在产品有一个需求, 就是用户现在处于商品的退款界面, 我这时候就想给客服发一条要退款商品的信息. 七鱼iOS端的做法是, 你必须拉起sessionViewController
界面, 才可以调用发消息的接口
QYSDK.shared().sessionViewController().sendText("test")
直接这样写是不行的. 因为此时sessionViewController
并没有在栈中, 意思是: 其实真正的会话并没有创建成功, 那发送消息肯定就不行了. 会提示
![](https://img.haomeiwen.com/i2868984/4bc808afa5a0de00.jpg)
这就很坑, 我想给客服发消息就不能隐式地发了, 就必须创建一个控制器, 还必须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)
}
}
}
}
我创建了一个view
的size
为{1,1}
的控制器, 并且y
值为屏幕高度下面100
的位置, 这样就可以保证这个view其实是不在用户的视野内的. 然后用这个控制器去present
出来奇葩的sessionViewController
, 这还没完, 不知道里面有什么异步操作, 我延时一秒后, 竟然还有一定的概率真实的会话没有创建成功, 所以延迟1.5
秒, 虽然这不是什么好的操作, 但目前也只能这么玩了. 测试了一段时间, 是可以在用户无法感知的情况下, 去发送给客服消息的.
网友评论