播放器和推流
首先说一下,直播中最最重要的元素,那就是视频播放器了。视频播放器的选择,其实是非常多的,最著名的,非b站的IJKPlayer莫属了。其实现在很多三方的播放器,开发者在编写的时候,都是按照系统的MPMoviePlayer的接口设计的,所以,你只要学会使用一个播放器,其他播放器的使用都会很轻松的上手。
附上两个比较有参考价值的demo,一个是自定义IJKPlayer,进度条、音量、亮度,可以参考这个demo,对IJKPlayer进行深度的个性化定制(其他播放器也适用),比如大部分播放器支持的屏幕手势(滑动调整音量、亮度、进度等),另一个是ZFPlayer,这个播放器基于AVPlayer,主要可以参考里面的横竖平切换的处理,也可以直接拿来做普通的视频播放器继承在应用中,很多功能都已经做好,用起来很方便。
关于直播的推流,目前来说最火的应该是这个了LFLiveKit。具体我没有使用过,但有一些个人仿写项目都是IJKPlayer配合LFLiveKit完成的。
下面推荐几个个人仿写的项目,可以参考下大部分直播中会出现的场景的处理策略。这个是仿映客的520Linkee,这个是仿喵播的MiaowShow,这两个都是市面上比较常见的个人手机端直播的典型实现方案。
至于我所使用的播放器和推流SDK,因为我们的直播服务是和金山云合作的,所以两个SDK都是用的金山云自家的SDK,他们的SDK更新频率挺快的,而且最新版已经支持https了。但他们的SDK也存在一些bug,不过好在他们的每一版更新都会及时的进行修复。
经过对比了好多家的SDK demo(阿里、网易、腾讯、七牛等)后,你会发现金山的SDK demo是写的最完善的,推流端你直接拿过来给个推流地址就可以推了,包括美颜、码率、编码等等,都在demo上有选项可供设置,你只要在开发的时候,对这些功能重新设计下UI就好了。播放器demo、推流demo,建议在使用的过程中,多跟进他们的更新release,你会发现他们每次更新都会优化很多功能、修复很多bug(不像友盟,每次更新都有新bug!!!气人!!!)。
聊天
既然大家都在看直播,互动肯定也少不了,直播聊天室就必须要有。我们用的是融云,因为融云的宣传和口碑都不错,所以就选择了融云,而且也是好多直播服务商的合作伙伴,所以可以放心使用。其他的还有环信和野狗,环信的控制台和文档,不如融云友好,野狗的没有试过,个人建议使用融云。而且融云官网有集成了播放器、聊天的直播间demo可以参考,里面带了一个香港某电视台的直播流,可以用来测试用来rtmp://live.hkstv.hk.lxdns.com/live/hks。
然后聊天中的聊天列表的处理,可以参考我的这篇简书来处理,以优化性能//www.greatytc.com/p/518e9c169274。
这里有一点需要注意,在一个controller中,将当前controller设置为融云的消息接收代理,就可以接收融云消息了。
[[RCIMClient sharedRCIMClient]setReceiveMessageDelegate:selfobject:nil];
在页面dealloc中不要只调用 [RCIMClient sharedRCIMClient] quitChatRoom 退出直播间就觉得没事了,因为退出直播间是异步的,可能在当前controller dealloc后才会退出,如果在这段时间收到新的消息,[RCIMClient sharedRCIMClient]就会因为delegate释放了而导致崩溃,所以要在当前controller的dealloc中设置消息接收代理为nil。
[[RCIMClient sharedRCIMClient]setReceiveMessageDelegate:nilobject:nil];
点赞动画
点赞动画可以参考这个https://github.com/singer1026/DMHeartFlyAnimation,主要通过CAKeyFrameAnimation和UIBezierPath完成,也可以自行修改代码修改动画轨迹、替换点赞图片等。
弹幕
弹幕建议使用BarrageRenderer,性能不错,git主页的介绍,就能让你很简单的上手使用,但如果你要做历史消息的弹幕和即时消息结合的弹幕,建议历史弹幕的遍历以及时间轴绑定,还是自己写比较好,因为这个库的redisplay以及绑定时间轴方法,在与即时消息结合的时候,弹幕的展示可能会有重复出现多次的现象。
网络切换
直播中我们要考虑用户的当前网络状态,移动网络帮他停止播放,或者切换到wifi的时候,帮他重连,以减少流量的耗费。网络的变化主要通过两种方式判断,一种是Reachability,另一种是获取状态栏上的网络状态。
Reachability写在AppDelegate中,在网络状态变化的时候,block中的代码就会被调用,你想把网络变化的消息发送给直播页面,直接用通知中心就可以,然后Reachability建议使用AFNetworking的,因为之前有文章说Reachability库可能会引起不支持ipv6导致审核被拒,我们项目中用的AFNetworking中的Reachability,没有问题:
- (void)monitorNetworking { AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]; [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {switch(status) { wifi网络break; 移动网络break;caseAFNetworkReachabilityStatusNotReachable: 无网络break;caseAFNetworkReachabilityStatusUnknown: 未知网络break;default:break; } }];//开始监控[mgr startMonitoring];}
获取状态栏网络状态,有人说在状态栏隐藏的页面,没法获取网络状态,实测是可以获取的,方法里面有我写的枚举,替换下就好了:
- (NSString*)getCurrentNetWork {NSArray*subviews = [[[[UIApplicationsharedApplication] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];for(idchildinsubviews) {if([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {//获取到状态栏码intnetworkType = [[child valueForKeyPath:@"dataNetworkType"] intValue];switch(networkType) {case0: {// states = NetworkStatesNone;returnCurrentNetWorkNone; }break;case1: {// states = NetworkStates2G;returnCurrentNetWorkMobile; }break;case2: {// states = NetworkStates3G;returnCurrentNetWorkMobile; }break;case3: {// states = NetworkStates4G;returnCurrentNetWorkMobile; }break;case5: {// states = NetworkStatesWIFI;returnCurrentNetWorkWifi; }break;default: {returnCurrentNetWorkNone; }break; } } }returnCurrentNetWorkNone;}