前言
最近为我们的名厨APP加入了直播功能,总体来说,难度不能算特别高,但对细节的打磨,才是直播的难点所在,因为,一个直播间,播放、聊天、点赞、弹幕等等等,全部放在一个页面去处理,你就不得不考虑这其中的性能问题以及功能过多导致的潜藏bug了,我这里就我所做的直播功能进行一些总结,有需要开发直播模块的开发者,可以稍微参考下,我也会粘一些git上比较好的库过来,减少大家的开发成本
播放器和推流
首先说一下,直播中最最重要的元素,那就是视频播放器了。视频播放器的选择,其实是非常多的,最著名的,非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 。
然后聊天中的聊天列表的处理,可以参考我的这篇简书来处理,以优化性能 http://www.jianshu.com/p/518e9c169274 。
这里有一点需要注意,在一个controller中,将当前controller设置为融云的消息接收代理,就可以接收融云消息了。
[[RCIMClient sharedRCIMClient] setReceiveMessageDelegate:self object:nil];
在页面dealloc中不要只调用 [RCIMClient sharedRCIMClient] quitChatRoom 退出直播间就觉得没事了,因为退出直播间是异步的,可能在当前controller dealloc后才会退出,如果在这段时间收到新的消息,[RCIMClient sharedRCIMClient]就会因为delegate释放了而导致崩溃,所以要在当前controller的dealloc中设置消息接收代理为nil。
[[RCIMClient sharedRCIMClient] setReceiveMessageDelegate:nil object: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;
case AFNetworkReachabilityStatusNotReachable:
无网络
break;
case AFNetworkReachabilityStatusUnknown:
未知网络
break;
default:
break;
}
}];
//开始监控
[mgr startMonitoring];
}
获取状态栏网络状态,有人说在状态栏隐藏的页面,没法获取网络状态,实测是可以获取的,方法里面有我写的枚举,替换下就好了:
- (NSString *)getCurrentNetWork {
NSArray *subviews = [[[[UIApplication sharedApplication] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
for (id child in subviews) {
if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
//获取到状态栏码
int networkType = [[child valueForKeyPath:@"dataNetworkType"] intValue];
switch (networkType) {
case 0: {
// states = NetworkStatesNone;
return CurrentNetWorkNone;
}
break;
case 1: {
// states = NetworkStates2G;
return CurrentNetWorkMobile;
}
break;
case 2: {
// states = NetworkStates3G;
return CurrentNetWorkMobile;
}
break;
case 3: {
// states = NetworkStates4G;
return CurrentNetWorkMobile;
}
break;
case 5: {
// states = NetworkStatesWIFI;
return CurrentNetWorkWifi;
}
break;
default: {
return CurrentNetWorkNone;
}
break;
}
}
}
return CurrentNetWorkNone;
}
结语
如果还想了解其他我没有列举出来的功能的话,可以给我留言,我会尽我能力所及的补充完善这篇文章。