不少iOS应用启动时都添加了类似动画的视频广告,今天做了一个小demo,简洁易用!
一、资源
广告视频采用mp4格式
采用AVFoundition框架
#import <AVFoundation/AVFoundation.h>
二、代码实现
1.创建动画功能
@property (nonatomic, strong) AVPlayer * player;
@property (nonatomic, strong) AVPlayerItem * playerItem;
- (void)createAvPlayer
{
CGRect playerFrame = CGRectMake(0, 0, kScreenWith, kScreenHeight);
NSURL * url = [[NSBundle mainBundle] URLForResource:@"guideVideo" withExtension:@"mp4"];
AVURLAsset * asset = [AVURLAsset assetWithURL:url];
_playerItem = [AVPlayerItem playerItemWithAsset: asset];
_player = [[AVPlayer alloc]initWithPlayerItem:_playerItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
playerLayer.frame = playerFrame;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[self.view.layer addSublayer:playerLayer];
[_player play];
}
这时候可以播放了。
2.如果播放前需要有个缓冲效果,可以获取视频的第一帧图片作为封面加在视图上,当动画开始播放时,移除封面。
@property (nonatomic, strong) UIImageView * coverImageView;
- (void)creatCoverImageView
{
self.coverImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.coverImageView];
self.coverImageView.image = [self getVideoPreViewImage];
}
/*** 获取视频第一帧 ***/
- (UIImage*)getVideoPreViewImage
{
NSURL * url = [[NSBundle mainBundle] URLForResource:@"guideVideo" withExtension:@"mp4"];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator * gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform = YES;
CMTime time = CMTimeMakeWithSeconds(0.0, 600);
NSError *error = nil;
CMTime actualTime;
CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
UIImage *img = [[UIImage alloc] initWithCGImage:image];
CGImageRelease(image);
return img;
}
注册AVPlayerItem 播放状态的观察者
- (void)addVideoKVO
{
//KVO
[_playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)removeVideoKVO
{
[_playerItem removeObserver:self forKeyPath:@"status"];
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"status"])
{
AVPlayerItemStatus status = _playerItem.status;
switch (status)
{
case AVPlayerItemStatusReadyToPlay:
{
NSLog(@"AVPlayerItemStatusReadyToPlay");//当播放开始时,移除封面
[self.coverImageView removeFromSuperview];
}
break;
case AVPlayerItemStatusUnknown:
{
NSLog(@"AVPlayerItemStatusUnknown");
}
break;
case AVPlayerItemStatusFailed:
{
NSLog(@"AVPlayerItemStatusFailed");
}
break;
default:
break;
}
}
}
3.注册其他消息类型
-(void)addNotification
{
//给AVPlayerItem添加播放完成通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginSccess:) name:k_Notification_login object:nil];
}
- (void)playbackFinished:(NSNotification *)notification
{
// 播放完成后重复播放
// 跳到最新的时间点开始播放
[_player seekToTime:kCMTimeZero];
[_player play];
}
- (void)appWillResignActive:(NSNotification *)notification
{
if (self.player)
{
[self.player pause];
self.time = self.player.currentTime;
}
}
- (void)appBecomeActive:(NSNotification *)notification
{
//在刚启动播放的时候,以及在播放到最后一帧的时候,有可能会出现异常并crash
//用@try@catch来捕获这个异常,当出现异常的时候直接调用play让播放器自己决定播放的进度
@try {
[self.player seekToTime:self.time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[self.player play];
}
}];
} @catch (NSException *exception) {
[self.player play];
} @finally {
}
}
- (void)loginSccess:(NSNotification *)notification
{
[self.navigationController popViewControllerAnimated:NO];
}