cdts/xdts-ios 3/TreeHole/Code/Base/PYHTTPManager.m
2024-01-02 18:08:42 +08:00

510 lines
21 KiB
Objective-C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// PYHTTPManager.m
// Food
//
// Created by ko1o, on 2019/7/27.
// Copyright © 2019年 ko1o. All rights reserved.
//
#import <NSString+TUIUtil.h>
#import "PYHTTPManager.h"
#import "AFHTTPSessionManager.h"
//#import "PYAccountService.h"
//#import "PYLoginViewController.h"
//#import "PYNewLoginViewController.h"
#import <AliyunOSSiOS/OSSService.h>
#if IS_DEBUG
static NSString * const salt = @"FFAsdaAoXidicS";
#else
static NSString * const salt = @"sdfsaAoXidiZs";
#endif
const NSInteger kNoLoginCode = 100;
//static BOSClient *bosClient = nil;
//static NSString *bucketname = nil;
//static NSDictionary *typeConfigDic = nil;
static OSSClient *_aliOSSClient;
static NSString *_expirationTimeInGMTFormat;
static NSString *kBucketName = nil;
//static NSString *kAccessKeyId = @"LTAI4GJ3K5yB7xnatvAQdEi5";
//static NSString *kAccessKeySecret = @"6dbahs8GFIZQtslSbQZa6xn2R1pdOA";
//static NSString *kEndpoint = @"https://oss-cn-shenzhen.aliyuncs.com";
static NSString *kSSOCacheAvatarDir = @"avatar"; // 头像目录
static NSString *kSSOCacheAvatarBgDir = @"cover"; // 头像背景目录
static NSString *kSSOCacheReport = @"report"; // 举报
static NSString *kSSOCacheProfilePhoto = @"profile_photo"; // 照片墙
static NSString *kSSOCacheBottlePhoto = @"bottle_photo"; // 瓶子图片
static NSString *kSSOCacheBottleVoice = @"bottle_voice"; // 瓶子语音
static NSString *kSSOCacheiOSTestDir = @"iostest";
static dispatch_queue_t uploadQueue; // 上传队列
void runInMainThread(void(^action)(void)) {
dispatch_async(dispatch_get_main_queue(), action);
}
///网络状态改变通知Key
#define NotificationName_ReachabilityStatusChange @"TH_ReachabilityStatusChange"
@implementation PYHTTPManager
static AFHTTPSessionManager *_manager;
+ (void)load {
_manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:PYHttpBaseUrl]];
_manager.securityPolicy.allowInvalidCertificates =YES;
_manager.requestSerializer = [AFJSONRequestSerializer serializer];
// _manager.responseSerializer = [AFJSONResponseSerializer serializer];
_manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", nil];
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
//如果是需要验证自建证书需要设置为YES
[securityPolicy setAllowInvalidCertificates:NO];
[_manager setSecurityPolicy:securityPolicy];
uploadQueue = dispatch_queue_create("com.youth.uploadfile", DISPATCH_QUEUE_SERIAL);
// [self getSetupOSSClientWithCompletion:^(BOOL succeed) {
//
// }];
}
+ (void)showLoginPage
{
// UINavigationController *currectNav = [PYAppService currentNavigationController];
// if ([currectNav.viewControllers.firstObject isKindOfClass:[PYNewLoginViewController class]]) {
// return;
// }
// PYNavigationViewController *nav = [[PYNavigationViewController alloc] initWithRootViewController:[PYNewLoginViewController new]];
// 取消所有请求
[_manager.operationQueue cancelAllOperations];
// [[PYAppService currentViewController] presentViewController:nav animated:YES completion:nil];
}
+ (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block
{
[_manager.reachabilityManager startMonitoring];
[_manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
//发送网络状态修改通知, 可在全局调用一次就好
[NSNotificationCenter.defaultCenter postNotificationName:NotificationName_ReachabilityStatusChange object:nil userInfo:@{NotificationName_ReachabilityStatusChange : @(status)}];
//兼容旧代码
if (block) {
block(status);
}
}];
}
///监听网络状态改变通知
+ (void)addObserverForReachabilityStatusChange:(nullable void (^)(AFNetworkReachabilityStatus status))changeBlock {
[NSNotificationCenter.defaultCenter addObserverForName:NotificationName_ReachabilityStatusChange object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
if ([note.userInfo.allKeys containsObject:NotificationName_ReachabilityStatusChange]) {
NSNumber *statusNum = [note.userInfo objectForKey:NotificationName_ReachabilityStatusChange];
changeBlock(statusNum.integerValue);
}
}];
}
+ (BOOL)isNetReachable
{
return [_manager.reachabilityManager isReachable];
}
/// 直接显示后台返回的message 服务列表
+ (NSArray *)showRspMessageServerNames
{
return @[
@"activebm/",
@"userwsub/",
@"invoiceaddc/",
@"invoiceadd/"
];
}
+ (NSArray *)ignoreErrorMsg {
return @[@""];
}
+ (NSArray *)handleErrorCodeWithPath:(NSString *)path {
if ([path isEqualToString:@"learnroomdetail"]) {
return @[@(1200), @(1201), @(1202)];
}
return nil;
}
+ (NSError *)errorWithPath:(NSString *)path forCode:(int)code userInfo:(NSDictionary *)userInfo {
if ([[self handleErrorCodeWithPath:path] containsObject:@(code)]) {
return [NSError errorWithDomain:NSCocoaErrorDomain code:code userInfo:userInfo];
}
return nil;
}
+ (NSDictionary *)headers {
NSMutableDictionary *headersM = [NSMutableDictionary dictionary];
if ([LoginService token]) {
headersM[@"Authorization"] = [@"Bearer " stringByAppendingString:[LoginService token]];
}
return headersM;
}
+ (NSMutableDictionary *)commonParamsM {
NSMutableDictionary *commonParamsM = [NSMutableDictionary dictionary];
// * post请求的统一基础参数,内含:
// * device_brand: 手机厂商(系统 api 获取)
// * device_model: 手机型号(系统 api 获取)
// * app_version_name: 应用版本名3个数字4.1.12
// * app_version_code应用开发版本号客户端自己的 bundle id1/123
// * interface_version: 请求的接口版本号1.0
// * device_platform: 操作系统iOS / Android
UIDevice *device = [UIDevice currentDevice];
commonParamsM[@"device_brand"] = @"Apple";
commonParamsM[@"device_model"] = device.model ?: @"Unknown";
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];//获取app版本信息
commonParamsM[@"app_version_name"] = infoDictionary[@"CFBundleShortVersionString"] ?: @"Unknown";
NSInteger interVersionCode = (NSInteger)infoDictionary[@"CFBundleVersion"];
NSString *versionCodeStr = [NSString stringWithFormat:@"%lu",interVersionCode];
commonParamsM[@"app_version_code"] = versionCodeStr;
// commonParamsM[@"app_version_code"] = infoDictionary[@"CFBundleVersion"] ?: @"Unknown";
commonParamsM[@"interface_version"] = infoDictionary[@"CFBundleShortVersionString"] ?: @"Unknown";
commonParamsM[@"device_platform"] = @"iOS";
commonParamsM[@"os_version"] = [UIDevice currentDevice].systemVersion;
return commonParamsM;
}
+ (NSString *)generateSignWithParams:(NSDictionary *)params {
NSArray *sortedKeys = [params.allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return obj1 > obj2;
}];
NSMutableString *signStrM = [NSMutableString stringWithFormat:@"%@,", salt];
for (NSString *key in sortedKeys) {
NSString *value = params[key];
if (key && value) {
[signStrM appendFormat:@"%@:%@,", key, value];
}
}
[signStrM appendString:salt];
return [signStrM md5];
}
+ (void)handleRsp:(id)responseObject path:(NSString *)path callback:(PYHTTPManagerCallback)callback {
int code = [responseObject[@"code"] intValue];
// NSLog(@"code==%d",code);
//9999封号
if (code == 9998 || code == 9999) { // 接口认证失败APP需要重新登录
[SVProgressHUD dismiss];
[PYAppService logout];
return;
}
if (code == 10) { // 需要购买会员
[SVProgressHUD dismiss];
[PYAppService showVipAlertWithPath:path title:responseObject[@"title"] msg:responseObject[@"message"] source:nil];
return;
}
NSError *handleError = [self errorWithPath:path forCode:code userInfo:responseObject];
if (code != 0 && !handleError) {
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:code userInfo:responseObject];
if (![[self ignoreErrorMsg] containsObject:path]) {
if (![responseObject[@"message"] isEqualToString:@"auth header is empty"]) {
[SVProgressHUD showErrorWithStatus:responseObject[@"message"] ?: @"网络异常,请稍后再试~"];
}
}
if (callback) {
callback(nil, error);
}
return;
}
id result = responseObject[@"data"];
if ([result isKindOfClass:NSNull.class]) {
result = nil;
}
if (callback) {
callback(result, handleError);
}
}
+ (void)postWithPath:(NSString *)path params:(NSDictionary *)params callback:(PYHTTPManagerCallback)callback{
NSLog(@"path===%@,[self headers]%@",path,[self headers]);
NSMutableDictionary *args = [self commonParamsM];
NSLog(@"path===%@,[self headers]%@",path,[self headers]);
[args addEntriesFromDictionary:params];
args[@"sign"] = [self generateSignWithParams:args];
NSLog(@"params===%@",params);
[_manager POST:path parameters:args headers:[self headers] progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleRsp:responseObject path:path callback:callback];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (callback) {
if (error) {
[SVProgressHUD showErrorWithStatus:error.localizedDescription ?: @"网络异常,请稍后再试~"];
}
callback(nil, error);
}
}];
}
+ (void)getWithPath:(NSString *)path params:(NSDictionary *)params callback:(PYHTTPManagerCallback)callback {
NSMutableDictionary *args = [self commonParamsM];
[args addEntriesFromDictionary:params];
[_manager GET:path parameters:args headers:[self headers] progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleRsp:responseObject path:path callback:callback];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (error.code == kNoLoginCode) {
[self showLoginPage];
return ;
}
if (callback) {
if (error) {
[SVProgressHUD showErrorWithStatus:error.localizedDescription ?: @"网络异常,请稍后再试~"];
}
callback(nil, error);
}
}];
}
+ (void)post:(NSString *)url params:(NSDictionary *)params imageses:(NSArray<NSArray<UIImage *> *> *)imageses imageNames:(NSArray<NSString *> *)imageNames callback:(PYHTTPManagerCallback)callback
{
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:PYHttpBaseUrl]];
// [manager.requestSerializer setValue:@"multipart/form-data;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
NSMutableDictionary *args = [NSMutableDictionary dictionary];
[args addEntriesFromDictionary:params];
// NSLog(@"PYHttpBaseUrl===%@",PYHttpBaseUrl);
[manager POST:url
parameters:args
headers:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
for (int j = 0; j < imageses.count; j++) {
NSArray *images = imageses[j];
NSString *imageName = imageNames[j];
for (int i = 0 ;i < images.count; i++) {
UIImage *image = images[i];
NSData *data = UIImageJPEGRepresentation(image, 1.0);
[formData appendPartWithFileData:data name:imageName fileName:[NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID]UUIDString]] mimeType:@"image/jpeg"];
}
}
} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if ([responseObject[@"code"] integerValue] != 200) {
NSError *error = [NSError errorWithDomain:@"" code:[responseObject[@"code"] integerValue] userInfo:responseObject];
callback(nil, error);
[SVProgressHUD showErrorWithStatus:responseObject[@"message"]];
} else {
callback(responseObject[@"data"], nil);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[SVProgressHUD showErrorWithStatus:[error localizedDescription]];
callback(nil, error);
}];
}
+ (NSString *)subfixForScene:(AliOSSUploadScene)scene
{
switch (scene) {
case AliOSSUploadSceneAvatar:
case AliOSSUploadSceneAvatarBg:
case AliOSSUploadSceneReport:
case AliOSSUploadSceneiOSTest:
case AliOSSUploadSceneProfilePhoto:
case AliOSSUploadSceneBottlePhoto:
return @"jpg";
case AliOSSUploadSceneBottleVoice:
return @"m4a";
}
return @"jpg";
}
+ (NSString *)cachePathForScene:(AliOSSUploadScene)scene
{
switch (scene) {
case AliOSSUploadSceneAvatar :
return kSSOCacheAvatarDir;
case AliOSSUploadSceneAvatarBg:
return kSSOCacheAvatarBgDir;
case AliOSSUploadSceneReport:
return kSSOCacheReport;
case AliOSSUploadSceneProfilePhoto:
return kSSOCacheProfilePhoto;
case AliOSSUploadSceneBottlePhoto:
return kSSOCacheBottlePhoto;
case AliOSSUploadSceneBottleVoice:
return kSSOCacheBottleVoice;
}
return kSSOCacheiOSTestDir;
}
+ (void)getSetupOSSClientWithCompletion:(void(^)(BOOL succeed))completion {
[self postWithPath:@"ossauth" params:nil callback:^(id _Nullable rsp, NSError * _Nullable error) {
if (!error && rsp) {
id<OSSCredentialProvider> credential = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * {
// 您需要在此处实现获取一个FederationToken并构造成OSSFederationToken对象返回。
// 如果由于某种原因获取失败直接返回nil。
OSSFederationToken *token = [OSSFederationToken new];
// 从STS服务获取的临时访问密钥AccessKey ID和AccessKey Secret
token.tAccessKey = rsp[@"access_key_id"];
token.tSecretKey = rsp[@"access_key_secret"];
// 从STS服务获取的安全令牌SecurityToken
token.tToken = rsp[@"security_token"];
// 临时访问凭证的过期时间。
token.expirationTimeInGMTFormat = rsp[@"expiration"];
return token;
}];
_expirationTimeInGMTFormat = rsp[@"expiration"];
_aliOSSClient = [[OSSClient alloc] initWithEndpoint:rsp[@"end_point"] credentialProvider:credential];
kBucketName = rsp[@"bucket_name"] ?: @"xidi-official-website";
runInMainThread(^{
if (completion) {
completion(YES);
}
});
} else {
runInMainThread(^{
if (completion) {
completion(NO);
}
});
}
}];
}
+ (void)uploadFileWithScene:(AliOSSUploadScene)scene
data:(NSData *)data
completion:(PYHTTPManagerCallback)completion
{
dispatch_async(uploadQueue, ^{
@synchronized (self) {
BOOL needNewOssClient = YES;
if (_expirationTimeInGMTFormat != nil && _aliOSSClient != nil) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
//2022-06-06T10:01:27Z
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
NSDate *date = [dateFormatter dateFromString:_expirationTimeInGMTFormat];
if (date != nil && date.timeIntervalSinceNow > 60) {
needNewOssClient = NO;
}
}
if (needNewOssClient == YES || _aliOSSClient == nil) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self getSetupOSSClientWithCompletion:^(BOOL succeed) {
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
if (!_aliOSSClient) {
runInMainThread(^{
[SVProgressHUD showErrorWithStatus:@"上传失败"];
completion(nil, [NSError errorWithDomain:@"com.youth" code:-1 userInfo:nil]);
});
return;
}
}
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
put.bucketName = kBucketName;
NSString *userID = [LoginService tokenInfo][@"id"] ?: [NSString stringWithFormat:@"random_%d", arc4random()];
NSString *prefix = [NSString stringWithFormat:@"%@_%.0f", userID, [[NSDate date] timeIntervalSince1970] * 100000.0]; // 毫秒
NSString *fileName = [NSString stringWithFormat:@"%@.%@", prefix, [self subfixForScene:scene]];
//objectKey等同于objectName表示上传文件到OSS时需要指定包含文件后缀在内的完整路径例如abc/efg/123.jpg。
NSString *cacheDir = [self cachePathForScene:scene];
put.objectKey = [NSString stringWithFormat:@"%@/%@", cacheDir, fileName];
// 直接上传NSData。
put.uploadingData = data;
// put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
// NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
// };
// [SVProgressHUD showWithStatus:@"文件上传中..."];
OSSTask * putTask = [_aliOSSClient putObject:put];
[putTask continueWithBlock:^id(OSSTask *task) {
if (completion) {
if (!task.error) {
// [SVProgressHUD dismiss];
NSLog(@"upload object success!");
// sign public url
OSSTask *task = [_aliOSSClient presignPublicURLWithBucketName:kBucketName
withObjectKey:put.objectKey];
if (!task.error) {
runInMainThread(^{
completion(task.result, nil);
});
} else {
NSLog(@"sign url error: %@", task.error);
runInMainThread(^{
completion(nil, task.error);
[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"上传失败 sign %@", [task.error.userInfo objectForKey:@"message"]]];
});
}
} else {
NSLog(@"upload object failed, error: %@" , task.error);
runInMainThread(^{
completion(nil, task.error);
[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"上传失败%@", [task.error.userInfo objectForKey:@"message"]]];
});
}
}
return nil;
}];
});
}
+ (void)uploadFileWithScene:(AliOSSUploadScene)scene
datas:(NSArray<NSData *> *)datas
completion:(PYHTTPManagerCallback)completion
{
NSInteger totalTaskCount = datas.count;
__block NSInteger finishTaskCount = 0;
NSMutableArray *fileUrls = [NSMutableArray array];
for (NSData *data in datas) {
[self uploadFileWithScene:scene data:data completion:^(id _Nullable rsp, NSError * _Nullable error) {
@synchronized (self) {
finishTaskCount++;
if (rsp && !error && completion) {
[fileUrls addObject:rsp];
if (finishTaskCount >= totalTaskCount && fileUrls.count == finishTaskCount) {
// 排序
[fileUrls sortUsingComparator:^NSComparisonResult(NSString *url1, NSString *url2) {
return [url1 compare:url2];
}];
runInMainThread(^{
completion(fileUrls, nil);
});
}
}
if (error) {
runInMainThread(^{
completion(nil, error);
});
}
}
}];
usleep(10000); // 10毫秒
}
}
@end