文档
流程
Node
环境下生成上传地址- 客户端使用文件上传的方式向第一步生成的地址
PUT
方式上传文件
使用方式
- 需要先由服务单生成上传地址
[RKMediaUploader uploadImage:img toURLString:uploadUrl fileName:imgName progress:^(float progress) {
NSLog(@"minio-image-progress:%f",progress);
if (ybprogress) {
ybprogress(progress);
}
} completion:^(int code, NSString *key, NSString *msg) {
if (code == 0) {
NSLog(@"minio-image-:%d-%@-%@",code,key,msg);
NSString *linkKey = [NSString stringWithFormat:@"minio_%@",key];
complete(0,linkKey);
}else {
if (complete) {
complete(code,msg);
}
}
}];
客户端上传代码
RKMediaUploader.h
//
// RKMediaUploader.h
// YBLiveOne
//
// Created by yunbao02 on 2025/8/2.
// Copyright © 2025 iOS. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void(^UploadProgressBlock)(float progress);
//typedef void(^UploadCompletionBlock)(id response, NSError *error);
// code=0 成功
typedef void(^UploadCompletionBlock)(int code,NSString *key,NSString *msg);
@interface RKMediaUploader : NSObject
/**
上传图片
@param image 要上传的图片
@param urlString 上传接口URL
@param fileName 文件名
@param progress 进度回调
@param completion 完成回调
*/
+ (void)uploadImage:(UIImage *)image
toURLString:(NSString *)urlString
fileName:(NSString *)fileName
progress:(UploadProgressBlock)progress
completion:(UploadCompletionBlock)completion;
/**
上传视频/音频
@param filePath 视频/音频本地URL
@param urlString 上传接口URL
@param fileName 文件名
@param progress 进度回调
@param completion 完成回调
*/
+ (void)uploadVideoOrAudioWithFilePath:(NSString *)filePath
toURLString:(NSString *)urlString
fileName:(NSString *)fileName
progress:(UploadProgressBlock)progress
completion:(UploadCompletionBlock)completion;
@end
RKMediaUploader.m
//
// RKMediaUploader.m
// YBLiveOne
//
// Created by yunbao02 on 2025/8/2.
// Copyright © 2025 iOS. All rights reserved.
//
#import "RKMediaUploader.h"
#import "RKMediaUploaderDelegate.h"
@implementation RKMediaUploader
// 上传图片,适配PUT方法
+ (void)uploadImage:(UIImage *)image
toURLString:(NSString *)urlString
fileName:(NSString *)fileName
progress:(UploadProgressBlock)progress
completion:(UploadCompletionBlock)completion {
if (!image || !urlString.length || !fileName || !fileName.length) {
if (completion) {
// NSError *error = [NSError errorWithDomain:@"RKMediaUploader" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"图片或URL为空"}];
// completion(nil, error);
completion(-1,@"",@"图片、上传地址、文件名为空");
}
return;
}
// 处理图片数据,尝试JPEG和PNG两种格式
NSData *imageData = UIImagePNGRepresentation(image);
NSString *mimeType = @"image/png";
if (!imageData) {
imageData = UIImageJPEGRepresentation(image, 0.8);
mimeType = @"image/jpeg";
}
// 检查图片数据是否有效
if (!imageData) {
if (completion) {
// NSError *error = [NSError errorWithDomain:@"RKMediaUploader" code:-4 userInfo:@{NSLocalizedDescriptionKey:@"无法将图片转换为数据"}];
// completion(nil, error);
completion(-1,@"",@"无法将图片转换为数据");
}
return;
}
[self uploadFileData:imageData
fileName:fileName
mimeType:mimeType
urlString:urlString
parameters:nil
progress:progress
completion:completion];
}
// 上传视频,适配PUT方法
+ (void)uploadVideoOrAudioWithFilePath:(NSString *)filePath
toURLString:(NSString *)urlString
fileName:(NSString *)fileName
progress:(UploadProgressBlock)progress
completion:(UploadCompletionBlock)completion {
if (!filePath || !filePath.length || !urlString.length || !fileName || !fileName.length) {
if (completion) {
// NSError *error = [NSError errorWithDomain:@"RKMediaUploader" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"视频URL或上传URL为空"}];
// completion(nil, error);
completion(-1,@"",@"视频/音频文件、上传地址、文件名为空");
}
return;
}
// 读取视频数据
// NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
NSData *videoData = [NSData dataWithContentsOfFile:filePath];
if (!videoData) {
if (completion) {
// NSError *error = [NSError errorWithDomain:@"RKMediaUploader" code:-2 userInfo:@{NSLocalizedDescriptionKey:@"无法读取视频文件"}];
// completion(nil, error);
completion(-1,@"",@"无法读取视频/音频文件");
}
return;
}
// 类型
NSString *mineType = @"video/mp4";
if ([filePath hasSuffix:@".m4a"]) {
mineType = @"audio/x-m4a";
}else if ([filePath hasSuffix:@".wav"]){
mineType = @"audio/wav";
}else if ([filePath hasSuffix:@".mp3"]){
mineType = @"audio/mpeg";
}
[self uploadFileData:videoData
fileName:fileName
mimeType:mineType
urlString:urlString
parameters:nil
progress:progress
completion:completion];
}
// 通用文件上传方法,适配PUT
+ (void)uploadFileData:(NSData *)fileData
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType
urlString:(NSString *)urlString
parameters:(NSDictionary *)parameters
progress:(UploadProgressBlock)progress
completion:(UploadCompletionBlock)completion {
NSURL *url = [NSURL URLWithString:urlString];
if (!url) {
if (completion) {
// NSError *error = [NSError errorWithDomain:@"RKMediaUploader" code:-3 userInfo:@{NSLocalizedDescriptionKey:@"URL格式不正确"}];
// completion(nil, error);
completion(-1,@"",@"上传地址格式不正确");
}
return;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"PUT"; // 使用PUT方法
// 设置正确的Content-Type,直接使用文件的MIME类型
[request setValue:mimeType forHTTPHeaderField:@"Content-Type"];
// 如果需要传递文件名,可以通过自定义头字段
if (fileName) {
[request setValue:fileName forHTTPHeaderField:@"X-Filename"];
}
// 对于PUT方法,直接使用文件数据作为请求体,不需要multipart包装
NSData *httpBody = fileData;
// 创建会话配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 创建代理对象并设置回调
RKMediaUploaderDelegate *delegate = [[RKMediaUploaderDelegate alloc] init];
delegate.fileName = fileName;
delegate.progressBlock = progress;
delegate.completionBlock = completion;
delegate.responseData = [NSMutableData data];
// 创建会话,使用自定义代理
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
delegate:delegate
delegateQueue:[NSOperationQueue mainQueue]];
// 创建上传任务
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:httpBody];
// 强引用代理,防止被提前释放
delegate.task = uploadTask;
// 开始任务
[uploadTask resume];
}
@end
RKMediaUploaderDelegate.h
//
// RKMediaUploaderDelegate.h
// YBLiveOne
//
// Created by yunbao02 on 2025/8/2.
// Copyright © 2025 iOS. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RKMediaUploader.h"
@interface RKMediaUploaderDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
@property(nonatomic,strong)NSString *fileName;
@property (nonatomic, copy) UploadProgressBlock progressBlock;
@property (nonatomic, copy) UploadCompletionBlock completionBlock;
@property (nonatomic, strong) NSMutableData *responseData;
@property (nonatomic, strong) NSURLSessionTask *task;
@end
RKMediaUploaderDelegate.m
//
// RKMediaUploaderDelegate.m
// YBLiveOne
//
// Created by yunbao02 on 2025/8/2.
// Copyright © 2025 iOS. All rights reserved.
//
#import "RKMediaUploaderDelegate.h"
@implementation RKMediaUploaderDelegate
#pragma mark - NSURLSessionTaskDelegate
// 上传进度回调
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
if (self.progressBlock && totalBytesExpectedToSend > 0) {
float progress = (float)totalBytesSent / totalBytesExpectedToSend;
self.progressBlock(progress);
}
}
// 任务完成回调
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (self.completionBlock) {
if (error) {
// self.completionBlock(nil, error);
self.completionBlock(-1,@"",[NSString stringWithFormat:@"%@",error]);
} else if (self.responseData.length > 0) {
// 尝试解析JSON
id responseObject = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:nil];
if (!responseObject) {
// 解析失败则返回字符串
responseObject = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
}
// self.completionBlock(responseObject, nil);
self.completionBlock(0,_fileName,@"上传成功");
} else {
// self.completionBlock(nil, nil);
self.completionBlock(0,_fileName,@"上传成功");
}
}
// 清理引用
self.fileName = nil;
self.task = nil;
self.progressBlock = nil;
self.completionBlock = nil;
}
#pragma mark - NSURLSessionDataDelegate
// 接收响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
// 允许处理响应数据
completionHandler(NSURLSessionResponseAllow);
}
// 接收数据
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
@end