├── DGDownloadManager ├── Assets │ └── .gitkeep ├── Classes │ ├── .gitkeep │ ├── DGDownloadManagers │ │ ├── DGDownloadItem.m │ │ ├── NSDataAdditions.h │ │ ├── DGHttpConfig.h │ │ ├── DGHttpConfig.m │ │ ├── DGFileManager.h │ │ ├── DGDownloadSaveItem.h │ │ ├── DGDownloadSaveItem.m │ │ ├── NSDataAdditions.m │ │ ├── DGDownloadManager.h │ │ ├── DGDownloadItem.h │ │ ├── DGFileManager.m │ │ └── DGDownloadManager.m │ └── DGBackgroudDownloadManagers │ │ ├── NSURLSession+CorrectedResumeData.h │ │ ├── NSData+Category.h │ │ ├── DGBackgroudDownloadSaveModel.h │ │ ├── DGBackgroudDownloadCacheManager.h │ │ ├── DGBackgroudDownloadDelegate.h │ │ ├── DGBackgroudDownloadSaveModel.m │ │ ├── DGBackgroudDownloadModel.m │ │ ├── NSData+Category.m │ │ ├── DGBackgroudDownloadModel.h │ │ ├── DGBackgroudDownloadManager.h │ │ ├── DGBackgroudDownloadDelegate.m │ │ ├── DGBackgroudDownloadCacheManager.m │ │ ├── NSURLSession+CorrectedResumeData.m │ │ └── DGBackgroudDownloadManager.m └── .gitignore ├── _Pods.xcodeproj ├── 1.png ├── 2.png ├── Example ├── Tests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Tests-Prefix.pch │ ├── Tests-Info.plist │ └── Tests.m ├── DGDownloadManager │ ├── 1.png │ ├── 2.png │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── ViewController.h │ ├── AppDelegate.h │ ├── DownloadCell.h │ ├── main.m │ ├── DownloadCell.m │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── AppDelegate.m │ ├── DownloadCell.xib │ └── ViewController.m ├── build │ └── XCBuildData │ │ ├── 4cd2e3696df79c4caf3ef0db80b22f53-desc.xcbuild │ │ ├── 5932e3ab26b5df551435b24d8f6227a7-desc.xcbuild │ │ └── BuildDescriptionCacheIndex-57db9e6df40832bc0636c71d4ce1435d ├── Podfile ├── DGDownloadManager.xcworkspace │ └── contents.xcworkspacedata ├── Podfile.lock └── DGDownloadManager.xcodeproj │ └── project.pbxproj ├── .gitignore ├── .travis.yml ├── LICENSE ├── DGDownloadManager.podspec └── README.md /DGDownloadManager/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/2.png -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/Example/DGDownloadManager/1.png -------------------------------------------------------------------------------- /Example/DGDownloadManager/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/Example/DGDownloadManager/2.png -------------------------------------------------------------------------------- /Example/DGDownloadManager/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/build/XCBuildData/4cd2e3696df79c4caf3ef0db80b22f53-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/Example/build/XCBuildData/4cd2e3696df79c4caf3ef0db80b22f53-desc.xcbuild -------------------------------------------------------------------------------- /Example/build/XCBuildData/5932e3ab26b5df551435b24d8f6227a7-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/Example/build/XCBuildData/5932e3ab26b5df551435b24d8f6227a7-desc.xcbuild -------------------------------------------------------------------------------- /Example/build/XCBuildData/BuildDescriptionCacheIndex-57db9e6df40832bc0636c71d4ce1435d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liudiange/DGDownloadManager/HEAD/Example/build/XCBuildData/BuildDescriptionCacheIndex-57db9e6df40832bc0636c71d4ce1435d -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | 2 | use_frameworks! 3 | platform :ios, '9.0' 4 | 5 | target 'DGDownloadManager' do 6 | 7 | #pod 'DGDownloadManager/DGBackgroudDownloadManagers', :path => '../' 8 | pod 'DGDownloadManager',:subspecs => ['DGBackgroudDownloadManagers','DGDownloadManagers'], :path => '../' 9 | 10 | end 11 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadItem.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "DGDownloadItem.h" 10 | 11 | @implementation DGDownloadItem 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | Example/Pods/* 4 | !Example/Pods/Pods.xcodeproj/project.pbxproj 5 | 6 | 7 | Example/DGDownloadManager.xcodeproj/* 8 | !Example/DGDownloadManager.xcodeproj/project.pbxproj 9 | 10 | Example/DGDownloadManager.xcworkspace/* 11 | !Example/DGDownloadManager.xcworkspace/contents.xcworkspacedata 12 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/25. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Example/DGDownloadManager.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/25. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/DownloadCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // downloadCell.h 3 | // DownloadManager 4 | // 5 | // Created by 刘殿阁 on 2017/11/17. 6 | // Copyright © 2017年 刘殿阁. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import "DGBackgroudDownloadModel.h" 12 | 13 | @interface DownloadCell : UITableViewCell 14 | 15 | @property (nonatomic, strong) DGBackgroudDownloadModel *model; 16 | 17 | @end 18 | 19 | 20 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/25. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/NSURLSession+CorrectedResumeData.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSURLSession+CorrectedResumeData.h 3 | // BackgroundDownloadDemo 4 | // 5 | // Created by admin on 2016/10/12. 6 | // Copyright © 2016年 hkhust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSURLSession (CorrectedResumeData) 12 | 13 | - (NSURLSessionDownloadTask *)downloadTaskWithCorrectResumeData:(NSData *)resumeData; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/NSDataAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataAdditions.h 3 | // TapKit 4 | // 5 | // Created by Kevin on 5/22/14. 6 | // Copyright (c) 2014 Tapmob. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSData (TapKit) 12 | 13 | /** 14 | 生成MD5 15 | 16 | @return 返回MD5的字符串 17 | */ 18 | - (NSString *)DG_MD5HashString; 19 | /** 20 | 生成SHA1 21 | 22 | @return 返回SHA1的字符串 23 | */ 24 | - (NSString *)DG_SHA1HashString; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/NSData+Category.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Category.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/28/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSData (Category) 14 | 15 | /** 16 | 生成MD5 17 | 18 | @return 返回MD5的字符串 19 | */ 20 | - (NSString *)DG_MD5HashString; 21 | /** 22 | 生成SHA1 23 | 24 | @return 返回SHA1的字符串 25 | */ 26 | - (NSString *)DG_SHA1HashString; 27 | 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/DGDownloadManager.xcworkspace -scheme DGDownloadManager-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGHttpConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGHttpConfig.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface DGHttpConfig : NSObject 14 | #pragma mark - 借口的配置 15 | 16 | extern NSString * const DGDownloadFinish; 17 | 18 | extern NSString * const DGCancelAllSong; 19 | 20 | extern NSString * const DGCancelOneSong; 21 | 22 | extern NSString * const DGResumeAllSong; 23 | 24 | extern NSString * const DGResumeOneSong; 25 | 26 | extern NSString * const DGSuspendAllSong; 27 | 28 | extern NSString * const DGSuspendOneSong; 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGHttpConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGHttpConfig.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "DGHttpConfig.h" 10 | 11 | @implementation DGHttpConfig 12 | #pragma mark - 借口的配置 13 | 14 | NSString * const DGDownloadFinish = @"donwloadFinish"; 15 | 16 | NSString * const DGCancelAllSong = @"cancelAllSong"; 17 | 18 | NSString * const DGCancelOneSong = @"cancelOneSong"; 19 | 20 | NSString * const DGResumeAllSong = @"resumeAllSong"; 21 | 22 | NSString * const DGResumeOneSong = @"resumeOneSong"; 23 | 24 | NSString * const DGSuspendAllSong = @"suspendAllSong"; 25 | 26 | NSString * const DGSuspendOneSong = @"suspendOneSong"; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadSaveModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadSaveModel.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/7/21. 6 | // 7 | 8 | #import 9 | #import "DGBackgroudDownloadModel.h" 10 | 11 | 12 | @interface DGBackgroudDownloadSaveModel : NSObject 13 | 14 | /** 下载的自定义的缓存文件名*/ 15 | @property (nonatomic, copy) NSString *customCacheName; 16 | 17 | /** 请求的url */ 18 | @property (nonatomic, copy) NSString *requestUrl; 19 | 20 | /** 下载的状态 */ 21 | @property (nonatomic, assign) DGBackgroudDownloadStatus downloadStatus; 22 | 23 | /** 下载的进度 */ 24 | @property (nonatomic, assign) CGFloat progress; 25 | 26 | /** 缓存的文件的路径 */ 27 | @property (nonatomic, copy) NSString *cachePath; 28 | 29 | 30 | 31 | @end 32 | 33 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadManagerTests.m 3 | // DGDownloadManagerTests 4 | // 5 | // Created by shaoyeliudiange@163.com on 03/06/2021. 6 | // Copyright (c) 2021 shaoyeliudiange@163.com. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /DGDownloadManager/.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | # Pods/ 38 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGFileManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGFileManager.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DGDownloadSaveItem.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface DGFileManager : NSObject 15 | /** 16 | * 17 | * 创建目录 18 | */ 19 | + (BOOL)DG_CreatPath:(NSString *)path; 20 | /** 21 | * 22 | * 判断路径是佛存在 23 | */ 24 | + (BOOL)DG_FileIsExist:(NSString *)path; 25 | /** 26 | * 27 | * 删除文件 28 | */ 29 | + (BOOL)DG_DeleteFile:(NSString *)path; 30 | /** 31 | * 32 | * 获取缓存的文件夹路径 33 | */ 34 | + (NSString *)DG_GetCachePath; 35 | 36 | /// 存储下载完成的数据item 37 | /// @param item item 38 | + (void)saveDownloaditem:(DGDownloadItem *)item; 39 | 40 | 41 | /// 获取所有已经下载过的model 42 | + (NSMutableArray *)getAllDownloadItems; 43 | 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadSaveItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadSaveItem.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/7/21. 6 | // 7 | 8 | #import 9 | #import "DGDownloadItem.h" 10 | 11 | @interface DGDownloadSaveItem : NSObject 12 | 13 | /** 下载的自定义的缓存文件名*/ 14 | @property (nonatomic, copy) NSString *customCacheName; 15 | 16 | /** 请求的url */ 17 | @property (nonatomic, copy) NSString *requestUrl; 18 | 19 | /** 下载的状态 */ 20 | @property (nonatomic, assign) DGDownloadStatus downloadStatus; 21 | 22 | /** 下载的进度 */ 23 | @property (nonatomic, assign) CGFloat progress; 24 | 25 | /** 临时存储的文件路径 */ 26 | @property (nonatomic, copy) NSString *temPath; 27 | 28 | /** 缓存的文件的路径 */ 29 | @property (nonatomic, copy) NSString *cachePath; 30 | 31 | /** 请求的方法 */ 32 | @property (nonatomic, copy) NSString *requestMethod; 33 | 34 | /** 参数 */ 35 | @property (nonatomic, strong) NSDictionary *paramDic; 36 | 37 | 38 | 39 | 40 | @end 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/DownloadCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // downloadCell.m 3 | // DownloadManager 4 | // 5 | // Created by 刘殿阁 on 2017/11/17. 6 | // Copyright © 2017年 刘殿阁. All rights reserved. 7 | // 8 | 9 | #import "DownloadCell.h" 10 | 11 | @interface DownloadCell () 12 | 13 | @property (weak, nonatomic) IBOutlet UIProgressView *progressView; 14 | 15 | @property (weak, nonatomic) IBOutlet UILabel *progressLable; 16 | 17 | @property (unsafe_unretained, nonatomic) IBOutlet UILabel *nameLable; 18 | 19 | @end 20 | 21 | @implementation DownloadCell 22 | 23 | - (void)setModel:(DGBackgroudDownloadModel *)model{ 24 | _model = model; 25 | 26 | __weak typeof(self) weakSelf = self; 27 | _model.downloadProgressBlock = ^(CGFloat progress, CGFloat speed) { 28 | dispatch_async(dispatch_get_main_queue(), ^{ 29 | weakSelf.progressView.progress = progress; 30 | weakSelf.progressLable.text = [NSString stringWithFormat:@"%0.2f%%-%0.1fk/s",(progress *100),speed]; 31 | }); 32 | }; 33 | 34 | self.nameLable.text = [_model.requestUrl lastPathComponent]; 35 | 36 | } 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 shaoyeliudiange 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadCacheManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGCacheManager.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/3/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DGBackgroudDownloadModel.h" 11 | #import "DGBackgroudDownloadSaveModel.h" 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | 15 | @interface DGBackgroudDownloadCacheManager : NSObject 16 | 17 | /// 存储resumeData 18 | /// @param downloadUrl 下载的url 19 | /// @param resumeData resumedata 20 | + (void)saveResumeDataWithUrl:(NSString *)downloadUrl 21 | resumeData:(NSData *)resumeData; 22 | 23 | /// 通过一个下载的连接来获取存储的resumedata 24 | /// @param downloadUrl 下载的url 25 | + (NSData *)getResumeData:(NSString *)downloadUrl; 26 | 27 | /// 删除一个resumedata 28 | /// @param downloadUrl 下载的url 29 | + (void)deleteResumeDataWithUrl:(NSString *)downloadUrl; 30 | 31 | /// 存储下载完成的数据model 32 | /// @param model model 33 | + (void)saveDownloadModel:(DGBackgroudDownloadModel *)model; 34 | 35 | 36 | /// 获取所有已经下载过的model 37 | + (NSMutableArray *)getAllDownloadModels; 38 | 39 | @end 40 | 41 | NS_ASSUME_NONNULL_END 42 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadDelegate.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/25/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void(^DownloadFinishBlock)(NSURLSessionDownloadTask *downloadTask,NSURL *location); 12 | 13 | // speed 是kb/s 14 | typedef void(^DownloadProgressBlock)(CGFloat progress,CGFloat speed); 15 | 16 | typedef void(^DownloadErrorBlock)(NSError *error); 17 | 18 | typedef void(^DownloadFinishEventBlock)(NSString *identifier); 19 | 20 | @interface DGBackgroudDownloadDelegate :NSObject 21 | 22 | /** resumeData使用 */ 23 | @property (nonatomic, strong) NSData *resumeData; 24 | 25 | /** 下载完成回调 */ 26 | @property (nonatomic, strong) DownloadFinishBlock downloadFinishBlock; 27 | 28 | /** 下载进度条回调 */ 29 | @property (nonatomic, strong) DownloadProgressBlock downloadProgressBlock; 30 | 31 | /** 下载出错回调 */ 32 | @property (nonatomic, strong) DownloadErrorBlock downloadErrorBlock; 33 | 34 | /** 下载完成后台session回调 */ 35 | @property (nonatomic, strong) DownloadFinishEventBlock downloadFinishEventBlock; 36 | 37 | /// 获取下载的进度 38 | - (CGFloat)getDownloadProgress; 39 | 40 | @end 41 | 42 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadSaveModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadSaveModel.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/7/21. 6 | // 7 | 8 | #import "DGBackgroudDownloadSaveModel.h" 9 | 10 | 11 | @interface DGBackgroudDownloadSaveModel() 12 | 13 | 14 | 15 | @end 16 | @implementation DGBackgroudDownloadSaveModel 17 | 18 | -(instancetype)initWithCoder:(NSCoder *)coder{ 19 | if (self = [super init]) { 20 | self.cachePath = [coder decodeObjectForKey:@"cachePath"]; 21 | self.customCacheName = [coder decodeObjectForKey:@"customCacheName"]; 22 | self.requestUrl = [coder decodeObjectForKey:@"requestUrl"]; 23 | self.downloadStatus = [coder decodeIntegerForKey:@"downloadStatus"]; 24 | self.progress = [coder decodeFloatForKey:@"progress"]; 25 | } 26 | return self; 27 | } 28 | - (void)encodeWithCoder:(NSCoder *)coder 29 | { 30 | [coder encodeObject:self.customCacheName forKey:@"customCacheName"]; 31 | [coder encodeObject:self.requestUrl forKey:@"requestUrl"]; 32 | [coder encodeObject:self.cachePath forKey:@"cachePath"]; 33 | [coder encodeFloat:self.progress forKey:@"progress"]; 34 | [coder encodeInteger:self.downloadStatus forKey:@"downloadStatus"]; 35 | 36 | } 37 | @end 38 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (3.1.0): 3 | - AFNetworking/NSURLSession (= 3.1.0) 4 | - AFNetworking/Reachability (= 3.1.0) 5 | - AFNetworking/Security (= 3.1.0) 6 | - AFNetworking/Serialization (= 3.1.0) 7 | - AFNetworking/UIKit (= 3.1.0) 8 | - AFNetworking/NSURLSession (3.1.0): 9 | - AFNetworking/Reachability 10 | - AFNetworking/Security 11 | - AFNetworking/Serialization 12 | - AFNetworking/Reachability (3.1.0) 13 | - AFNetworking/Security (3.1.0) 14 | - AFNetworking/Serialization (3.1.0) 15 | - AFNetworking/UIKit (3.1.0): 16 | - AFNetworking/NSURLSession 17 | - DGDownloadManager/DGBackgroudDownloadManagers (1.1.14): 18 | - AFNetworking (~> 3.1.0) 19 | - DGDownloadManager/DGDownloadManagers (1.1.14): 20 | - AFNetworking (~> 3.1.0) 21 | 22 | DEPENDENCIES: 23 | - DGDownloadManager/DGBackgroudDownloadManagers (from `../`) 24 | - DGDownloadManager/DGDownloadManagers (from `../`) 25 | 26 | SPEC REPOS: 27 | trunk: 28 | - AFNetworking 29 | 30 | EXTERNAL SOURCES: 31 | DGDownloadManager: 32 | :path: "../" 33 | 34 | SPEC CHECKSUMS: 35 | AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67 36 | DGDownloadManager: 5ba202d07d0823da4366a8bf9f48bc8cc4b88218 37 | 38 | PODFILE CHECKSUM: 6f8f34a7acc90ecae6c8d4ffaccd60433f1218a0 39 | 40 | COCOAPODS: 1.10.0 41 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadSaveItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadSaveItem.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/7/21. 6 | // 7 | 8 | #import "DGDownloadSaveItem.h" 9 | 10 | @implementation DGDownloadSaveItem 11 | 12 | -(instancetype)initWithCoder:(NSCoder *)coder{ 13 | if (self = [super init]) { 14 | self.cachePath = [coder decodeObjectForKey:@"cachePath"]; 15 | self.temPath = [coder decodeObjectForKey:@"temPath"]; 16 | self.customCacheName = [coder decodeObjectForKey:@"customCacheName"]; 17 | self.requestUrl = [coder decodeObjectForKey:@"requestUrl"]; 18 | self.downloadStatus = [coder decodeIntegerForKey:@"downloadStatus"]; 19 | self.progress = [coder decodeFloatForKey:@"progress"]; 20 | self.paramDic = [coder decodeObjectForKey:@"paramDic"]; 21 | self.requestMethod = [coder decodeObjectForKey:@"requestMethod"]; 22 | } 23 | return self; 24 | } 25 | - (void)encodeWithCoder:(NSCoder *)coder 26 | { 27 | [coder encodeObject:self.customCacheName forKey:@"customCacheName"]; 28 | [coder encodeObject:self.requestUrl forKey:@"requestUrl"]; 29 | [coder encodeObject:self.cachePath forKey:@"cachePath"]; 30 | [coder encodeObject:self.temPath forKey:@"temPath"]; 31 | [coder encodeObject:self.requestMethod forKey:@"requestMethod"]; 32 | [coder encodeObject:self.paramDic forKey:@"paramDic"]; 33 | [coder encodeFloat:self.progress forKey:@"progress"]; 34 | [coder encodeInteger:self.downloadStatus forKey:@"downloadStatus"]; 35 | 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadModel.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/24/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import "DGBackgroudDownloadModel.h" 10 | #import "NSData+Category.h" 11 | 12 | @implementation DGBackgroudDownloadModel 13 | 14 | #pragma mark -- 懒加载 15 | - (DGBackgroudDownloadDelegate*)downloaDelegate{ 16 | if (!_downloaDelegate) { 17 | _downloaDelegate = [[DGBackgroudDownloadDelegate alloc] init]; 18 | } 19 | return _downloaDelegate; 20 | } 21 | - (NSURLSession *)session{ 22 | 23 | if (!_session) { 24 | NSString *buildStr = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; 25 | NSString *itemStr = [[self.requestUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 26 | if (itemStr.length > 0) { 27 | buildStr = [NSString stringWithFormat:@"%@_%@",buildStr,itemStr]; 28 | } 29 | NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:buildStr]; 30 | _session = [NSURLSession sessionWithConfiguration:sessionConfig 31 | delegate:self.downloaDelegate 32 | delegateQueue:[NSOperationQueue mainQueue]]; 33 | } 34 | return _session; 35 | } 36 | #pragma mark - 基本方法 37 | 38 | - (CGFloat)progress{ 39 | return [self.downloaDelegate getDownloadProgress]; 40 | } 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/NSData+Category.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Category.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/28/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import "NSData+Category.h" 10 | #import 11 | 12 | @implementation NSData (Category) 13 | 14 | /** 15 | 生成MD5 16 | 17 | @return 返回MD5的字符串 18 | */ 19 | - (NSString *)DG_MD5HashString 20 | { 21 | unsigned char result[CC_MD5_DIGEST_LENGTH]; 22 | CC_MD5([self bytes], (CC_LONG)[self length], result); 23 | 24 | NSString *fmt = @"%02x%02x%02x%02x" 25 | @"%02x%02x%02x%02x" 26 | @"%02x%02x%02x%02x" 27 | @"%02x%02x%02x%02x"; 28 | 29 | return [[NSString alloc] initWithFormat:fmt, 30 | result[ 0], result[ 1], result[ 2], result[ 3], 31 | result[ 4], result[ 5], result[ 6], result[ 7], 32 | result[ 8], result[ 9], result[10], result[11], 33 | result[12], result[13], result[14], result[15]]; 34 | } 35 | /** 36 | 生成SHA1 37 | 38 | @return 返回SHA1的字符串 39 | */ 40 | - (NSString *)DG_SHA1HashString 41 | { 42 | unsigned char result[CC_SHA1_DIGEST_LENGTH]; 43 | CC_SHA1([self bytes], (CC_LONG)[self length], result); 44 | 45 | NSString *fmt = @"%02x%02x%02x%02x" 46 | @"%02x%02x%02x%02x" 47 | @"%02x%02x%02x%02x" 48 | @"%02x%02x%02x%02x" 49 | @"%02x%02x%02x%02x"; 50 | 51 | return [[NSString alloc] initWithFormat:fmt, 52 | result[ 0], result[ 1], result[ 2], result[ 3], 53 | result[ 4], result[ 5], result[ 6], result[ 7], 54 | result[ 8], result[ 9], result[10], result[11], 55 | result[12], result[13], result[14], result[15], 56 | result[16], result[17], result[18], result[19]]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/NSDataAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataAdditions.m 3 | // TapKit 4 | // 5 | // Created by Kevin on 5/22/14. 6 | // Copyright (c) 2014 Tapmob. All rights reserved. 7 | // 8 | 9 | #import "NSDataAdditions.h" 10 | #import 11 | 12 | @implementation NSData (TapKit) 13 | 14 | #pragma mark - Hash 15 | /** 16 | 生成MD5 17 | 18 | @return 返回MD5的字符串 19 | */ 20 | - (NSString *)DG_MD5HashString 21 | { 22 | unsigned char result[CC_MD5_DIGEST_LENGTH]; 23 | CC_MD5([self bytes], (CC_LONG)[self length], result); 24 | 25 | NSString *fmt = @"%02x%02x%02x%02x" 26 | @"%02x%02x%02x%02x" 27 | @"%02x%02x%02x%02x" 28 | @"%02x%02x%02x%02x"; 29 | 30 | return [[NSString alloc] initWithFormat:fmt, 31 | result[ 0], result[ 1], result[ 2], result[ 3], 32 | result[ 4], result[ 5], result[ 6], result[ 7], 33 | result[ 8], result[ 9], result[10], result[11], 34 | result[12], result[13], result[14], result[15]]; 35 | } 36 | /** 37 | 生成SHA1 38 | 39 | @return 返回SHA1的字符串 40 | */ 41 | - (NSString *)DG_SHA1HashString 42 | { 43 | unsigned char result[CC_SHA1_DIGEST_LENGTH]; 44 | CC_SHA1([self bytes], (CC_LONG)[self length], result); 45 | 46 | NSString *fmt = @"%02x%02x%02x%02x" 47 | @"%02x%02x%02x%02x" 48 | @"%02x%02x%02x%02x" 49 | @"%02x%02x%02x%02x" 50 | @"%02x%02x%02x%02x"; 51 | 52 | return [[NSString alloc] initWithFormat:fmt, 53 | result[ 0], result[ 1], result[ 2], result[ 3], 54 | result[ 4], result[ 5], result[ 6], result[ 7], 55 | result[ 8], result[ 9], result[10], result[11], 56 | result[12], result[13], result[14], result[15], 57 | result[16], result[17], result[18], result[19]]; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadModel.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/24/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "DGBackgroudDownloadDelegate.h" 12 | 13 | // 是否下载 1.等待中 2.正在下载 3.暂停 4.下载完成 5.下载失败 14 | typedef NS_ENUM(NSUInteger,DGBackgroudDownloadStatus) { 15 | 16 | DGBackgroudDownloadStatusUnKnown = 0, 17 | DGBackgroudDownloadStatusWaiting = 1, 18 | DGBackgroudDownloadStatusDownloading = 2, 19 | DGBackgroudDownloadStatusDownloadSuspend = 3, 20 | DGBackgroudDownloadStatusDownloadFinish = 4, 21 | DGBackgroudDownloadStatusError = 5 22 | }; 23 | 24 | @interface DGBackgroudDownloadModel : NSObject 25 | 26 | /** 下载的自定义的缓存文件名*/ 27 | @property (nonatomic, copy) NSString *customCacheName; 28 | 29 | /** 下载的任务 */ 30 | @property (nonatomic, strong) NSURLSessionDownloadTask *task; 31 | 32 | /** 下载的session */ 33 | @property (nonatomic, strong) NSURLSession *session; 34 | 35 | /** 请求的url */ 36 | @property (nonatomic, copy) NSString *requestUrl; 37 | 38 | /** 下载的状态 */ 39 | @property (nonatomic, assign) DGBackgroudDownloadStatus downloadStatus; 40 | 41 | /** 下载的进度 */ 42 | @property (nonatomic, assign, readonly) CGFloat progress; 43 | 44 | /** 缓存的文件的路径 */ 45 | @property (nonatomic, copy) NSString *cachePath; 46 | 47 | /** DGBackgroudDownloadDelegate 用作代理 */ 48 | @property (nonatomic, strong) DGBackgroudDownloadDelegate *downloaDelegate; 49 | 50 | /** 下载进度的block */ 51 | @property (nonatomic, strong) DownloadProgressBlock downloadProgressBlock; 52 | 53 | /** 下载信息反馈 */ 54 | @property (nonatomic, strong) DownloadErrorBlock downloadErrorBlock; 55 | 56 | /** 下载完成反馈 */ 57 | @property (nonatomic, strong) DownloadFinishBlock downloadFinishBlcok; 58 | 59 | 60 | @end 61 | 62 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadManager.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DGDownloadItem.h" 11 | #import "DGDownloadSaveItem.h" 12 | 13 | #define MAXTASK_COUNT 3 14 | @interface DGDownloadManager : NSObject 15 | 16 | + (instancetype)shareManager; 17 | 18 | #pragma mark - 外部可以拿到的相关的属性 19 | 20 | /** 最大任务数量*/ 21 | @property (nonatomic, assign) int DG_MaxTaskCount; 22 | 23 | /** 存放需要下载的数组*/ 24 | @property (nonatomic, strong) NSMutableArray *DG_DownloadArray; 25 | 26 | /** 是否在网络恢复的情况下,自动恢复下载功能,默认为false*/ 27 | @property (nonatomic, assign) BOOL DG_AutoDownload; 28 | 29 | #pragma mark - 外部调用的方法 30 | /** 31 | 开始下载 32 | 33 | @param downloadUrl 下载的路径 34 | @param requestMethod 请求的方法 35 | @param customCacheName 自定义的缓存的名字 36 | */ 37 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 38 | withMethod:(NSString *)requestMethod 39 | withCustomCacheName:(NSString *)customCacheName; 40 | /** 41 | 开始下载 42 | 43 | @param downloadUrl 下载的路径 (请求的方式是get) 44 | @param customCacheName 自定义的缓存的名字 45 | */ 46 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 47 | withCustomCacheName:(NSString *)customCacheName; 48 | 49 | /** 50 | 暂停某一个下载 51 | 52 | @param url 暂停的全下载路径 53 | */ 54 | - (void)DG_SuspendWithUrl:(NSString *)url; 55 | 56 | /** 57 | 暂停所有的下载 58 | */ 59 | - (void)DG_SuspendAllRequest; 60 | /** 61 | 恢复某一个下载 62 | 63 | @param url 下载的全链接 64 | */ 65 | - (void)DG_ResumeWithUrl:(NSString *)url; 66 | /** 67 | 恢复所有暂停的下载 68 | */ 69 | - (void)DG_ResumeAllRequest; 70 | /** 71 | 取消一个下载 72 | 73 | @param url 下载的全链接 74 | */ 75 | - (void)DG_CancelWithUrl:(NSString *)url; 76 | /** 77 | 取消所有的下载的任务 78 | */ 79 | - (void)DG_CancelAllRequest; 80 | 81 | #pragma mark--获取数据相关 82 | /** 83 | 获取所有下载完成的数据model的数据源 84 | */ 85 | - (NSMutableArray *)DG_GetAllDownloadItems; 86 | 87 | @end 88 | 89 | 90 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadItem.h 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DGDownloadItem.h" 11 | #import "DGHttpConfig.h" 12 | #import 13 | 14 | // 是否下载 1.等待中 2.正在下载 3.暂停 4.下载完成 5.下载失败 15 | typedef NS_ENUM(NSUInteger,DGDownloadStatus) { 16 | 17 | DGDownloadStatusUnKnown = 0, 18 | DGDownloadStatusWaiting = 1, 19 | DGDownloadStatusDownloading = 2, 20 | DGDownloadStatusDownloadSuspend = 3, 21 | DGDownloadStatusDownloadFinish = 4, 22 | DGDownloadStatusError = 5 23 | }; 24 | 25 | @interface DGDownloadItem : NSObject 26 | 27 | /** 下载的自定义的缓存文件名*/ 28 | @property (nonatomic, copy) NSString *customCacheName; 29 | 30 | /** 请求的url */ 31 | @property (nonatomic, copy) NSString *requestUrl; 32 | 33 | /** 下载的任务 */ 34 | @property (nonatomic, strong) NSURLSessionTask *task; 35 | 36 | /** 管理者 */ 37 | @property (nonatomic, strong) AFHTTPSessionManager *manager; 38 | 39 | /** 下载的状态 */ 40 | @property (nonatomic, assign) DGDownloadStatus downloadStatus; 41 | 42 | /** 返回的response */ 43 | @property (nonatomic, strong) NSURLResponse *response; 44 | 45 | /** 错误的信息 */ 46 | @property (nonatomic, strong) NSError *error; 47 | 48 | /** 下载的进度 */ 49 | @property (nonatomic, assign) CGFloat progress; 50 | 51 | /** 临时存储的文件路径 */ 52 | @property (nonatomic, copy) NSString *temPath; 53 | 54 | /** 缓存的文件的路径 */ 55 | @property (nonatomic, copy) NSString *cachePath; 56 | 57 | /** 请求的方法 */ 58 | @property (nonatomic, copy) NSString *requestMethod; 59 | 60 | /** 参数 */ 61 | @property (nonatomic, strong) NSDictionary *paramDic; 62 | 63 | /** NSFileHandle */ 64 | @property (nonatomic, strong) NSFileHandle *itemFileHandle; 65 | 66 | // 下载进度的block 67 | @property (nonatomic, strong) void (^DGDownloadProgressBlock)(CGFloat progress); 68 | 69 | // 下载信息反馈 70 | @property (nonatomic, strong) void (^DGDownloadCompletionHandler)(NSError *error); 71 | 72 | 73 | @end 74 | 75 | 76 | -------------------------------------------------------------------------------- /DGDownloadManager.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint DGDownloadManager.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'DGDownloadManager' 11 | s.version = '1.1.15' 12 | s.summary = 'DGDownloadManager summary' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | TODO: Add long description of the pod here. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/liudiange/DGDownloadManager' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'shaoyeliudiange@163.com' => 'hzycode@163.com' } 28 | s.source = { :git => 'https://github.com/liudiange/DGDownloadManager.git', :tag => s.version.to_s } 29 | # s.social_media_url = 'https://twitter.com/' 30 | 31 | s.ios.deployment_target = '9.0' 32 | 33 | #s.source_files = 'DGDownloadManager/Classes/**/*' 34 | s.subspec 'DGBackgroudDownloadManagers' do |sb| 35 | sb.source_files = 'DGDownloadManager/Classes/DGBackgroudDownloadManagers/**/*' 36 | sb.dependency "AFNetworking", "~> 3.1.0" 37 | end 38 | 39 | s.subspec 'DGDownloadManagers' do |ss| 40 | ss.source_files = 'DGDownloadManager/Classes/DGDownloadManagers/**/*' 41 | ss.dependency "AFNetworking", "~> 3.1.0" 42 | end 43 | 44 | # s.resource_bundles = { 45 | # 'DGDownloadManager' => ['DGDownloadManager/Assets/*.png'] 46 | # } 47 | 48 | # s.public_header_files = 'Pod/Classes/**/*.h' 49 | # s.frameworks = 'UIKit', 'MapKit' 50 | # s.dependency "AFNetworking", "~> 3.1.0" 51 | end 52 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadManager.h 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/24/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DGBackgroudDownloadModel.h" 11 | #import "DGBackgroudDownloadSaveModel.h" 12 | 13 | 14 | @interface DGBackgroudDownloadManager : NSObject 15 | 16 | + (instancetype)shareManager; 17 | 18 | #pragma mark -- 外界提供的属性和方法 19 | 20 | /** 最大任务数量*/ 21 | @property (nonatomic, assign) int DG_MaxTaskCount; 22 | 23 | /** 是否在网络恢复的情况下,自动恢复下载功能,默认为false*/ 24 | @property (nonatomic, assign) BOOL DG_AutoDownload; 25 | 26 | /** 存放数据源数组*/ 27 | @property (nonatomic, strong, readonly) NSMutableArray *DG_BackgroudDownloadArray; 28 | 29 | #pragma mark--下载的方法 30 | /* 处理后台通知的相关事件需要在这个方法中写入 31 | - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler 32 | @param completionHandler completionHandler 33 | @param identifier identifier 34 | */ 35 | - (void)handleBackgroudcompletionHandler:(void(^)(void))completionHandler 36 | identifier:(NSString *)identifier; 37 | 38 | 39 | /** 40 | 开始下载 41 | 42 | @param downloadUrl 下载的路径 43 | @param customCacheName 自定义的缓存的名字 44 | */ 45 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 46 | withCustomCacheName:(NSString *)customCacheName; 47 | 48 | /** 49 | 暂停某一个下载 50 | 51 | @param url 暂停的全下载路径 52 | */ 53 | - (void)DG_SuspendWithUrl:(NSString *)url; 54 | 55 | /** 56 | 暂停所有的下载 57 | */ 58 | - (void)DG_SuspendAllRequest; 59 | 60 | /** 61 | 恢复某一个下载 62 | 63 | @param url 下载的全链接 64 | */ 65 | - (void)DG_ResumeWithUrl:(NSString *)url; 66 | 67 | /** 68 | 恢复所有暂停的下载 69 | */ 70 | - (void)DG_ResumeAllRequest; 71 | 72 | /** 73 | 取消一个下载 74 | 75 | @param url 下载的全链接 76 | */ 77 | - (void)DG_CancelWithUrl:(NSString *)url; 78 | 79 | /** 80 | 取消所有的下载的任务 81 | */ 82 | - (void)DG_CancelAllRequest; 83 | #pragma mark--获取数据相关 84 | /** 85 | 获取所有下载完成的数据model的数据源 86 | */ 87 | - (NSMutableArray *)DG_GetAllDownloadModels; 88 | 89 | 90 | @end 91 | 92 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/25. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "DGBackgroudDownloadManager.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | return YES; 22 | } 23 | 24 | -(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler{ 25 | 26 | [[DGBackgroudDownloadManager shareManager] handleBackgroudcompletionHandler: completionHandler 27 | identifier: identifier]; 28 | 29 | } 30 | 31 | - (void)applicationWillResignActive:(UIApplication *)application { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 34 | } 35 | 36 | 37 | - (void)applicationDidEnterBackground:(UIApplication *)application { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | 43 | - (void)applicationWillEnterForeground:(UIApplication *)application { 44 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | 48 | - (void)applicationDidBecomeActive:(UIApplication *)application { 49 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 50 | } 51 | 52 | 53 | - (void)applicationWillTerminate:(UIApplication *)application { 54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 55 | } 56 | 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGFileManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGFileManager.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "DGFileManager.h" 10 | #import "NSDataAdditions.h" 11 | 12 | 13 | #define cacheItemDataPath [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DGDownload"] stringByAppendingPathComponent:@"cacheDownloadItems.plist"] 14 | 15 | @implementation DGFileManager 16 | /** 17 | * 18 | * 创建目录 19 | */ 20 | + (BOOL)DG_CreatPath:(NSString *)path{ 21 | if (path.length > 0) { 22 | NSFileManager *manager = [NSFileManager defaultManager]; 23 | [manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; 24 | BOOL flag = [manager createFileAtPath:path contents:nil attributes:nil]; 25 | return flag; 26 | } 27 | return NO; 28 | } 29 | /** 30 | * 31 | * 判断路径是佛存在 32 | */ 33 | + (BOOL)DG_FileIsExist:(NSString *)path{ 34 | if (path.length > 0) { 35 | NSFileManager *manager = [NSFileManager defaultManager]; 36 | return [manager fileExistsAtPath:path]; 37 | } 38 | return NO; 39 | } 40 | /** 41 | * 42 | * 删除文件 43 | */ 44 | + (BOOL)DG_DeleteFile:(NSString *)path{ 45 | if (path.length > 0) { 46 | NSFileManager * manager = [NSFileManager defaultManager]; 47 | return [manager removeItemAtPath:path error:nil]; 48 | } 49 | return NO; 50 | 51 | } 52 | /** 53 | * 54 | * 获取缓存的文件夹路径 55 | */ 56 | + (NSString *)DG_GetCachePath{ 57 | 58 | return [[NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingString:@"/DG_LocalMusic"]; 59 | } 60 | 61 | /// 存储下载完成的数据item 62 | /// @param item item 63 | + (void)saveDownloaditem:(DGDownloadItem *)item{ 64 | if (item.requestUrl.length == 0) { 65 | return; 66 | } 67 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 68 | NSString *key = [[item.requestUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 69 | 70 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheItemDataPath]) { 71 | [[NSFileManager defaultManager] createFileAtPath:cacheItemDataPath contents:nil attributes:nil]; 72 | }else{ 73 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheItemDataPath]; 74 | } 75 | 76 | DGDownloadSaveItem *saveItem = [[DGDownloadSaveItem alloc] init]; 77 | saveItem.requestUrl = item.requestUrl; 78 | saveItem.customCacheName = item.customCacheName; 79 | saveItem.cachePath = item.cachePath; 80 | saveItem.progress = item.progress; 81 | saveItem.downloadStatus = item.downloadStatus; 82 | saveItem.temPath = item.temPath; 83 | saveItem.paramDic = item.paramDic; 84 | saveItem.requestMethod = item.requestMethod; 85 | resumeMap[key] = saveItem; 86 | [NSKeyedArchiver archiveRootObject:resumeMap toFile:cacheItemDataPath]; 87 | } 88 | 89 | 90 | /// 获取所有已经下载过的model 91 | + (NSMutableArray *)getAllDownloadItems{ 92 | 93 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 94 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheItemDataPath]) { 95 | return nil; 96 | }else{ 97 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheItemDataPath]; 98 | } 99 | if (resumeMap.allKeys.count == 0) { 100 | return nil; 101 | } 102 | NSMutableArray *temArray = [NSMutableArray array]; 103 | for (DGDownloadSaveItem *item in resumeMap.allValues) { 104 | [temArray addObject:item]; 105 | } 106 | return temArray; 107 | 108 | } 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadDelegate.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/25/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "DGBackgroudDownloadDelegate.h" 12 | #import "NSData+Category.h" 13 | #import "DGBackgroudDownloadCacheManager.h" 14 | 15 | @interface DGBackgroudDownloadDelegate () 16 | 17 | /** 当前的进度*/ 18 | @property (nonatomic, assign) CGFloat progress; 19 | 20 | /** 当前的时间毫秒级*/ 21 | @property (nonatomic, assign) long long int lastTime; 22 | 23 | /** 上一次的写入多少*/ 24 | @property (nonatomic, assign) int64_t lastBytesWritten; 25 | 26 | 27 | @end 28 | 29 | @implementation DGBackgroudDownloadDelegate 30 | 31 | #pragma mark - 公共方法 32 | 33 | /// 获取下载的进度 34 | - (CGFloat )getDownloadProgress{ 35 | return self.progress; 36 | } 37 | 38 | #pragma mark - 代理 39 | 40 | - (void)URLSession:(NSURLSession *)session 41 | downloadTask:(NSURLSessionDownloadTask *)downloadTask 42 | didFinishDownloadingToURL:(NSURL *)location { 43 | 44 | if (self.downloadFinishBlock) { 45 | self.downloadFinishBlock(downloadTask,location); 46 | } 47 | 48 | } 49 | 50 | - (void)URLSession:(NSURLSession *)session 51 | downloadTask:(NSURLSessionDownloadTask *)downloadTask 52 | didResumeAtOffset:(int64_t)fileOffset 53 | expectedTotalBytes:(int64_t)expectedTotalBytes { 54 | 55 | 56 | } 57 | 58 | - (void)URLSession:(NSURLSession *)session 59 | downloadTask:(NSURLSessionDownloadTask *)downloadTask 60 | didWriteData:(int64_t)bytesWritten 61 | totalBytesWritten:(int64_t)totalBytesWritten 62 | totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { 63 | 64 | long long int currentTime = [[[NSDate alloc] init] timeIntervalSince1970] *1000; 65 | long long int subtractTime = 0; 66 | if (self.lastTime > 0) { 67 | subtractTime = currentTime - self.lastTime; 68 | }else{ 69 | subtractTime = 1000; 70 | } 71 | // 多少 k/s totalBytesWritten是字节 72 | CGFloat speed = (CGFloat)(totalBytesWritten - self.lastBytesWritten) / subtractTime; 73 | 74 | self.progress = (CGFloat)totalBytesWritten / totalBytesExpectedToWrite; 75 | if (self.downloadProgressBlock) { 76 | self.downloadProgressBlock(self.progress,speed); 77 | } 78 | 79 | self.lastTime = currentTime; 80 | self.lastBytesWritten = totalBytesWritten; 81 | } 82 | 83 | - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { 84 | 85 | if (session.configuration.identifier && self.downloadFinishEventBlock) { 86 | if (self.downloadFinishEventBlock) { 87 | self.downloadFinishEventBlock(session.configuration.identifier); 88 | } 89 | } 90 | } 91 | /* 92 | * 该方法下载成功和失败都会回调,只是失败的是error是有值的, 93 | * 在下载失败时,error的userinfo属性可以通过NSURLSessionDownloadTaskResumeData 94 | * 这个key来取到resumeData(和上面的resumeData是一样的),再通过resumeData恢复下载 95 | */ 96 | - (void)URLSession:(NSURLSession *)session 97 | task:(NSURLSessionTask *)task 98 | didCompleteWithError:(NSError *)error { 99 | 100 | if (error) { 101 | if ([error.userInfo.allKeys containsObject:NSURLSessionDownloadTaskResumeData]) { 102 | 103 | NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; 104 | if (resumeData.length) { 105 | self.resumeData = resumeData; 106 | [DGBackgroudDownloadCacheManager saveResumeDataWithUrl:task.currentRequest.URL.absoluteString resumeData:resumeData]; 107 | } 108 | } 109 | if (self.downloadErrorBlock) { 110 | self.downloadErrorBlock(error); 111 | } 112 | } 113 | } 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadCacheManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGCacheManager.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 3/3/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | 9 | #import "DGBackgroudDownloadCacheManager.h" 10 | #import "NSData+Category.h" 11 | #import 12 | #import "DGBackgroudDownloadSaveModel.h" 13 | 14 | #define cacheDataPath [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DGBackgroudDownload"] stringByAppendingPathComponent:@"cacheResumeData.plist"] 15 | #define cacheModelDataPath [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DGBackgroudDownload"] stringByAppendingPathComponent:@"cacheDownloadModel.plist"] 16 | 17 | @implementation DGBackgroudDownloadCacheManager 18 | 19 | /// 存储resumeData 20 | /// @param downloadUrl 下载的url 21 | /// @param resumeData resumedata 22 | + (void)saveResumeDataWithUrl:(NSString *)downloadUrl resumeData:(NSData *)resumeData{ 23 | 24 | if (downloadUrl.length == 0 || resumeData.length == 0) { 25 | return; 26 | } 27 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 28 | NSString *key = [[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 29 | 30 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheDataPath]) { 31 | [[NSFileManager defaultManager] createFileAtPath:cacheDataPath contents:nil attributes:nil]; 32 | }else{ 33 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheDataPath]; 34 | } 35 | resumeMap[key] = resumeData; 36 | [NSKeyedArchiver archiveRootObject:resumeMap toFile:cacheDataPath]; 37 | 38 | } 39 | 40 | /// 通过一个下载的连接来获取存储的resumedata 41 | /// @param downloadUrl 下载的url 42 | + (NSData *)getResumeData:(NSString *)downloadUrl{ 43 | 44 | if (downloadUrl.length == 0) { 45 | return nil; 46 | } 47 | NSString *key = [[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 48 | NSData *resumeData; 49 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 50 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheDataPath]) { 51 | return nil; 52 | }else{ 53 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheDataPath]; 54 | } 55 | if ([resumeMap.allKeys containsObject:key]) { 56 | resumeData = resumeMap[key]; 57 | } 58 | return resumeData; 59 | } 60 | 61 | /// 删除一个resumedata 62 | /// @param downloadUrl 下载的url 63 | + (void)deleteResumeDataWithUrl:(NSString *)downloadUrl{ 64 | 65 | if (downloadUrl.length == 0) { 66 | return; 67 | } 68 | NSString *key = [[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 69 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 70 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheDataPath]) { 71 | return ; 72 | }else{ 73 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheDataPath]; 74 | } 75 | if ([resumeMap.allKeys containsObject:key]) { 76 | [resumeMap removeObjectForKey:key]; 77 | [NSKeyedArchiver archiveRootObject:resumeMap toFile:cacheDataPath]; 78 | } 79 | } 80 | 81 | /// 存储下载完成的数据model 82 | /// @param model model 83 | + (void)saveDownloadModel:(DGBackgroudDownloadModel *)model{ 84 | 85 | if (model.requestUrl.length == 0) { 86 | return; 87 | } 88 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 89 | NSString *key = [[model.requestUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString]; 90 | 91 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheModelDataPath]) { 92 | [[NSFileManager defaultManager] createFileAtPath:cacheModelDataPath contents:nil attributes:nil]; 93 | }else{ 94 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheModelDataPath]; 95 | } 96 | 97 | DGBackgroudDownloadSaveModel *saveModel = [[DGBackgroudDownloadSaveModel alloc] init]; 98 | saveModel.requestUrl = model.requestUrl; 99 | saveModel.customCacheName = model.customCacheName; 100 | saveModel.cachePath = model.cachePath; 101 | saveModel.progress = model.progress; 102 | saveModel.downloadStatus = model.downloadStatus; 103 | resumeMap[key] = saveModel; 104 | [NSKeyedArchiver archiveRootObject:resumeMap toFile:cacheModelDataPath]; 105 | 106 | } 107 | 108 | /// 获取所有已经下载过的model 109 | + (NSMutableArray *)getAllDownloadModels{ 110 | 111 | NSMutableDictionary *resumeMap = [NSMutableDictionary new]; 112 | if (![[NSFileManager defaultManager] fileExistsAtPath:cacheModelDataPath]) { 113 | return nil; 114 | }else{ 115 | resumeMap = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:cacheModelDataPath]; 116 | } 117 | if (resumeMap.allKeys.count == 0) { 118 | return nil; 119 | } 120 | NSMutableArray *temArray = [NSMutableArray array]; 121 | for (DGBackgroudDownloadSaveModel *model in resumeMap.allValues) { 122 | [temArray addObject:model]; 123 | } 124 | return temArray; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/DownloadCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/NSURLSession+CorrectedResumeData.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSURLSession+CorrectedResumeData.m 3 | // BackgroundDownloadDemo 4 | // 5 | // Created by admin on 2016/10/12. 6 | // Copyright © 2016年 hkhust. All rights reserved. 7 | // 8 | 9 | #import "NSURLSession+CorrectedResumeData.h" 10 | #import 11 | 12 | #define IS_IOS10ORLATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10) 13 | 14 | #pragma mark- private 15 | 16 | static NSData * correctRequestData(NSData *data) { 17 | if (!data) { 18 | return nil; 19 | } 20 | // return the same data if it's correct 21 | if ([NSKeyedUnarchiver unarchiveObjectWithData:data] != nil) { 22 | return data; 23 | } 24 | NSMutableDictionary *archive = [[NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil] mutableCopy]; 25 | 26 | if (!archive) { 27 | return nil; 28 | } 29 | NSInteger k = 0; 30 | id objectss = archive[@"$objects"]; 31 | while ([objectss[1] objectForKey:[NSString stringWithFormat:@"$%ld",k]] != nil) { 32 | k += 1; 33 | } 34 | NSInteger i = 0; 35 | while ([archive[@"$objects"][1] objectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld",i]] != nil) { 36 | NSMutableArray *arr = archive[@"$objects"]; 37 | NSMutableDictionary *dic = arr[1]; 38 | id obj = [dic objectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld",i]]; 39 | if (obj) { 40 | [dic setValue:obj forKey:[NSString stringWithFormat:@"$%ld",i+k]]; 41 | [dic removeObjectForKey:[NSString stringWithFormat:@"__nsurlrequest_proto_prop_obj_%ld",i]]; 42 | [arr replaceObjectAtIndex:1 withObject:dic]; 43 | archive[@"$objects"] = arr; 44 | } 45 | i++; 46 | } 47 | if ([archive[@"$objects"][1] objectForKey:@"__nsurlrequest_proto_props"] != nil) { 48 | NSMutableArray *arr = archive[@"$objects"]; 49 | NSMutableDictionary *dic = arr[1]; 50 | id obj = [dic objectForKey:@"__nsurlrequest_proto_props"]; 51 | if (obj) { 52 | [dic setValue:obj forKey:[NSString stringWithFormat:@"$%ld",i+k]]; 53 | [dic removeObjectForKey:@"__nsurlrequest_proto_props"]; 54 | [arr replaceObjectAtIndex:1 withObject:dic]; 55 | archive[@"$objects"] = arr; 56 | } 57 | } 58 | // Rectify weird "NSKeyedArchiveRootObjectKey" top key to NSKeyedArchiveRootObjectKey = "root" 59 | if ([archive[@"$top"] objectForKey:@"NSKeyedArchiveRootObjectKey"] != nil) { 60 | [archive[@"$top"] setObject:archive[@"$top"][@"NSKeyedArchiveRootObjectKey"] forKey: NSKeyedArchiveRootObjectKey]; 61 | [archive[@"$top"] removeObjectForKey:@"NSKeyedArchiveRootObjectKey"]; 62 | } 63 | // Reencode archived object 64 | NSData *result = [NSPropertyListSerialization dataWithPropertyList:archive format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil]; 65 | return result; 66 | } 67 | 68 | static NSMutableDictionary *getResumeDictionary(NSData *data) { 69 | NSMutableDictionary *iresumeDictionary = nil; 70 | if (IS_IOS10ORLATER) { 71 | id root = nil; 72 | id keyedUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 73 | @try { 74 | root = [keyedUnarchiver decodeTopLevelObjectForKey:@"NSKeyedArchiveRootObjectKey" error:nil]; 75 | if (root == nil) { 76 | root = [keyedUnarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:nil]; 77 | } 78 | } @catch(NSException *exception) { 79 | 80 | } 81 | [keyedUnarchiver finishDecoding]; 82 | iresumeDictionary = [root mutableCopy]; 83 | } 84 | 85 | if (iresumeDictionary == nil) { 86 | iresumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil]; 87 | } 88 | return iresumeDictionary; 89 | } 90 | 91 | static NSData *correctResumeData(NSData *data) { 92 | NSString *kResumeCurrentRequest = @"NSURLSessionResumeCurrentRequest"; 93 | NSString *kResumeOriginalRequest = @"NSURLSessionResumeOriginalRequest"; 94 | if (data == nil) { 95 | return nil; 96 | } 97 | NSMutableDictionary *resumeDictionary = getResumeDictionary(data); 98 | if (resumeDictionary == nil) { 99 | return nil; 100 | } 101 | resumeDictionary[kResumeCurrentRequest] = correctRequestData(resumeDictionary[kResumeCurrentRequest]); 102 | resumeDictionary[kResumeOriginalRequest] = correctRequestData(resumeDictionary[kResumeOriginalRequest]); 103 | NSData *result = [NSPropertyListSerialization dataWithPropertyList:resumeDictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:nil]; 104 | return result; 105 | } 106 | 107 | @implementation NSURLSession (CorrectedResumeData) 108 | 109 | - (NSURLSessionDownloadTask *)downloadTaskWithCorrectResumeData:(NSData *)resumeData { 110 | NSString *kResumeCurrentRequest = @"NSURLSessionResumeCurrentRequest"; 111 | NSString *kResumeOriginalRequest = @"NSURLSessionResumeOriginalRequest"; 112 | 113 | NSData *cData = correctResumeData(resumeData); 114 | cData = cData ? cData:resumeData; 115 | NSURLSessionDownloadTask *task = [self downloadTaskWithResumeData:cData]; 116 | NSMutableDictionary *resumeDic = getResumeDictionary(cData); 117 | if (resumeDic) { 118 | if (task.originalRequest == nil) { 119 | NSData *originalReqData = resumeDic[kResumeOriginalRequest]; 120 | NSURLRequest *originalRequest = [NSKeyedUnarchiver unarchiveObjectWithData:originalReqData ]; 121 | if (originalRequest) { 122 | [task setValue:originalRequest forKey:@"originalRequest"]; 123 | } 124 | } 125 | if (task.currentRequest == nil) { 126 | NSData *currentReqData = resumeDic[kResumeCurrentRequest]; 127 | NSURLRequest *currentRequest = [NSKeyedUnarchiver unarchiveObjectWithData:currentReqData]; 128 | if (currentRequest) { 129 | [task setValue:currentRequest forKey:@"currentRequest"]; 130 | } 131 | } 132 | } 133 | return task; 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/25. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "DGBackgroudDownloadManager.h" 11 | #import "DownloadCell.h" 12 | 13 | // 这个链接是第三首歌曲的链接 14 | #define TEST_URL @"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg" 15 | 16 | @interface ViewController () 17 | 18 | @property (nonatomic, strong) NSMutableArray *dataArray; 19 | 20 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 21 | 22 | @end 23 | @implementation ViewController 24 | 25 | static NSString * const CELL_ID = @"cell_id"; 26 | 27 | - (NSMutableArray *)dataArray { 28 | if (!_dataArray) { 29 | _dataArray = [NSMutableArray array]; 30 | } 31 | return _dataArray; 32 | } 33 | 34 | - (void)viewDidLoad { 35 | [super viewDidLoad]; 36 | 37 | // 创建tableview 38 | [self setUpTableView]; 39 | } 40 | #pragma mark - 方法的响应 41 | /** 42 | * 43 | * 创建tabkeivew 44 | */ 45 | - (void)setUpTableView { 46 | 47 | [self.tableView registerNib:[UINib nibWithNibName:@"DownloadCell" bundle:nil] forCellReuseIdentifier:CELL_ID]; 48 | 49 | } 50 | /** 51 | * 52 | * 全部下载 53 | */ 54 | - (IBAction)downloadAllAction:(id)sender { 55 | 56 | [self.dataArray removeAllObjects]; 57 | 58 | // @"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg", 59 | // @"http://m4.pc6.com/cjh3/VicomsoftFTPClient.dmg", 60 | // @"https://qd.myapp.com/myapp/qqteam/pcqq/QQ9.0.8_2.exe", 61 | // @"http://gxiami.alicdn.com/xiami-desktop/update/XiamiMac-03051058.dmg" 62 | NSArray *list = @[ 63 | // @"https://officecdn-microsoft-com.akamaized.net/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Office_16.24.19041401_Installer.pkg", 64 | @"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg", 65 | @"http://m4.pc6.com/cjh3/VicomsoftFTPClient.dmg" 66 | ]; 67 | // 指定最大任务数量 68 | [DGBackgroudDownloadManager shareManager].DG_MaxTaskCount = 3; 69 | for (NSInteger index = 0; index < list.count; index ++) { 70 | [[DGBackgroudDownloadManager shareManager] DG_DownloadWithUrl:list[index] withCustomCacheName:nil]; 71 | } 72 | 73 | [self.dataArray addObjectsFromArray:[DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray]; 74 | [self.tableView reloadData]; 75 | 76 | if ([DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray.count == 0) { 77 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"歌曲已经都下载完了" preferredStyle:UIAlertControllerStyleAlert]; 78 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; 79 | [alertController addAction:okAction]; 80 | [self presentViewController:alertController animated:YES completion:nil]; 81 | } 82 | } 83 | /** 84 | * 85 | * 单曲下载 86 | */ 87 | - (IBAction)singleAction:(id)sender { 88 | [self.dataArray removeAllObjects]; 89 | 90 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用 91 | [DGBackgroudDownloadManager shareManager].DG_MaxTaskCount = 2; 92 | 93 | // 第一首歌曲 94 | [[DGBackgroudDownloadManager shareManager] DG_DownloadWithUrl:TEST_URL withCustomCacheName: nil]; 95 | [self.dataArray addObjectsFromArray:[DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray]; 96 | [self.tableView reloadData]; 97 | 98 | if ([DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray.count == 0) { 99 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"歌曲已经都下载完了" preferredStyle:UIAlertControllerStyleAlert]; 100 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; 101 | [alertController addAction:okAction]; 102 | [self presentViewController:alertController animated:YES completion:nil]; 103 | } 104 | } 105 | /** 106 | * 107 | * 取消全部 108 | */ 109 | - (IBAction)cancleAllAction:(UIButton *)sender { 110 | [[DGBackgroudDownloadManager shareManager] DG_CancelAllRequest]; 111 | 112 | } 113 | /** 114 | * 115 | * 取消某一首歌曲 116 | */ 117 | - (IBAction)cancleOneAction:(UIButton *)sender { 118 | [[DGBackgroudDownloadManager shareManager] DG_CancelWithUrl:TEST_URL]; 119 | } 120 | /** 121 | * 122 | * 暂停全部 123 | */ 124 | 125 | - (IBAction)suspendAllAction:(id)sender { 126 | 127 | [[DGBackgroudDownloadManager shareManager] DG_SuspendAllRequest]; 128 | } 129 | /** 130 | * 131 | * 暂停某一首歌曲 132 | */ 133 | - (IBAction)suspendOneAction:(id)sender { 134 | [[DGBackgroudDownloadManager shareManager] DG_SuspendWithUrl:TEST_URL]; 135 | } 136 | /** 137 | * 138 | * 恢复全部 139 | */ 140 | - (IBAction)resumeAllAction:(id)sender { 141 | [[DGBackgroudDownloadManager shareManager] DG_ResumeAllRequest]; 142 | } 143 | /** 144 | * 145 | * 恢复某一首歌曲 146 | */ 147 | - (IBAction)resumeOneAction:(id)sender { 148 | 149 | [[DGBackgroudDownloadManager shareManager] DG_ResumeWithUrl:TEST_URL]; 150 | } 151 | - (IBAction)getAllDownloadModels:(UIButton *)sender { 152 | NSArray *array = [[DGBackgroudDownloadManager shareManager] DG_GetAllDownloadModels]; 153 | NSLog(@"所有的array --- %@",array); 154 | } 155 | 156 | 157 | #pragma mark - datasource 158 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 159 | 160 | return self.dataArray.count; 161 | } 162 | 163 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 164 | 165 | __weak typeof(self)weakSelf = self; 166 | DGBackgroudDownloadModel *model = self.dataArray[indexPath.row]; 167 | DownloadCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID]; 168 | cell.model = model; 169 | cell.model.downloadFinishBlcok = ^(NSURLSessionDownloadTask *downloadTask, NSURL *location) { 170 | [weakSelf.dataArray removeAllObjects]; 171 | [weakSelf.dataArray addObjectsFromArray:[DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray]; 172 | dispatch_async(dispatch_get_main_queue(), ^{ 173 | [weakSelf.tableView reloadData]; 174 | }); 175 | }; 176 | return cell; 177 | } 178 | 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #DGDownloadManager 2 | ![image](https://github.com/liudiange/DGDownloadManager/blob/master/1.png) 3 | 4 | 下载管理器,只要传递下载的url来进行下载,支持ios 和macos (Download Manager, as long as the URL passed to download download, support ios and macos) 5 | 6 | ## 下载管理器实现的功能:(Download Manager to achieve the function:) 7 | - 支持断点续传 (Support HTTP) 8 | - 支持最大的下载任务个数 (Support the largest number of download tasks) 9 | - 传递url进行下载 (Pass url to download) 10 | - 可以暂停全部 ( Pause all) 11 | - 可以暂停某一链接 (Pause a link) 12 | - 可以取消全部 (Cancel all) 13 | - 可以取消某一链接 (Cancel a link) 14 | - 可以恢复下载一链接 (Resume downloading a link) 15 | - 可以恢复全部下载 (Resume all downloads) 16 | ## 思路(idea) 17 | ![image](https://github.com/liudiange/DGDownloadManager/blob/master/2.png) 18 | 19 | ##### 解释(explain): 20 | - 其中DGDownloadManager负责全局的管理,创建一个下载队列管理的数组,需要下载的添加进数组,下载完成的从数组中移除,并且发送通知下载已经完成。(DGDownload Manager is responsible for global management, creating an array of download queue management, adding downloads to the array, removing downloads from the array, and sending notifications that downloads have been completed) 21 | - DGDownloaditem是每一个下载的模型。它提供了下载的相关的属性以及下载进度的block。(DGDownloaditem is a model for each download. It provides the relevant attributes of the download and the block of the download progress) 22 | - DGHttpConfig存储发送通知的key(Storage key for sending notifications)。 23 | - 其中后台下载使用的是这个管理 DGBackgroudDownloadManager,他区分DGDownloadManager,因为他是通过resumeData方式进行实现的,他可以实现后台下载,杀死进程之后会进行断点续传(The background download uses the management DGBackgroudDownloadManager, which distinguishes DGDownloadManager, because it is realized by the resumeData method, and it can realize the background download. After the process is killed, the download will be resumed.) 24 | - DGBackgroudDownloadModel 这个是后台下载的model,你可以继承它。他里面包含下载的状态,下载进度,下载速度等等(DGBackgroudDownloadModel This is a model downloaded in the background, you can inherit it. It contains download status, download progress, download speed, etc.) 25 | 26 | ## 安装 (install) 27 | - 全部导入方式1 (all in import method1) 28 | ````objc 29 | pod 'DGDownloadManager', '~>1.1.14' 30 | ```` 31 | 32 | - 全部导入方式2 (all in import method2) 33 | ````objc 34 | pod 'DGDownloadManager',:subspecs => ['DGBackgroudDownloadManagers','DGDownloadManagers'] 35 | ```` 36 | 37 | - 只是导入后台下载的框架 (import DGBackgroudDownloadManagers only) 38 | ````objc 39 | pod 'DGDownloadManager/DGBackgroudDownloadManagers', '~>1.1.14' 40 | ```` 41 | - 只是导入前台下载的框架 (import DGDownloadManagers only) 42 | ````objc 43 | pod 'DGDownloadManager/DGDownloadManagers', '~>1.1.14' 44 | ```` 45 | 46 | ## 使用 (use) 47 | - 开始下载(单一) (Start downloading (single)) 48 | ````objc 49 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用,默认最大任务是3 50 | [DGDownloadManager shareManager].DG_MaxTaskCount = 2; 51 | // 其中小不点.mp3为自定义的名字,可以为nil(Which 小不点.mp3 is a custom name, can be nil) 52 | [[DGDownloadManager shareManager] DG_DownloadWithUrl:TEST_URL withCustomCacheName:@"小不点.mp3"]; 53 | 54 | ```` 55 | ````objc 56 | // 支持后台下载的方式 57 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用,默认最大任务是3 58 | [DGBackgroudDownloadManager shareManager].DG_MaxTaskCount = 3; 59 | // 其中小不点.mp3为自定义的名字,可以为nil(Which 小不点.mp3 is a custom name, can be nil) 60 | [[DGBackgroudDownloadManager shareManager] DG_DownloadWithUrl:TEST_URL withCustomCacheName: @"小不点.mp3"]; 61 | ```` 62 | 63 | - 批量下载 (Batch download) 64 | ````objc 65 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用,默认最大任务是3 66 | [DGDownloadManager shareManager].DG_MaxTaskCount = 2; 67 | NSArray *customCacheName = @[@"上海滩.mp3",@"大长今.mp3",@"日子.mp3",@"想一想.mp3",@"哈哈.mp3"]; 68 | [self.dataArray removeAllObjects]; 69 | NSArray *list = @[ 70 | @"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=6990539Z0K8&ua=Mac_sst&version=1.0", 71 | @"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=63880300430&ua=Mac_sst&version=1.0", 72 | @"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=6005970S6G0&ua=Mac_sst&version=1.0", 73 | @"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=63273401896&ua=Mac_sst&version=1.0", 74 | @"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=69906300114&ua=Mac_sst&version=1.0" 75 | ]; 76 | // 指定最大任务数量 77 | [DGDownloadManager shareManager].DG_MaxTaskCount = 4; 78 | for (NSInteger index = 0; index < list.count; index ++) { 79 | [[DGDownloadManager shareManager] DG_DownloadWithUrl:list[index] withCustomCacheName:customCacheName[index]]; 80 | } 81 | ```` 82 | ````objc 83 | NSArray *list = @[ 84 | @"https://officecdn-microsoft-com.akamaized.net/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate/Microsoft_Office_16.24.19041401_Installer.pkg", 85 | @"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg", 86 | @"http://m4.pc6.com/cjh3/VicomsoftFTPClient.dmg" 87 | ]; 88 | // 指定最大任务数量 89 | [DGBackgroudDownloadManager shareManager].DG_MaxTaskCount = 3; 90 | for (NSInteger index = 0; index < list.count; index ++) { 91 | [[DGBackgroudDownloadManager shareManager] DG_DownloadWithUrl:list[index] withCustomCacheName:nil]; 92 | } 93 | [self.dataArray addObjectsFromArray:[DGBackgroudDownloadManager shareManager].DG_BackgroudDownloadArray]; 94 | [self.tableView reloadData]; 95 | ```` 96 | 97 | - 暂停全部 (Pause all) 98 | ````objc 99 | 100 | [[DGDownloadManager shareManager] DG_SuspendAllRequest]; 101 | 102 | ```` 103 | ````objc 104 | 105 | [[DGBackgroudDownloadManager shareManager] DG_SuspendAllRequest]; 106 | 107 | ```` 108 | - 暂停某一链接 (Pause a link) 109 | ````objc 110 | 111 | [[DGDownloadManager shareManager] DG_SuspendWithUrl:@"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=69906300114&ua=Mac_sst&version=1.0"]; 112 | 113 | ```` 114 | ````objc 115 | 116 | [[DGBackgroudDownloadManager shareManager] DG_SuspendWithUrl:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg"]; 117 | 118 | ```` 119 | - 取消全部 (Cancel all) 120 | ````objc 121 | 122 | [[DGDownloadManager shareManager] DG_CancelAllRequest]; 123 | 124 | ```` 125 | ````objc 126 | 127 | [[DGBackgroudDownloadManager shareManager] DG_CancelAllRequest]; 128 | 129 | ```` 130 | - 取消某一链接 (Cancel a link) 131 | ````objc 132 | 133 | [[DGDownloadManager shareManager] DG_CancelWithUrl:@"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=69906300114&ua=Mac_sst&version=1.0"]; 134 | 135 | ```` 136 | ````objc 137 | 138 | [[DGBackgroudDownloadManager shareManager] DG_CancelWithUrl:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg"]; 139 | 140 | ```` 141 | - 恢复所有 (Restore all) 142 | ````objc 143 | 144 | [[DGDownloadManager shareManager] DG_ResumeAllRequest]; 145 | 146 | ```` 147 | ````objc 148 | 149 | [[DGBackgroudDownloadManager shareManager] DG_ResumeAllRequest]; 150 | 151 | ```` 152 | - 恢复一首链接 (Restore a link) 153 | ````objc 154 | 155 | [[DGDownloadManager shareManager] DG_ResumeWithUrl:@"http://218.200.160.29/rdp2/test/mac/listen.do?contentid=69906300114&ua=Mac_sst&version=1.0"]; 156 | 157 | ```` 158 | ````objc 159 | 160 | [[DGBackgroudDownloadManager shareManager] DG_ResumeWithUrl:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.2.dmg"]; 161 | 162 | ```` 163 | - 修改最大的下载的任务数量,需要在下载之前配置 (Modify the maximum number of download tasks, need to be configured before downloading) 164 | ````objc 165 | 166 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用,默认最大任务是3 167 | [DGDownloadManager shareManager].DG_MaxTaskCount = 2; 168 | 169 | ```` 170 | ````objc 171 | 172 | // 指定最大任务数量 需要在下载歌曲前指定否则不起作用,默认最大任务是3 173 | [DGBackgroudDownloadManager shareManager].DG_MaxTaskCount = 2; 174 | 175 | ```` 176 | - 获取下载进度(Get download progress) 177 | 178 | ````objc 179 | 180 | // 需要自己获取当前下载的item(Need to get the current download item) 181 | 182 | item.DGDownloadProgressBlock = ^(CGFloat progress) { 183 | dispatch_async(dispatch_get_main_queue(), ^{ 184 | weakSelf.progressView.progress = progress; 185 | weakSelf.progressLable.text = [NSString stringWithFormat:@"%d%%",(int)(progress *100)]; 186 | }); 187 | }; 188 | 189 | ```` 190 | ````objc 191 | _model.downloadProgressBlock = ^(CGFloat progress, CGFloat speed) { 192 | dispatch_async(dispatch_get_main_queue(), ^{ 193 | weakSelf.progressView.progress = progress; 194 | weakSelf.progressLable.text = [NSString stringWithFormat:@"%0.2f%%-%0.1fk/s",(progress *100),speed]; 195 | }); 196 | }; 197 | 198 | ```` 199 | - 获取下载的状态(Get the status of the download) 200 | 201 | ````objc 202 | 203 | // 需要自己获取当前下载的item(Need to get the current download item) 204 | item.downloadStatus 205 | 206 | ```` 207 | ````objc 208 | // 需要自己获取当前下载的item(Need to get the current download Status) 209 | model.downloadStatus 210 | ```` 211 | - 开启自动网络恢复(open network restore) 212 | 213 | ````objc 214 | // 需要在下载任务之前进行设置 215 | [DGDownloadManager shareManager].DG_AutoDownload = YES; 216 | 217 | ```` 218 | ````objc 219 | // 需要在下载任务之前进行设置 220 | [DGBackgroudDownloadManager shareManager].DG_AutoDownload = YES; 221 | ```` 222 | - 后台下载需要注意点(pay attentiton for DGBackgroudDownloadManager) 223 | ````objc 224 | // 需要在appdelegate 方法里面写上 225 | -(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler{ 226 | 227 | [[DGBackgroudDownloadManager shareManager] handleBackgroudcompletionHandler: completionHandler 228 | identifier: identifier]; 229 | 230 | } 231 | ```` 232 | - 获取下载成功的数据源(get success data) 233 | ````objc 234 | // 获取下载成功的数据item 235 | [[DGDownloadManager shareManager] DG_GetAllDownloadItems]; 236 | ```` 237 | ````objc 238 | // 获取下载成功的数据model 239 | [[DGBackgroudDownloadManager shareManager] DG_GetAllDownloadModels]; 240 | ```` 241 | 242 | ## 期待(hope) 243 | - 有什么bug或者我不满足的需求,欢迎 Issues我(There are any bugs or not satisfied, welcome to issues me) 244 | - 请大神给我指正或者建议,我将不胜感激。(Please give me advice or suggestions, I will be honored) 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /Example/DGDownloadManager/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 44 | 52 | 60 | 68 | 76 | 84 | 92 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGDownloadManagers/DGDownloadManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGDownloadManager.m 3 | // DGDownloadManager 4 | // 5 | // Created by apple on 2019/2/26. 6 | // Copyright © 2019年 apple. All rights reserved. 7 | // 8 | 9 | #import "DGDownloadManager.h" 10 | #import "NSDataAdditions.h" 11 | #import "DGFileManager.h" 12 | #import 13 | 14 | @interface DGDownloadManager () 15 | // 锁 16 | @property(nonatomic, strong)NSLock *lock; 17 | 18 | @end 19 | 20 | @implementation DGDownloadManager 21 | + (instancetype)shareManager { 22 | static DGDownloadManager *_manager = nil; 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | _manager = [[self alloc] init]; 26 | }); 27 | return _manager; 28 | } 29 | -(instancetype)init { 30 | if (self == [super init]) { 31 | _lock = [[NSLock alloc] init]; 32 | // 增加网络变化 33 | [self listenNetwork]; 34 | 35 | } 36 | return self; 37 | } 38 | #pragma mark - 懒加载 39 | -(NSMutableArray *)DG_DownloadArray { 40 | if (!_DG_DownloadArray) { 41 | _DG_DownloadArray = [NSMutableArray array]; 42 | } 43 | return _DG_DownloadArray; 44 | } 45 | #pragma mark - 外部调用的方法 46 | /** 47 | 开始下载 48 | 49 | @param downloadUrl 下载的路径 50 | @param requestMethod 请求的方法 51 | @param customCacheName 自定义的缓存的名字 52 | */ 53 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 54 | withMethod:(NSString *)requestMethod 55 | withCustomCacheName:(NSString *)customCacheName{ 56 | 57 | if (downloadUrl.length == 0) { return;} 58 | [_lock lock]; 59 | // 取消下载相关的东西 60 | DGDownloadItem *item = [self getItemFromArray:_DG_DownloadArray withUrl:downloadUrl]; 61 | if (!item) { 62 | item = [[DGDownloadItem alloc] init]; 63 | item.requestUrl = downloadUrl; 64 | item.downloadStatus = DGDownloadStatusWaiting; 65 | item.progress = 0.0; 66 | item.customCacheName = customCacheName; 67 | item.temPath = [self getTemPath:downloadUrl]; 68 | // 方案二需要这样写 69 | item.cachePath = [self getCache:downloadUrl withResponse:nil customCahceName:customCacheName]; 70 | item.requestMethod = requestMethod; 71 | item.paramDic = nil; 72 | // 已经下载的就不用下载了 73 | if ([[NSFileManager defaultManager] attributesOfItemAtPath:item.cachePath error:nil].fileSize <= 0) { 74 | [self.DG_DownloadArray addObject:item]; 75 | } 76 | } 77 | // 设置最大线程来进行下载任务 78 | [self DG_CheckDownload]; 79 | [_lock unlock]; 80 | } 81 | /** 82 | 开始下载 83 | 84 | @param downloadUrl 下载的路径 (请求的方式是get) 85 | @param customCacheName 自定义的缓存的名字 86 | */ 87 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 88 | withCustomCacheName:(NSString *)customCacheName{ 89 | 90 | if (downloadUrl.length == 0) { return;} 91 | [_lock lock]; 92 | // 取消下载相关的东西 93 | DGDownloadItem *item = [self getItemFromArray:_DG_DownloadArray withUrl:downloadUrl]; 94 | if (!item) { 95 | item = [[DGDownloadItem alloc] init]; 96 | item.requestUrl = downloadUrl; 97 | item.downloadStatus = DGDownloadStatusWaiting; 98 | item.progress = 0.0; 99 | item.customCacheName = customCacheName; 100 | item.temPath = [self getTemPath:downloadUrl]; 101 | // 方案二需要这样写 102 | item.cachePath = [self getCache:downloadUrl withResponse:nil customCahceName:customCacheName]; 103 | item.requestMethod = @"GET"; 104 | item.paramDic = nil; 105 | // 已经下载的就不用下载了 106 | if ([[NSFileManager defaultManager] attributesOfItemAtPath:item.cachePath error:nil].fileSize <= 0) { 107 | [self.DG_DownloadArray addObject:item]; 108 | } 109 | } 110 | // 设置最大线程来进行下载任务 111 | [self DG_CheckDownload]; 112 | [_lock unlock]; 113 | 114 | } 115 | /** 116 | 暂停某一个下载 117 | 118 | @param url 暂停的全下载路径 119 | */ 120 | - (void)DG_SuspendWithUrl:(NSString *)url{ 121 | 122 | if (url.length == 0) { 123 | return; 124 | } 125 | [_lock lock]; 126 | DGDownloadItem *item = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 127 | [item.task suspend]; 128 | item.downloadStatus = DGDownloadStatusDownloadSuspend; 129 | // 暂停某一首歌曲 130 | [[NSNotificationCenter defaultCenter] postNotificationName:DGSuspendOneSong object:nil]; 131 | [_lock unlock]; 132 | 133 | } 134 | 135 | /** 136 | 暂停所有的下载 137 | */ 138 | - (void)DG_SuspendAllRequest{ 139 | [_lock lock]; 140 | for (DGDownloadItem *item in _DG_DownloadArray) { 141 | if (item.downloadStatus == DGDownloadStatusDownloading || item.downloadStatus == DGDownloadStatusWaiting || item.downloadStatus == DGDownloadStatusError) { 142 | [item.task suspend]; 143 | item.downloadStatus = DGDownloadStatusDownloadSuspend; 144 | } 145 | } 146 | [_lock unlock]; 147 | // 暂停所有的歌曲(通知) 148 | [[NSNotificationCenter defaultCenter] postNotificationName:DGSuspendAllSong object:nil]; 149 | } 150 | /** 151 | 恢复某一个下载 152 | 153 | @param url 下载的全链接 154 | */ 155 | - (void)DG_ResumeWithUrl:(NSString *)url{ 156 | if (url.length == 0) { 157 | return; 158 | } 159 | [_lock lock]; 160 | DGDownloadItem *item = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 161 | if (!item) { 162 | item = [[DGDownloadItem alloc] init]; 163 | item.requestUrl = url; 164 | item.downloadStatus = DGDownloadStatusWaiting; 165 | item.progress = 0.0; 166 | item.temPath = [self getTemPath:url]; 167 | item.paramDic = nil; 168 | [_DG_DownloadArray addObject:item]; 169 | }else { 170 | item.downloadStatus = DGDownloadStatusWaiting; 171 | } 172 | [self DG_CheckDownload]; 173 | [_lock unlock]; 174 | [[NSNotificationCenter defaultCenter] postNotificationName:DGResumeOneSong object:nil]; 175 | } 176 | /** 177 | 恢复所有暂停的下载 178 | */ 179 | - (void)DG_ResumeAllRequest{ 180 | [_lock lock]; 181 | for (DGDownloadItem *item in _DG_DownloadArray) { 182 | if (item.downloadStatus != DGDownloadStatusError || item.downloadStatus != DGDownloadStatusDownloadFinish) { 183 | item.downloadStatus = DGDownloadStatusWaiting; 184 | } 185 | } 186 | [self DG_CheckDownload]; 187 | [_lock unlock]; 188 | [[NSNotificationCenter defaultCenter] postNotificationName:DGResumeAllSong object:nil]; 189 | } 190 | /** 191 | 取消一个下载 192 | 193 | @param url 下载的全链接 194 | */ 195 | - (void)DG_CancelWithUrl:(NSString *)url{ 196 | if (url.length == 0) { 197 | return; 198 | } 199 | [_lock lock]; 200 | DGDownloadItem *item = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 201 | if (item.downloadStatus == DGDownloadStatusDownloadFinish) { 202 | return; 203 | }else { 204 | [item.task cancel]; 205 | item.task = nil; 206 | // 删除临时文件夹的缓存东西 207 | [[NSFileManager defaultManager] removeItemAtPath:item.temPath error:nil]; 208 | } 209 | if (item) { 210 | [_DG_DownloadArray removeObject:item]; 211 | } 212 | [_lock unlock]; 213 | [[NSNotificationCenter defaultCenter] postNotificationName:DGCancelOneSong object:nil]; 214 | } 215 | /** 216 | 取消所有的下载的任务 217 | */ 218 | - (void)DG_CancelAllRequest{ 219 | [_lock lock]; 220 | for (DGDownloadItem *item in _DG_DownloadArray) { 221 | [item.task cancel]; 222 | item.task = nil; 223 | // 删除临时文件夹的缓存东西 224 | [[NSFileManager defaultManager] removeItemAtPath:item.temPath error:nil]; 225 | } 226 | [_DG_DownloadArray removeAllObjects]; 227 | _DG_DownloadArray = nil; 228 | [_lock unlock]; 229 | 230 | [[NSNotificationCenter defaultCenter] postNotificationName:DGCancelAllSong object:nil]; 231 | } 232 | #pragma mark--获取数据相关 233 | /** 234 | 获取所有下载完成的数据model的数据源 235 | */ 236 | - (NSMutableArray *)DG_GetAllDownloadItems{ 237 | return [DGFileManager getAllDownloadItems]; 238 | } 239 | #pragma mark - 自身需要实现的方法 240 | /** 241 | 便利数组获取item 242 | 243 | @param itemArray 传递的数组 244 | @param url url 245 | @return 单个下载的对象 246 | */ 247 | - (DGDownloadItem *)getItemFromArray:(NSArray *)itemArray withUrl:(NSString *)url { 248 | DGDownloadItem *getItem = nil; 249 | for (DGDownloadItem *item in itemArray) { 250 | if ([item.requestUrl isEqualToString:url]) { 251 | getItem = item; 252 | break; 253 | } 254 | } 255 | return getItem; 256 | } 257 | /** 258 | 获取临时文件夹 (全路径) 259 | 260 | @param downloadUrl 下载的全路径 261 | @return 临时文件的路径 262 | */ 263 | - (NSString *)getTemPath:(NSString *)downloadUrl { 264 | 265 | if (downloadUrl.length <= 0) { 266 | return nil; 267 | } 268 | NSFileManager *fileManager = [NSFileManager defaultManager]; 269 | NSString *temPath = NSTemporaryDirectory(); 270 | NSString *nameStr =[[[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString] stringByAppendingString:@".download"]; 271 | temPath = [temPath stringByAppendingPathComponent:nameStr]; 272 | if (![fileManager fileExistsAtPath:temPath]) { 273 | [fileManager createFileAtPath:temPath contents:nil attributes:nil]; 274 | } 275 | return temPath; 276 | } 277 | /** 278 | * 279 | * 获取缓存的文件夹的路径 280 | */ 281 | - (NSString *)getCache:(NSString *)downloadUrl withResponse:(NSURLResponse *)response customCahceName:(NSString *)customCacheName{ 282 | 283 | if (downloadUrl.length <= 0) { 284 | return nil; 285 | } 286 | NSFileManager *fileManager = [NSFileManager defaultManager]; 287 | NSString *cachePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DGDownload"]; 288 | if (![fileManager fileExistsAtPath:cachePath]) { 289 | [fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:nil]; 290 | } 291 | // 方案二 自己用md5 或者其他的方式加密命名 292 | if (customCacheName.length > 0) { 293 | cachePath = [cachePath stringByAppendingPathComponent:customCacheName]; 294 | }else { 295 | NSString *lastComponent = downloadUrl.lastPathComponent; 296 | if (lastComponent.length == 0) { 297 | lastComponent = [[[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString] stringByAppendingString:@".download"]; 298 | } 299 | cachePath = [cachePath stringByAppendingPathComponent: lastComponent]; 300 | } 301 | if (![fileManager fileExistsAtPath:cachePath]) { 302 | [fileManager createFileAtPath:cachePath contents:nil attributes:nil]; 303 | } 304 | return cachePath; 305 | } 306 | 307 | /** 308 | 检查下载相关的 309 | */ 310 | - (void)DG_CheckDownload { 311 | 312 | NSInteger downloadingCount = 0; 313 | BOOL flag = YES; 314 | for (DGDownloadItem *item in _DG_DownloadArray) { 315 | if (item.downloadStatus == DGDownloadStatusDownloading) { 316 | downloadingCount ++; 317 | } 318 | if (self.DG_MaxTaskCount == 0) { 319 | self.DG_MaxTaskCount = MAXTASK_COUNT; 320 | } 321 | if (downloadingCount >= self.DG_MaxTaskCount) { 322 | flag = NO; 323 | break; 324 | } 325 | } 326 | if (flag) { 327 | for (DGDownloadItem *item in _DG_DownloadArray) { 328 | if (item.downloadStatus == DGDownloadStatusWaiting) { 329 | if (self.DG_MaxTaskCount == 0) { 330 | self.DG_MaxTaskCount = MAXTASK_COUNT; 331 | } 332 | if (self.DG_MaxTaskCount - downloadingCount > 0) { 333 | [self DG_BeginDownloadWithItem:item]; 334 | downloadingCount ++; 335 | }else { 336 | break; 337 | } 338 | } 339 | } 340 | } 341 | } 342 | /** 343 | 开始单个下载的任务 344 | 345 | @param item item 346 | */ 347 | - (void)DG_BeginDownloadWithItem:(DGDownloadItem *)item { 348 | 349 | if (item.requestUrl.length == 0) { 350 | return; 351 | } 352 | item.downloadStatus = DGDownloadStatusDownloading; 353 | // 如果任务正在进行 取消 354 | [self DG_CancelTask:item]; 355 | // 取消请求的缓存 356 | [[NSURLCache sharedURLCache] removeAllCachedResponses]; 357 | // 开始下载任务 358 | NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; 359 | AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; 360 | manager.responseSerializer = [AFHTTPResponseSerializer serializer]; 361 | NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:item.requestMethod URLString:item.requestUrl parameters:item.paramDic error:nil]; 362 | // 读取数据 363 | NSDictionary *dic = [[NSFileManager defaultManager] attributesOfItemAtPath:item.temPath error:nil]; 364 | unsigned long long cacheNumber = dic.fileSize; 365 | // 断点续传 366 | if (cacheNumber > 0) { 367 | NSString *rangStr = [NSString stringWithFormat:@"bytes=%llu-",cacheNumber]; 368 | [request setValue:rangStr forHTTPHeaderField:@"Range"]; 369 | } 370 | __weak typeof(self)weakSelf = self; 371 | [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) { 372 | [weakSelf.lock lock]; 373 | 374 | item.downloadStatus = DGDownloadStatusDownloading; 375 | // 写入数据 376 | if (!item.itemFileHandle) { 377 | item.itemFileHandle = [NSFileHandle fileHandleForWritingAtPath:item.temPath]; 378 | } 379 | [item.itemFileHandle seekToEndOfFile]; 380 | [item.itemFileHandle writeData:data]; 381 | // 计算进度 382 | unsigned long long receiveNumber = (unsigned long long )dataTask.countOfBytesReceived + cacheNumber; 383 | unsigned long long expectNumber = (unsigned long long)dataTask.countOfBytesExpectedToReceive + cacheNumber; 384 | CGFloat progress = (CGFloat)receiveNumber/expectNumber *1.0; 385 | item.progress = progress; 386 | if (item.DGDownloadProgressBlock) { 387 | item.DGDownloadProgressBlock(progress); 388 | } 389 | [weakSelf.lock unlock]; 390 | }]; 391 | // 完成 392 | item.task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { 393 | [weakSelf.lock lock]; 394 | item.error = error; 395 | if (error) { 396 | item.downloadStatus = DGDownloadStatusError; 397 | if (item.DGDownloadCompletionHandler) { 398 | item.DGDownloadCompletionHandler(error); 399 | } 400 | }else { 401 | item.downloadStatus = DGDownloadStatusDownloadFinish; 402 | // 这个路径要根据自己的实际情况处理 403 | item.cachePath = [weakSelf getCache:item.requestUrl withResponse:response customCahceName:item.customCacheName]; 404 | // 删除文件,防止出现错误 405 | [[NSFileManager defaultManager] removeItemAtPath:item.cachePath error:nil]; 406 | // 存放到自己想存放的路径 407 | NSError *transError = nil; 408 | [[NSFileManager defaultManager] moveItemAtPath:item.temPath toPath:item.cachePath error:&transError]; 409 | 410 | [DGFileManager saveDownloaditem:item]; 411 | // 从数组中移除成功的 412 | [weakSelf.DG_DownloadArray removeObject:item]; 413 | // 删除临时的文件 414 | [[NSFileManager defaultManager] removeItemAtPath:item.temPath error:nil]; 415 | if (item.DGDownloadCompletionHandler) { 416 | item.DGDownloadCompletionHandler(nil); 417 | } 418 | [[NSNotificationCenter defaultCenter] postNotificationName:DGDownloadFinish object:nil]; 419 | item.response = response; 420 | // 递归调用 421 | [weakSelf DG_CheckDownload]; 422 | } 423 | [weakSelf.lock unlock]; 424 | }]; 425 | 426 | [item.task resume]; 427 | item.manager = manager; 428 | } 429 | /** 430 | * 431 | * 取消正在下载的任务 432 | */ 433 | - (void)DG_CancelTask:(DGDownloadItem *)item { 434 | 435 | if (item.task) { 436 | [item.task cancel]; 437 | item.task = nil; 438 | } 439 | item.progress = 0; 440 | [item.manager setDataTaskDidReceiveDataBlock:NULL]; 441 | item.response = nil; 442 | item.error = nil; 443 | } 444 | #pragma mark -- 内部监听方法调用 445 | 446 | /// 监听网络变化自动恢复下载 447 | - (void)listenNetwork{ 448 | 449 | __weak typeof(DGDownloadManager *)weakSelf = self; 450 | [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 451 | switch (status) { 452 | case AFNetworkReachabilityStatusReachableViaWiFi: 453 | case AFNetworkReachabilityStatusReachableViaWWAN: 454 | { 455 | if (weakSelf.DG_AutoDownload) { 456 | [weakSelf DG_ResumeAllRequest]; 457 | } 458 | } 459 | break; 460 | default: 461 | break; 462 | } 463 | }]; 464 | } 465 | 466 | 467 | @end 468 | -------------------------------------------------------------------------------- /DGDownloadManager/Classes/DGBackgroudDownloadManagers/DGBackgroudDownloadManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DGBackgroudDownloadManager.m 3 | // DGDownloadManager 4 | // 5 | // Created by Brown on 2/24/21. 6 | // Copyright © 2021 apple. All rights reserved. 7 | // 8 | #import "DGBackgroudDownloadManager.h" 9 | #import "DGBackgroudDownloadCacheManager.h" 10 | #import "NSURLSession+CorrectedResumeData.h" 11 | #import "NSData+Category.h" 12 | #import 13 | #import 14 | 15 | 16 | #define MAXTASK_COUNT 3 17 | typedef void(^CompletionHandlerType)(void); 18 | 19 | @interface DGBackgroudDownloadManager () 20 | 21 | /** 锁*/ 22 | @property (nonatomic, strong) NSLock *lock; 23 | 24 | /** 存放identifier的字典*/ 25 | @property (nonatomic, strong) NSMutableDictionary *cacheDic; 26 | 27 | /** 存放下载model的数据*/ 28 | @property (nonatomic, strong) NSMutableArray *DG_DownloadArray; 29 | 30 | 31 | @end 32 | 33 | @implementation DGBackgroudDownloadManager 34 | 35 | + (instancetype)shareManager{ 36 | 37 | static DGBackgroudDownloadManager *_manager = nil; 38 | static dispatch_once_t onceToken; 39 | dispatch_once(&onceToken, ^{ 40 | _manager = [[self alloc] init]; 41 | }); 42 | return _manager; 43 | 44 | } 45 | - (instancetype)init { 46 | if (self == [super init]) { 47 | self.lock = [[NSLock alloc] init]; 48 | [self listenNetwork]; 49 | } 50 | return self; 51 | } 52 | 53 | #pragma mark - 懒加载 54 | - (NSMutableArray *)DG_DownloadArray { 55 | if (!_DG_DownloadArray) { 56 | _DG_DownloadArray = [NSMutableArray array]; 57 | } 58 | return _DG_DownloadArray; 59 | } 60 | 61 | - (NSMutableDictionary *)cacheDic { 62 | if (!_cacheDic) { 63 | _cacheDic = [NSMutableDictionary dictionary]; 64 | } 65 | return _cacheDic; 66 | } 67 | -(NSMutableArray *)DG_BackgroudDownloadArray{ 68 | return self.DG_DownloadArray; 69 | } 70 | 71 | #pragma mark -- 其他事件的相应 72 | 73 | /* 处理后台通知的相关事件需要在这个方法中写入 74 | - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler 75 | @param completionHandler completionHandler 76 | @param identifier identifier 77 | */ 78 | - (void)handleBackgroudcompletionHandler:(void(^)(void))completionHandler 79 | identifier:(NSString *)identifier{ 80 | if (identifier.length > 0) { 81 | self.cacheDic[identifier] = completionHandler; 82 | } 83 | } 84 | 85 | /** 86 | 开始下载 87 | 88 | @param downloadUrl 下载的路径 89 | @param customCacheName 自定义的缓存的名字 90 | */ 91 | - (void)DG_DownloadWithUrl:(NSString *)downloadUrl 92 | withCustomCacheName:(NSString *)customCacheName{ 93 | 94 | // 为空不处理 95 | if (downloadUrl.length == 0) { 96 | return; 97 | } 98 | // 判断缓存中是否存在,说明已经下载过了 99 | NSString *cachePath = [self getCache:downloadUrl customCahceName:customCacheName]; 100 | if ([[NSFileManager defaultManager] attributesOfItemAtPath:cachePath error:nil].fileSize > 0) { 101 | return; 102 | } 103 | 104 | [self.lock lock]; 105 | DGBackgroudDownloadModel *model = [self getItemFromArray:_DG_DownloadArray withUrl:downloadUrl]; 106 | if (!model) { 107 | model = [[DGBackgroudDownloadModel alloc] init]; 108 | model.requestUrl = downloadUrl; 109 | model.downloadStatus = DGBackgroudDownloadStatusWaiting; 110 | model.customCacheName = customCacheName; 111 | model.cachePath = [self getCache:downloadUrl customCahceName:customCacheName]; 112 | [self.DG_DownloadArray addObject:model]; 113 | }else{ 114 | model.downloadStatus = DGBackgroudDownloadStatusWaiting; 115 | } 116 | 117 | [self DG_CheckDownload]; 118 | [_lock unlock]; 119 | } 120 | 121 | /** 122 | 暂停某一个下载 123 | 124 | @param url 暂停的全下载路径 125 | */ 126 | - (void)DG_SuspendWithUrl:(NSString *)url{ 127 | 128 | if (url.length == 0) { 129 | return; 130 | } 131 | DGBackgroudDownloadModel *model = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 132 | if (!model) { 133 | return; 134 | } 135 | model.downloadStatus = DGBackgroudDownloadStatusDownloadSuspend; 136 | __weak typeof(DGBackgroudDownloadModel *)weakModel = model; 137 | [model.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { 138 | weakModel.downloaDelegate.resumeData = resumeData; 139 | }]; 140 | } 141 | 142 | /** 143 | 暂停所有的下载 144 | */ 145 | - (void)DG_SuspendAllRequest{ 146 | 147 | [_lock lock]; 148 | for (DGBackgroudDownloadModel *model in _DG_DownloadArray) { 149 | if (model.downloadStatus == DGBackgroudDownloadStatusDownloading || model.downloadStatus == DGBackgroudDownloadStatusWaiting || model.downloadStatus == DGBackgroudDownloadStatusError) { 150 | model.downloadStatus = DGBackgroudDownloadStatusDownloadSuspend; 151 | __weak typeof(DGBackgroudDownloadModel *)weakModel = model; 152 | [model.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { 153 | weakModel.downloaDelegate.resumeData = resumeData; 154 | }]; 155 | } 156 | } 157 | [_lock unlock]; 158 | } 159 | /** 160 | 恢复某一个下载 161 | 162 | @param url 下载的全链接 163 | */ 164 | - (void)DG_ResumeWithUrl:(NSString *)url { 165 | 166 | if (url.length == 0) { 167 | return; 168 | } 169 | [_lock lock]; 170 | DGBackgroudDownloadModel *model = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 171 | if (!model) { 172 | model = [[DGBackgroudDownloadModel alloc] init]; 173 | model.requestUrl = url; 174 | model.downloadStatus = DGBackgroudDownloadStatusWaiting; 175 | [_DG_DownloadArray addObject:model]; 176 | }else{ 177 | model.downloadStatus = DGBackgroudDownloadStatusWaiting; 178 | } 179 | [_lock unlock]; 180 | [self DG_CheckDownload]; 181 | 182 | } 183 | /** 184 | 恢复所有暂停的下载 185 | */ 186 | - (void)DG_ResumeAllRequest{ 187 | 188 | [_lock lock]; 189 | for (DGBackgroudDownloadModel *model in _DG_DownloadArray) { 190 | if (model.downloadStatus != DGBackgroudDownloadStatusError || model.downloadStatus != DGBackgroudDownloadStatusDownloadFinish) { 191 | model.downloadStatus = DGBackgroudDownloadStatusWaiting; 192 | } 193 | } 194 | [self DG_CheckDownload]; 195 | [_lock unlock]; 196 | } 197 | /** 198 | 取消一个下载 199 | 200 | @param url 下载的全链接 201 | */ 202 | - (void)DG_CancelWithUrl:(NSString *)url { 203 | 204 | if (url.length == 0) { 205 | return; 206 | } 207 | [_lock lock]; 208 | DGBackgroudDownloadModel *model = [self getItemFromArray:_DG_DownloadArray withUrl:url]; 209 | if (model.downloadStatus == DGBackgroudDownloadStatusDownloadFinish) { 210 | return; 211 | }else { 212 | [model.task cancel]; 213 | model.task = nil; 214 | } 215 | if (model) { 216 | [_DG_DownloadArray removeObject:model]; 217 | } 218 | [_lock unlock]; 219 | 220 | } 221 | /** 222 | 取消所有的下载的任务 223 | */ 224 | - (void)DG_CancelAllRequest{ 225 | 226 | if (_DG_DownloadArray.count == 0) { 227 | return; 228 | } 229 | 230 | [_lock lock]; 231 | for (DGBackgroudDownloadModel *model in _DG_DownloadArray) { 232 | [model.session invalidateAndCancel]; 233 | model.downloaDelegate.resumeData = nil; 234 | [model.task cancel]; 235 | model.task = nil; 236 | } 237 | [_DG_DownloadArray removeAllObjects]; 238 | _DG_DownloadArray = nil; 239 | [_lock unlock]; 240 | } 241 | #pragma mark - 自身需要实现的方法 242 | /** 243 | 便利数组获取item 244 | 245 | @param itemArray 传递的数组 246 | @param url url 247 | @return 单个下载的对象 248 | */ 249 | - (DGBackgroudDownloadModel *)getItemFromArray:(NSArray *)itemArray 250 | withUrl:(NSString *)url { 251 | DGBackgroudDownloadModel *itemModel = nil; 252 | for (DGBackgroudDownloadModel *model in itemArray) { 253 | if ([model.requestUrl isEqualToString:url]) { 254 | itemModel = model; 255 | break; 256 | } 257 | } 258 | return itemModel; 259 | } 260 | /// 获取缓存的文件夹的路径 261 | /// @param downloadUrl downloadUrl 262 | /// @param customCacheName 自定义图片的名字 263 | - (NSString *)getCache:(NSString *)downloadUrl 264 | customCahceName:(NSString *)customCacheName{ 265 | 266 | if (downloadUrl.length <= 0) { 267 | return nil; 268 | } 269 | NSFileManager *fileManager = [NSFileManager defaultManager]; 270 | NSString *cachePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DGBackgroudDownload"]; 271 | if (![fileManager fileExistsAtPath:cachePath]) { 272 | [fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:nil]; 273 | } 274 | // 方案二 自己用md5 或者其他的方式加密命名 275 | if (customCacheName.length > 0) { 276 | cachePath = [cachePath stringByAppendingPathComponent:customCacheName]; 277 | }else { 278 | NSString *lastComponent = downloadUrl.lastPathComponent; 279 | if (lastComponent.length == 0) { 280 | lastComponent = [[[downloadUrl dataUsingEncoding:NSUTF8StringEncoding] DG_MD5HashString] stringByAppendingString:@".download"]; 281 | } 282 | cachePath = [cachePath stringByAppendingPathComponent: lastComponent]; 283 | } 284 | if (![fileManager fileExistsAtPath:cachePath]) { 285 | [fileManager createFileAtPath:cachePath contents:nil attributes:nil]; 286 | } 287 | return cachePath; 288 | } 289 | 290 | /** 291 | 检查下载相关的 292 | */ 293 | - (void)DG_CheckDownload { 294 | 295 | NSInteger downloadingCount = 0; 296 | BOOL flag = YES; 297 | for (DGBackgroudDownloadModel *model in _DG_DownloadArray) { 298 | if (model.downloadStatus == DGBackgroudDownloadStatusDownloading) { 299 | downloadingCount ++; 300 | } 301 | if (self.DG_MaxTaskCount == 0) { 302 | self.DG_MaxTaskCount = MAXTASK_COUNT; 303 | } 304 | if (downloadingCount >= self.DG_MaxTaskCount) { 305 | flag = NO; 306 | break; 307 | } 308 | } 309 | if (flag) { 310 | for (DGBackgroudDownloadModel *model in _DG_DownloadArray) { 311 | if (model.downloadStatus == DGBackgroudDownloadStatusWaiting) { 312 | if (self.DG_MaxTaskCount == 0) { 313 | self.DG_MaxTaskCount = MAXTASK_COUNT; 314 | } 315 | if (self.DG_MaxTaskCount - downloadingCount > 0) { 316 | [self DG_BeginDownloadWithModel: model]; 317 | downloadingCount ++; 318 | }else { 319 | break; 320 | } 321 | } 322 | } 323 | } 324 | } 325 | /** 326 | 开始单个下载的任务 327 | 328 | @param model model 329 | */ 330 | - (void)DG_BeginDownloadWithModel:(DGBackgroudDownloadModel *)model { 331 | 332 | if (model.requestUrl.length == 0 || model.downloadStatus == DGBackgroudDownloadStatusDownloading) { 333 | return; 334 | } 335 | 336 | __weak typeof(DGBackgroudDownloadModel *)weakModel = model; 337 | 338 | model.downloadStatus = DGBackgroudDownloadStatusDownloading; 339 | if (model.task) { 340 | [model.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { 341 | weakModel.downloaDelegate.resumeData = resumeData; 342 | }]; 343 | }else{ 344 | // 回掉错误代理可以拿到resumedata 345 | [model.session getTasksWithCompletionHandler:^(NSArray * _Nonnull dataTasks, NSArray * _Nonnull uploadTasks, NSArray * _Nonnull downloadTasks) { 346 | 347 | }]; 348 | } 349 | 350 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 351 | if (model.downloaDelegate.resumeData.length == 0) { 352 | model.downloaDelegate.resumeData = [DGBackgroudDownloadCacheManager getResumeData:model.requestUrl]; 353 | } 354 | [self handleModel:model]; 355 | }); 356 | 357 | } 358 | 359 | /// model 的相关的监听 360 | /// @param model model 361 | - (void)handleModel:(DGBackgroudDownloadModel *)model { 362 | 363 | __weak typeof(DGBackgroudDownloadModel *)weakModel = model; 364 | __weak typeof(self)weakSelf = self; 365 | 366 | if (model.downloaDelegate.resumeData.length > 0) { 367 | 368 | if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.2) { 369 | model.task = [model.session downloadTaskWithResumeData: model.downloaDelegate.resumeData]; 370 | }else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10){ 371 | model.task = [model.session downloadTaskWithCorrectResumeData: model.downloaDelegate.resumeData]; 372 | }else{ 373 | model.task = [model.session downloadTaskWithResumeData:model.downloaDelegate.resumeData]; 374 | } 375 | [model.task resume]; 376 | 377 | }else{ 378 | NSURL *downloadUrl = [NSURL URLWithString:model.requestUrl]; 379 | NSURLRequest *request = [NSURLRequest requestWithURL:downloadUrl]; 380 | model.task = [model.session downloadTaskWithRequest:request]; 381 | [model.task resume]; 382 | } 383 | // 移除老的resumeData 384 | [DGBackgroudDownloadCacheManager deleteResumeDataWithUrl:model.requestUrl]; 385 | 386 | // 监听过了不在监听 387 | if (model.downloaDelegate.downloadFinishBlock) { 388 | return; 389 | } 390 | 391 | // 各种监听 392 | model.downloaDelegate.downloadFinishBlock = ^(NSURLSessionDownloadTask *downloadTask, NSURL *location) { 393 | 394 | weakModel.downloadStatus = DGBackgroudDownloadStatusDownloadFinish; 395 | // 删除文件,防止出现错误 396 | [[NSFileManager defaultManager] removeItemAtPath:weakModel.cachePath error:nil]; 397 | 398 | NSError *transError = nil; 399 | NSString *locationString = [location path]; 400 | [[NSFileManager defaultManager] moveItemAtPath:locationString toPath:weakModel.cachePath error:&transError]; 401 | [[NSFileManager defaultManager] removeItemAtPath:locationString error:nil]; 402 | 403 | // 删除resumedata 404 | [DGBackgroudDownloadCacheManager deleteResumeDataWithUrl:weakModel.requestUrl]; 405 | 406 | [weakModel.session invalidateAndCancel]; 407 | [weakModel.task cancel]; 408 | weakModel.task = nil; 409 | 410 | // 存储model 411 | [DGBackgroudDownloadCacheManager saveDownloadModel:weakModel]; 412 | 413 | [weakSelf.lock lock]; 414 | [weakSelf.DG_DownloadArray removeObject:weakModel]; 415 | [weakSelf DG_CheckDownload]; 416 | [weakSelf.lock unlock]; 417 | 418 | if (weakModel.downloadFinishBlcok) { 419 | weakModel.downloadFinishBlcok(downloadTask, location); 420 | } 421 | }; 422 | 423 | model.downloaDelegate.downloadProgressBlock = ^(CGFloat progress,CGFloat speed) { 424 | if (weakModel.downloadProgressBlock) { 425 | weakModel.downloadProgressBlock(progress,speed); 426 | } 427 | }; 428 | 429 | model.downloaDelegate.downloadErrorBlock = ^(NSError *error) { 430 | weakModel.downloadStatus = DGBackgroudDownloadStatusError; 431 | if (weakModel.cachePath.length > 0 && 432 | [[NSFileManager defaultManager] attributesOfItemAtPath:weakModel.cachePath error:nil].fileSize > 0) { 433 | return; 434 | } 435 | if (weakModel.downloadErrorBlock && !error) { 436 | weakModel.downloadErrorBlock(error); 437 | } 438 | }; 439 | 440 | model.downloaDelegate.downloadFinishEventBlock = ^(NSString *identifier) { 441 | weakModel.downloadStatus = DGBackgroudDownloadStatusDownloadFinish; 442 | if ([weakSelf.cacheDic.allKeys containsObject:identifier]) { 443 | CompletionHandlerType completionHandler = weakSelf.cacheDic[identifier]; 444 | if (completionHandler) { 445 | completionHandler(); 446 | } 447 | [weakSelf.cacheDic removeObjectForKey:identifier]; 448 | } 449 | }; 450 | } 451 | #pragma mark--获取数据相关 452 | /** 453 | 获取所有下载完成的数据model的数据源 454 | */ 455 | - (NSMutableArray *)DG_GetAllDownloadModels{ 456 | 457 | return [DGBackgroudDownloadCacheManager getAllDownloadModels]; 458 | } 459 | 460 | #pragma mark -- 内部监听方法调用 461 | 462 | /// 监听网络变化自动恢复下载 463 | - (void)listenNetwork{ 464 | 465 | __weak typeof(DGBackgroudDownloadManager *)weakSelf = self; 466 | [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 467 | switch (status) { 468 | case AFNetworkReachabilityStatusReachableViaWiFi: 469 | case AFNetworkReachabilityStatusReachableViaWWAN: 470 | { 471 | if (weakSelf.DG_AutoDownload) { 472 | [weakSelf DG_ResumeAllRequest]; 473 | } 474 | } 475 | break; 476 | default: 477 | break; 478 | } 479 | }]; 480 | } 481 | 482 | @end 483 | -------------------------------------------------------------------------------- /Example/DGDownloadManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 18B2553A22250E790000934E /* DownloadCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 18B2553822250E790000934E /* DownloadCell.m */; }; 11 | 18B2553B22250E790000934E /* DownloadCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 18B2553922250E790000934E /* DownloadCell.xib */; }; 12 | 18DEDD792223EE3800AA9C34 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 18DEDD782223EE3800AA9C34 /* AppDelegate.m */; }; 13 | 18DEDD7C2223EE3800AA9C34 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 18DEDD7B2223EE3800AA9C34 /* ViewController.m */; }; 14 | 18DEDD7F2223EE3800AA9C34 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 18DEDD7D2223EE3800AA9C34 /* Main.storyboard */; }; 15 | 18DEDD812223EE3B00AA9C34 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 18DEDD802223EE3B00AA9C34 /* Assets.xcassets */; }; 16 | 18DEDD842223EE3B00AA9C34 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 18DEDD822223EE3B00AA9C34 /* LaunchScreen.storyboard */; }; 17 | 18DEDD872223EE3B00AA9C34 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 18DEDD862223EE3B00AA9C34 /* main.m */; }; 18 | 32DF0DCC620FE9B249B1C4A5 /* Pods_DGDownloadManager.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9937D66E0D46977B8ABBB3B /* Pods_DGDownloadManager.framework */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 18B2553722250E790000934E /* DownloadCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DownloadCell.h; sourceTree = ""; }; 23 | 18B2553822250E790000934E /* DownloadCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DownloadCell.m; sourceTree = ""; }; 24 | 18B2553922250E790000934E /* DownloadCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DownloadCell.xib; sourceTree = ""; }; 25 | 18DEDD742223EE3800AA9C34 /* DGDownloadManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DGDownloadManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 18DEDD772223EE3800AA9C34 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 27 | 18DEDD782223EE3800AA9C34 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 28 | 18DEDD7A2223EE3800AA9C34 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 29 | 18DEDD7B2223EE3800AA9C34 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 30 | 18DEDD7E2223EE3800AA9C34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 31 | 18DEDD802223EE3B00AA9C34 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32 | 18DEDD832223EE3B00AA9C34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 33 | 18DEDD852223EE3B00AA9C34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | 18DEDD862223EE3B00AA9C34 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 20011278B47377539116AE7A /* Pods-DGDownloadManager.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DGDownloadManager.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DGDownloadManager/Pods-DGDownloadManager.debug.xcconfig"; sourceTree = ""; }; 36 | 8797FD7BF41AC80931C1781A /* Pods-DGDownloadManager.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DGDownloadManager.release.xcconfig"; path = "Pods/Target Support Files/Pods-DGDownloadManager/Pods-DGDownloadManager.release.xcconfig"; sourceTree = ""; }; 37 | F9937D66E0D46977B8ABBB3B /* Pods_DGDownloadManager.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DGDownloadManager.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 18DEDD712223EE3800AA9C34 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | 32DF0DCC620FE9B249B1C4A5 /* Pods_DGDownloadManager.framework in Frameworks */, 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 18DEDD6B2223EE3800AA9C34 = { 53 | isa = PBXGroup; 54 | children = ( 55 | 18DEDD762223EE3800AA9C34 /* DGDownloadManager */, 56 | 18DEDD752223EE3800AA9C34 /* Products */, 57 | 7F0828B6D60A946250E7F617 /* Pods */, 58 | 90550873E0FA1046782BB717 /* Frameworks */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | 18DEDD752223EE3800AA9C34 /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 18DEDD742223EE3800AA9C34 /* DGDownloadManager.app */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | 18DEDD762223EE3800AA9C34 /* DGDownloadManager */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 18DEDD772223EE3800AA9C34 /* AppDelegate.h */, 74 | 18DEDD782223EE3800AA9C34 /* AppDelegate.m */, 75 | 18DEDD7A2223EE3800AA9C34 /* ViewController.h */, 76 | 18DEDD7B2223EE3800AA9C34 /* ViewController.m */, 77 | 18DEDD7D2223EE3800AA9C34 /* Main.storyboard */, 78 | 18B2553722250E790000934E /* DownloadCell.h */, 79 | 18B2553822250E790000934E /* DownloadCell.m */, 80 | 18B2553922250E790000934E /* DownloadCell.xib */, 81 | 18DEDD802223EE3B00AA9C34 /* Assets.xcassets */, 82 | 18DEDD822223EE3B00AA9C34 /* LaunchScreen.storyboard */, 83 | 18DEDD852223EE3B00AA9C34 /* Info.plist */, 84 | 18DEDD862223EE3B00AA9C34 /* main.m */, 85 | ); 86 | path = DGDownloadManager; 87 | sourceTree = ""; 88 | }; 89 | 7F0828B6D60A946250E7F617 /* Pods */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 20011278B47377539116AE7A /* Pods-DGDownloadManager.debug.xcconfig */, 93 | 8797FD7BF41AC80931C1781A /* Pods-DGDownloadManager.release.xcconfig */, 94 | ); 95 | name = Pods; 96 | sourceTree = ""; 97 | }; 98 | 90550873E0FA1046782BB717 /* Frameworks */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | F9937D66E0D46977B8ABBB3B /* Pods_DGDownloadManager.framework */, 102 | ); 103 | name = Frameworks; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | 18DEDD732223EE3800AA9C34 /* DGDownloadManager */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = 18DEDD8A2223EE3B00AA9C34 /* Build configuration list for PBXNativeTarget "DGDownloadManager" */; 112 | buildPhases = ( 113 | BF58106A9FDD02F8E5F33395 /* [CP] Check Pods Manifest.lock */, 114 | 18DEDD702223EE3800AA9C34 /* Sources */, 115 | 18DEDD712223EE3800AA9C34 /* Frameworks */, 116 | 18DEDD722223EE3800AA9C34 /* Resources */, 117 | AD29A2E4F9B78BA3E43567EC /* [CP] Embed Pods Frameworks */, 118 | ); 119 | buildRules = ( 120 | ); 121 | dependencies = ( 122 | ); 123 | name = DGDownloadManager; 124 | productName = DGDownloadManager; 125 | productReference = 18DEDD742223EE3800AA9C34 /* DGDownloadManager.app */; 126 | productType = "com.apple.product-type.application"; 127 | }; 128 | /* End PBXNativeTarget section */ 129 | 130 | /* Begin PBXProject section */ 131 | 18DEDD6C2223EE3800AA9C34 /* Project object */ = { 132 | isa = PBXProject; 133 | attributes = { 134 | LastUpgradeCheck = 1010; 135 | ORGANIZATIONNAME = apple; 136 | TargetAttributes = { 137 | 18DEDD732223EE3800AA9C34 = { 138 | CreatedOnToolsVersion = 10.1; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = 18DEDD6F2223EE3800AA9C34 /* Build configuration list for PBXProject "DGDownloadManager" */; 143 | compatibilityVersion = "Xcode 9.3"; 144 | developmentRegion = en; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = 18DEDD6B2223EE3800AA9C34; 151 | productRefGroup = 18DEDD752223EE3800AA9C34 /* Products */; 152 | projectDirPath = ""; 153 | projectRoot = ""; 154 | targets = ( 155 | 18DEDD732223EE3800AA9C34 /* DGDownloadManager */, 156 | ); 157 | }; 158 | /* End PBXProject section */ 159 | 160 | /* Begin PBXResourcesBuildPhase section */ 161 | 18DEDD722223EE3800AA9C34 /* Resources */ = { 162 | isa = PBXResourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 18DEDD842223EE3B00AA9C34 /* LaunchScreen.storyboard in Resources */, 166 | 18B2553B22250E790000934E /* DownloadCell.xib in Resources */, 167 | 18DEDD812223EE3B00AA9C34 /* Assets.xcassets in Resources */, 168 | 18DEDD7F2223EE3800AA9C34 /* Main.storyboard in Resources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXResourcesBuildPhase section */ 173 | 174 | /* Begin PBXShellScriptBuildPhase section */ 175 | AD29A2E4F9B78BA3E43567EC /* [CP] Embed Pods Frameworks */ = { 176 | isa = PBXShellScriptBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | ); 180 | inputFileListPaths = ( 181 | "${PODS_ROOT}/Target Support Files/Pods-DGDownloadManager/Pods-DGDownloadManager-frameworks-${CONFIGURATION}-input-files.xcfilelist", 182 | ); 183 | name = "[CP] Embed Pods Frameworks"; 184 | outputFileListPaths = ( 185 | "${PODS_ROOT}/Target Support Files/Pods-DGDownloadManager/Pods-DGDownloadManager-frameworks-${CONFIGURATION}-output-files.xcfilelist", 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | shellPath = /bin/sh; 189 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DGDownloadManager/Pods-DGDownloadManager-frameworks.sh\"\n"; 190 | showEnvVarsInLog = 0; 191 | }; 192 | BF58106A9FDD02F8E5F33395 /* [CP] Check Pods Manifest.lock */ = { 193 | isa = PBXShellScriptBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | ); 197 | inputPaths = ( 198 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 199 | "${PODS_ROOT}/Manifest.lock", 200 | ); 201 | name = "[CP] Check Pods Manifest.lock"; 202 | outputPaths = ( 203 | "$(DERIVED_FILE_DIR)/Pods-DGDownloadManager-checkManifestLockResult.txt", 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | shellPath = /bin/sh; 207 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 208 | showEnvVarsInLog = 0; 209 | }; 210 | /* End PBXShellScriptBuildPhase section */ 211 | 212 | /* Begin PBXSourcesBuildPhase section */ 213 | 18DEDD702223EE3800AA9C34 /* Sources */ = { 214 | isa = PBXSourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | 18DEDD7C2223EE3800AA9C34 /* ViewController.m in Sources */, 218 | 18B2553A22250E790000934E /* DownloadCell.m in Sources */, 219 | 18DEDD872223EE3B00AA9C34 /* main.m in Sources */, 220 | 18DEDD792223EE3800AA9C34 /* AppDelegate.m in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXSourcesBuildPhase section */ 225 | 226 | /* Begin PBXVariantGroup section */ 227 | 18DEDD7D2223EE3800AA9C34 /* Main.storyboard */ = { 228 | isa = PBXVariantGroup; 229 | children = ( 230 | 18DEDD7E2223EE3800AA9C34 /* Base */, 231 | ); 232 | name = Main.storyboard; 233 | sourceTree = ""; 234 | }; 235 | 18DEDD822223EE3B00AA9C34 /* LaunchScreen.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | 18DEDD832223EE3B00AA9C34 /* Base */, 239 | ); 240 | name = LaunchScreen.storyboard; 241 | sourceTree = ""; 242 | }; 243 | /* End PBXVariantGroup section */ 244 | 245 | /* Begin XCBuildConfiguration section */ 246 | 18DEDD882223EE3B00AA9C34 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_NONNULL = YES; 251 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_ENABLE_OBJC_WEAK = YES; 257 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_COMMA = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 262 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 263 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 270 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 271 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 272 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 273 | CLANG_WARN_STRICT_PROTOTYPES = YES; 274 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 275 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 276 | CLANG_WARN_UNREACHABLE_CODE = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | CODE_SIGN_IDENTITY = "iPhone Developer"; 279 | COPY_PHASE_STRIP = NO; 280 | DEBUG_INFORMATION_FORMAT = dwarf; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | ENABLE_TESTABILITY = YES; 283 | GCC_C_LANGUAGE_STANDARD = gnu11; 284 | GCC_DYNAMIC_NO_PIC = NO; 285 | GCC_NO_COMMON_BLOCKS = YES; 286 | GCC_OPTIMIZATION_LEVEL = 0; 287 | GCC_PREPROCESSOR_DEFINITIONS = ( 288 | "DEBUG=1", 289 | "$(inherited)", 290 | ); 291 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 292 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 293 | GCC_WARN_UNDECLARED_SELECTOR = YES; 294 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 295 | GCC_WARN_UNUSED_FUNCTION = YES; 296 | GCC_WARN_UNUSED_VARIABLE = YES; 297 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 298 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 299 | MTL_FAST_MATH = YES; 300 | ONLY_ACTIVE_ARCH = YES; 301 | SDKROOT = iphoneos; 302 | }; 303 | name = Debug; 304 | }; 305 | 18DEDD892223EE3B00AA9C34 /* Release */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ALWAYS_SEARCH_USER_PATHS = NO; 309 | CLANG_ANALYZER_NONNULL = YES; 310 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 312 | CLANG_CXX_LIBRARY = "libc++"; 313 | CLANG_ENABLE_MODULES = YES; 314 | CLANG_ENABLE_OBJC_ARC = YES; 315 | CLANG_ENABLE_OBJC_WEAK = YES; 316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_COMMA = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 322 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 323 | CLANG_WARN_EMPTY_BODY = YES; 324 | CLANG_WARN_ENUM_CONVERSION = YES; 325 | CLANG_WARN_INFINITE_RECURSION = YES; 326 | CLANG_WARN_INT_CONVERSION = YES; 327 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 328 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 329 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 331 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 332 | CLANG_WARN_STRICT_PROTOTYPES = YES; 333 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 334 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 335 | CLANG_WARN_UNREACHABLE_CODE = YES; 336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 337 | CODE_SIGN_IDENTITY = "iPhone Developer"; 338 | COPY_PHASE_STRIP = NO; 339 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 340 | ENABLE_NS_ASSERTIONS = NO; 341 | ENABLE_STRICT_OBJC_MSGSEND = YES; 342 | GCC_C_LANGUAGE_STANDARD = gnu11; 343 | GCC_NO_COMMON_BLOCKS = YES; 344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 346 | GCC_WARN_UNDECLARED_SELECTOR = YES; 347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 348 | GCC_WARN_UNUSED_FUNCTION = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 351 | MTL_ENABLE_DEBUG_INFO = NO; 352 | MTL_FAST_MATH = YES; 353 | SDKROOT = iphoneos; 354 | VALIDATE_PRODUCT = YES; 355 | }; 356 | name = Release; 357 | }; 358 | 18DEDD8B2223EE3B00AA9C34 /* Debug */ = { 359 | isa = XCBuildConfiguration; 360 | baseConfigurationReference = 20011278B47377539116AE7A /* Pods-DGDownloadManager.debug.xcconfig */; 361 | buildSettings = { 362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 363 | CODE_SIGN_STYLE = Manual; 364 | DEVELOPMENT_TEAM = VHJ5B2N34K; 365 | INFOPLIST_FILE = DGDownloadManager/Info.plist; 366 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 367 | LD_RUNPATH_SEARCH_PATHS = ( 368 | "$(inherited)", 369 | "@executable_path/Frameworks", 370 | ); 371 | PRODUCT_BUNDLE_IDENTIFIER = com.testm6.amuse2; 372 | PRODUCT_NAME = "$(TARGET_NAME)"; 373 | PROVISIONING_PROFILE_SPECIFIER = testm6develop2; 374 | TARGETED_DEVICE_FAMILY = 1; 375 | }; 376 | name = Debug; 377 | }; 378 | 18DEDD8C2223EE3B00AA9C34 /* Release */ = { 379 | isa = XCBuildConfiguration; 380 | baseConfigurationReference = 8797FD7BF41AC80931C1781A /* Pods-DGDownloadManager.release.xcconfig */; 381 | buildSettings = { 382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 383 | CODE_SIGN_IDENTITY = "iPhone Distribution"; 384 | CODE_SIGN_STYLE = Manual; 385 | DEVELOPMENT_TEAM = VHJ5B2N34K; 386 | INFOPLIST_FILE = DGDownloadManager/Info.plist; 387 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 388 | LD_RUNPATH_SEARCH_PATHS = ( 389 | "$(inherited)", 390 | "@executable_path/Frameworks", 391 | ); 392 | PRODUCT_BUNDLE_IDENTIFIER = com.testm6.amuse2; 393 | PRODUCT_NAME = "$(TARGET_NAME)"; 394 | PROVISIONING_PROFILE_SPECIFIER = TestM62; 395 | TARGETED_DEVICE_FAMILY = 1; 396 | }; 397 | name = Release; 398 | }; 399 | /* End XCBuildConfiguration section */ 400 | 401 | /* Begin XCConfigurationList section */ 402 | 18DEDD6F2223EE3800AA9C34 /* Build configuration list for PBXProject "DGDownloadManager" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 18DEDD882223EE3B00AA9C34 /* Debug */, 406 | 18DEDD892223EE3B00AA9C34 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | 18DEDD8A2223EE3B00AA9C34 /* Build configuration list for PBXNativeTarget "DGDownloadManager" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 18DEDD8B2223EE3B00AA9C34 /* Debug */, 415 | 18DEDD8C2223EE3B00AA9C34 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | /* End XCConfigurationList section */ 421 | }; 422 | rootObject = 18DEDD6C2223EE3800AA9C34 /* Project object */; 423 | } 424 | --------------------------------------------------------------------------------