// // NetworkingManager.m // SRKnow // // Created by CYH on 2020/7/21. // Copyright © 2020 shirong. All rights reserved. // #import "NetworkingManager.h" #import "NetworkingTool.h" #import #import "NetworkingInterface.h" @interface NetworkingManager () ///主域名是否为动态获取 @property(nonatomic, readonly, assign)BOOL isDynamicMainHost; ///主域名 @property(nonatomic, copy)NSString *mainHost; @property(nonatomic, strong)NSMutableDictionary *scheduledRequestHeaders; @end @implementation NetworkingManager @synthesize mainHost = _mainHost; #pragma mark - 项目定制设置 ///定制初始化 - (void)scheduledInit { _isDynamicMainHost = NO; self.networkingContextType = NetworkingContextType_Release; ///监听登录和退出登录的通知 __weak typeof(self) weakSelf = self; [NSNotificationCenter.defaultCenter addObserverForName:LoginSuccessNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { //登录成功, 设置请求头 NSString *userToken = [LoginService token]; NSLog(@"CYH===%@", userToken); [weakSelf setScheduleRequestHeader:@{ @"Authorization" : [@"Bearer " stringByAppendingString:userToken] }]; }]; [NSNotificationCenter.defaultCenter addObserverForName:LogoutSuccessNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { //退出登录成功, 清空请求头 [weakSelf setScheduleRequestHeader:nil]; }]; NSString *userToken = [LoginService token]; if (userToken.length) { [weakSelf setScheduleRequestHeader:@{ @"Authorization" : [@"Bearer " stringByAppendingString:userToken] }]; } [NetworkingTool setRequestSerializer:CYHRequestSerializerHTTP]; [NetworkingTool setRequestTimeout:8.0f]; [NetworkingTool setResponseSerializer:CYHResponseSerializerJSON]; // [NetworkingTool.sessionManager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; /* _isDynamicMainHost = NO; /定制请求头参数 NSString *token = WLUserManager.share.token.token; token = [NSString stringWithFormat:@"Bearer%@", token]; _scheduledHeaders = @{ @"App" : @"iOS", @"App-Model" : [WLTool getCurrentDeviceModel], @"App-Version" : VERSION_CODE, @"iOS_App_Version" : VERSION_CODE, @"deviceID" : [WLTool currentIdentifier], @"App-Channel" : @"app_store", @"User-Agent" : @"iOS", @"Authorization" : token }; ///定制-请求序列化格式为JSON AFJSONRequestSerializer *jsonRequestSerializer = [AFJSONRequestSerializer serializer]; //超时设置 httpRequestSerializer.timeoutInterval = 8.0f; NetworkingTool.sessionManager.requestSerializer = httpRequestSerializer; [NetworkingTool.sessionManager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; ///定制 - 响应序列化格式为HTTP AFHTTPResponseSerializer *httpResponseSerializer = [AFHTTPResponseSerializer serializer]; //response可接受的内容类型 httpResponseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/javascript", @"text/plain", @"image/jpeg", nil]; NetworkingTool.sessionManager.responseSerializer = httpResponseSerializer; */ /** 定制安全策略 * 安全策略 - AFSecurityPolicy - AFSSLPinningMode说明 * AFSSLPinningModeNone(默认): 不使用固定证书(本地)验证服务器。直接从客户端系统中的受信任颁发机构 CA 列表中去验证 * AFSSLPinningModePublicKey: 代表会对服务器返回的证书中的PublicKey进行验证,通过则通过,否则不通过 * AFSSLPinningModeCertificate: 代表会对服务器返回的证书同本地证书全部进行校验,通过则通过,否则不通过 // 使用允许无效或过期的证书,默认是不允许。 NetworkingTool.sessionManager.securityPolicy.allowInvalidCertificates = YES; // 是否验证证书中的域名domain NetworkingTool.sessionManager.securityPolicy.validatesDomainName = NO; // 打开状态栏的等待菊花 [AFNetworkActivityIndicatorManager sharedManager].enabled = YES; */ } + (NSString *)fullUrlWithPath:(NSString *)path { //新接口用V2,旧接口用V1 return [[self.shared mainHost] stringByAppendingFormat:@"/api/%@", path]; } #pragma mark - 环境切换 //#ifdef DEBUG /////调试阶段: 在这里手动修改测试环境; //- (NetworkingContextType)getDebugNetworkingContextType { // return NetworkingContextType_Test; //} //#endif ///切换环境及域名 - (void)setNetworkingContextType:(NetworkingContextType)networkingContextType { #ifdef DEBUG //调试阶段 #else //发布阶段 // networkingContextType = NetworkingContextType_Release; #endif // _networkingContextType = NetworkingContextType_Test; _networkingContextType = networkingContextType; if (!_isDynamicMainHost) { ///不是动态获取 self.mainHost = BaseHostUrl; return; } ///动态获取 if (networkingContextType == NetworkingContextType_Release) { ///正式环境 ///从网络获取或沙盒中获取 NSString *host = @"http://chat.yuantiyu.com"; if (!host) { ///沙盒中为nil, 网络获取并赋值给self.mainHost,并保存 [self requestMainHost]; } return; } if (networkingContextType == NetworkingContextType_PreRelease) { ///预生产环境 self.mainHost = @"http://chat.yuantiyu.com"; return; } ///测试环境 self.mainHost = @"http://chat.yuantiyu.com"; } ///主域名 //- (NSString *)mainHost { // if (!_mainHost) { //#ifdef DEBUG //调试阶段 // self.networkingContextType = [self getDebugNetworkingContextType]; //#else //发布阶段 // self.networkingContextType = NetworkingContextType_Release; //#endif // } // return _mainHost; //} //+ (NSDictionary *)scheduledHeaders { // NSMutableDictionary *dicM = [NSMutableDictionary dictionary]; //// dicM[@"X-Token"] = LQInteractorManager.sharedInstance.userInfoManager.userInfoModel.token; // return dicM; //} #pragma mark - 动态获取主域名(根据项目设置) ///根据项目要求,主域名是否需要动态获取 ? (动态获取存进沙盒,每次请求检查主域名) : (写死) - (void)requestMainHost { [NetworkingTool BasePOST:@"" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { }]; } #pragma mark - POST /** * 项目定制_POST请求 * @param targetUrl url路径 * @param paramDic 参数 * @param successBlock 回调 * @param failureBlock 回调 */ + (nullable NSURLSessionDataTask *)scheduledPOST:(NSString *)targetUrl parameters:(nullable id)paramDic success:(nullable void (^)(NSURLSessionDataTask *task, NetResponseModel* _Nullable responseModel))successBlock failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failureBlock { __weak typeof(self) weakSelf = self; NSString *fullUrl = [self fullUrlWithPath:targetUrl]; NSMutableDictionary *paramDicM = [NSMutableDictionary dictionaryWithDictionary:paramDic]; ///添加其他参数 [weakSelf scheduledParam:paramDicM]; return [NetworkingTool BasePOST:fullUrl parameters:paramDicM headers:NetworkingManager.shared.scheduledRequestHeaders progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { ///第一层返回信息数据 NetResponseModel *responseModel = [weakSelf modelWithJSON:responseObject]; /* if (responseModel.code == 1002) { ///未登录 [GraceHudTool.sharedInstance showText:responseModel.msg inView:UIApplication.sharedApplication.keyWindow]; // [LQInteractorManager showLandingContainerViewControllerForWindowsRootViewController:LQLandingShowType_Landing]; return; } if (responseModel.code == 1003) { ///没有权限 [GraceHudTool.sharedInstance showText:responseModel.msg inView:UIApplication.sharedApplication.keyWindow]; return; } if (responseModel.code == 1001) { ///其他错误 [GraceHudTool.sharedInstance showText:responseModel.msg inView:UIApplication.sharedApplication.keyWindow]; return; } */ ///第二层返回信息: 业务真正需要的数据 // NetResponseModel *responseDataModel = [NetResponseModel new]; // responseDataModel.code = responseModel.code; // responseDataModel.data = responseModel.data[@"info"]; // responseDataModel.msg = responseModel.msg; if (responseModel.code != 0) { ///其他错误 // [GraceHudTool.sharedInstance showText:responseModel.message inView:UIApplication.sharedApplication.windows.firstObject]; return; } if (successBlock) { successBlock(task, responseModel); } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failureBlock) { failureBlock(task, error); return; } // [GraceHudTool.sharedInstance showText:error.domain inView:UIApplication.sharedApplication.windows.firstObject]; }]; } #pragma mark - GET /** * GET请求 * @param targetUrl URL路径 * @param paramDic 参数 * @param successBlock 回调 * @param failureBlock 回调 */ + (nullable NSURLSessionDataTask *)scheduledGET:(NSString *)targetUrl parameters:(NSDictionary *)paramDic success:(nullable void (^)(NSURLSessionDataTask *task, NetResponseModel* _Nullable responseModel))successBlock failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failureBlock { __weak typeof(self) weakSelf = self; NSString *fullUrl = [self fullUrlWithPath:targetUrl]; NSMutableDictionary *paramDicM = [NSMutableDictionary dictionaryWithDictionary:paramDic]; ///添加其他参数 [self scheduledParam:paramDicM]; return [NetworkingTool BaseGet:fullUrl parameters:paramDicM headers:NetworkingManager.shared.scheduledRequestHeaders progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { ///第一层返回信息数据 NetResponseModel *responseModel = [weakSelf modelWithJSON:responseObject]; if (responseModel.code != 0) { ///其他错误 // [GraceHudTool.sharedInstance showText:responseModel.message inView:UIApplication.sharedApplication.windows.firstObject]; return; } if (successBlock) { successBlock(task, responseModel); } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failureBlock) { failureBlock(task, error); return; } // [GraceHudTool.sharedInstance showText:error.domain inView:UIApplication.sharedApplication.windows.firstObject]; }]; } ///定制请求参数: 添加签名 + (void)scheduledParam:(NSMutableDictionary *)parameterM { /* NSString *const kRequestSalt = @"479b2e5623028967e78ee79aa5aa8a6613d6e4e93d83fa50252b9984af5db4e0c00e7de564d12f6aa4deec7837e2829c"; NSString *app_name = @"iOS"; NSString *app_secret = kRequestSalt; NSString *time = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]]; [parameterM setObject:app_name forKey:@"app_name"]; [parameterM setObject:time forKey:@"time"]; [parameterM setObject:app_secret forKey:@"app_secret"]; [parameterM setObject:@"1" forKey:@"check_sign"]; //对parameterM根据key进行升序排序==>sign. NSArray *sortKeys = [parameterM allKeysSorted]; NSMutableString *sign = [NSMutableString string]; [sortKeys enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *value = parameterM[obj]; if ([value isKindOfClass:NSString.class]) { value = [value stringByURLEncode]; // value = value.wl_encodingUrlParameterString; } [sign appendFormat:@"%@=%@%@", obj, value, ((idx == (sortKeys.count-1)) ? @"" : @"&")]; }]; [parameterM setObject:sign.md5String forKey:@"sign"]; [parameterM removeObjectForKey:@"app_secret"]; */ } #pragma mark - 上传 /// upload上传文件 /// @param url 服务器URL /// @param data 文件二进制数据 /// @param uploadProgress 上传进度回调 /// @param completionHandler 上传完成回调 + (nullable NSURLSessionUploadTask *)scheduleUploadFile:(NSString *)url fileData:(NSData *)data progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { // __weak typeof(self) weakSelf = self; NSString *fullUrl = [self fullUrlWithPath:url]; // NSMutableDictionary *paramDicM = [NSMutableDictionary dictionaryWithDictionary:paramDic]; ///添加其他参数 // [self scheduledParam:paramDicM]; return [NetworkingTool upload:fullUrl fileData:data progress:uploadProgress completionHandler:completionHandler]; } /// upload上传文件 /// @param url 服务器URL /// @param data 文件二进制数据 /// @param uploadProgress 上传进度回调 /// @param completionHandler 上传完成回调 + (void)scheduleUploadFiles:(NSString *)url fileDatas:(NSArray *)datas progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress completionHandler:(void (^)(NSArray *fileUrlPaths))completionHandler { NSMutableArray *paths = [NSMutableArray array]; dispatch_queue_t globalQuene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); for (NSData *data in datas) { dispatch_group_enter(group); dispatch_async(globalQuene, ^{ [self scheduleUploadFile:url fileData:data progress:uploadProgress completionHandler:^(NSURLResponse * _Nonnull response, id _Nonnull responseObject, NSError * _Nonnull error) { NSLog(@"%@", response); if (!error) { [paths addObject:responseObject]; } dispatch_group_leave(group); }]; }); } //一直等待完成 dispatch_group_wait(group, DISPATCH_TIME_FOREVER); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"完成"); if (completionHandler) { completionHandler(paths); } }); } /// From表单提交 /// 上传数据 - POST请求 - Form表单提交数据(创建并运行一个包含多部分 "POST "请求的 "NSURLSessionDataTask"。) /// @param URLString URLString /// @param paramDic 参数 /// @param headerDic 附加到这个请求的默认头部的头部 /// @param block 一个接受单个参数并将数据附加到HTTP body的块。block参数是一个采用`AFMultipartFormData`协议的对象。 /// @param uploadProgress 上传进度回调 /// @param successBlock 成功回调 ---> Model /// @param failureBlock 失败回调 + (nullable NSURLSessionDataTask *)upload_POST:(NSString *)URLString parameters:(nullable id)paramDic headers:(nullable NSDictionary *)headerDic constructingBodyWithBlock:(nullable void (^)(id formData))block progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress success:(nullable void (^)(NSURLSessionDataTask *task, NetResponseModel* _Nullable responseModel))successBlock failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failureBlock { NSString *fullUrl = [self fullUrlWithPath:URLString]; // [BaseUrl stringByAppendingString:URLString]; __weak typeof(self) weakSelf = self; return [NetworkingTool upload_BasePOST:fullUrl parameters:paramDic headers:headerDic constructingBodyWithBlock:block progress:uploadProgress success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NetResponseModel *responseModel = [weakSelf modelWithJSON:responseObject]; if (successBlock) { successBlock(task, responseModel); } } failure:failureBlock]; } + (NetResponseModel *)modelWithJSON:(NSDictionary *)dic { return [NetResponseModel yy_modelWithJSON:dic]; } //MARK: - Get&Set - (void)setScheduleRequestHeader:(NSDictionary *)reqHeader { [self.scheduledRequestHeaders removeAllObjects]; [self.scheduledRequestHeaders setDictionary:reqHeader]; self.scheduledRequestHeaders[@"device_brand"] = @"Apple"; self.scheduledRequestHeaders[@"device_model"] = [THNetworkInterfaceService deviceModel]; self.scheduledRequestHeaders[@"app_version_name"] = [THNetworkInterfaceService version]; self.scheduledRequestHeaders[@"app_version_code"] = [THNetworkInterfaceService bundleVersion]; self.scheduledRequestHeaders[@"interface_version"] = [THNetworkInterfaceService version];; self.scheduledRequestHeaders[@"device_platform"] = @"iOS"; self.scheduledRequestHeaders[@"os_version"] = [THNetworkInterfaceService deviceSystemVersion]; } - (void)setMainHost:(NSString *)mainHost { _mainHost = mainHost; ///发送通知: 第一次赋值 或 被修改 [NSNotificationCenter.defaultCenter postNotificationName:MainHostURL_DidChangeNotifyKEY object:nil userInfo:nil]; } - (NSMutableDictionary *)scheduledRequestHeaders { if (!_scheduledRequestHeaders) { _scheduledRequestHeaders = [NSMutableDictionary dictionary]; } return _scheduledRequestHeaders; } #pragma mark - 单例 + (instancetype)shared { return [[self alloc] init]; } // 创建静态对象 防止外部访问 static NetworkingManager *_instance; + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (_instance == nil) { _instance = [super allocWithZone:zone]; [_instance scheduledInit]; } }); return _instance; } // 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone -(id)copyWithZone:(NSZone *)zone { return _instance; } -(id)mutableCopyWithZone:(NSZone *)zone { return _instance; } @end