// // SPSBNetworkManager.m // 我的社保 // // Created by shanp on 2021/4/20. // #import "SPSBNetworkManager.h" #import #import #import #import "SPSBConstantProfile.h" #import "SPSBKeyProfile.h" #import "SPSBEnumerationProfile.h" #import "SPSBBusinessManager.h" #import #import "SPSBNotificationDelegateManager.h" #import static const NSInteger SPSBTimeOutMinute = 60; const NSInteger SPSBNetworkCallbackSuccessCode = 200; const NSInteger SPSBNetworkCallbackNeedLogin = 10004; const NSInteger SPSBNetworkCallbackKeyInvalid = 601; typedef void(^SPSBNetworkSuccessBlock)(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject); typedef void(^SPSBNetworkFailureBlock)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error); @interface SPSBUrlDicValue : NSObject @property (nonatomic, strong) SPSBNetworkManagerCallbackBlock spsb_callbackBlock; @property (nonatomic, strong, nullable) NSURLSessionTask *spsb_task; @end @implementation SPSBUrlDicValue @end @interface SPSBNetworkManager () { AFHTTPSessionManager *_manager; NSInteger _timeOut;//超时标识 bool _isLogin;//60秒循环时判断是否已经登录成功,发起请求是不用做判断 NSMutableDictionary *_urlDic;//判断重复请求 } @end @implementation SPSBNetworkManager - (instancetype)init { self = [super init]; if (!self) return nil; _manager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; _timeOut = 0; _isLogin = false; NSString *sysVersion = [[UIDevice currentDevice] systemVersion]; [_manager.requestSerializer setValue:[NSString stringWithFormat:@"iOS%@#%ld", sysVersion, (long)SPSBCurrentVersion] forHTTPHeaderField:@"User-Agent"]; spsb_setNotificationKey(SPSBLoggingNotificationKey); _urlDic = NSMutableDictionary.new; return self; } - (void)dealloc { spsb_removeNotificationKey(SPSBLoggingNotificationKey); } - (void)networkUseMethod:(SPSBNetworkMethod)method isLogin:(bool)isLogin url:(NSString *)url urlParameters:(nullable NSDictionary *)urlParameters parameters:(nullable NSDictionary *)parameters completion:(SPSBNetworkManagerCallbackBlock)completion { [self networkUseMethod:method isLogin:isLogin url:url filtrationKey:@"" urlParameters:urlParameters parameters:parameters completion:completion]; } - (void)networkUseMethod:(SPSBNetworkMethod)method isLogin:(bool)isLogin url:(NSString *)url filtrationKey:(NSString *)filtrationKey urlParameters:(nullable NSDictionary *)urlParameters parameters:(nullable NSDictionary *)parameters completion:(SPSBNetworkManagerCallbackBlock)completion { NSMutableString *u = [url mutableCopy]; if (urlParameters) { [urlParameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { if (![obj isKindOfClass:[NSString class]]) { obj = [NSString stringWithFormat:@"%@", obj]; } [u replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key] withString:obj options:NSLiteralSearch range:NSMakeRange(0, u.length)]; }]; } debugLog(@"method=>%@----url=>%@----parameters=>%@", @[@"get", @"post", @"put", @"delete"][method], url ,parameters); NSString *key = [self getDicKeyWithUrl:url filtrationKey:filtrationKey]; SPSBUrlDicValue *value = SPSBUrlDicValue.new; value.spsb_callbackBlock = completion; if (_urlDic[key]) { _urlDic[key] = value; return; }; _urlDic[key] = value; if (isLogin) { [self networkNeedLoginUseMethod:method url:u parameters:parameters key:key]; } else { [self networkUseMethod:method url:u parameters:parameters key:key]; } } - (void)networkUseMethod:(SPSBNetworkMethod)method url:(NSString *)url parameters:(nullable NSDictionary *)parameters key:(NSString *)key { @weakify(self) SPSBNetworkSuccessBlock successBlock = ^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { @strongify(self) if (!self) return; debugLog(@"url=>%@----response=>%@", url, responseObject); [self handleCallBackData:responseObject key:key circulationAction:nil]; }; SPSBNetworkFailureBlock failureBlock = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { debugLog(@"url=>%@----error=>%@", url, error); @strongify(self) if (!self) return; if (error.code != -999) { [self handleFailureWithKey:key message:nil data:nil]; } }; [self useAFNetworkWithMethod:method url:url key:key parameters:parameters callBackSuccess:successBlock callBacekFail:failureBlock]; } - (void)networkNeedLoginUseMethod:(SPSBNetworkMethod)method url:(NSString *)url parameters:(nullable NSDictionary *)parameters key:(NSString *)key { if ([spsb_loginToken() isEqualToString:@""]) { @weakify(self) [self circulationWithIsNeedToLoginNotification:false url:url key:key circulationAction:^{ @strongify(self) [self networkNeedLoginUseMethod:method url:url parameters:parameters key:key]; }]; } else { @weakify(self) SPSBNetworkSuccessBlock successBlock = ^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { debugLog(@"url=>%@----response=>%@", url, responseObject); @strongify(self) if (!self) return; [self handleCallBackData:responseObject key:key circulationAction:^{ @weakify(self) [self circulationWithIsNeedToLoginNotification:true url:url key:key circulationAction:^{ @strongify(self) [self networkNeedLoginUseMethod:method url:url parameters:parameters key:key]; }]; }]; }; SPSBNetworkFailureBlock failureBlock = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { debugLog(@"url=>%@----error=>%@", url, error); @strongify(self) if (!self) return; if (error.code != -999) { [self handleFailureWithKey:key message:nil data:nil]; } }; NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:parameters]; [dic setObject:spsb_loginToken() forKey:@"key"]; [self useAFNetworkWithMethod:method url:url key:key parameters:dic callBackSuccess:successBlock callBacekFail:failureBlock]; } } - (void)useAFNetworkWithMethod:(SPSBNetworkMethod)method url:(NSString *)url key:(NSString *)key parameters:(nullable NSDictionary *)parameters callBackSuccess:(SPSBNetworkSuccessBlock)successBlock callBacekFail:(SPSBNetworkFailureBlock)failureBlock { NSURLSessionDataTask *task; switch (method) { case SPSBNetworkMethodGET: { task = [_manager GET:url parameters:parameters headers:@{} progress:nil success:successBlock failure:failureBlock]; } break; case SPSBNetworkMethodPOST: { task = [_manager POST:url parameters:parameters headers:@{} progress:nil success:successBlock failure:failureBlock]; } break; case SPSBNetworkMethodPUT: { task = [_manager PUT:url parameters:parameters headers:@{} success:successBlock failure:failureBlock]; } break; case SPSBNetworkMethodDELETE: { task = [_manager DELETE:url parameters:parameters headers:@{} success:successBlock failure:failureBlock]; } break; default: break; } if (_urlDic[key] && task) { _urlDic[key].spsb_task = task; } } - (void)circulationWithIsNeedToLoginNotification:(bool)flag url:(NSString *)url key:(NSString *)key circulationAction:(void(^_Nullable)(void))circulationAction { //60秒超时让用户自行选择退出还是继续 debugLog(@"timeout=>%ld", (long)_timeOut); debugLog(@"networkStatus=>%@", [jxh_userDefaults() objectForKey:SPSBNetworkStatusKey]); if (_timeOut > SPSBTimeOutMinute || [[jxh_userDefaults() objectForKey:SPSBNetworkStatusKey] unsignedIntegerValue] == SPSBNetworkStatusNo) { _timeOut = 0; [self handleFailureWithKey:key message:nil data:nil]; } else { if (flag) { spsb_postNotification(SPSBAppStatusNotificationKey, @selector(spsb_appNeedLogin), spsb_appNeedLogin); } NSMutableDictionary *dic = [@{@"url": url, @"key": key} mutableCopy]; if (circulationAction) { dic[@"circulationAction"] = circulationAction; } [self performSelector:@selector(waitForLogin:) withObject:dic afterDelay:2.0]; _timeOut += 2; } } - (void)waitForLogin:(NSDictionary *)dic { if (self && self->_isLogin && dic[@"circulationAction"]) { ((void(^)(void))dic[@"circulationAction"])(); } else { [self circulationWithIsNeedToLoginNotification:false url:dic[@"url"] key:dic[@"key"] circulationAction:dic[@"circulationAction"]]; } } - (void)handleCallBackData:(id)responseObject key:(NSString *)key circulationAction:(void(^_Nullable)(void))circulationAction { _timeOut = 0; if (responseObject) { NSDictionary *data = [self changeData:responseObject]; if ([data[@"code"] integerValue] == SPSBNetworkCallbackSuccessCode) { NSError *error = [NSError errorWithDomain:@"成功" code:SPSBNetworkErrorCodeSuccess userInfo:nil]; if (_urlDic[key]) { _urlDic[key].spsb_callbackBlock(error, data); [_urlDic removeObjectForKey:key]; } } else if ([data[@"code"] integerValue] == SPSBNetworkCallbackNeedLogin || [data[@"code"] integerValue] == SPSBNetworkCallbackKeyInvalid) { _isLogin = false; //去掉本地token [jxh_userDefaults() setObject:nil forKey:SPSBToken]; [jxh_userDefaults() synchronize]; if (circulationAction) { circulationAction(); } } else { [self handleFailureWithKey:key message:data[@"msg"] data:data]; } } else { [self handleFailureWithKey:key message:nil data:nil]; } } - (NSDictionary *)changeData:(NSDictionary *)data { NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:data]; if (dict[@"msg"] && (jxh_isNullClass(dict[@"msg"]) || [dict[@"msg"] isEqualToString:@""])) { [dict removeObjectForKey:@"msg"]; } if (dict[@"data"] && jxh_isNullClass(dict[@"data"])) { [dict removeObjectForKey:@"data"]; } return dict; } - (void)handleFailureWithKey:(NSString *)key message:(nullable NSString *)message data:(nullable id)data { NSError *error; if ([[jxh_userDefaults() objectForKey:SPSBNetworkStatusKey] unsignedIntegerValue] == SPSBNetworkStatusNo) { error = [NSError errorWithDomain:@"网络连接不稳定" code:SPSBNetworkErrorCodeNetwrokMiss userInfo:nil]; } else if (message) { error = [NSError errorWithDomain:message code:SPSBNetworkErrorCodeConnectErrorMessage userInfo:nil]; } else { error = [NSError errorWithDomain:@"" code:SPSBNetworkErrorCodeConnectError userInfo:nil]; } if (_urlDic[key]) { _urlDic[key].spsb_callbackBlock(error, data); [_urlDic removeObjectForKey:key]; } } - (NSString *)getDicKeyWithUrl:(NSString *)url filtrationKey:(nonnull NSString *)filtrationKey { return [NSString stringWithFormat:@"%@%@", url, filtrationKey]; } - (void)cancelUrl:(NSString *)url filtrationKey:(nonnull NSString *)filtrationKey { NSString *key = [self getDicKeyWithUrl:url filtrationKey:filtrationKey]; if (_urlDic[key].spsb_task) { [_urlDic[key].spsb_task cancel]; } _urlDic[key] = nil; } - (void)cancelAll { [_manager.operationQueue cancelAllOperations]; [_urlDic removeAllObjects]; [NSObject cancelPreviousPerformRequestsWithTarget:self]; } - (void)networkDownloadImageWithUrl:(NSString *)url key:(NSString *)key completion:(SPSBNetworkManagerCallbackBlock)completion { @weakify(self) [[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:url] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { @strongify(self) if (!completion || !self) return; if (image) { NSError *error = [NSError errorWithDomain:@"成功" code:SPSBNetworkErrorCodeSuccess userInfo:nil]; completion(error, @{@"image": image, @"key": key}); return; } else if (error && error.code == SDWebImageErrorCancelled) { return; } SPSBUrlDicValue *value = SPSBUrlDicValue.new; value.spsb_callbackBlock = completion; self->_urlDic[key] = value; [self handleFailureWithKey:key message:nil data:@{@"key": key}]; }]; } - (void)networkPostImageWihtUrl:(NSString *)url parameters:(nullable NSDictionary *)parameters imageArray:(NSArray *)imageArray completion:(SPSBNetworkManagerCallbackBlock)completion { NSString *key = [self getDicKeyWithUrl:url filtrationKey:[NSString stringWithFormat:@"%lf", [[NSDate new] timeIntervalSince1970] * 1000]]; SPSBUrlDicValue *value = SPSBUrlDicValue.new; value.spsb_callbackBlock = completion; if (_urlDic[key]) { _urlDic[key] = value; return; }; _urlDic[key] = value; [self networkPostImageWihtUrl:url key:key parameters:parameters imageArray:imageArray completion:completion]; } - (void)networkPostImageWihtUrl:(NSString *)url key:(NSString *)key parameters:(nullable NSDictionary *)parameters imageArray:(NSArray *)imageArray completion:(SPSBNetworkManagerCallbackBlock)completion { if ([spsb_loginToken() isEqualToString:@""]) { @weakify(self) [self circulationWithIsNeedToLoginNotification:false url:url key:key circulationAction:^{ @strongify(self) [self networkPostImageWihtUrl:url key:key parameters:parameters imageArray:imageArray completion:completion]; }]; } else { NSMutableDictionary *dict; if (parameters) { dict = [NSMutableDictionary dictionaryWithDictionary:parameters]; } else { dict = NSMutableDictionary.new; } [dict setObject:spsb_loginToken() forKey:@"key"]; @weakify(self) SPSBNetworkSuccessBlock successBlock = ^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { @strongify(self) debugLog(@"url=>%@----response=>%@", url, responseObject); if (!self) return; [self handleCallBackData:responseObject key:key circulationAction:^{ @weakify(self) [self circulationWithIsNeedToLoginNotification:true url:url key:key circulationAction:^{ @strongify(self) [self networkPostImageWihtUrl:url key:key parameters:parameters imageArray:imageArray completion:completion]; }]; }]; }; SPSBNetworkFailureBlock failureBlock = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { debugLog(@"url=>%@----error=>%@", url, error); @strongify(self) if (!self) return; if (error.code != -999) { [self handleFailureWithKey:key message:nil data:nil]; } }; NSURLSessionDataTask *task = [_manager POST:url parameters:dict headers:@{} constructingBodyWithBlock:^(id _Nonnull formData) { @strongify(self) [self appendData:formData imageArray:imageArray]; } progress:nil success:successBlock failure:failureBlock]; if (_urlDic[key]) { _urlDic[key].spsb_task = task; } } } - (void)appendData:(id)formData imageArray:(NSArray *)imageArray { for (NSInteger i = 0; i < imageArray.count; i ++) { UIImage *image = imageArray[i]; NSData *data = UIImageJPEGRepresentation(image, 0.5); NSString *str; if (data) { str = @"jpg"; } else { data = UIImagePNGRepresentation(image); str = @"png"; } [formData appendPartWithFileData:data name:[NSString stringWithFormat:@"file%ld", (long)i + 1] fileName:[NSString stringWithFormat:@"file%ld.%@", (long)i + 1, str] mimeType:@"application/octet-stream"]; } } #pragma mark - SPSBNotificationDelegate - (void)spsb_loggingStatusChanged:(SPSBLoggingStatus)status needCheckOrderBalanceNotPayOrders:(bool)flag { if (status == SPSBLoggingStatusLogin) { _isLogin = true; } else { _isLogin = false; } } @end