123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- //
- // BuryPoint.m
- // BuryPoint
- //
- // Created by Felix on 2018/8/10.
- // Copyright © 2018年 Felix. All rights reserved.
- //
- #import "BuryPoint.h"
- #import "VclSystemInfo.h"
- #import <Foundation/NSURLSession.h>
- #import <UIKit/UIKit.h>
- #import "Domains.h"
- #import "BuryPointModel.h"
- #import <MJExtension.h>
- #import "UseAccountManage.h"
- #import "CloudPhoneAPI.h"
- #import "HWBuryPointModel.h"
- #import "FMDB.h"
- #define LOG_TIME_FORMAT @"yyyy-MM-dd HH:mm:ss.SSS"
- #define BuryPoint_FORM_BOUNDARY @"BuryPoint_FORM_BOUNDARY"
- #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"
- // 目前開發用的域名是 dev env的域名 請在正式環境改成 stag env的域名
- // stag env 下
- // 國內地區存儲在 qcloud的logfiles-stag bucket
- // 海外地區存儲在 gcp的logfiles-stag bucket
- // 正式版 國內:https://stag.ipc.Vcl.optjoy.cn:30011/apis/v1 海外:https://stag.ipc.Vcl.optjoy.io:30011/apis/v1
- #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"
- #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"
- #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"
- //
- FOUNDATION_EXPORT BuriedPointType const CloudPhoneTypeWelfare;
- //
- FOUNDATION_EXPORT BuriedPointType const CloudPhoneTypeCloudGame;
- //
- FOUNDATION_EXPORT BuriedPointType const CloudPhoneTypeMime;
- /**埋点字段value值*/
- // 云手机
- NSString *const BuriedPointTypeCloudPhone = @"dt_tab_iOS_云手机";
- // 云盘
- NSString *const BuriedPointTypeCloudStore = @"dt_tab_iOS_云盘";
- // 福利社区
- NSString *const BuriedPointTypeWelfare = @"dt_tab_iOS_福利社区";
- // 云游戏
- NSString *const BuriedPointTypeCloudGame = @"dt_tab_iOS_云游试玩";
- // 我的
- NSString *const BuriedPointTypeMime = @"dt_tab_iOS_我的";
- // 裂变活动-免费领机
- NSString *const BuriedPointTypeReceivePhone = @"dt_裂变_iOS_免费领机";
- // 双旦活动-前往分配时长
- // 支付结果页面进入周年庆活动
- NSString *const BuriedPointTypePaySuccessEnter = @"znq_2022_iOS_支付按钮";
- // 周年庆活动-分配确认
- NSString *const BuriedPointTypeClickDistribute = @"znq_2022_iOS_分配确认按钮";
- // 周年庆活动-分配确认 弹窗确认
- NSString *const BuriedPointTypeSureDistribute = @"znq_2022_iOS_确认弹窗确认";
- // 周年庆活动-分配确认 弹窗取消
- NSString *const BuriedPointTypeCancelDistribute = @"znq_2022_iOS_确认弹窗取消";
- // 周年庆活动-未分配返回
- NSString *const BuriedPointTypeDistributeBack = @"znq_2022_iOS_未分配返回";
- // 快捷方式创建埋点
- NSString *const BuriedPointTypeShortcutCreat = @"shortcut_iOS_create";
- // 快捷方式打开埋点
- NSString *const BuriedPointTypeShortcutOpen = @"shortcut_iOS_click";
- // 云手机试用续费弹窗
- NSString *const BuriedPointTypePlayActCodeForceCloseBuy = @"激活码-强制关闭-去购买";
- NSString *const BuriedPointTypePlayActCodeForceCloseCancel = @"激活码-强制关闭-取消";
- NSString *const BuriedPointTypePlayActCodeForceCloseGiveUp = @"激活码-强制关闭-放弃";
- NSString *const BuriedPointTypePlayActCodeForceCloseContinue = @"激活码-强制关闭-继续观看";
- NSString *const BuriedPointTypePlayActCodeCloseBuy = @"激活码-关闭-去购买";
- NSString *const BuriedPointTypePlayActCodeCloseCancel = @"激活码-关闭-取消";
- NSString *const BuriedPointTypePlayActCodeBreakBuy = @"激活码-断线-去购买";
- NSString *const BuriedPointTypePlayActCodeBreakCancel = @"激活码-断线-取消";
- NSString *const BuriedPointTypePlayFreeForceCloseBuy = @"免费试用-强制关闭-去购买";
- NSString *const BuriedPointTypePlayFreeForceCloseCancel = @"免费试用-强制关闭-取消";
- NSString *const BuriedPointTypePlayFreeForceCloseGiveUp = @"免费试用-强制关闭-放弃";
- NSString *const BuriedPointTypePlayFreeForceCloseContinue = @"免费试用-强制关闭-继续观看";
- NSString *const BuriedPointTypePlayFreeCloseBuy = @"免费试用-关闭-去购买";
- NSString *const BuriedPointTypePlayFreeCloseCancel = @"免费试用-关闭-取消";
- @interface BuryPoint () <NSURLSessionDelegate>
- @property (nonatomic, copy) NSMutableArray<NSString *> *pendingUploads; // 待上传的文件所在路径;
- @property (nonatomic, assign) BOOL isFormDataEmpty; // 是否为空表单上传,默认YES
- @property (nonatomic, copy) NSString *currentReport; // 程序本次启动新创建的文件名,上方待上传的文件pendingUploads不包含新创建的文件
- @end
- static BuryPoint *_instance = nil;
- @implementation BuryPoint
- + (instancetype)sharedInstance {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- _instance = [[BuryPoint alloc] init];
- });
- return _instance;
- }
- + (instancetype)allocWithZone:(struct _NSZone *)zone {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- _instance = [super allocWithZone:zone];
- });
- return _instance;
- }
- - (instancetype)copyWithZone:(NSZone *)zone {
- return _instance;
- }
- - (instancetype)init {
- return [self initWithBasePath:self.getBasePath];
- }
- - (instancetype)initWithBasePath:(NSString *)basePath {
- if (self = [super init]) {
-
- // 0.initialized data
- self.isFormDataEmpty = YES;
-
- // 2.获取已存在的异常文件的文件路径
- [self getPendingUploadFiles];
-
- // 3.创建本次的启动日志文件
- [self createNewReportFile];
-
- // 4.上传已存在的日志文件
- [self uploadReportFiles]; /*获取数据上传到服务器*/
-
- }
- return self;
- }
- // 将信息写入到
- - (void)writeContent:(NSString *)content {
- [self write:content filename:self.currentReport];
- }
- - (void)write:(NSString *)content filename:(NSString *)filename {
- if (!filename) {
- return;
- }
- @try {
- NSString *path = [self getReportsDirectory];
- if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
- // 创建日志文件的绝对路径
- [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
- }
-
- NSString *filePath = [path stringByAppendingPathComponent:filename];
- if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
- [content writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
- return;
- }
-
- NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
- // 将写入文件操作的指针跳到文件的末端
- [fileHandle seekToEndOfFile];
- // 追加写入数据
- [fileHandle writeData:[[NSString stringWithFormat:@"\n%@", content] dataUsingEncoding:NSUTF8StringEncoding]];
- [fileHandle closeFile];
- }
- @catch (NSException *exception) {
-
- }
- @finally {
-
- }
- }
- - (void)clearCrashFile {
- [self clearFile:self.currentReport];
- }
- - (void)clearFile:(NSString *)filename {
- @try {
- NSString *path = self.getReportsDirectory;
- if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
- // 创建日志文件的绝对路径
- [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
- }
-
- NSString *filePath = [path stringByAppendingPathComponent:filename];
- if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
- NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
- // 将写入文件操作的指针跳到文件的末端
- [fileHandle truncateFileAtOffset:0];
- [fileHandle closeFile];
- }
- }
- @catch (NSException *exception) {
- HLog(@"[BuryPoint] clear local file error with exception:\n%@", exception);
- }
- @finally {
-
- }
- }
- /**
- 根据本地文件的全路径,删除文件
-
- @param fullPath 全路径
- */
- - (BOOL)removeLocalFileWithFullPath:(NSString *)fullPath {
- BOOL result = NO;
- NSError *error = nil;
- if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
- result = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
- }
- if (error) {
- HLog(@"[BuryPoint] remove local file with error: %@.", error);
- }
- return result;
- }
- - (void)uploadReportFiles {
- NSArray *paths = [self.pendingUploads copy];
- if (paths.count == 0) {
- return;
- }
- [self uploadBuryPointData:paths];
- }
- - (void)uploadBuryPointData:(NSArray<NSString *> *)filePaths
- {
- NSMutableArray *emptyFileFullPaths = [NSMutableArray array];
- NSMutableArray *uploadFileFullPaths = [NSMutableArray array];
-
- NSMutableArray *dataArray = [[NSMutableArray alloc] init];
- for (NSString *obj in filePaths) {
- NSData *data = [NSData dataWithContentsOfFile:obj];
- NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- NSArray *strARy = [dataStr componentsSeparatedByString:@"__"];
- for (NSString *subStr in strARy) {
- // HLog(@"subStr %@ subStrCount %lu",subStr, (unsigned long)subStr.length);
- if (subStr.length > 0) { //去除换行或者空数据
- BuryPointModel *model = [subStr mj_JSONObject];
- NSDictionary *dic = [model mj_keyValues];
- [dataArray addObject:dic];
- }
- }
- // HLog(@"dataStr %@ strARy %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], strARy);
-
- // 如果是有数据才进行拼接并且上传
- if (data.length) {
- self.isFormDataEmpty = NO;
- [uploadFileFullPaths addObject:obj];
- }
- else { // 否则本地的空文件直接删除
- if ([self.pendingUploads containsObject:obj]) {
- [self.pendingUploads removeObject:obj];
- [emptyFileFullPaths addObject:obj];
- }
- }
- }
-
- // 如果上传的文件都为空,则不进行下方的上传操作
- if (self.isFormDataEmpty) {
- return;
- }
-
- for (NSString *path in emptyFileFullPaths) {
- [self removeLocalFileWithFullPath:path];
- }
-
- for (NSString *path in uploadFileFullPaths) {
- [self removeLocalFileWithFullPath:path];
- }
-
- // [[UseAccountManage shareInstance] extensionPublicToBuryPointPostCallBackCode:PostBurialSiteLogAPI Parameters:dataArray success:^(id _Nonnull responseObject) {
- // SuperModel *mod = [[SuperModel alloc] initWithDictionary:responseObject error:nil];
- // if (mod.status && mod.status.integerValue == 0) {
- // //上传成功后把文件缓存清除
- // for (NSString *path in uploadFileFullPaths) {
- // [self removeLocalFileWithFullPath:path];
- // }
- // }
- // } failure:^(NSError * _Nonnull error) {
- //
- // }];
- }
- /**
- 获取应用程序的BundleName
- */
- - (NSString *)getBundleName {
- NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
- if (!bundleName) {
- bundleName = @"Unknown";
- }
- return bundleName;
- }
- /**
- 获取Log日志存储的位置
-
- ~/Library/Caches/BuryPoint/JoyLite/Reports/...
-
- @return 日志文件所在路径
- */
- - (NSString *)getBasePath {
- NSArray *directories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
-
- if (0 == directories.count) {
- HLog(@"Could not locate caches directory path.");
- return nil;
- }
-
- NSString *cachesPath = [directories firstObject];
- if (0 == cachesPath.length) {
- HLog(@"Could not locate caches directory path.");
- return nil;
- }
-
- NSString *path = [@"BuryPoint" stringByAppendingPathComponent:[self getBundleName]];
-
- return [cachesPath stringByAppendingPathComponent:path];
- }
- /**
- 获取日志文件存储所在的目录文件路径
- ~/Library/Caches/BuryPoint/双子星云手机/Reports/...
- */
- - (NSString *)getReportsDirectory {
- return [self.getBasePath stringByAppendingPathComponent:@"Reports"];
- }
- /**
- 获取待上传的文件列表
- */
- - (void)getPendingUploadFiles {
- // 所查找文件夹的路径
- NSString *reportPath = [self getReportsDirectory];
- // 目录迭代器
- NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:reportPath];
- NSMutableArray<NSString *> *array = [NSMutableArray array];
- for (NSString *name in enumerator) {
- if ([name.pathExtension isEqualToString:@"txt"]) {
-
- [array addObject:[[self getReportsDirectory] stringByAppendingPathComponent:name]];
- }
- }
-
- [self.pendingUploads addObjectsFromArray:array];
-
- //修改本地文件保存最大数量
- while ([self.pendingUploads count] > 50)
- {
- NSString *path = [self.pendingUploads firstObject];
-
- [self removeLocalFileWithFullPath:path];
- [self.pendingUploads removeObject:path];
- }
- }
- /**
- 每次崩溃时,信息保存的文件名称
- */
- - (void)createNewReportFile {
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- dateFormatter.dateFormat = @"yyyy.MM.dd_HH.mm.ss.ssss";
- NSString *filename = [NSString stringWithFormat:@"log_%@_ios.txt", [dateFormatter stringFromDate:[NSDate date]]];
- [[NSFileManager defaultManager] createFileAtPath:[[self getReportsDirectory] stringByAppendingPathComponent:filename] contents:nil attributes:nil];
- self.currentReport = [filename copy];
- }
- - (NSString *)getHttpRequestURLString {
- NSString *result = [HWDataManager getStringWithKey:@"chinaArea"];
- if ([result isEqualToString:@"1"]) { // 国内
- return HTTP_REQUEST_URL_STRING_CN;
- }
- else { // 国外
- NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
- if ([appID isEqualToString:@"com.jjyang.dadaCamera"] ||
- [appID isEqualToString:@"com.dafeng.dadasmartcam"]) { // 大丰项目
- return HTTP_REQUEST_URL_STRING_IO_DF;
- }
- else {
- return HTTP_REQUEST_URL_STRING_IO;
- }
- }
- }
- - (NSMutableArray<NSString *> *)pendingUploads {
- if (!_pendingUploads) {
- _pendingUploads = [NSMutableArray array];
- }
- return _pendingUploads;
- }
- // 类似:2EAA6CEC-6BAC-43B2-84B2-E528D03C01FD,总长36.
- - (NSString *)fetchDeviceUUID {
- NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString;
- return uuid;
- }
- + (void)reportBuriedPointWithType:(NSString *)type {
-
- NSMutableDictionary *params = [NSMutableDictionary dictionary];
- [params setObject:type forKey:@"pointName"];
-
- [[UseAccountManage shareInstance] CommonPostCallBackCode:TabBarItemClickAPI Parameters:params success:^(id _Nonnull responseObject) {
-
- } failure:^(NSError * _Nonnull error) {
- HLog(@"%@", error);
- }];
- }
- #pragma mark - 全新埋点 7.1
- /** 保存或更新埋点数组缓存数据 */
- + (void)saveHWBuryPointModelListWithModel:(HWBuryPointModel *)model {
- // NSArray *dataSource = [HWBuryPointModel bg_findAll:DB_HWBuryPointModelList_TableName];
-
- // 更新数据库
- model.bg_tableName = DB_HWBuryPointModelList_TableName;
- [model bg_saveOrUpdateAsync:^(BOOL isSuccess) {
- HLog(@"HWBuryPointModel 更新: %@", isSuccess ? @"成功":@"失败");
- }];
- }
- + (void)updateBuryPointModelListWithModel:(HWBuryPointModel *)model{
- NSMutableArray *dictArr = [NSMutableArray array];
- NSDictionary *dict = [model mj_keyValues];
- [dictArr addObject:dict];
-
- [[UseAccountManage shareInstance] extensionPublicToBuryPointPostCallBackCode:NewBuryPointAPI Parameters:dictArr success:^(id _Nonnull responseObject) {
-
- if (CODE == 0) {
- HLog(@"\n实时上报完成")
- }
-
- } failure:^(NSError * _Nonnull error) {
- HLog(@"%@",error)
- }];
- }
- /** 读取埋点数组缓存数据 */
- + (NSMutableArray *)readHWBuryPointModelList {
- NSMutableArray *array = [NSMutableArray array];
- NSArray *dataSource = [HWBuryPointModel bg_findAll:DB_HWBuryPointModelList_TableName];
- for (HWBuryPointModel *model in dataSource) {
- [array addObject:model];
- }
- return array;
- }
- /** 清空埋点数组缓存数据 */
- + (void)clearHWBuryPointModelList {
- [HWBuryPointModel bg_clearAsync:DB_HWBuryPointModelList_TableName complete:^(BOOL isSuccess) {
- HLog(@"HWBuryPointModel 数据清空: %@", isSuccess ? @"成功":@"失败");
- }];
- }
- @end
|