iOS文件上传功能
Morris_
2019.05.14
搭建本地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在做其他操作吗?
人云亦云?或者说我不知道怎么使用?