VclCrash.m 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. //
  2. // VclCrash.m
  3. // VclCrash
  4. //
  5. // Created by Felix on 2018/8/10.
  6. // Copyright © 2018年 Felix. All rights reserved.
  7. //
  8. #import "VclCrash.h"
  9. #import "VclSystemInfo.h"
  10. #import <Foundation/NSURLSession.h>
  11. #import <UIKit/UIKit.h>
  12. #import "Domains.h"
  13. #import "BuryPointModel.h"
  14. #define LOG_TIME_FORMAT @"yyyy-MM-dd HH:mm:ss.SSS"
  15. #define VclCRASH_FORM_BOUNDARY @"VclCRASH_FORM_BOUNDARY"
  16. #define HTTP_REQUEST_URL_STRING @"http://dev2.ipc.Vcl.optjoy.io:30288/apis/v1/logfile/logfile/upload/app/ios/resource?uid=12345&access_token=9999"
  17. // 目前開發用的域名是 dev env的域名 請在正式環境改成 stag env的域名
  18. // stag env 下
  19. // 國內地區存儲在 qcloud的logfiles-stag bucket
  20. // 海外地區存儲在 gcp的logfiles-stag bucket
  21. // 正式版 國內:https://stag.ipc.Vcl.optjoy.cn:30011/apis/v1 海外:https://stag.ipc.Vcl.optjoy.io:30011/apis/v1
  22. #define HTTP_REQUEST_URL_STRING_CN @"https://stag.ipc.Vcl.optjoy.cn:30011/apis/v1/logfile/logfile/upload/app/ios/resource?uid=12345&access_token=9999"
  23. #define HTTP_REQUEST_URL_STRING_IO @"https://stag.ipc.Vcl.optjoy.io:30011/apis/v1/logfile/logfile/upload/app/ios/resource?uid=12345&access_token=9999"
  24. #define HTTP_REQUEST_URL_STRING_IO_DF @"https://ipc.dada.p.optjoy.io:30011/apis/v1/logfile/logfile/upload/app/ios/resource?uid=12345&access_token=9999"
  25. @interface VclCrash () <NSURLSessionDelegate>
  26. @property (nonatomic, copy) NSMutableArray<NSString *> *pendingUploads; // 待上传的文件所在路径;
  27. @property (nonatomic, assign) BOOL isFormDataEmpty; // 是否为空表单上传,默认YES
  28. @property (nonatomic, copy) NSString *currentReport; // 程序本次启动新创建的文件名,上方待上传的文件pendingUploads不包含新创建的文件
  29. @end
  30. static VclCrash *_instance = nil;
  31. @implementation VclCrash
  32. + (instancetype)sharedInstance {
  33. static dispatch_once_t onceToken;
  34. dispatch_once(&onceToken, ^{
  35. _instance = [[VclCrash alloc] init];
  36. });
  37. return _instance;
  38. }
  39. + (instancetype)allocWithZone:(struct _NSZone *)zone {
  40. static dispatch_once_t onceToken;
  41. dispatch_once(&onceToken, ^{
  42. _instance = [super allocWithZone:zone];
  43. });
  44. return _instance;
  45. }
  46. - (instancetype)copyWithZone:(NSZone *)zone {
  47. return _instance;
  48. }
  49. - (instancetype)init {
  50. return [self initWithBasePath:self.getBasePath];
  51. }
  52. - (instancetype)initWithBasePath:(NSString *)basePath {
  53. if (self = [super init]) {
  54. // 0.initialized data
  55. self.isFormDataEmpty = YES;
  56. // app启动的时候需要做的事情
  57. // 1.设置异常监听
  58. //[self setDefaultUncaughtExceptionHandler];
  59. // 2.获取已存在的异常文件的文件路径
  60. [self getPendingUploadFiles];
  61. // 3.创建本次的启动日志文件
  62. [self createNewReportFile];
  63. // // 4.上传已存在的日志文件
  64. // [self uploadReportFiles]; /*暂时不上传*/
  65. // 4.创建本次的崩溃文件日志文件
  66. [self createCrashReportFile];
  67. // 5.获取数据上传到服务器
  68. [self uploadCrashReportFiles];
  69. }
  70. return self;
  71. }
  72. // 程序崩溃时回调函数
  73. void UncaughtExceptionHandler(NSException *exception) {
  74. // 出现异常的堆栈信息
  75. NSArray *callStackSymbols = [exception callStackSymbols];
  76. // 出现异常的原因
  77. NSString *reason = [exception reason];
  78. // 异常的名称
  79. NSString *name = [exception name];
  80. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  81. [dateFormatter setDateFormat:LOG_TIME_FORMAT];
  82. // 出现异常的时间
  83. NSString *time = [dateFormatter stringFromDate:[NSDate date]];
  84. NSString *exceptionInfo = [NSString stringWithFormat:@"Exception Time:%@\nException Name:%@\nException Reason:%@\nException Stack:%@", time, name, reason, callStackSymbols];
  85. // [[VclCrash sharedInstance] writeCrashContent:exceptionInfo];
  86. // 以写文件的方式把奔溃信息写入文件,BuryPointModel
  87. [[VclCrash sharedInstance] writeCrashContent:[BuryPointModel crashModelWithString:exceptionInfo]];
  88. }
  89. // 拦截signal
  90. void SignalHandler(int signal) {
  91. }
  92. - (void)setDefaultUncaughtExceptionHandler {
  93. NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
  94. signal(SIGABRT, SignalHandler);
  95. signal(SIGILL, SignalHandler);
  96. signal(SIGSEGV, SignalHandler);
  97. signal(SIGFPE, SignalHandler);
  98. signal(SIGBUS, SignalHandler);
  99. signal(SIGPIPE, SignalHandler);
  100. }
  101. //createCrashReportFile
  102. // 将信息写入到
  103. - (void)writeContent:(NSString *)content {
  104. [self write:content filename:self.currentReport];
  105. }
  106. // 崩溃信息写入到崩溃日志
  107. - (void)writeCrashContent:(NSString *)content {
  108. [self write:content filename:[self createCrashReportFile]];
  109. }
  110. - (void)write:(NSString *)content filename:(NSString *)filename {
  111. if (!filename) {
  112. return;
  113. }
  114. @try {
  115. NSString *path = [self getReportsDirectory];
  116. if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
  117. // 创建日志文件的绝对路径
  118. [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
  119. }
  120. NSString *filePath = [path stringByAppendingPathComponent:filename];
  121. if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  122. [content writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
  123. return;
  124. }
  125. NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
  126. // 将写入文件操作的指针跳到文件的末端
  127. [fileHandle seekToEndOfFile];
  128. // 追加写入数据
  129. [fileHandle writeData:[[NSString stringWithFormat:@"\n%@", content] dataUsingEncoding:NSUTF8StringEncoding]];
  130. [fileHandle closeFile];
  131. }
  132. @catch (NSException *exception) {
  133. }
  134. @finally {
  135. }
  136. }
  137. - (void)clearCrashFile {
  138. [self clearFile:self.currentReport];
  139. }
  140. - (void)clearFile:(NSString *)filename {
  141. @try {
  142. NSString *path = self.getReportsDirectory;
  143. if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
  144. // 创建日志文件的绝对路径
  145. [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
  146. }
  147. NSString *filePath = [path stringByAppendingPathComponent:filename];
  148. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  149. NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
  150. // 将写入文件操作的指针跳到文件的末端
  151. [fileHandle truncateFileAtOffset:0];
  152. [fileHandle closeFile];
  153. }
  154. }
  155. @catch (NSException *exception) {
  156. HLog(@"[VclCrash] clear local file error with exception:\n%@", exception);
  157. }
  158. @finally {
  159. }
  160. }
  161. /**
  162. 根据本地文件的全路径,删除文件
  163. @param fullPath 全路径
  164. */
  165. - (BOOL)removeLocalFileWithFullPath:(NSString *)fullPath {
  166. BOOL result = NO;
  167. NSError *error = nil;
  168. if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
  169. result = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
  170. }
  171. if (error) {
  172. HLog(@"[VclCrash] remove local file with error: %@.", error);
  173. }
  174. return result;
  175. }
  176. - (void)uploadReportFiles {
  177. NSArray *paths = [self.pendingUploads copy];
  178. [self uploadWithFilePaths:paths params:@{@"userName" : @"999", @"uid" : @"12345", @"access_token": @"9999", @"type" : @"txt"}];
  179. }
  180. /**
  181. 上传多个文件
  182. @param filePaths 待上传的文件所在路径
  183. @param params 参数
  184. */
  185. - (void)uploadWithFilePaths:(NSArray<NSString *> *)filePaths params:(NSDictionary *)params {
  186. NSURL *url = [NSURL URLWithString:[self getHttpRequestURLString]];
  187. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  188. // 分界线 --VclCRASH_FORM_BOUNDARY
  189. NSString *BOUNDARY = [[NSString alloc] initWithFormat:@"\r\n--%@\r\n", VclCRASH_FORM_BOUNDARY];
  190. // 结束符:--VclCRASH_FORM_BOUNDARY--
  191. NSString *BOUNDARY_EOF = [[NSString alloc] initWithFormat:@"\r\n--%@--\r\n", VclCRASH_FORM_BOUNDARY];
  192. // 声明requestData,用来放入http body
  193. NSMutableData *requestData = [NSMutableData data];
  194. // 时间格式对象
  195. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  196. NSMutableArray *emptyFileFullPaths = [NSMutableArray array];
  197. // 参数的集合的所有key的集合
  198. NSString *uuid = [self fetchDeviceUUID];
  199. NSString *headerFlag = [NSString stringWithFormat:@"%@_", uuid];
  200. for (NSString *obj in filePaths) {
  201. NSData *data = [NSData dataWithContentsOfFile:obj];
  202. // 如果是有数据才进行拼接并且上传
  203. if (data.length) {
  204. // http body的字符串
  205. NSMutableString *body = [[NSMutableString alloc] init];
  206. [body appendFormat:@"%@", BOUNDARY];
  207. dateFormatter.dateFormat = @"yyyy.MM.dd_HH.mm.ss.sss";
  208. NSString *fileName = [obj lastPathComponent];
  209. fileName = [headerFlag stringByAppendingString:fileName];
  210. [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileName, fileName];
  211. [body appendFormat:@"Content-Type: \"%@\";\r\n\r\n", @"text/plain"];
  212. // 将body字符串转化为UTF8格式的二进制
  213. [requestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
  214. [requestData appendData:[[VclSystemInfo sharedInstance] systemInfoData]];
  215. [requestData appendData:data];
  216. self.isFormDataEmpty = NO;
  217. }
  218. else { // 否则本地的空文件直接删除
  219. if ([self.pendingUploads containsObject:obj]) {
  220. [self.pendingUploads removeObject:obj];
  221. [emptyFileFullPaths addObject:obj];
  222. }
  223. }
  224. }
  225. for (NSString *path in emptyFileFullPaths) {
  226. [self removeLocalFileWithFullPath:path];
  227. }
  228. // 加入结束符
  229. [requestData appendData:[BOUNDARY_EOF dataUsingEncoding:NSUTF8StringEncoding]];
  230. // 如果上传的文件都为空,则不进行下方的上传操作
  231. if (self.isFormDataEmpty) {
  232. return;
  233. }
  234. // 设置HTTPHeader
  235. // 设置HTTPHeader中Content-Type的值
  236. NSString *content = [[NSString alloc] initWithFormat:@"multipart/form-data; boundary=%@", VclCRASH_FORM_BOUNDARY];
  237. [request setValue:content forHTTPHeaderField:@"Content-Type"];
  238. // 设置Content-Length
  239. [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)requestData.length] forHTTPHeaderField:@"Content-Length"];
  240. // 设置时间戳
  241. [dateFormatter setDateFormat:@"yyyyMMddHHmmssSSS"];
  242. NSString *timestamp = [dateFormatter stringFromDate:[NSDate date]];
  243. [request setValue:timestamp forHTTPHeaderField:@"Timestamp"];
  244. // 设置app/{{platform}}/下的子目录
  245. [dateFormatter setDateFormat:@"yyyyMMdd"];
  246. NSString *directory = [dateFormatter stringFromDate:[NSDate date]];
  247. [request setValue:directory forHTTPHeaderField:@"Filename"];
  248. // 设置http body
  249. [request setHTTPBody:requestData];
  250. // http method
  251. [request setHTTPMethod:@"POST"];
  252. // URLSession
  253. NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
  254. NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:Nil];
  255. // NSURLSession *session = [NSURLSession sharedSession];
  256. // 上传任务
  257. HLog(@"------------%@",self.pendingUploads);
  258. __block NSMutableArray *pendingUploads = [self.pendingUploads copy];
  259. NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request
  260. fromData:requestData
  261. completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  262. if (data) {
  263. NSDictionary *dict = nil;
  264. NSMutableArray *uploaded = [NSMutableArray array];
  265. dict = [NSJSONSerialization JSONObjectWithData:data
  266. options:NSJSONReadingMutableLeaves
  267. error:nil];
  268. NSArray *results = [[dict objectForKey:@"result"] componentsSeparatedByString:@";"];
  269. // 已上传成功被返回的文件名
  270. for (NSString *name in results) {
  271. if (name.lastPathComponent.length > 37) {
  272. name = [name.lastPathComponent substringFromIndex:37];
  273. }
  274. else {
  275. name = name.lastPathComponent;
  276. }
  277. for (NSString *filePath in pendingUploads) {
  278. if ([filePath.lastPathComponent isEqualToString:name]) {
  279. [uploaded addObject:filePath];
  280. break;
  281. }
  282. else {
  283. continue;
  284. }
  285. }
  286. }
  287. // 删除本地的文件
  288. for (NSString *path in uploaded) {
  289. [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
  290. }
  291. HLog(@"-------------data:%@", dict);
  292. HLog(@"-------------uploaded:%@", uploaded);
  293. HLog(@"-------------response:%@", response);
  294. HLog(@"-------------error:%@", error);
  295. }
  296. }];
  297. [task resume];
  298. }
  299. - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
  300. NSArray *domains = [[Domains sharedInstance] domains];
  301. if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  302. HLog(@"challenge.protectionSpace.host:%@", challenge.protectionSpace.host);
  303. if([domains containsObject:challenge.protectionSpace.host]) {
  304. NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
  305. completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
  306. }
  307. }
  308. }
  309. /**
  310. 获取应用程序的BundleName
  311. */
  312. - (NSString *)getBundleName {
  313. NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
  314. if (!bundleName) {
  315. bundleName = @"Unknown";
  316. }
  317. return bundleName;
  318. }
  319. /**
  320. 获取Log日志存储的位置
  321. ~/Library/Caches/VclCrash/JoyLite/Reports/...
  322. @return 日志文件所在路径
  323. */
  324. - (NSString *)getBasePath {
  325. NSArray *directories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  326. if (0 == directories.count) {
  327. HLog(@"Could not locate caches directory path.");
  328. return nil;
  329. }
  330. NSString *cachesPath = [directories firstObject];
  331. if (0 == cachesPath.length) {
  332. HLog(@"Could not locate caches directory path.");
  333. return nil;
  334. }
  335. NSString *path = [@"VclCrash" stringByAppendingPathComponent:[self getBundleName]];
  336. return [cachesPath stringByAppendingPathComponent:path];
  337. }
  338. /**
  339. 获取日志文件存储所在的目录文件路径
  340. ~/Library/Caches/VclCrash/JoyLite/Reports/...
  341. */
  342. - (NSString *)getReportsDirectory {
  343. return [self.getBasePath stringByAppendingPathComponent:@"Reports"];
  344. }
  345. /**
  346. 获取待上传的文件列表
  347. */
  348. - (void)getPendingUploadFiles {
  349. // 所查找文件夹的路径
  350. NSString *reportPath = [self getReportsDirectory];
  351. // 目录迭代器
  352. NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:reportPath];
  353. NSMutableArray<NSString *> *array = [NSMutableArray array];
  354. for (NSString *name in enumerator) {
  355. if ([name.pathExtension isEqualToString:@"txt"]) {
  356. [array addObject:[[self getReportsDirectory] stringByAppendingPathComponent:name]];
  357. }
  358. }
  359. [self.pendingUploads addObjectsFromArray:array];
  360. while ([self.pendingUploads count] > 200)
  361. {
  362. NSString *path = [self.pendingUploads firstObject];
  363. [self removeLocalFileWithFullPath:path];
  364. [self.pendingUploads removeObject:path];
  365. }
  366. }
  367. /**
  368. 每次崩溃时,信息保存的文件名称
  369. */
  370. - (void)createNewReportFile {
  371. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  372. dateFormatter.dateFormat = @"yyyy.MM.dd_HH.mm.ss.ssss";
  373. NSString *filename = [NSString stringWithFormat:@"log_%@_ios.txt", [dateFormatter stringFromDate:[NSDate date]]];
  374. [[NSFileManager defaultManager] createFileAtPath:[[self getReportsDirectory] stringByAppendingPathComponent:filename] contents:nil attributes:nil];
  375. self.currentReport = [filename copy];
  376. }
  377. - (NSString *)createCrashReportFile {
  378. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  379. dateFormatter.dateFormat = @"yyyy.MM.dd_HH.mm.ss.ssss";
  380. NSString *filename = [NSString stringWithFormat:@"log_%@_ios_crash.txt", [dateFormatter stringFromDate:[NSDate date]]];
  381. [[NSFileManager defaultManager] createFileAtPath:[[self getReportsDirectory] stringByAppendingPathComponent:filename] contents:nil attributes:nil];
  382. return filename;
  383. }
  384. - (NSString *)getHttpRequestURLString {
  385. NSString *result = [HWDataManager getStringWithKey:@"chinaArea"];
  386. if ([result isEqualToString:@"1"]) { // 国内
  387. return HTTP_REQUEST_URL_STRING_CN;
  388. }
  389. else { // 国外
  390. NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
  391. if ([appID isEqualToString:@"com.jjyang.dadaCamera"] ||
  392. [appID isEqualToString:@"com.dafeng.dadasmartcam"]) { // 大丰项目
  393. return HTTP_REQUEST_URL_STRING_IO_DF;
  394. }
  395. else {
  396. return HTTP_REQUEST_URL_STRING_IO;
  397. }
  398. }
  399. }
  400. - (NSMutableArray<NSString *> *)pendingUploads {
  401. if (!_pendingUploads) {
  402. _pendingUploads = [NSMutableArray array];
  403. }
  404. return _pendingUploads;
  405. }
  406. // 类似:2EAA6CEC-6BAC-43B2-84B2-E528D03C01FD,总长36.
  407. - (NSString *)fetchDeviceUUID {
  408. NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString;
  409. return uuid;
  410. }
  411. - (void)uploadCrashReportFiles {
  412. NSArray *paths = [self.pendingUploads copy];
  413. NSMutableArray *uploadArray = [[NSMutableArray alloc] init];
  414. for (NSString *obj in paths) {
  415. KyoLog(@"文件路径 obj %@",obj);
  416. if ([obj containsString:@"ios_crash.txt"]) { //只上传奔溃文件的日志,做个文件路径的筛选
  417. KyoLog(@"崩溃日志文件路径 obj %@",obj);
  418. [uploadArray addObject:obj];
  419. }
  420. }
  421. if (uploadArray.count == 0) {
  422. return;
  423. }
  424. [self uploadBuryPointData:[NSArray arrayWithArray:uploadArray]];
  425. }
  426. - (void)uploadBuryPointData:(NSArray<NSString *> *)filePaths
  427. {
  428. NSMutableArray *emptyFileFullPaths = [NSMutableArray array];
  429. NSMutableArray *uploadFileFullPaths = [NSMutableArray array];
  430. NSMutableArray *dataArray = [[NSMutableArray alloc] init];
  431. for (NSString *obj in filePaths) {
  432. NSData *data = [NSData dataWithContentsOfFile:obj];
  433. NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  434. NSArray *strARy = [dataStr componentsSeparatedByString:@"__"];
  435. for (NSString *subStr in strARy) {
  436. // HLog(@"subStr %@ subStrCount %lu",subStr, (unsigned long)subStr.length);
  437. if (subStr.length > 0) { //去除换行或者空数据
  438. BuryPointModel *model = [subStr mj_JSONObject];
  439. NSDictionary *dic = [model mj_keyValues];
  440. [dataArray addObject:dic];
  441. }
  442. }
  443. // HLog(@"dataStr %@ strARy %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], strARy);
  444. // 如果是有数据才进行拼接并且上传
  445. if (data.length) {
  446. self.isFormDataEmpty = NO;
  447. [uploadFileFullPaths addObject:obj];
  448. }
  449. else { // 否则本地的空文件直接删除
  450. if ([self.pendingUploads containsObject:obj]) {
  451. [self.pendingUploads removeObject:obj];
  452. [emptyFileFullPaths addObject:obj];
  453. }
  454. }
  455. }
  456. // 如果上传的文件都为空,则不进行下方的上传操作
  457. if (self.isFormDataEmpty) {
  458. return;
  459. }
  460. for (NSString *path in emptyFileFullPaths) {
  461. [self removeLocalFileWithFullPath:path];
  462. }
  463. for (NSString *path in uploadFileFullPaths) {
  464. [self removeLocalFileWithFullPath:path];
  465. }
  466. // [[UseAccountManage shareInstance] extensionPublicToBuryPointPostCallBackCode:PostBurialSiteLogAPI Parameters:dataArray success:^(id _Nonnull responseObject) {
  467. // SuperModel *mod = [[SuperModel alloc] initWithDictionary:responseObject error:nil];
  468. // if (mod.status && mod.status.integerValue == 0) {
  469. // //上传成功后把文件缓存清除
  470. // for (NSString *path in uploadFileFullPaths) {
  471. // [self removeLocalFileWithFullPath:path];
  472. // }
  473. // }
  474. // } failure:^(NSError * _Nonnull error) {
  475. //
  476. // }];
  477. }
  478. @end