如何重新架構 JPVideoPlayer

NewPan發表於2019-02-23

如何重新架構 JPVideoPlayer

注意:此文為配合 JPVideoPlayer version 2.0 版本釋出而寫,如果你想了解 2.0 版本的更新內容和所有實現細節,請點選前往 GitHub

導言:我幾個月前寫了一個在 UITableView 中滑動 UITableViewCell 播放視訊的框架,類似於“新浪微博” 和 “Facebook” 首頁視訊播放。我也為第一版本的 JPVideoPlayer 實現寫了兩篇文章:
01、[iOS]仿微博視訊邊下邊播之封裝播放器 講述如何封裝一個實現了邊下邊播並且快取的視訊播放器。
02、[iOS]仿微博視訊邊下邊播之滑動TableView自動播放 講述如何實現在UITableView中滑動播放視訊,並且是流暢,不阻塞執行緒,沒有任何卡頓的實現滑動播放視訊。同時也將講述當UITableView滾動時,以什麼樣的策略,來確定究竟哪一個cell應該播放視訊。

當時匆忙實現功能,沒有仔細斟酌架構的問題,也沒有徹底的實現單個功能的元件化。而且由於架構設計不足帶來一些不可避免的問題。這些問題,1.0 版本的使用者應該有所體會。前段時間獨自回了一趟老家,車程比較長,而且可以專注而不被打擾,在車上寫了一個 2.0 版本。2.0 版本有部分內容模仿了SDWebImage 的設計。

2.x 版本效果如下:

如何重新架構 JPVideoPlayer

01.JPVideoPlayer Version 2.0 如何使用?

考慮到 API 和架構都重新設計了,尤其是 API 全部重新設計,1.0 版本的 API 已經不能沿用了,機智的我已經做好了被罵得很慘的心理準備了。

如果你是新的使用者,就不會受之前版本的影響。最終不管你是新使用者還是老使用者,你一定會喜歡這種新的 API 設計的,因為這是目前 iOS 最受歡迎的 API 設計。

Objective-C:

#import <UIView+WebVideoCache.h>

...
NSURL *url = [NSURL URLWithString:@"http://lavaweb-10015286.video.myqcloud.com/%E5%B0%BD%E6%83%85LAVA.mp4"];
[aview jp_playVideoWithURL:url];
複製程式碼

02.JPVideoPlayer Version 2.0 內部執行細節?

很多使用者可能不會有時間去讀原始碼,但是也許會關心 2.0 版本內部實現的一些大的方式,所以這裡我總結了一張 2.0 版本的實現大致結構圖表,如下:

如何重新架構 JPVideoPlayer

下面我用文字來表述一下框架內部的運作順序:

  • 01.提供給外部呼叫的 API 非常簡潔,採用為 UIView 新增分類方法的形式為外界呼叫,只要匯入了標頭檔案,所有 UIView 的子類都擁有播放視訊的方法。框架把 UIView 的分類方法作為和框架內部互動的橋樑。

  • 02.JPVideoPlayerManager 負責甄別使用者傳過來的 URL,根據不同的 URL 作出不同的反應進行視訊播放。具體細節如下:

  • 02.1、是否是本地檔案路徑,如果是本地路徑,直接把路徑給負責視訊播放的工具類 JPVideoPlayerPlayVideoTool 進行視訊播放;

  • 02.2、如果不是本地路徑,再根據 URL 生成快取的 key 給 JPVideoPlayerCache 工具類查詢是否有本地快取檔案,如果有快取就把快取路徑返還給JPVideoPlayerManagerJPVideoPlayerManager 會把路徑給負責視訊播放的工具類 JPVideoPlayerPlayVideoTool 進行視訊播放;

  • 02.3、如果沒有本地快取,就把 URL 給 JPVideoPlayerDownloader 下載工具類,這個工具類就會去網路上下載視訊資料,每下載完一段資料,都會返回給 JPVideoPlayerManagerJPVideoPlayerManager 會先把這段資料給 JPVideoPlayerCacheJPVideoPlayerCache 先把資料快取到磁碟,然後再把快取的路徑返還給JPVideoPlayerManagerJPVideoPlayerManager 會把路徑給負責視訊播放的工具類 JPVideoPlayerPlayVideoTool 進行視訊播放。

03. JPVideoPlayer Version 2.0 更新了哪些內容?

類名 功能點
JPVideoPlayerDownloaderOperation 下載單個視訊檔案工具
JPVideoPlayerDownloader 下載工具類,管理下載操作佇列
JPVideoPlayerCachePathTool 管理臨時和完整視訊儲存路徑
JPVideoPlayerCacheConfig 快取配置檔案,包括快取週期,最大磁碟快取等
JPVideoPlayerCache 快取工具類,負責視訊資料的存、取、刪、更新
JPVideoPlayerResourceLoader 視訊播放器的資料代理,負責將網路視訊資料填充給播放器
JPVideoPlayerPlayVideoTool 視訊播放工具類
JPVideoPlayerManager 管理者,協調各個模組相互配合工作

接下來我將大致描述一下每個類的實現:

  • 01.JPVideoPlayerDownloaderOperation:它繼承自 NSOperation,它內部持有一個 NSURLSession 例項物件,由這個例項物件去負責下載視訊資料,JPVideoPlayerDownloaderOperation 成為這個例項物件的代理,監聽獲取下載到的資料,並將獲得的資料回傳給操作的所有者 JPVideoPlayerDownloader

  • 02.JPVideoPlayerDownloader:它持有一個下載佇列,下載佇列裡存放的是 JPVideoPlayerDownloaderOperation 例項物件。考慮到播放視訊資料量較大而且是持續的,為了將所有的網路資源用於載入當前使用者播放的視訊,提升使用體驗,所以這個佇列在任何時候都只允許一個下載操作執行。它接收到 JPVideoPlayerDownloaderOperation 回撥的資料以後會繼續把資料回傳出去。

  • 03.JPVideoPlayerCachePathTool:它負責管理快取檔案的路徑,包括臨時和完整視訊儲存路徑兩個部分。

  • 04.JPVideoPlayerCacheConfig:這個類存放著快取儲存週期,最大磁碟快取等快取配置資料。

  • 05.JPVideoPlayerCache:它負責資料的存、取、刪、更新等功能。當呼叫存資料的功能時,會在臨時檔案存放的資料夾內新建一個 mp4 檔案,並開始將資料寫入到這個檔案內,存完一段資料以後,會將儲存資料的路徑回撥出去。每次播放視訊的時候,都會去查詢快取中有沒有這個 URL 的完整資料快取,如果有就會把路徑回撥出去。它還對外提供獲取快取大小的功能,如果你需要在設定裡獲取當前視訊快取,可以呼叫這個介面。它還有刪除快取視訊資料的功能。

  • 06.JPVideoPlayerResourceLoader 這個類沿用自 1.0 版本,負責從已經下載的資料中找出播放器需要的資料,並將資料填充到播放器的資料請求中進行視訊播放。

  • 07.JPVideoPlayerPlayVideoTool 這個類持有一個視訊播放器,負責串聯從視訊資料到影象和影音的整個播放功能。

  • 08.JPVideoPlayerManager 它是框架的管理者、大管家,它的具體功能上面“內部細節”已經陳述過了,這裡不重複了。

  • 09.其他還有一個資料載入進度條和一個緩衝狀態指示器,這些都很簡單。還有就是 2.0 版本的 Demo 將 UITableViewController 視訊播放抽到一個分類中集中管理,也方便後期維護,如果你的需求和 Demo 類似,可以考慮直接把這個分類拽進專案,需要改動的程式碼很少,就能實現。

04.為什麼要這麼改?

這個問題我想從使用者和我自己,還有它本來應該是什麼樣子這些維度來分析。

04.1、使用者角度
  • 01.首先,受使用者歡迎的框架應該要具備兩個基本的素質。第一,呼叫起來方便,能一行程式碼解決的,絕不搞兩行。第二,不侵入使用者的專案,萬一哪天框架不維護了,也不要成為使用者的累贅。

  • 02.其次,我說一個我今天看一個框架的感受,是一個類似微信選擇多張照片的框架,框架對外提供的介面不夠我用,所以我只能去框架內部改,但是當我找一個功能的時候,框架文件沒有說明,我在那些程式碼應該放的位置也沒有找到,需求就是改字型和顏色,我找了一上午,終於在一個不可能猜到的位置找到了那幾行程式碼。這裡就有幾個問題點:

  • 我們對外提供的介面儘量讓使用者夠用,如果沒有考慮到,那使用者就可能會來框架裡改。
  • 我們的框架類的命名,方法的命名都應該遵守蘋果的那套標準,因為大家天天在用的都是蘋果 API,如果完全不遵守蘋果那套,那使用者來到框架裡就是一頭霧水,這裡有一個溝通成本的問題,看懂程式碼之前還要先熟悉我們特有的標準。就像去美國,要和美國人說話,要先學英語。
  • 文件一定要詳實,每個人水平都不一樣,程式碼可能看不懂,但是文字誰都認識,這是作者和使用者溝通的基礎。
04.2、作者角度

維護框架其實也是很花時間的一件事情,1.0 版本的時候,就經常有使用者給我留言,發QQ訊息和我溝通實現的細節,還要他們希望下個版本希望加進去的一些功能。

當時很多功能的程式碼都混在一個類裡,第一就是這個類上千行程式碼,我自己要改一個東西都需要用搜尋功能才能找到,各個方法之間相互呼叫的時候跳來跳去,頭暈眼花。

現在每個模組劃分完功能以後,每個功能的核心程式碼都高度集中在對應的類裡,隱藏實現的細節,遮蔽了外部的干擾,只對外提供必要的介面。現在除錯問題的時候,分析到出現問題可能的模組以後,能快速定位到對應類的對應方法裡,只需要在當前類裡專注當前的問題就可以了,不需要考慮外部的影響。這個效率的提升還是蠻明顯的。

所以從作者的角度,這個架構的好處就是,第一,方便我後期的維護,提高效率;第二,方便和使用者的溝通,減少溝通成本;第三,當有新功能的時候,我能快速的把程式碼寫到對應的類別裡。

04.3、它本來的樣子

前段時間看 BBC 的 “Planet Earth” 紀錄片,裡面說螞蟻巢穴裡有幾千萬只螞蟻,但是卻分工明確,秩序盡然。原來,螞蟻分為四類:

  • 蟻后,也叫蟻皇,是一族之主,專管產卵繁殖,一般一群只有一個,體型特大,行動不便,由工蟻侍候。
  • 雄蟻,專與蟻后交配,交配後即死亡,一群中有數十隻或數百隻,要看蟻群的大小。
  • 工蟻,是蟻群中的主要成員,專司覓食、飼養幼蟻、侍候蟻后、搬家清掃等等雜勤工作。
  • 兵蟻,個頭較大,雙顎發達,是蟻群中的保衛者,擔負著本蟻群的安全,如有外蟻入侵,或爭奪食物時,必誓死決鬥。

我們的程式碼或許也可以仿照大自然,先劃分功能,再列出幾個類,將功能點挨個集中到類裡,武裝出類,就是所謂的物件。這就是我理解的框架應該有的美。

05.Update.

2017.04.04 更新.

如何重新架構 JPVideoPlayer

2017.05.31 更新:

如何重新架構 JPVideoPlayer

2017.05.02 更新. 有些朋友反應有些視訊無法邊下邊播, 具體解決思路請參考 這篇博文

NewPan 的文章集合

下面這個連結是我所有文章的一個集合目錄。這些文章凡是涉及實現的,每篇文章中都有 Github 地址,Github 上都有原始碼。

NewPan 的文章集合索引

如果你有問題,除了在文章最後留言,還可以在微博 @盼盼_HKbuy 上給我留言,以及訪問我的 Github

相關文章