NSURLSession 后台上传文件
2023-12-10 本文已影响0人
d4d5907268a9
#import "AppDelegate.h"
#import "ViewController.h"
#import "define.h"
#define IS_IOS10ORLATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10)
#define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx"
#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
typedef void(^CompletionHandlerType)();
@interface AppDelegate ()
@property (strong, nonatomic) NSMutableDictionary *completionHandlerDictionary;
//@property (strong, nonatomic) NSURLSessionUploadTask *uploadTask;
@property (strong, nonatomic) NSURLSession *backgroundSession;
@property (strong, nonatomic) NSData *resumeData;
@property (strong, nonatomic) UILocalNotification *localNotification;
@property (nonatomic, strong) NSMutableArray *mutableArr;
@property (nonatomic, strong) NSMutableArray *dataMutableArr;
//用于判断最后一个任务完成上传 才发出通知
@property (nonatomic) NSInteger dataNum;
@end
@implementation AppDelegate
- (NSMutableArray *)mutableArr{
if (!_mutableArr) {
_mutableArr = [NSMutableArray array];
}
return _mutableArr;
}
- (NSMutableArray *)dataMutableArr{
if (!_dataMutableArr) {
_dataMutableArr = [NSMutableArray array];
}
return _dataMutableArr;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.dataNum = 0;
self.backgroundSession = [self backgroundURLSession];
[self initLocalNotification];
// ios8后,需要添加这个注册,才能得到授权
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationType type = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
// 通知重复提示的单位,可以是天、周、月
self.localNotification.repeatInterval = 0;
} else {
// 通知重复提示的单位,可以是天、周、月
self.localNotification.repeatInterval = 0;
}
UILocalNotification *localNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification) {
[self application:application didReceiveLocalNotification:localNotification];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
self.window.rootViewController = nvc;
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
// 你必须重新建立一个后台 seesion 的参照
// 否则 NSURLSessionDownloadDelegate 和 NSURLSessionDelegate 方法会因为
// 没有 对 session 的 delegate 设定而不会被调用。参见上面的 backgroundURLSession
NSURLSession *backgroundSession = [self backgroundURLSession];
NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession);
// 保存 completion handler 以在处理 session 事件后更新 UI
[self addCompletionHandler:completionHandler forSession:identifier];
}
#pragma mark Save completionHandler
- (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString *)identifier {
if ([self.completionHandlerDictionary objectForKey:identifier]) {
NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.\n");
}
[self.completionHandlerDictionary setObject:handler forKey:identifier];
}
- (void)callCompletionHandlerForSession:(NSString *)identifier {
CompletionHandlerType handler = [self.completionHandlerDictionary objectForKey: identifier];
if (handler) {
[self.completionHandlerDictionary removeObjectForKey: identifier];
NSLog(@"Calling completion handler for session %@", identifier);
handler();
}
}
#pragma mark - Local Notification
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"上传通知"
message:notification.alertBody
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alert show];
// 图标上的数字减1
application.applicationIconBadgeNumber -= 1;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// 图标上的数字减1
application.applicationIconBadgeNumber -= 1;
}
- (void)initLocalNotification {
self.localNotification = [[UILocalNotification alloc] init];
self.localNotification.fireDate = [[NSDate date] dateByAddingTimeInterval:5];
self.localNotification.alertAction = nil;
self.localNotification.soundName = UILocalNotificationDefaultSoundName;
self.localNotification.alertBody = @"上传完成了!";
self.localNotification.applicationIconBadgeNumber = 1;
self.localNotification.repeatInterval = 0;
}
- (void)sendLocalNotification {
[[UIApplication sharedApplication] scheduleLocalNotification:self.localNotification];
}
#pragma mark - backgroundURLSession
- (NSURLSession *)backgroundURLSession {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *identifier = @"from.hx";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
});
return session;
}
- (void)uploadDataWithImageFileArr:(NSMutableArray *)array andIp:(NSString *)ip{
NSURL *uploadURL = [NSURL URLWithString:ip];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:uploadURL];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
[request addValue:@"text/html" forHTTPHeaderField:@"Accept"];
[request setHTTPMethod:@"PUT"];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setTimeoutInterval:60];
for (int i = 0; i < array.count; i++) {
NSDate *nowdate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setDateFormat:@"MMddHHmm"];
NSString *datestr = [formatter stringFromDate:nowdate];
NSString *identifier = @"from.hx";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromFile:[NSURL URLWithString:array[i]]];
[task resume];
}
}
- (void)uploadDataWithImageArr:(NSMutableArray *)array andIp:(NSString *)ip{
_dataMutableArr = array;
NSURL *uploadURL = [NSURL URLWithString:ip];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:uploadURL cachePolicy:0 timeoutInterval:60];
// 1> PUT方法
// PUT
// 1) 文件大小无限制
// 2) 可以覆盖文件
// POST
// 1) 通常有限制2M
// 2) 新建文件,不能重名
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
[request addValue:@"text/html" forHTTPHeaderField:@"Accept"];
for (int i = 0; i < array.count; i++) {
NSDate *nowdate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setDateFormat:@"MMddHHmmss"];
NSString *datestr = [formatter stringFromDate:nowdate];
ZRLog(@"datestr:%@", datestr);
NSString *identifier = @"from.hx";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:[self saveImage:array[i] WithName:[NSString stringWithFormat:@"%@.jpeg",datestr]]]];
[task resume];
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
NSString * htmlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
ZRLog(@"htmlstring:+++++++:%@", htmlString);
NSError *error = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData:data options:NSJSONReadingAllowFragments
error:&error];
if (jsonObject != nil && error == nil){
ZRLog(@"Successfully deserialized...");
//如果jsonObject是字典类
if ([jsonObject isKindOfClass:[NSDictionary class]]){
NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
NSLog(@"Dersialized JSON Dictionary = %@", deserializedDictionary);
}
//如果jsonObject是数组类
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
ZRLog(@"Dersialized JSON Array = %@", deserializedArray);
[self.mutableArr addObjectsFromArray:deserializedArray];
ZRLog(@"++++++++++dataMutableArr:%@", self.mutableArr);
// ZRLog(@"uuid:%@", deserializedArray[0][@"uuid"]);
} else {
NSLog(@"I can't deal with it");
}
}
else if (error != nil){
NSLog(@"An error happened while deserializing the JSON data.");
}else if ([data length] == 0 &&error == nil){
NSLog(@"No data was returned after serialization.");
}
else if (error != nil){
NSLog(@"An error happened = %@", error);
}
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
if (session.configuration.identifier) {
// 调用在 -application:handleEventsForBackgroundURLSession: 中保存的 handler
[self callCompletionHandlerForSession:session.configuration.identifier];
}
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if (error) {
// check if resume data are available
if ([error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]) {
NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData];
//通过之前保存的resumeData,获取断点的NSURLSessionTask,调用resume恢复下载
self.resumeData = resumeData;
}
} else {
_dataNum++;
if (_dataNum == _dataMutableArr.count) {
[self sendLocalNotification];
[self postDownlaodProgressNotification:@"1"];
}
}
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
//self.progressview.progress = totalBytesSent/(float)totalBytesExpectedToSend;
NSString *strProgress = [NSString stringWithFormat:@"%.2f",totalBytesSent/(float)totalBytesExpectedToSend];
[self postDownlaodProgressNotification:strProgress];
ZRLog(@"------------already sent:%lld",bytesSent);
ZRLog(@"------------totoal to send:%lld",totalBytesSent);
ZRLog(@"------------expected send:%lld",totalBytesExpectedToSend);
}
- (void)postDownlaodProgressNotification:(NSString *)strProgress {
NSDictionary *userInfo = @{@"progress":strProgress};
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kuploadProgressNotification object:nil userInfo:userInfo];
});
}
/**
* 保存图片
*/
-(NSString *)saveImage:(UIImage *)tempImage WithName:(NSString *)imageName{
NSData* imageData;
// //判断图片是不是png格式的文件
// if (UIImagePNGRepresentation(tempImage)) {
// //返回为png图像。
// imageData = UIImagePNGRepresentation(tempImage);
// }else {
// //返回为JPEG图像。
// imageData = UIImageJPEGRepresentation(tempImage, 1.0);
// }
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:imageName];
NSArray *nameAry=[fullPathToFile componentsSeparatedByString:@"/"];
ZRLog(@"===imageName========%@", imageName);
ZRLog(@"===fullPathToFile===%@",fullPathToFile);
ZRLog(@"===FileName===%@",[nameAry objectAtIndex:[nameAry count]-1]);
[[self gotDataImage:tempImage fileName:imageName] writeToFile:fullPathToFile atomically:NO];
return fullPathToFile;
}
- (NSData *)gotDataImage:(UIImage *)image fileName:(NSString *)filename{
NSMutableData *fileData = [NSMutableData data];
//5.1 文件参数
/*
--分隔符
Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
Content-Type: image/png(MIMEType:大类型/小类型)
空行
文件参数
*/
[fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
//name:file 服务器规定的参数
//filename:Snip20160225_341.png 文件保存到服务器上面的名称
//Content-Type:文件的类型
NSDate *nowdate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
[formatter setDateFormat:@"MMddHHmm"];
NSString *datestr = [formatter stringFromDate:nowdate];
[fileData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=tianmen %@; filename=%@", datestr, filename] dataUsingEncoding:NSUTF8StringEncoding]];
//[fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Sss.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:[@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding]];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
//UIImage --->NSData
NSData *imageData = UIImageJPEGRepresentation(image,0.5);
[fileData appendData:imageData];
[fileData appendData:KNewLine];
[fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
return fileData;
}
@end