1.x.x 遷移指南
概述
本專案是點播 SDK 2.x.x 的範例 Demo,其 1.x.x 專案為 polyv-ios-client-demo,由於 2.x.x 並非在 1.x.x 的基礎上開發,因此沒有放在同一個專案中,也正因如此,2.x.x 的介面會與 1.x.x 不同。
本文件透過常用的使用方式,介紹如何快速從點播 1.x.x SDK 遷移到 2.x.x。
配置播放器
類別名稱變化:
| 1.x.x | 2.x.x |
|---|---|
| SkinVideoViewController | PLVVodSkinPlayerController |
詳細配置可參考 PLVSimpleDetailController、PLVCourseDetailController 或 PLVVodVidTestController 中的配置。
部署
1.x.x 部署:
// 初始化
_videoPlayer = [[SkinVideoViewController alloc] initWithFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, width, width*(9.0/16.0))];
[_videoPlayer configObserver];
// 添加到视图
[self.view addSubview:self.videoPlayer.view];
[self.videoPlayer setParentViewController:self];
// 需要保留导航栏
[self.videoPlayer keepNavigationBar:YES];
[self.videoPlayer setNavigationController:self.navigationController];
2.x.x 不再使用 frame 佈局,而是採用 Auto Layout 的方式佈局。2.x.x 為方便開發者使用 Auto Layout,省去了自動佈局的程式碼,取而代之的是需要事先佈局一個在直屏狀態或半屏狀態時的佔位視圖:

2.x.x 播放器部署程式碼如下:
PLVVodSkinPlayerController *player = [[PLVVodSkinPlayerController alloc] initWithNibName:nil bundle:nil];
[player addPlayerOnPlaceholderView:self.playerPlaceholder rootViewController:self];
self.player = player;
2.x.x 播放器部署不需要主動呼叫配置方法來實現配置,其 SDK 內部會在適當的時機完成配置。
若需要像 Demo 那樣由播放器控制狀態列(status bar)樣式,還需實作兩個 UIViewController 方法。
- (BOOL)prefersStatusBarHidden {
return self.player.prefersStatusBarHidden;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return self.player.preferredStatusBarStyle;
}
由於
PLVVodPlayerViewController基底類別播放器的基底類別是UIViewController的子類別,因此你甚至可以像使用一般UIViewController物件一樣操作播放器。
設定播放影片
1.x.x 設定播放影片:
[self.videoPlayer setVid:self.video.vid];
2.x.x 設定播放影片:
_weak typeof(self) weakSelf = self;
[PLVVodVideo requestVideoWithVid:vid completion:^(PLVVodVideo *video, NSError *error) {
if (!video.available) return;
weakSelf.player.video = video;
}];
2.x.x 播放給定 vid 的影片是透過取得一個 PLVVodVideo 物件,並傳遞給播放器來實現播放影片。雖然操作比以前複雜,但這大大提高了資料的統一性,其體現在 SDK 的下載影片介面也是透過傳遞 PLVVodVideo 物件來新增下載。另一方面,也提高了影片資料的可重複使用性,使用者根據取得的 PLVVodVideo 物件,透過存取其屬性,即可獲得該影片的所有可用資訊。
播放器功能配置與狀態回呼
2.x.x 播放器功能配置及其狀態取得與回呼可參考 播放器配置。
配置下載器
類別名稱變化:
| 1.x.x | 2.x.x |
|---|---|
| PvUrlSessionDownload | PLVVodDownloadManager PLVVodDownloadInfo |
建立下載器
1.x.x 下載器建立:
PvUrlSessionDownload *downloader = [[PvUrlSessionDownload alloc] initWithVid:video.vid level:video.level];
//设置下载代理为自身,需要实现四个代理方法download delegate
[downloader setDownloadDelegate:self];
[downloader start];
2.x.x 不需要開發者主動建立並管理下載器,取而代之的是使用 PLVVodDownloadManager 統一管理一個下載佇列,開發者只需要操作佇列的開始和停止即可。因此,新增下載器的操作也變成了加入佇列下載:
PLVVodDownloadManager *downloadManager = [PLVVodDownloadManager sharedManager];
PLVVodDownloadInfo *info = [downloadManager downloadVideo:self.video];
[downloadManager startDownload];
狀態監聽
1.x.x 狀態監聽:
// 下载失败回调
- (void)dataDownloadFailed:(PvUrlSessionDownload *)downloader withVid:(NSString *)vid reason:(NSString *)reason {
[[FMDBHelper sharedInstance] updateDownloadStatic:vid status:-1];
NSLog(@"dataDownloadFailed %@ - %@", vid, reason);
}
// 实时获取下载进度百分比回调
- (void)dataDownloadAtPercent:(PvUrlSessionDownload *)downloader withVid:(NSString *)vid percent:(NSNumber *)aPercent {
// !!!: 频繁写入数据库会造成UI卡顿风险,因此此处是隔3秒更新一次数据库
NSTimeInterval timeDiff = [[NSDate date] timeIntervalSinceDate:self.lastTime];
if (timeDiff > 3) {
[[FMDBHelper sharedInstance] updateDownloadPercent:vid percent:aPercent];
self.lastTime = [NSDate date];
}
Video *video = self.videoDic[vid];
video.percent = aPercent.floatValue;
[self updateCellWithVid:vid];
}
// 实时下载速率回调
- (void)dataDownloadAtRate:(PvUrlSessionDownload *)downloader withVid:(NSString *)vid rate:(NSNumber *)aRate {
Video *video = self.videoDic[vid];
video.rate = aRate.floatValue;
[self updateCellWithVid:vid];
}
// 下载状态回调
- (void)downloader:(PvUrlSessionDownload *)downloader withVid:(NSString *)vid didChangeDownloadState:(PLVDownloadState)state {
switch (state) {
case PLVDownloadStatePreparing:{
}break;
case PLVDownloadStateReady:{
NSLog(@"%@ 任务创建", vid);
}break;
case PLVDownloadStateRunning:{
NSLog(@"%@ 任务开始", vid);
}break;
case PLVDownloadStateStopping:{
NSLog(@"%@ 正在停止", vid);
}break;
case PLVDownloadStateStopped:{
NSLog(@"%@ 任务停止", vid);
}break;
case PLVDownloadStateSuccess:{
NSLog(@"%@ 任务完成", vid);
[[FMDBHelper sharedInstance] updateDownloadPercent:vid percent:[NSNumber numberWithInt:100]];
[[FMDBHelper sharedInstance] updateDownloadStatic:vid status:1];
}break;
case PLVDownloadStateFailed:{
}break;
default:{}break;
}
}
1.x.x 使用 PvUrlSessionDownload 下載器物件的委派方法實現狀態回呼與監聽,開發者需要管理維護每個下載器物件,且也無法主動取得其下載狀態。
2.x.x 則使用了透過 PLVVodDownloadInfo 下載資訊物件將下載資訊回呼出來,該物件可在新增下載時從其回傳值取得。
/**
添加至下载队列
添加下载器,仅当 video 错误时,才会报错,quality 错误时,只会警告,并切换到最近的质量进行下载。
@param video PLVVodVideo 视频对象
@param quality 视频画质
@return 下载信息
*/
- (PLVVodDownloadInfo *)downloadVideo:(PLVVodVideo *)video quality:(PLVVodQuality)quality;
/**
使用后台设置的默认画质添加至下载队列
@param video PLVVodVideo 视频对象
@return 下载信息
*/
- (PLVVodDownloadInfo *)downloadVideo:(PLVVodVideo *)video;
開發者可透過 PLVVodDownloadInfo 物件屬性取得其狀態,並透過實作其對應的 Block 實現回呼處理:
/// 下载状态
@property (nonatomic, assign, readonly) PLVVodDownloadState state;
@property (nonatomic, copy) void (^stateDidChangeBlock)(PLVVodDownloadInfo *info);
/// 下载速率(单位:byte/s)
@property (nonatomic, assign, readonly) double bytesPerSeconds;
@property (nonatomic, copy) void (^bytesPerSecondsDidChangeBlock)(PLVVodDownloadInfo *info);
/// 下载进度(0-1)
@property (nonatomic, assign, readonly) double progress;
@property (nonatomic, copy) void (^progressDidChangeBlock)(PLVVodDownloadInfo *info);
例如取得下載進度:
// 获取 `PLVVodDownloadInfo` 对象
PLVVodDownloadInfo *info;
info.progressDidChangeBlock = ^(PLVVodDownloadInfo *info) {
NSLog(@"downlaod %@ progress: %@", info.vid, [NSNumberFormatter localizedStringFromNumber:@(info.progress) numberStyle:NSNumberFormatterPercentStyle]);
};
錯誤處理
1.x.x 的下載錯誤資訊透過 PvUrlSessionDownload 的委派方法 ataDownloadFailed:withVid:reason: 回呼,錯誤資訊僅包含一個字串,較難定位錯誤原因。
2.x.x 的下載中產生的錯誤資訊統一透過 PLVVodDownloadManager 的回呼屬性將錯誤資訊呈現給使用者:
/// 下载错误回调
@property (nonatomic, copy) void (^downloadErrorHandler)(PLVVodVideo *video, NSError *error);
2.x.x 使用標準的 NSError 物件將錯誤的詳細資訊進行封裝,開發者透過 NSError 物件可更輕鬆地理解、定位與解決錯誤。
