iOS文件上传功能

iOS文件上传功能

									Morris_
									2019.05.14

demo下载

搭建本地php环境

在本地搭建一个php服务,在iOS端进行图片、文件等上传测试。

一、搭建服务

常用命令

查看本地php版本
php - v

在本机上开一个服务,并且指定工作目录。局域网内用户都可访问。
php -S 0.0.0.0:9999 -t /Users/Document/php/

监听该服务
Listening on http://0.0.0.0:9999

开启服务
php -S 0.0.0.0:9999 -t /Users/Document/php/

//关闭服务
Ctrl + c

搭建一个本地的php服务

1、搭建php环境

php - v 查看php环境版本,我是下载了个软件,在电脑上默认装了php环境,具体怎么装还得看专业的。

2、本地新建一个php工作文件夹

我在/Users/xxx/Documents/php/下创建了文件夹upload,则工作空间是在/Users/xxx/Documents/php/upload/下。

3、在upload文件夹下创建一个文件,改名字为upload_file.php保存

即创建一个php文件,在文件中写如下php代码

<?php

ini_set('memory_limit',0);
ini_set('post_max_size','1024G');
ini_set('upload_max_filesize','1000G');
set_time_limit(0);

move_uploaded_file($_FILES["file"]["tmp_name"],"/Users/xxx/Documents/php/upload/".$_FILES["file"]["name"]);
exit(json_encode([
    "status"=>200
]));

设置上传文件大小限制。

move_uploaded_file()这个方法是下载文件,并将文件move操作。

上传上来的文件是uploaded,会到电脑的/tmp目录下,move操作将其转移到upload目录下。上传的文件首先是会短暂的存储到电脑的/tmp文件中,如果不做处理,生命周期结束后,/tmp中文件将被删除。

上传成功后有个返回码200。

4、开启服务

终端中进入工作目录upload文件下:cd /Users/xxx/Documents/php/upload

开启服务并指定当前服务的工作区间:php -S 0.0.0.0:9999 -t /Users/xxx/Documents/php/upload/

完成

然后就OK了,局域网内的用户都可访问,域名是本地ip+/upload.php: http://172.16.11.223:9999/upload.php

二、上传文件

选取手机相册里的图片、拍照、选取iCloud里面的文件,进行上传。

基础知识

先看一些基础知识。

  • 打开相册

先在plist文件中添加相册使用权限申请的key和value。

- (IBAction)photoABtnClick:(UIButton *)sender {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    //如果需要编辑图片,建议sourceType选择UIImagePickerControllerSourceTypeSavedPhotosAlbum,如果不需要,可选择UIImagePickerControllerSourceTypePhotoLibrary。
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}
  • 打开相机

先在plist文件中添加相机使用权限申请的key和value。

- (IBAction)cameraBtnClick:(UIButton *)sender {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}
  • 打开iCloud
- (IBAction)iCloudBtnClick:(UIButton *)sender {
    if (![DocUploadViewController ICloudEnable]) {
        NSLog(@"iCloud没有开启");
        return;
    }
    NSArray *documentTypes = @[@"public.content",
                               @"public.text",
                               @"public.source-code",
                               @"public.image",
                               @"public.jpeg",
                               @"public.png",
                               @"com.adobe.pdf",
                               @"com.apple.keynote.key",
                               @"com.microsoft.word.doc",
                               @"com.microsoft.excel.xls",
                               @"com.microsoft.powerpoint.ppt"];
    UIDocumentPickerViewController *picker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:documentTypes inMode:UIDocumentPickerModeOpen];
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}

使用iCloud前先判断是否有权限:

+ (BOOL)ICloudEnable {
    NSURL *url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    return url != nil;
}

UIImagePickerController和UIDocumentPickerViewController是系统的UIKit框架下的两个类。在使用iCloud前需要先打开App的iCloud使用权限,请阅读 Enabling CloudKit in Your App

  • 压缩图片的方法
UIImageJPEGRepresentation(image, 0.8)
  • 获取相册回调返回的图片URL
 NSURL *url = nil;
 if (@available(iOS 11.0, *)) {
     url = info[UIImagePickerControllerImageURL];
 } else {
     url = info[UIImagePickerControllerReferenceURL];
 }
  • 获取选择相册/拍照的照片
 //获取经过编辑后的图片
 UIImage *image = info[UIImagePickerControllerEditedImage];
 if (!image) {
 //如果未编辑,取原图
 image = info[UIImagePickerControllerOriginalImage];
 }
  • 将图片保存到相册
 //保存到相册
 [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    [PHAssetChangeRequest creationRequestForAssetFromImage:iamge];
 } completionHandler:^(BOOL success, NSError * _Nullable error) {
 
 }];

PHPhotoLibrary是系统的Photos框架下的一个类,使用需引头文件#import <Photos/Photos.h>。

performChanges相当于打开相册,PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];是将图片写入相册,通过request.placeholderForCreatedAsset.localIdentifier可读取写入后的文件id。

  • 获取相册图片信息
 //获取图片信息
 PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[locolId] options:nil];
 PHAsset *asset = [result firstObject];
 [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
 
    NSLog(@"==>%@",info);
 
 }];

这里的locolId就是保存在相册里的文件identifier。

  • 读取iCoud文件信息
	 //创建doc
    WeCDocument *document = [[WeCDocument alloc] initWithFileURL:documentsURL];
    
    //打开doc
    [document openWithCompletionHandler:^(BOOL success) {
        if (success)
        {
        
        }
        else
        {
        
        }
        //关闭doc
        [document closeWithCompletionHandler:^(BOOL success) {
            
        }];
    }];

由于CompletionHandler这个block里对document持有一份引用,多以document对象不会被直接释放掉,等回调过来后需要关闭doc,document对象才会被释放。

这里ICDocument是继承UIDocument的类,实现如下:

@interface WeCDocument : UIDocument

@property (nonatomic, strong, nullable) NSData *data;
//文件名
@property (nonatomic, copy, nullable) NSString *fileName;
//文件类型
@property (nonatomic, copy, nullable) NSString *MIMEType;

@end

@implementation WeCDocument

- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError * _Nullable __autoreleasing *)outError
{
    //.page等文件会闪退
    if ([contents isKindOfClass:[NSData class]])
    {
        self.data = [contents copy];
        self.fileName = self.fileURL.lastPathComponent;
        if (self.fileName && self.fileName.length) {
            NSRange startRange = [self.fileName rangeOfString:@"."];
            self.MIMEType = [self.fileName substringFromIndex:startRange.location];
        }
    }
    else {
        NSLog(@"读取文件出错!");
        return NO;
    }
    return YES;
}

@end

这里通过documentURL去获取的文件名和类型。

信息回调

  • UIImagePickerControllerDelegate

选择相册文件或者拍照后,回调方法:

//selected
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //此处需要先dismiss掉picker,然后再present出alert,佛否则alert显示不出,bug
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    //获取经过编辑后的图片
    UIImage *image = info[UIImagePickerControllerEditedImage];
    if (!image) {
        //如果未编辑,取原图
        image = info[UIImagePickerControllerOriginalImage];
    }
    
    if (picker.sourceType == UIImagePickerControllerSourceTypeSavedPhotosAlbum)
    {
        NSURL *url = nil;
        if (@available(iOS 11.0, *)) {
            url = info[UIImagePickerControllerImageURL];
        } else {
            url = info[UIImagePickerControllerReferenceURL];
        }
        [self selectedImage:image url:url reName:nil];
    }
    else if (picker.sourceType == UIImagePickerControllerSourceTypeCamera)
    {
        __block NSString *locolId = nil;
        
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            //保存到相册
            PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
            locolId = request.placeholderForCreatedAsset.localIdentifier;
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (error == nil) {
                //获取图片信息
                PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[locolId] options:nil];
                PHAsset *asset = [result firstObject];
                [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                    
                    NSURL *url = info[@"PHImageFileURLKey"];
                    [self selectedImage:image url:url reName:nil];
                }];
            }
            else {
                NSLog(@"图片保存失败!");
            }
        }];
    }
}
//cancel
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissViewControllerAnimated:YES completion:nil];
}
  • UIDocumentPickerDelegate
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls
{
    [self selectedDocumentAtURLs:urls reName:nil];
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url
{
    [self selectedDocumentAtURLs:@[url] reName:nil];
}

iCloud选取文件后,会返回一个documentURL,即文件路径的URL。

上传

起初我想都通过传入url,读取文件,然后上传,后来发现了问题:NSURL有个属性isFileURL,iCloud获取的文件返回的documentURL的isFileURL是YES,这说明从iCloud获取的documentURL是文件URL。但是从相册或者拍照得到的文件的url并非是文件路径,它的isFileURL是NO。从documentURL里获取文件信息可以通过系统提供的类UIDocument来获取,但是相册和拍照的url不是文件url,使用UIDocument直接闪退,闪退信息:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'must pass a valid file URL to -[UIDocument initWithFileURL:]'

看来获取文件信息,相册/拍照和iCloud是不同的。

后来分别提供了两个方法,一个上传图片,一个上传iCloud文件。

/**
 *  iCloud文件上传
 *  documentsURL 文件地址;rename 文件重命名,文件名不需带文件类型后缀
 */
+ (void)uploadICloudFileWithUrl:(NSURL *)documentsURL
                         reName:(nullable NSString *)rename
                       progress:(nullable void (^)(NSProgress * progress))uploadProgress
                         sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
                        failure:(void(^)(NSError *error))uploadFailure;

/**
 图片上传,相册、拍照文件上传。
 url为referenceURL,相册UIImagePickerControllerReferenceURL,拍照PHImageFileURLKey,可为空,为空时不会上传源文件名称。
 rename,通过此值修改上传文件名称,文件名不需带文件类型后缀。
 */
+ (void)uploadImage:(UIImage *)image
       referenceURL:(nullable NSURL *)url
             reName:(nullable NSString *)rename
           progress:(nullable void (^)(NSProgress * progress))uploadProgress
             sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
            failure:(void(^)(NSError *error))uploadFailure;

这块代码比较多,直接看demo吧,调试demo前先自己搭建好本地的php服务,修改请求地址,然后可以上传图片到本地服务。

完整代码

WeUpload.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface WeUpload : NSObject

/**
 *  iCloud文件上传
 *  documentsURL 文件地址;rename 文件重命名,文件名不需带文件类型后缀
 */
+ (void)uploadICloudFileWithUrl:(NSURL *)documentsURL
                         reName:(nullable NSString *)rename
                       progress:(nullable void (^)(NSProgress * progress))uploadProgress
                         sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
                        failure:(void(^)(NSError *error))uploadFailure;

/**
 图片上传,相册、拍照文件上传。
 url为referenceURL,相册UIImagePickerControllerReferenceURL,拍照PHImageFileURLKey,可为空,为空时不会上传源文件名称。
 rename,通过此值修改上传文件名称,文件名不需带文件类型后缀。
 */
+ (void)uploadImage:(UIImage *)image
       referenceURL:(nullable NSURL *)url
             reName:(nullable NSString *)rename
           progress:(nullable void (^)(NSProgress * progress))uploadProgress
             sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
            failure:(void(^)(NSError *error))uploadFailure;

@end

NS_ASSUME_NONNULL_END

WeUpload.m

#import "WeUpload.h"
#import <Photos/Photos.h>
#import "AFHTTPSessionManager.h"

AFHTTPSessionManager *_manager = nil;

///iCloud文件上传使用
@interface WeDocument : UIDocument

@property (nonatomic, strong, nullable) NSData *data;
//文件名
@property (nonatomic, copy, nullable) NSString *fileName;
//文件类型
@property (nonatomic, copy, nullable) NSString *MIMEType;
//文件大小
@property (nonatomic, assign) NSUInteger length;

@end

@implementation WeDocument

- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError * _Nullable __autoreleasing *)outError
{
    //目前不支持.page
    if ([contents isKindOfClass:[NSData class]])
    {
        self.data = [contents copy];
        self.fileName = self.fileURL.lastPathComponent;
        if (self.fileName && self.fileName.length) {
            NSRange startRange = [self.fileName rangeOfString:@"."];
            self.MIMEType = [self.fileName substringFromIndex:startRange.location];
        }
        self.length = self.data.length;
    }
    else {
        NSLog(@"读取文件出错!");
        return NO;
    }
    return YES;
}

@end



@implementation WeUpload

/**
 *  iCloud文件上传
 *  documentsURL 文件地址;rename 文件重命名,文件名不需带文件类型后缀
 */
+ (void)uploadICloudFileWithUrl:(NSURL *)documentsURL
                         reName:(nullable NSString *)rename
                       progress:(nullable void (^)(NSProgress * progress))uploadProgress
                         sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
                        failure:(void(^)(NSError *error))uploadFailure
{
    if (!documentsURL.isFileURL) {
        [self onError:[NSError errorWithDomain:@"URL error , is not file url" code:-1 userInfo:nil] errorBlock:uploadFailure];
        return;
    }
    
    WeDocument *document = [[WeDocument alloc] initWithFileURL:documentsURL];
    
    //打开文件
    [document openWithCompletionHandler:^(BOOL success) {
        if (success)
        {
            //文件重命名
            if (rename && rename.length>0) {
                //server端从文件名中获取后缀,进行文档转化,因此文件名需要包含文件类型后缀
                document.fileName = [rename stringByAppendingString:document.MIMEType];
            }
            
            //上传
            [WeUpload uploadWithFileData:document.data fileName:document.fileName fileType:document.MIMEType progress:^(NSProgress *progress) {
                [WeUpload progress:progress progressBlock:uploadProgress];
            } success:^(NSDictionary *responseObject) {
                [WeUpload onSucess:responseObject sucessBlock:uploadSuccess];
            } failure:^(NSError *error) {
                [WeUpload onError:error errorBlock:uploadFailure];
            }];
        }
        else
        {
            [WeUpload onError:[NSError errorWithDomain:@"文件读取失败" code:-1 userInfo:nil] errorBlock:uploadFailure];
        }
        [document closeWithCompletionHandler:^(BOOL success) {
            
        }];
    }];
}

/**
 图片上传,相册、拍照文件上传。
 url为referenceURL,相册UIImagePickerControllerReferenceURL,拍照PHImageFileURLKey,可为空,为空时不会上传源文件名称。
 rename,通过此值修改上传文件名称,文件名不需带文件类型后缀。
 */
+ (void)uploadImage:(UIImage *)image
       referenceURL:(nullable NSURL *)url
             reName:(nullable NSString *)rename
           progress:(nullable void (^)(NSProgress * progress))uploadProgress
             sucess:(void(^)(NSDictionary *responseObject))uploadSuccess
            failure:(void(^)(NSError *error))uploadFailure
{
    if (!image) {
        [self onError:[NSError errorWithDomain:@"文件为空!" code:10020 userInfo:nil] errorBlock:uploadFailure];
        return;
    }
    if (![image isKindOfClass:[UIImage class]]) {
        [self onError:[NSError errorWithDomain:@"文件格式不支持!" code:40010 userInfo:nil] errorBlock:uploadFailure];
        return;
    }
    
    //文件
    NSData *data = UIImageJPEGRepresentation(image, 0.8);
    
    //相册资源
    __block NSURL *FileURL = url;
    if ([url.absoluteString containsString:@"assets-library"])
    {
        //读取文件信息
        PHFetchResult*result = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
        PHAsset *asset = [result firstObject];
        PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
        [[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
            
            FileURL = info[@"PHImageFileURLKey"];
            
            //默认类型png
            NSString *mimeType = @".png";
            //默认名称
            NSString *fileName = [FileURL lastPathComponent];
            //MIMEType
            if (fileName && fileName.length) {
                NSRange startRange = [fileName rangeOfString:@"."];
                mimeType = [fileName substringFromIndex:startRange.location];
            }
            //重命名
            if (rename && rename.length>0) {
                //server端从文件名中获取后缀,进行文档转化,因此文件名需要包含文件类型后缀
                fileName = [rename stringByAppendingString:mimeType];
            }
            //上传
            [WeUpload uploadWithFileData:data fileName:fileName fileType:mimeType progress:^(NSProgress *progress) {
                [WeUpload progress:progress progressBlock:uploadProgress];
            } success:^(NSDictionary *responseObject) {
                [WeUpload onSucess:responseObject sucessBlock:uploadSuccess];
            } failure:^(NSError *error) {
                [WeUpload onError:error errorBlock:uploadFailure];
            }];
        }];
    }
    //拍照资源文件/其他
    else
    {
        //默认类型png
        NSString *mimeType = @".png";
        //默认名称
        NSString *fileName = [FileURL lastPathComponent];
        //MIMEType
        if (fileName && fileName.length) {
            NSRange startRange = [fileName rangeOfString:@"."];
            mimeType = [fileName substringFromIndex:startRange.location];
        }
        //重命名
        if (rename && rename.length>0) {
            //server端从文件名中获取后缀,进行文档转化,因此文件名需要包含文件类型后缀
            fileName = [rename stringByAppendingString:mimeType];
        }
        //上传
        [WeUpload uploadWithFileData:data fileName:fileName fileType:mimeType progress:^(NSProgress *progress) {
            [WeUpload progress:progress progressBlock:uploadProgress];
        } success:^(NSDictionary *responseObject) {
            [WeUpload onSucess:responseObject sucessBlock:uploadSuccess];
        } failure:^(NSError *error) {
            [WeUpload onError:error errorBlock:uploadFailure];
        }];
    }
}


#pragma mark - 回调
+ (void)onError:(NSError *)error errorBlock:(void(^)(NSError *error))uploadFailure {
    if (uploadFailure) {
        uploadFailure(error);
    }
}
+ (void)onSucess:(NSDictionary *)response sucessBlock:(void(^)(NSDictionary *responseObject))uploadSuccess {
    if (uploadSuccess) {
        uploadSuccess(response);
    }
}
+ (void)progress:(NSProgress *)progress progressBlock:(nullable void (^)(NSProgress * progress))uploadProgress {
    if (uploadProgress) {
        uploadProgress(progress);
    }
}


#pragma mark - 上传
+ (void)uploadWithFileData:(NSData *)data fileName:(nullable NSString *)name fileType:(NSString *)type progress:(nullable void (^)(NSProgress * progress))WeUploadProgress success:(void(^)(NSDictionary *responseObject))success failure:(void(^)(NSError *error))failure
{
    //文件类型获取失败,return,否则会闪退
    if (!type || type.length <= 0) {
        if (failure) {
            failure([NSError errorWithDomain:@"文件类型获取失败!" code:-1 userInfo:nil]);
        }
        return;
    }
    //如无文件名,生成时间戳作为文件名
    if (!name || name.length <= 0) {
        name = [NSString stringWithFormat:@"%f%@",[[NSDate date] timeIntervalSince1970],type];
    }
    
    if (!_manager) {
        _manager = [AFHTTPSessionManager manager];
        _manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
        _manager.securityPolicy.allowInvalidCertificates = YES;
        [_manager.securityPolicy setValidatesDomainName:NO];
        _manager.responseSerializer = [[AFHTTPResponseSerializer alloc] init];
        _manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"application/json", @"text/json",@"text/plain", nil];
    }
    
    NSURLSessionDataTask *task = [[AFHTTPSessionManager manager] POST:@"http://172.16.11.223:9999/upload_file.php" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        //这里的file需要和server保持一致
        [formData appendPartWithFileData:data name:@"file" fileName:name mimeType:type];
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (WeUploadProgress) {
            WeUploadProgress(uploadProgress);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if ([responseObject[@"code"] integerValue] == 200) {
            if (success) {
                success(responseObject);
            }
        }
        else {
            if (failure) {
                failure([NSError errorWithDomain:responseObject[@"msg"] code:[responseObject[@"code"] integerValue] userInfo:nil]);
            }
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
    [task resume];
}

@end

ViewController.m

#import "ViewController.h"
#import <Photos/Photos.h>
#import "MBProgressHUD.h"
#import "WeUpload.h"

@interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate,UIDocumentPickerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
}
//拍照上传
- (IBAction)cameraBtnClick:(UIButton *)sender {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}

//相册
- (IBAction)photoAButtonAction:(UIButton *)sender {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    //如果需要编辑图片,建议sourceType选择UIImagePickerControllerSourceTypeSavedPhotosAlbum,如果不需要,可选择UIImagePickerControllerSourceTypePhotoLibrary。
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}
//ICloud
- (IBAction)iCloudButtonAction:(UIButton *)sender {
    if (![ViewController ICloudEnable]) {
        NSLog(@"ICloud没有开启");
        return;
    }
    NSArray *documentTypes = @[@"public.content",
                               @"public.text",
                               @"public.source-code",
                               @"public.image",
                               @"public.jpeg",
                               @"public.png",
                               @"com.adobe.pdf",
                               @"com.apple.keynote.key",
                               @"com.microsoft.word.doc",
                               @"com.microsoft.excel.xls",
                               @"com.microsoft.powerpoint.ppt"];
    UIDocumentPickerViewController *picker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:documentTypes inMode:UIDocumentPickerModeOpen];
    picker.delegate = self;
    [self presentViewController:picker animated:YES completion:nil];
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}

#pragma mark - UIImagePickerControllerDelegate
//selected
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //此处需要先dismiss掉picker,然后再present出alert,佛否则alert显示会出bug
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    //获取经过编辑后的图片
    UIImage *image = info[UIImagePickerControllerEditedImage];
    if (!image) {
        //如果未编辑,取原图
        image = info[UIImagePickerControllerOriginalImage];
    }
    
    if (picker.sourceType == UIImagePickerControllerSourceTypeSavedPhotosAlbum)
    {
        NSURL *url = nil;
        if (@available(iOS 11.0, *)) {
            url = info[UIImagePickerControllerImageURL];
        } else {
            url = info[UIImagePickerControllerReferenceURL];
        }
        [self selectedImage:image url:url reName:nil];
    }
    else if (picker.sourceType == UIImagePickerControllerSourceTypeCamera)
    {
        __block NSString *locolId = nil;
        
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            //保存到相册
            PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
            locolId = request.placeholderForCreatedAsset.localIdentifier;
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (error == nil) {
                //获取图片信息
                PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[locolId] options:nil];
                PHAsset *asset = [result firstObject];
                [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                    
                    NSURL *url = info[@"PHImageFileURLKey"];
                    [self selectedImage:image url:url reName:nil];
                }];
            }
            else {
                NSLog(@"图片保存失败!");
            }
        }];
    }
}
//cancel
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissViewControllerAnimated:YES completion:nil];
}


#pragma mark - UIDocumentPickerDelegate
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls
{
    [self selectedDocumentAtURLs:urls reName:nil];
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
    [controller dismissViewControllerAnimated:YES completion:nil];
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url
{
    [self selectedDocumentAtURLs:@[url] reName:nil];
}

#pragma mark - NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    CGFloat progress = totalBytesSent * 1.0 / totalBytesExpectedToSend;
    NSLog(@"上传进度:%f%%",progress*100);
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"上传完成! Error:%@",error);
}

#pragma mark - private
#pragma mark - private
+ (BOOL)ICloudEnable {
    NSURL *url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    return url != nil;
}
//相册/拍照文件上传
- (void)selectedImage:(UIImage *)image url:(NSURL *)url reName:(NSString *)name
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"是否上传此文档?" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
        hud.mode = MBProgressHUDModeCustomView;
        hud.label.text = @"努力上传中...";
        UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
        progressView.progressTintColor = [UIColor redColor];
        progressView.trackTintColor = [UIColor redColor];
        hud.customView = progressView;
        
        [WeUpload uploadImage:image referenceURL:url reName:name progress:^(NSProgress * _Nonnull progress) {
            hud.progress  = progress.completedUnitCount * 1.0 / progress.totalUnitCount;
            NSLog(@"progress:%f",hud.progress);
        } sucess:^(NSDictionary * _Nonnull responseObject) {
            NSLog(@"responseObject:%@",responseObject);
            [MBProgressHUD hideHUDForView:self.view animated:NO];
        } failure:^(NSError * _Nonnull error) {
            [MBProgressHUD hideHUDForView:self.view animated:NO];
            NSLog(@"上传失败!%@",error);
        }];
    }];
    [alert addAction:cancel];
    [alert addAction:action];
    [self presentViewController:alert animated:NO completion:nil];
}
//iCloud文件上传
- (void)selectedDocumentAtURLs:(NSArray <NSURL *>*)urls reName:(NSString *)rename
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"是否上传此文档?" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    
    UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
        for (NSURL *url in urls) {
            MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
            hud.mode = MBProgressHUDModeCustomView;
            hud.label.text = @"努力上传中...";
            UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
            progressView.progressTintColor = [UIColor redColor];
            progressView.trackTintColor = [UIColor whiteColor];
            hud.customView = progressView;
            
            [WeUpload uploadICloudFileWithUrl:url reName:rename progress:^(NSProgress * _Nonnull progress) {
                hud.progress  = progress.completedUnitCount / (1.0 * progress.totalUnitCount);
                NSLog(@"progress:%f",hud.progress);
            } sucess:^(NSDictionary * _Nonnull responseObject) {
                [MBProgressHUD hideHUDForView:self.view animated:NO];
            } failure:^(NSError * _Nonnull error) {
                [MBProgressHUD hideHUDForView:self.view animated:NO];
                NSLog(@"上传失败!%@",error);
            }];
        }
    }];
    [alert addAction:cancel];
    [alert addAction:action];
    [self presentViewController:alert animated:NO completion:nil];
}

@end

疑问

  • 网上有关获取文件的MIMEType方法
-(NSString *)getMIMETypeURLRequestAtPath:(NSURL *)path
{
    NSURL *url = path;//[NSURL fileURLWithPath:path];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSHTTPURLResponse *response = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    NSString *mimeType = response.MIMEType;
    return mimeType;
}

我很纳闷,这个是个异步的怎么去获取MIMEType,难道是等获取到MIMEType在做其他操作吗?

人云亦云?或者说我不知道怎么使用?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值