相册功能实现教程
1. 概述
在本教程中,您将学习如何使用Mobile SDK访问飞机相机SD卡或机载闪存中的媒体资源。 在本教程结束时,您将拥有一个可用于预览照片,播放视频,下载或删除文件等的应用程序。
下面以Autel_UX_SDK demo为例讲解如何访问相册、下载、删除、播放等功能。
2. 相册流程图
以下为相册UI层、相册(本地相册)业务管理类、Mobile SDK之间的调用流程
以下为Mobile SDK所提供的接口梳理:
3. 相册API介绍
相册业务封装在Mobile SDK内,开发者可调用DroneConnection.shared.drone?.camera.playbackManager()获取到SD卡的相册管理类,也可调用DroneConnection.shared.drone?.camera.mmcPlaybackManager()获取到机载闪存的相册管理类;DroneConnection类是飞机对象管理单例类,存在于AutelUXFramework动态库中.
如果不希望通过上面的DroneConnection.shared.drone方式获取相机,也可以参考ATConsoleViewController 或者ATConsoleViewModel,它们遵循了CameraProtocol和DroneProtocol协议实时获取相机或者飞机的状态或者参数上报。
注意:若不是继承于BaseViewController的类但继承于NSObject 必须调用以下代码才能注册Protocol,否则遵循的Protocol将不能生效。BaseViewController已经自动注册Protocol,不必再次调用。
func registerProtocol() {
registerAutelProtocolsIfCan()
}
当类销毁时,需要调用以下以进行注销:
func removeProtocol() {
removeAutelProtocolsIfCan()
}
CameraProtocol:
public protocol CameraProtocol : AutelUXFramework.CheckProtocol {
func camera(_ camera: AUTELBaseCamera!, didUpdateConnectState connectState: AUTELCameraConnectState)
func camera(_ camera: AUTELBaseCamera!, didUpdateRecordRecoverState recoverState: AUTELCameraRecordRecoverState)
func camera(_ camera: AUTELBaseCamera!, didGenerateNewMediaFile newMedia: AUTELMedia!)
func camera(_ camera: AUTELBaseCamera!, didUpdateSDCardState sdCardState: AUTELCameraSDCardState!)
func camera(_ camera: AUTELBaseCamera!, didUpdateMMCState mmcState: AUTELCameraSDCardState!)
func camera(_ camera: AUTELBaseCamera!, didUpdateSystemState systemState: AUTELCameraSystemBaseState!)
func camera(_ camera: AUTELBaseCamera!, didUpdateParameters parameters: AUTELCameraParameters!, change: [AnyHashable : [Any]]!)
func camera(_ camera: AUTELBaseCamera!, didUpdateCurrentExposureValues exposureParameters: AUTELCameraExposureParameters!)
func camera(_ camera: AUTELBaseCamera!, didUpdateHistogramTotalPixels totalPixels: Int, andPixelsPerLevel pixelsArray: [Any]!)
func camera(_ camera: AUTELBaseCamera!, didUpdateTimeLapseCaptured captureCount: Int, andCountDown timeInterval: TimeInterval)
func camera(_ camera: AUTELBaseCamera!, didUpdateAutoFocusState focusState: AUTELCameraAFLensFocusState, andLensFocusAreaRowIndex rowIndex: Int, andColIndex colIndex: Int)
func camera(_ camera: AUTELBaseCamera!, didUpdateAeAfState state: AUTELCameraAFWorkStatus)
}
只要能获取到AUTELBaseCamera的实例对象,就可以获取到相册管理类playbackManager或mmcPlaybackManager。
3.1 获取相册列表
// 分页获取文件列表.(默认全部资源类型)
- (void)fetchMediaFileListFromOffset:(NSUInteger)offset
fileCount:(NSUInteger)count
withCompletion:(void (^_Nonnull)(NSArray<AUTELMedia *> *_Nullable mediaList, NSError *_Nullable error))block;
// 分页获取文件列表.(资源类型由调用方传入)
- (void)fetchMediaFileListFromOffset:(NSUInteger)offset
fileCount:(NSUInteger)count
fileType:(AUTELGetFileListType)fileType
withCompletion:(void (^_Nonnull)(NSArray<AUTELMedia *> *_Nullable mediaList, NSError *_Nullable error))block;
成功获取相册列表后,得到列表数组[AUTELMedia],AUTELMedia
为Mobile SDK封装的多媒体文件的基本属性。
/**
* 该类描述SD卡中多媒体文件的基本属性.
*
* This class contains information about a multi-media file on the SD card.
*/
@interface AUTELMedia : NSObject<NSCopying, NSCoding>
/**
* @brief 媒体文件名.
*
* Returns the name of the media file.
*/
@property (nonatomic, readonly) NSString *fileName;
/**
* @brief 媒体文件在SD卡中的存放路径.
*
* Returns the file path of the media file in SD card.
*/
@property (nonatomic, readonly) NSString *filePath;
/**
* @brief 媒体文件创建时间, 格式为: yyyy-MM-dd HH:mm:ss.
*
* Returns the time when the media file was created as a string in
* the format "yyyy-MM-dd HH:mm:ss".
*/
@property (nonatomic, readonly) NSString *timeCreated;
/**
* @brief 媒体文件下标, 新拍摄的文件排放在前.
*
* Returns the index of the media file. The latest taken file will be lined in the front.
*/
@property (nonatomic, readonly) NSUInteger mediaIndex;
/**
* @brief 媒体文件的字节大小.
*
* Returns the size, in bytes, of the media file.
*/
@property (nonatomic, readonly) long long fileSizeInBytes;
/**
* @brief 媒体文件的类型.
*
* Returns the type of media file.
*/
@property (nonatomic, readonly) AUTELMediaType mediaType;
/**
* @brief 媒体文件的唯一标识符.
*
* Returns the unique identifier of media file.
*/
@property (nonatomic, readonly) NSString *uniqueID;
/**
视频时长
*/
@property (nonatomic, assign) NSUInteger videoDuration;
/**
@brief 视频文件的分辨率, 图片文件无分辨率该值为`AUTELCameraVideoResolutionUnknown`, 视频文件初始值也为`AUTELCameraVideoResolutionUnknown`, 当请求过该文件的缩略图后, 该值才有意义。
Returns the resolution of video file.
*/
@property (nonatomic, readonly) AUTELCameraVideoResolution videoResolution;
/**
Returns the video framerate of video file.
*/
@property (nonatomic, readonly) AUTELCameraVideoFrameRate videoFrameRate;
/**
@brief 视频文件的压缩标准
Returns the compreassion standar of video file.
*/
@property (nonatomic, readonly) AUTELCameraVideoFileCompressionStandard videoCompressionStandard;
/**
@brief 全景照片类型
Returns the Types of panoramic photos.
*/
@property (nonatomic, assign) AUTELCameraPanoramaType panoramaType;
/**
@brief 照片任务类型
Returns the Types of mission photos.
*/
@property (nonatomic, assign) AUTELCameraMediaFileType fileType;
AUTELGetFileListType枚举参数说明
typedef NS_ENUM(NSInteger, AUTELGetFileListType) {
/**
* @brief Image file
*
* List of all files
*/
AUTELGetFileListTypeAll = 0,
/**
* @brief Video file list
*
* 视频文件列表
*/
AUTELGetFileListTypeVideo = 1,
/**
* @brief Picture file list
*
* 图片文件列表
*/
AUTELGetFileListTypePhoto = 2,
};
3.2 获取文件的相应缩略图
- (void)fetchThumbnailForMedia:(AUTELMedia *_Nonnull)media
withCompletion:(AUTELLowerResolutionImageCompletion)block; // 获取文件的相应缩略图.
3.3 获取文件的相应预览图
- (void)fetchPreviewImageForMedia:(AUTELMedia *_Nonnull)media
withCompletion:(AUTELLowerResolutionImageCompletion)block;// 获取文件的相应预览图.
3.4 获取视频缓存或下载视频
- (void)playerItemForVideo:(AUTELMedia *_Nonnull)media
withCompletion:(void (^_Nullable)(AVPlayerItem *_Nullable playerItem, BOOL isOriginalData, NSError * _Nullable error))block;// 是否存在缩略视频文件,不存在,判断是否存在原视频文件,不存在,请求缩略视频文件
调用示例
func fetchPlayerItem(media: ATMediaItem, completion: @escaping (Result<AVPlayerItem, Error>) -> Void) {
self.playbackManager?.playerItem(forVideo: media.media, withCompletion: { (item, flag, error) in
if let error = error{
completion(.failure(error.toPlaybackError))
return
}
if let item = item{
completion(.success(item))
}
})
}
3.5 删除资源文件
- (void)deleteMediaItem:(AUTELMedia *_Nonnull)media
withCompletion:(AUTELCompletionBlock)block;// 删除资源文件.
- (void)deleteMedia:(NSArray<AUTELMedia *> *_Nonnull)medias
withProgress:(AUTELFileDeletingProgress)progressBlock
deleteListCompletion:(AUTELFileDeleteListCompletion)deleteListBlock
overallCompletion:(AUTELFileDeleteCompletion)deleteAllBlock;
调用示例
func delete(medias: [AUTELMedia], progress: AUTELFileDeletingProgress?, completion: @escaping (Result<[AUTELMedia], Error>) -> Void) {
playbackManager?.deleteMedia(medias, withProgress: progress, deleteListCompletion: nil, overallCompletion: { (deleteMedias, error) in
if let error = error {
completion(.failure(error.toPlaybackError))
return
}
guard let deleteMedias = deleteMedias else{
completion(.failure(ATAlbumError.delete))
return
}
let mds = medias.filter { media -> Bool in
!deleteMedias.contains(where: { $0.uniqueID == media.uniqueID })
}
completion(.success(mds))
})
}
3.6 下载资源文件
- (void)downloadMedia:(NSArray<AUTELMedia *> *_Nonnull)medias
withPreparation:(AUTELFileDownloadPreparingBlock)prepareBlock
progress:(AUTELFileDownloadProgressBlock)progressBlock
downloadCompletion:(AUTELFileDownloadCompletionBlock)fileCompletionBlock
overallCompletion:(AUTELCompletionBlock)overallCompletionBlock;
- (void)downloadMedia:(NSArray<AUTELMedia *> *_Nonnull)medias
withType:(AUTELDownloadVideoResolutionType)resolutionType
preparation:(AUTELFileDownloadPreparingBlock)prepareBlock
progress:(AUTELFileDownloadProgressBlock)progressBlock
downloadCompletion:(AUTELFileDownloadCompletionBlock)fileCompletionBlock
overallCompletion:(AUTELCompletionBlock)overallCompletionBlock;
调用示例
func downloadOriginal(medias: [ATMediaItem]) {
mediaItems = medias
let medias = mediaItems.compactMap({ $0.media })
let totalBytes = medias.reduce(0) { (result, media) -> Int64 in
return result + media.fileSizeInBytes
}
printLog("totalBytes:",totalBytes)
var downloadedCount: Int = 0
let type = ATSettings.shared.flieExporLeve
ATMediaDataManager.shared.playbackManager?.downloadMedia(medias, with: type == 0 ? AUTELDownloadVideoResolutionType.thumbnail : .original, preparation: { (media, type, skip) in
guard let media = media else { return }
self.currentMedia = media.copy() as? AUTELMedia
self.preSize = 0
self.currentSize = 0
if skip{
downloadedCount += 1
}
}, progress: {[weak self] (total, expected) in
let progress = CGFloat(total)/CGFloat(expected)
self?.progressHandler?(downloadedCount,CGFloat(progress))
self?.currentSize = total
printLog("downloadMedia progress",progress,downloadedCount + 1)
}, downloadCompletion: { (location) in
guard let media = self.currentMedia, let uniqueID = location?.lastPathComponent.components(separatedBy: ".").first else { return }
printLog("downloadCompletion",location,uniqueID)
media.setValue(uniqueID, forKey: "uniqueID")
downloadedCount += 1
self.preSize = 0
self.currentSize = 0
self.saveMedia(media,originalPath: location)
}, overallCompletion: { (error) in
logInfo("图片下载失败:name:\(self.currentMedia?.fileName ?? ""), err:\(error?.localizedDescription) 回调 \(self.completionHandler)")
if let err = error as NSError? {
if let wifiDownload = err.userInfo["wifiDownload"] as? NSNumber,wifiDownload.boolValue == true,err.code != -999 {
if DroneConnection.shared.isConnected {
NotificationCenter.default.post(name: NSNotification.Name("WiFiDisConnectDownloadFailToRCDownload"), object: nil)
self.stopSpeedTimer()
return
}
}
}
self.completionHandler?(error?.toPlaybackError)
self.stopSpeedTimer()
})
startSpeedTimer()
}
3.7 取消下载
- (void)cancelDownloadingWithCompletion:(AUTELCompletionBlock)completion;
/** 取消所有下载<包括缩略图、高清图> */
- (void)cancelAllDownload;
- (void)cancelAllDownloadWithCompletionBlock:(void(^)())completionBlock;
调用示例
func cancelDownload(_ completionBlock:@escaping (()->())) {
if let playbackManager = playbackManager {
playbackManager.cancelDownloading(completion: { error in
completionBlock()
})
} else {
completionBlock()
}
}
4. 相册接入流程
下面以Autel_UX_SDK demo为例讲解如何进行相册功能开发。
在本例中,为方便相册功能开发,我们对底层Mobile SDK相册提供的API做了二次封装,主要涉及的类有ATMediaDataManager、ATAlbumViewController。
- ATAlbumViewController:相册视图控制器,主要支持SD卡、机载闪存、本地相册的相册列表的展示、下载、播放、删除功能的业务。
- ATMediaDataManager:对Mobile SDK提供API的二次封装,同时实现了本地相册的功能封装。
上述类封装在AutelUXFramework.framework动态库。
4.1 配置获取资源文件来源
4.1.1 资源文件存储类型
/** 媒体存储类型 */
public enum ATAlbumStoreType : Int {
case sdCard // 资源文件存储于SD卡
case flash // 资源文件存储于机载闪存
case local // 资源文件存储于手机本地相册
}
4.1.2 更新资源文件来源
在demo中,切换相册导航栏的SD卡、机载闪存、本地相册时,对应的要更新ATMediaDataManager.shared.storeType = type,保证能正确的读取到对应来源的资源文件。
比如,要请求SD卡内的资源,我们需要先配置ATMediaDataManager.shared.storeType = ATAlbumStoreType.sdCard。
func switchDidChange(index: Int) {
guard let type = ATAlbumStoreType(rawValue: index) else {
return
}
ATMediaDataManager.shared.storeType = type
collectionView.mj_header?.beginRefreshing()
}
4.2 获取资源文件
配置好资源文件来源(SD卡、机载闪存、本地相册)后,开始请求相册资源。
4.2.1 枚举类型
4.2.1.1 资源文件类型
typedef NS_ENUM(NSInteger, AUTELGetFileListType) {
/**
* @brief Image file
*
* List of all files
*/
AUTELGetFileListTypeAll = 0,
/**
* @brief Video file list
*
* 视频文件列表
*/
AUTELGetFileListTypeVideo = 1,
/**
* @brief Picture file list
*
* 图片文件列表
*/
AUTELGetFileListTypePhoto = 2,
};
4.2.1.2 资源文件类型
public enum ATMediaType : Int {
/** 照片 */
case photo
/** 视频 */
case video
/** 全景 */
case panaromic
/** 定时拍 */
case burst
/** 未知 */
case unknown
}
4.2.2 拉取相册列表
函数名
public func getFileList(with fileListType: AUTELGetFileListType = .all, offset: Int, count: Int, handler: @escaping (Result<[AUTELMedia], Error>) -> Void)
函数实例
ATMediaDataManager.shared.getFileList(with: .all, offset: pageIndex == 0 ? 0 : allMediaItems.count, count: pageCount) {[weak self] (result) in
completion()
guard let self = self else { return }
switch result{
case let .success(medias):
self.configMediaItems(medias)
case let .failure(error):
GCDUtils.main {
self.configMediaItems([])
ToastManager.shared.show(title: error.localizedDescription)
}
}
}
参数说明
fileListType(资源文件类型,见2.2.1.1):AUTELGetFileListType。可拉取全部类型资源文件,也可以单独拉取照片或单独拉取视频
offset(分页,从0开始):Int
count(每页数量,最大50):Int
handler(回调):<[AUTELMedia], Error>
4.2.3 获取首张照片缩略图
函数名
public func getFirstThumbImage(completion: @escaping (UIImage?) -> Void)
函数调用示例
private func setupThumbnail(){
if thumbnailImage.value != nil {
return
}
ATMediaDataManager.shared.getFirstThumbImage(completion: {[weak self] (image) in
if image != nil {
self?.thumbnailImage.accept(image)
}
})
}
4.2.4 获取本地相册缩略图(文件路径)
函数名
public func fetchThumbImagePath(media: AUTELMedia) -> String?
函数调用示例
func setAlbumLocalThumbImage(with media: ATMediaItem) {
GCDUtils.main {
guard let path = ATMediaDataManager.shared.fetchThumbImagePath(media: media.media) else{
return
}
self.image = UIImage(contentsOfFile: path)
}
}
4.2.5 获取本地相册原文件(文件路径)
函数名
public func fetchOriginalImagePath(media: AUTELMedia) -> String?
函数调用示例
func setAlbumLocalOriginalImage(with media: ATMediaItem) {
setAlbumLocalThumbImage(with: media)
guard let path = ATMediaDataManager.shared.fetchOriginalImagePath(media: media.media) else{
return
}
if media.mediaType == .video{
coverFromVideoPath(path, completion: { (image) in
GCDUtils.main {
self.image = image
}
})
return
}
GCDUtils.main {
self.image = UIImage(contentsOfFile: path)
}
}
4.2.6 读取资源文件基本信息
public struct ATMediaItem {
/** 资源文件 */
public var media: AUTELMedia
/** 文件类型 */
public var mediaType: AutelUXFramework.ATMediaType
/** 文件名(带后缀) */
public var fileName: String?
/** 创建时间戳 */
public var timestamp: TimeInterval
/** 视频时长 */
public var videoLength: String
/** 缩略图下载器 */
public let lowProvider: AutelUXFramework.ATImageDataProvider
/** 预览图下载器 */
public let highProvider: AutelUXFramework.ATImageDataProvider
/** 是否选中 */
public var isSelected: Bool
/** 选中下标 */
public var selectIndex: Int
/** 是否下载 */
public var isDownloaded: Bool { get }
public init(media: AUTELMedia, dateFormatter: DateFormatter?)
/**获取视频封面图。URL:视频文件本地路径*/
public func coverFromVideoPath(_ url: URL?) -> UIImage?
}
4.3 下载资源文件
4.3.1 枚举类型
4.3.1.1 资源清晰度(下载)
public enum PhotoResolutionType : Int {
/// 低清
case low
/// 高清
case high
/// 原文件
case original
/// 未知
case unknown
}
4.3.2 下载单个图片文件(原图,非缩略图)
函数名
public func startDownload(media: AUTELMedia, resoType: AutelUXFramework.PhotoResolutionType, completion: @escaping (Result<Data, Error>) -> Void)
函数调用示例
ATMediaDataManager.shared.startDownload(media: media, resoType: .original) { result in
}
参数说明
media(资源文件):AUTELMedia
resoType(清晰度,见2.2.1.2):PhotoResolutionType
completion(回调):<Data, Error>
4.3.3 下载缩略图(小)
利用资源文件基本信息模型中的缩略图下载器进行下载并缓存本地,依赖swift常用图片下载缓存管理库:kingfisher
属性名
lowProvider // 缩略图(小)下载管理器
函数调用示例
imageView.setAlbumThumbImage(with: media)
func setAlbumThumbImage(with media: ATMediaItem) {
GCDUtils.main {
self.kf.setImage(with: media.lowProvider, placeholder: self.placeholderImage)
}
}
4.3.4 下载预览图(大)
利用资源文件基本信息模型中的预览图下载器进行下载并缓存本地,依赖swift常用图片下载缓存管理库:kingfisher
属性名
highProvider // 预览图(大)下载管理器
函数调用示例
func config(media: ATMediaItem) {
self.media = media
imageView.setAlbumHighImage(with: media)
updateLayout()
}
func setAlbumHighImage(with media: ATMediaItem) {
GCDUtils.main {
self.kf.setImage(with: media.lowProvider, placeholder: self.placeholderImage, options: nil) {[weak self] (result) in
var placeImage: UIImage?
if case let .success(image) = result{
placeImage = image.image
}
self?.kf.setImage(with: media.highProvider, placeholder: placeImage ?? self?.placeholderImage, options: nil, completionHandler: nil)
}
}
}
4.3.5 下载多个图片文件
函数名
public func downloadOriginal(medias: [AutelUXFramework.ATMediaItem])
函数调用示例
func downloadItems(_ medias: [ATMediaItem]) {
ATMediaDataManager.shared.downloadOriginal(medias: medias)
showDownloadProgress(medias.count)
}
4.3.6 取消全部下载任务
函数名
public func cancelAllDownload()// 取消下载队列所有任务,结束正在下载的任务
函数调用示例
ATMediaDataManager.shared.cancelAllDownload(completionBlock)
4.3.7 取消当前下载任务
函数名
public func cancelDownload()
函数调用示例
func showDownloadProgress(_ mediasCount: Int) {
let progressView = ATAlbumProgressView()
var countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), 1,mediasCount)
var speedTitle = ": 0K/s" + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
let pop = ATPopup<ATAlert>.build.theme(.white).title(countTitle + speedTitle)
.addConfirmButton(title: "ATAlbumCancel".fLocal("ATAlbum")) { (alert) in
alert.hide(animiated: true)
ATMediaDataManager.shared.cancelDownload()
}.addCustomView(progressView).done()
pop.show(animiated: true)
progressView.snp.remakeConstraints { (make) in
make.edges.equalToSuperview()
make.width.height.equalTo(55.fit)
}
let downloader = ATMediaDataManager.shared.downloader
downloader.progressHandler = {[weak progressView, weak pop] count,progress in
GCDUtils.main {
progressView?.update(progress)
countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), count + 1,mediasCount)
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.speedHandler = {[weak pop] speed in
GCDUtils.main {
speedTitle = ": " + speed + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.completionHandler = { [weak self,weak pop] error in
GCDUtils.main {
pop?.hide(animiated: true)
if error != nil{
self?.showSuccessAlert(false)
}else{
self?.showFailedAlert(false)
}
}
}
}
4.4 删除资源文件
4.4.1 删除资源文件
函数名
public func delete(medias: [AUTELMedia], progress: AUTELFileDeletingProgress?, completion: @escaping (Result<[AUTELMedia], Error>) -> Void)
函数调用示例
func deleteItems(_ medias: [AUTELMedia]) {
var progressHandler: AUTELFileDeletingProgress?
var completionHandler: (() -> Void)?
showDeleteProgress(medias.count, progressHandler: &progressHandler, completionHandler: &completionHandler)
ATMediaDataManager.shared.delete(medias: medias, progress: progressHandler) { result in
GCDUtils.main {
completionHandler?()
switch result{
case let .success(medias):
self.removeItems(medias: medias)
self.showSuccessAlert()
case .failure(_):
self.showFailedAlert()
}
}
}
}
4.4.2 取消删除
函数名
public func cancelDelete()// 将所有删除任务清空,结束删除
函数调用示例
ATMediaDataManager.shared.cancelDelete()
4.5 播放视频文件
4.5.1 获取视频资源文件(视频)
函数名
public func fetchPlayerItem(media: AUTELMedia, completion: @escaping (Result<AVPlayerItem, Error>) -> Void)
函数调用示例
func play(_ playerView: ATPlayerView) {
guard let media = media else {
return
}
if let media = media as? ATMediaItem, let localPath = ATMediaDataManager.shared.fetchLocalPath(media: media, media.videoPathType) {// 如果存在视频media,并且media存在本地文件路径
let item = AVPlayerItem(url: URL(fileURLWithPath: localPath))
playerView.setPlayerItem(item)
playerView.player?.autoReplay = false
}else {// 通过此方法获取视频文件路径
loadingIndicatorView.startAnimating()
media.fetchPlayerItem {[weak playerView] result in
GCDUtils.main {
self.loadingIndicatorView.stopAnimating()
switch result{
case let .success(item):
playerView?.setPlayerItem(item)
playerView?.player?.autoReplay = false
playerView?.player?.uniqueID = media.uniqueID
playerView?.player?.play()
case .failure(_):
// ToastManager.shared.show(title: error.localizedDescription)
break
}
}
}
}
playerView.player?.uniqueID = media.uniqueID
contentView.addSubview(playerView)
playerView.snp.remakeConstraints { (make) in
make.edges.equalTo(imageView)
}
playerView.player?.play()
self.playerView = playerView
contentView.layoutIfNeeded()
}
4.6 下载管理模块
4.6.1 获取下载管理模块
属性调用示例
let downloader = ATMediaDataManager.shared.downloader
通过let downloader = ATMediaDataManager.shared.downloader获取到下载管理模块后,可以通过调用下载进度回调progressHandler、下载速度回调speedHandler、完成回调completionHandler来进行界面展示
func showDownloadProgress(_ mediasCount: Int) {
let progressView = ATAlbumProgressView()
var countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), 1,mediasCount)
var speedTitle = ": 0K/s" + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
let pop = ATPopup<ATAlert>.build.theme(.white).title(countTitle + speedTitle)
.addConfirmButton(title: "ATAlbumCancel".fLocal("ATAlbum")) { (alert) in
alert.hide(animiated: true)
ATMediaDataManager.shared.cancelDownload()
}.addCustomView(progressView).done()
pop.show(animiated: true)
progressView.snp.remakeConstraints { (make) in
make.edges.equalToSuperview()
make.width.height.equalTo(55.fit)
}
let downloader = ATMediaDataManager.shared.downloader
downloader.progressHandler = {[weak progressView, weak pop] count,progress in
GCDUtils.main {
progressView?.update(progress)
countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), count + 1,mediasCount)
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.speedHandler = {[weak pop] speed in
GCDUtils.main {
speedTitle = ": " + speed + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.completionHandler = { [weak self,weak pop] error in
GCDUtils.main {
pop?.hide(animiated: true)
if error != nil{
self?.showSuccessAlert(false)
}else{
self?.showFailedAlert(false)
}
}
}
}
4.6.2 展示下载进度
通过let downloader = ATMediaDataManager.shared.downloader获取下载管理器,进而获取下载速度、下载进度、完成情况。
函数调用示例
func showDownloadProgress(_ mediasCount: Int) {
let progressView = ATAlbumProgressView()
var countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), 1,mediasCount)
var speedTitle = ": 0K/s" + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
let pop = ATPopup<ATAlert>.build.theme(.white).title(countTitle + speedTitle)
.addConfirmButton(title: "ATAlbumCancel".fLocal("ATAlbum")) { (alert) in
alert.hide(animiated: true)
ATMediaDataManager.shared.cancelDownload()
}.addCustomView(progressView).done()
pop.show(animiated: true)
progressView.snp.remakeConstraints { (make) in
make.edges.equalToSuperview()
make.width.height.equalTo(55.fit)
}
let downloader = ATMediaDataManager.shared.downloader
downloader.progressHandler = {[weak progressView, weak pop] count,progress in
GCDUtils.main {
progressView?.update(progress)
countTitle = String(format: "ATAlbumDownloading".fLocal("ATAlbum"), count + 1,mediasCount)
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.speedHandler = {[weak pop] speed in
GCDUtils.main {
speedTitle = ": " + speed + "\n\n" + "ATAlbumDownloadSpeedLow".fLocal("ATAlbum")
pop?.viewModel.title = countTitle + speedTitle
pop?.update()
}
}
downloader.completionHandler = { [weak self,weak pop] error in
GCDUtils.main {
pop?.hide(animiated: true)
if error != nil{
self?.showSuccessAlert(false)
}else{
self?.showFailedAlert(false)
}
}
}
}