Commit 9172ebcf authored by 乔金柱's avatar 乔金柱

Merge branch 'lym/phobos' into 'master'

Lym/phobos

See merge request !67
parents b69e3137 ad9814f5
......@@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */
53FEA2B1456611226517963E /* Pods_GMPhobos_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 307F0A9AE09C3400AA3E80C3 /* Pods_GMPhobos_Example.framework */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
......@@ -100,7 +99,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
53FEA2B1456611226517963E /* Pods_GMPhobos_Example.framework in Frameworks */,
......@@ -439,18 +437,18 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${BUILT_PRODUCTS_DIR}/GMCache/GMCache.framework",
"${BUILT_PRODUCTS_DIR}/GMPhobos/GMPhobos.framework",
"${BUILT_PRODUCTS_DIR}/MJExtension/MJExtension.framework",
"${BUILT_PRODUCTS_DIR}/MagicalRecord/MagicalRecord.framework",
"${BUILT_PRODUCTS_DIR}/TMCache/TMCache.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMCache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMPhobos.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJExtension.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MagicalRecord.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TMCache.framework",
);
runOnlyForDeploymentPostprocessing = 0;
......
......@@ -22,7 +22,11 @@ NSString *const MockEventId = @"eventId";
NSString *const MockUserId = @"1";
NSString *const MockCityId = @"beijing";
@interface GMViewController ()
@interface GMViewController ()<UITableViewDelegate ,UITableViewDataSource>
{
UITableView *_tableView;
NSArray *_dataSource;
}
@end
......@@ -31,12 +35,126 @@ NSString *const MockCityId = @"beijing";
- (void)viewDidLoad
{
[super viewDidLoad];
[self sdk];
_dataSource = @[
@"pageView",
@"100个线程 * 100数据",
@"计数发送",
@"瞬间发送",
@"瞬间发送和计数发送",
@"表中有多少条数据",
@"清空数据"
];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
[self.view addSubview:_tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.count + 100;
}
#ifdef POD_CONFIGURATION_APP_STORE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (indexPath.row < _dataSource.count) {
cell.textLabel.text = _dataSource[indexPath.row];
} else {
cell.textLabel.text = [NSString stringWithFormat:@"%ld", indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= _dataSource.count) return;
switch (indexPath.row) {
case 0: //pageView
{
for (int i = 0; i < 20; i++) {
[self pageView:i];
}
}
break;
case 1://100个线程 * 100数据"
{
dispatch_queue_t queue = dispatch_queue_create("lym", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 100; i++) {
dispatch_async(queue, ^{
for (int j = 0; j< 100; j++) {
[Phobos track:@"100*100" attributes:@{@"index":@(i)} sendNow:NO];
}
});
}
}
break;
case 2://@"计数发送",
{
for (int i = 0; i< 10000; i++) {
[Phobos track:@"计数发送" attributes:@{@"index":@(i)} sendNow:NO];
}
NSLog(@"&&&&&&&&&&&&&&&&&");
}
break;
case 3://@"瞬间发送",
{
[Phobos track:@"瞬间发送" attributes:@{@"index":@(0)} sendNow:YES];
}
break;
case 4://瞬间发送和计数发送
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (int i = 0; i< 1000; i++) {
[Phobos track:@"瞬间发送和计数发送" attributes:@{@"index":@(i)} sendNow:i % 9];
}
});
}
break;
case 5://表中有多少条数据
{
[Phobos fetchToBeSendPhobosDataCount];
}
break;
case 6://清空数据
{
[Phobos removeAllPhobosData];
}
break;
default:
break;
}
}
-(void)pageView:(int)index {
NSString *inDate = [PhobosUtil currentTime];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:inDate forKey:@"in"];
[dict setObject:@"home" forKey:@"page_name"];
[dict setObject:@"referrer" forKey:@"referrer"];
[dict setObject:@"referrer" forKey:@"referrer"];
[dict setObject:@(0) forKey:@"fake"];
[dict setObject:@"referrer_id" forKey:@"referrer_id"];
[dict setObject:@"extra_param" forKey:@"extra_param"];
[dict setObject:@"referrer_tab_name" forKey:@"referrer_tab_name"];
[dict setObject:@(0) forKey:@"is_push"];
[dict setObject:@[@"home", @"search_home"] forKey:@"referrer_link"];
NSString *name = [NSString stringWithFormat:@"page_view-%d", index];
[Phobos track:name attributes:dict];
}
- (void)sdk {
#ifdef POD_CONFIGURATION_APP_STORE
NSString *url = @"http://log.gmei.com/log/collect";
#else
#else
NSString *url = @"http://log.test.igengmei.com/log/collect";
#endif
#endif
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:PhobosGray];
Phobos *client = [Phobos clientWithAppName:MockAppName channelId:MockChannelId];
[Phobos setSharedClient:client];
......@@ -47,46 +165,7 @@ NSString *const MockCityId = @"beijing";
Phobos.sharedClient.getTopController = ^UIViewController * _Nonnull{
return self;
};
NSString *inDate = [PhobosUtil currentTime];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:inDate forKey:@"in"];
[dict setObject:@"test" forKey:@"page_name"];
[dict setObject:@"" forKey:@"business_id"];
[dict setObject:@"" forKey:@"referrer"];
[dict setObject:@(0) forKey:@"fake"];
[dict setObject:@"" forKey:@"referrer_id"];
[dict setObject:@"" forKey:@"extra_param"];
[dict setObject:@"" forKey:@"referrer_tab_name"];
[dict setObject:@(0) forKey:@"is_push"];
[dict setObject:@(0) forKey:@"is_first"];
// [Phobos track:@"page_view" attributes:dict];
// NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//
// [Phobos track:@"page_view" attributes:dict];
// array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
for (int i = 0; i < 200; i++) {
[Phobos track:[NSString stringWithFormat:@"tt-%d", i] attributes:dict sendNow:YES];
[Phobos track:[NSString stringWithFormat:@"pv-%d", i] attributes:dict sendNow:(arc4random() % 2 == 0)];
}
for (int i = 5; i < 5; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[Phobos track:[NSString stringWithFormat:@"ay-%d", i] attributes:dict sendNow:YES];
});
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
swiftVC *vc = [swiftVC new];
[self presentViewController:vc animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
PODS:
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- GMCache (1.0.1):
- TMCache (= 2.1.0)
- GMPhobos (2.1.2):
- GMPhobos (2.1.6):
- FMDB
- GMCache
- MagicalRecord
- MJExtension
- MagicalRecord (2.3.2):
- MagicalRecord/Core (= 2.3.2)
- MagicalRecord/Core (2.3.2)
- MJExtension (3.2.1)
- TMCache (2.1.0)
......@@ -18,7 +18,7 @@ SPEC REPOS:
"git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git":
- GMCache
https://github.com/CocoaPods/Specs.git:
- MagicalRecord
- FMDB
- MJExtension
- TMCache
......@@ -27,12 +27,12 @@ EXTERNAL SOURCES:
:path: "../"
SPEC CHECKSUMS:
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMPhobos: b86a68a2d1d5a40cebc0f1d89306fe86907371cf
MagicalRecord: 53bed74b4323b930992a725be713e53b37d19755
GMPhobos: 362953ef30431bd6a5bb4d96acdf9b9f55cedf32
MJExtension: 635f2c663dcb1bf76fa4b715b2570a5710aec545
TMCache: 95ebcc9b3c7e90fb5fd8fc3036cba3aa781c9bed
PODFILE CHECKSUM: ea0fac2144ac80baf8f21576cde49526c19991ad
COCOAPODS: 1.9.3
COCOAPODS: 1.10.0.beta.1
......@@ -26,7 +26,7 @@ Pod::Spec.new do |s|
s.source_files = 'GMPhobos/Classes/**/*'
s.dependency 'GMCache'
s.dependency 'MJExtension'
s.dependency 'MagicalRecord'
s.dependency 'FMDB'
s.library = 'z'
s.resource = 'GMPhobos/*.xcdatamodeld'
......
......@@ -34,8 +34,10 @@ typedef NS_ENUM(NSInteger, GMViewTrackerType) {
}; // 记录方式
@interface GMExposureManager : NSObject
/// 设置上报数据地址
@property (nonatomic, copy) NSString *uploadExposureAPI;
/**
* 精准曝光数据上报模式
* 默认为 GMExpoUploadModePage
......
......@@ -173,9 +173,6 @@ NS_ASSUME_NONNULL_BEGIN
/** 获取所有非立即发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount;
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData;
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData;
......
......@@ -32,8 +32,6 @@ static NewPhobos *_sharedClient;
@implementation NewPhobos
static dispatch_semaphore_t _phobos_semaphore;
+ (NewPhobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId{
NewPhobos.sharedClient.appName = appName;
NewPhobos.sharedClient.channelId = channelId;
......@@ -42,7 +40,6 @@ static dispatch_semaphore_t _phobos_semaphore;
- (instancetype)init {
if (self = [super init]) {
_phobos_semaphore = dispatch_semaphore_create(1);
_appName = @"";
_channelId = @"";
_logEnabled = NO;
......@@ -108,14 +105,14 @@ static dispatch_semaphore_t _phobos_semaphore;
- (void)handleEventDeviceOpened{
/** 每次打开APP埋点 **/
NSDictionary *dict = @{@"build_cpu_abi": [PhobosUtil currentDeviceCPUType],
@"cpu_count": [PhobosUtil currentDeviceCPUCount],
@"mac_address": [PhobosUtil getMacAddress],
@"phone_operator": [PhobosUtil getTelephonyInfo],
@"total_memory": [PhobosUtil getTotalMemorySize],
@"run_time": [PhobosUtil deviceRunTime],
@"uuid": [PhobosUtil deviceId],
@"build_version_release": [[UIDevice currentDevice] systemVersion],
NSDictionary *dict = @{@"build_cpu_abi": PhobosSafeString([PhobosUtil currentDeviceCPUType]),
@"cpu_count": PhobosSafeString([PhobosUtil currentDeviceCPUCount]),
@"mac_address": PhobosSafeString([PhobosUtil getMacAddress]),
@"phone_operator": PhobosSafeString([PhobosUtil getTelephonyInfo]),
@"total_memory": PhobosSafeString([PhobosUtil getTotalMemorySize]),
@"run_time": PhobosSafeString([PhobosUtil deviceRunTime]),
@"uuid": PhobosSafeString([PhobosUtil deviceId]),
@"build_version_release": PhobosSafeString([[UIDevice currentDevice] systemVersion]),
};
[NewPhobos track:@"device_opened" attributes:dict sendNow:YES];
}
......@@ -177,7 +174,6 @@ static dispatch_semaphore_t _phobos_semaphore;
phobosLog(@"handleAppInForeground");
[self handleSessionStart];
[self handleEventDeviceOpened];
[NewPhobos disposeSendDataWithImmediately:NO];
[self handlePVEventAppInForeground];
}
......@@ -190,7 +186,6 @@ static dispatch_semaphore_t _phobos_semaphore;
phobosLog(@"handleAppInBackgound");
[self handlePVEventAppInBackgound];
[self handleSessionOver];
[NewPhobos disposeSendDataWithImmediately:NO];
}
/**
......@@ -218,7 +213,7 @@ static dispatch_semaphore_t _phobos_semaphore;
@"uuid": [PhobosUtil deviceId],
@"build_version_release": [[UIDevice currentDevice] systemVersion],
};
[NewPhobos track:@"on_app_session_over" attributes:dict];
[NewPhobos trackSessionOverWithAttributes:dict];
[GMCache removeObjectAtDocumentPathWithkey:PhobosBeginTime];
//当前session结束之后,把id置为0
_serialId = 0;
......@@ -336,7 +331,6 @@ static dispatch_semaphore_t _phobos_semaphore;
[deviceParams setValue:[PhobosUtil getIPAddress:YES] forKey:@"ip"];
[deviceParams setValue:PhobosSafeString(_networkStatus) forKey:@"net_type"];
[deviceParams setValue:PhobosSafeString([PhobosUtil platform]) forKey:@"model"];
[deviceParams setValue:@(_isGray) forKey:@"isGray"];
[deviceParams setValue:PhobosSafeString([UIDevice currentDevice].systemVersion) forKey:@"sys_version"];
NSMutableDictionary *appParams = [NSMutableDictionary new];
......@@ -345,6 +339,7 @@ static dispatch_semaphore_t _phobos_semaphore;
[appParams setValue:PhobosSafeString(_appVersion) forKey:@"version"];
[appParams setValue:PhobosSafeString(_channelId) forKey:@"channel"];
[appParams setValue:PhobosSafeString(_userType) forKey:@"user_type"];
[appParams setValue:@(_isGray) forKey:@"is_gray"];
[appParams setValue:PhobosSafeString(_currentCityId) forKey:@"current_city_id"];
[appParams setValue:@(_serialId++) forKey:@"serial_id"];
......@@ -389,11 +384,11 @@ static dispatch_semaphore_t _phobos_semaphore;
}
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes {
[self track:@"on_cick_button" attributes:attributes];
[self track:@"on_click_button" attributes:attributes];
}
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow {
[self track:@"on_cick_button" attributes:attributes sendNow:sendNow];
[self track:@"on_click_button" attributes:attributes sendNow:sendNow];
}
+ (void)track:(NSString *)eventName{
......@@ -418,47 +413,37 @@ static dispatch_semaphore_t _phobos_semaphore;
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI {
NSDictionary *dataDict = [_sharedClient prepareDictionaryForEvent:eventName attributes:attributes];
@try {
NSData *JSON = [PhobosUtil encodeJSON:dataDict];
[PhobosDataManager insertData:dataDict sendAPI:currentAPI];
[self disposeSendDataWithImmediately:sendNow];
[[PhobosDataManager sharedPhobosDataManager] insertData:dataDict sendAPI:currentAPI phobosType:eventName immediately:sendNow];
} @catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
}
/**
* 处理发送数据
* 为app_session_over提供埋点发送
* 其他情况在写入数据库成功,异步回调后在发送数据
* 这样可以优化发送次数,并能保障数据安全,但因为completion是使用主线程回调的,但进入后台后,主线程会休眠,所以单独处理该埋点
*/
+ (void)disposeSendDataWithImmediately:(BOOL)immediately {
NSInteger count = [PhobosDataManager fetchCountOfToBeSendEntities];
if (immediately || count >= PhobosShardCount) {
dispatch_semaphore_wait(_phobos_semaphore, DISPATCH_TIME_FOREVER);
NSArray<PhobosSendDataEntity *> *entities = [PhobosDataManager fetchToBeSendDataEntities];
[PhobosDataManager updateDataEntities:entities sendStatus:PhobosDataSendStatusSending];
dispatch_semaphore_signal(_phobos_semaphore);
[PhobosSendManager sendDataWithEntities:entities completion:^(NSArray<PhobosSendDataEntity *> * _Nonnull finishEntities, NSInteger code) {
[PhobosDataManager updateDataEntities:finishEntities sendStatus:(code == 200 ? PhobosDataSendStatusFinish : PhobosDataSendStatusError)];
}];
}
+ (void)trackSessionOverWithAttributes:(NSDictionary *)attributes {
NSDictionary *dataDict = [_sharedClient prepareDictionaryForEvent:@"on_app_session_over" attributes:attributes];
[[PhobosDataManager sharedPhobosDataManager] insertData:dataDict sendAPI:_sharedClient.serverAPI phobosType:@"on_app_session_over" immediately:YES];
}
@end
@implementation NewPhobos (UtilTest)
/** 获取所有非立即发送埋点数量 */
///** 获取所有非立即发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount {
return [PhobosDataManager fetchCountOfToBeSendEntities];
}
/** 获取待发送埋点数据, 用同步来保障异步获取数据 */
+ (NSArray *)fetchToBeSendPhobosData {
return [PhobosDataManager fetchToBeSendDataEntities];
return [[PhobosDataManager sharedPhobosDataManager] messageCount] ;
}
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData {
[PhobosDataManager deleteAllEntities];
[[PhobosDataManager sharedPhobosDataManager] removeAll];
}
@end
......@@ -98,14 +98,15 @@ static OldPhobos *sharedClient = nil;
- (void)handleEventDeviceOpened{
/** 每次打开APP埋点 **/
NSDictionary *dict = @{@"build_cpu_abi": [PhobosUtil currentDeviceCPUType],
@"cpu_count": [PhobosUtil currentDeviceCPUCount],
@"mac_address": [PhobosUtil getMacAddress],
@"phone_operator": [PhobosUtil getTelephonyInfo],
@"total_memory": [PhobosUtil getTotalMemorySize],
@"run_time": [PhobosUtil deviceRunTime],
@"uuid": [PhobosUtil deviceId],
@"build_version_release": [[UIDevice currentDevice] systemVersion],
NSDictionary *dict = @{@"build_cpu_abi": PhobosSafeString([PhobosUtil currentDeviceCPUType]),
@"cpu_count": PhobosSafeString([PhobosUtil currentDeviceCPUCount]),
@"mac_address": PhobosSafeString([PhobosUtil getMacAddress]),
@"phone_operator": PhobosSafeString([PhobosUtil getTelephonyInfo]),
@"total_memory": PhobosSafeString([PhobosUtil getTotalMemorySize]),
@"run_time": PhobosSafeString([PhobosUtil deviceRunTime]),
@"uuid": PhobosSafeString([PhobosUtil deviceId]),
@"build_version_release": PhobosSafeString([[UIDevice currentDevice] systemVersion]),
};
[OldPhobos track:@"device_opened" attributes:dict sendNow:YES];
}
......@@ -412,9 +413,9 @@ static OldPhobos *sharedClient = nil;
if (![attributes.allKeys containsObject:@"referrer_link"]) {
NSMutableDictionary *attributesParams = [NSMutableDictionary dictionaryWithDictionary:attributes];
if ([referrerLink isKindOfClass:[NSArray class]] && referrerLink.count) {
[attributesParams setValue:referrerLink forKey:@"referrer_link"];
[attributesParams setValue:[PhobosUtil convertToJsonString:referrerLink] forKey:@"referrer_link"];
} else {
[attributesParams setValue:@[] forKey:@"referrer_link"];
[attributesParams setValue:[PhobosUtil convertToJsonString:@[]] forKey:@"referrer_link"];
}
attributes = attributesParams;
}
......
......@@ -65,7 +65,7 @@ static BOOL isGray = NO;
if (isGray) {
[NewPhobos onClickButtonWithAttributes:attributes];
} else {
[self track:@"on_cick_button" attributes:attributes];
[self track:@"on_click_button" attributes:attributes];
}
}
......@@ -73,7 +73,7 @@ static BOOL isGray = NO;
if (isGray) {
[NewPhobos onClickButtonWithAttributes:attributes sendNow:sendNow];
} else {
[self track:@"on_cick_button" attributes:attributes sendNow:sendNow];
[self track:@"on_click_button" attributes:attributes sendNow:sendNow];
}
}
......@@ -244,10 +244,10 @@ static BOOL isGray = NO;
return isGray ? [NewPhobos fetchToBeSendPhobosDataCount] : 0;
}
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData {
return isGray ? [NewPhobos fetchToBeSendPhobosData] : @[];
}
///** 获取待发送埋点数据 */
//+ (NSArray *)fetchToBeSendPhobosData {
// return isGray ? [NewPhobos fetchToBeSendPhobosData] : @[];
//}
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData {
......
......@@ -16,7 +16,7 @@ typedef NS_ENUM (NSInteger, PhobosSigningType) {
PhobosSigningTypeDebug
};
static NSString *sdkVersion = @"2.0.4";
static NSString *sdkVersion = @"2.0.5";
#ifdef DEBUG
#define phobosLog(...) NSLog(@"[Phobos] %@",__VA_ARGS__)
......
//
// PhobosDataManager.h
// GMCache
//
// Created by Locus on 2020/1/21.
//
#import <Foundation/Foundation.h>
#import <MagicalRecord/MagicalRecord.h>
#import "PhobosSendDataEntity+CoreDataClass.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, PhobosDataSendStatus) {
PhobosDataSendStatusToBeSend = 1, // 待发送数据
PhobosDataSendStatusSending = 2, // 发送中数据
PhobosDataSendStatusFinish = 3, // 发送完成数据
PhobosDataSendStatusError = 4, // 发送失败数据
};
@interface PhobosDataManager : NSObject
/** 获取待发送数据,包含待发送数据和发送失败数据 */
+ (NSArray<PhobosSendDataEntity *> *)fetchToBeSendDataEntities;
/**
* 通过 searchFilter 获取数据
*/
+ (NSArray<PhobosSendDataEntity *> *)fetchDataEntitiesWithPredicate:(NSPredicate *)searchFilter;
/**
* 获取待发送和发送失败的数据数量
*/
+ (NSUInteger)fetchCountOfToBeSendEntities;
/**
* 通过 searchFilter 获取数据数量
*/
+ (NSUInteger)fetchCountOfEntitiesWithPredicate:(NSPredicate *)searchFilter;
/**
* 插入埋点数据
* data 埋点参数
* sendAPI 数据接收的服务器API
* completion 插入数据库成功后的回调方法,在保存完成后调用的完成块。如果发生错误,块将以“BOOL”和“NSError”实例的形式传递成功状态。总是在主队列上调用。
* 该方法调用完成,fetch方法获取相应的数据就可获取到,不需要等completion回调。
*/
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI;
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI completion:(MRSaveCompletionHandler)completion;
/**
* 修改埋点数据
* entities 需要修改的实体
* sendStatus 需要修改为的状态,
* completion 插入数据库成功后的回调方法,在保存完成后调用的完成块。如果发生错误,块将以“BOOL”和“NSError”实例的形式传递成功状态。总是在主队列上调用。
* 该方法调用完成,fetch方法获取相应的数据就可获取到,不需要等completion回调。
*/
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus;
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus completion:(MRSaveCompletionHandler)completion;
/**
* 删除数据
*/
+ (void)deleteDataEntities:(NSArray<PhobosSendDataEntity *> *)entities;
+ (void)deleteAllEntities;
@end
NS_ASSUME_NONNULL_END
//
// PhobosDataManager.m
// GMCache
//
// Created by Locus on 2020/1/21.
//
#import "PhobosDataManager.h"
#import "PhobosSendManager.h"
#import "PhobosConfig.h"
#import "PhobosUtil.h"
#import <MJExtension/MJExtension.h>
#import <mach/mach_time.h>
@implementation PhobosDataManager
static NSManagedObjectContext *PhobosDefaultContext;
static dispatch_semaphore_t phobos_semaphore_t;
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
phobos_semaphore_t = dispatch_semaphore_create(1);
// 创建 NSManagedObjectContext,供埋点库访问CoreData库使用
PhobosDefaultContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
// 获取埋点数据的实体
NSURL *modelURL = [bundle URLForResource:@"GMPhobosData" withExtension:@"momd"];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// 创建持久化存储调度器
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// 创建并关联SQLite数据库文件,如果已经存在则不会重复创建
NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
dataPath = [dataPath stringByAppendingFormat:@"/%@.sqlite",@"GMPhobos"];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:dataPath] options:nil error:nil];
// 设置storeCoordinator
PhobosDefaultContext.persistentStoreCoordinator = coordinator;
/** 将上次没有获取到发送结果的数据的状态修改为发送失败,待下次重新发送 */
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d", PhobosDataSendStatusSending];
NSArray<PhobosSendDataEntity *> *entities = [self fetchDataEntitiesWithPredicate:predicate];
[self updateDataEntities:entities sendStatus:PhobosDataSendStatusError];
/** 将发送成功的数据删除 */
NSPredicate *finishPredicate = [NSPredicate predicateWithFormat:@"status = %d", PhobosDataSendStatusFinish];
NSArray<PhobosSendDataEntity *> *finishEntities = [self fetchDataEntitiesWithPredicate:finishPredicate];
[self deleteDataEntities:finishEntities];
});
}
+ (NSArray<PhobosSendDataEntity *> *)fetchToBeSendDataEntities {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d or status = %d", PhobosDataSendStatusToBeSend, PhobosDataSendStatusError];
return [self fetchDataEntitiesWithPredicate:predicate];
}
+ (NSArray<PhobosSendDataEntity *> *)fetchDataEntitiesWithPredicate:(NSPredicate *)searchFilter {
return [PhobosSendDataEntity MR_findAllWithPredicate:searchFilter inContext:PhobosDefaultContext];
}
+ (NSUInteger)fetchCountOfToBeSendEntities {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d or status = %d", PhobosDataSendStatusToBeSend, PhobosDataSendStatusError];
return [self fetchCountOfEntitiesWithPredicate:predicate];
}
+ (NSUInteger)fetchCountOfEntitiesWithPredicate:(NSPredicate *)searchFilter {
return [[PhobosSendDataEntity MR_numberOfEntitiesWithPredicate:searchFilter inContext:PhobosDefaultContext] integerValue];
}
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI {
[self insertData:data sendAPI:sendAPI completion:nil];
}
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI completion:(MRSaveCompletionHandler)completion {
if (!sendAPI || [sendAPI isEqualToString:@""] || !data) {
return;
}
dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
PhobosSendDataEntity *entity = [PhobosSendDataEntity MR_createEntityInContext:PhobosDefaultContext];
entity.data = [data mj_JSONData];
entity.api = sendAPI;
entity.status = PhobosDataSendStatusToBeSend;
entity.id = mach_absolute_time();
dispatch_semaphore_signal(phobos_semaphore_t);
[self saveWithCompletion:completion];
}
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus {
[self updateDataEntities:entities sendStatus:sendStatus completion:nil];
}
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus completion:(MRSaveCompletionHandler)completion {
if (entities.count > 0) {
dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.status = sendStatus;
}];
dispatch_semaphore_signal(phobos_semaphore_t);
[self saveWithCompletion:completion];
}
}
+ (void)deleteDataEntities:(NSArray<PhobosSendDataEntity *> *)entities {
if (entities.count > 0) {
dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj MR_deleteEntityInContext:PhobosDefaultContext];
}];
dispatch_semaphore_signal(phobos_semaphore_t);
[self saveWithCompletion:nil];
}
}
+ (void)deleteAllEntities {
dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
[PhobosSendDataEntity MR_truncateAllInContext:PhobosDefaultContext];
dispatch_semaphore_signal(phobos_semaphore_t);
[self saveWithCompletion:nil];
}
/**
* 在保存完成后调用的完成块。如果发生错误,块将以“BOOL”和“NSError”实例的形式传递成功状态。总是在主队列上调用。
*/
+ (void)saveWithCompletion:(MRSaveCompletionHandler)completion {
[PhobosDefaultContext MR_saveOnlySelfWithCompletion:completion];
}
@end
//
// GMPhobosPageViewModel.h
// GMPhobos
//
// Created by edz on 2020/6/22.
//
#import "GMPhobosSqulitModel.h"
@interface GMPhobosPageViewModel : GMPhobosSqulitModel
@property (nonatomic, strong) NSString * gm_out;
@property (nonatomic, strong) NSString * gm_in;
@property (nonatomic, strong) NSString * gm_page_name;
@property (nonatomic, strong) NSString * gm_business_id;
@property (nonatomic, strong) NSString * gm_referrer;
@property (nonatomic, strong) NSString * gm_referrer_link;
@property (nonatomic, strong) NSString * gm_referrer_id;
@property (nonatomic, strong) NSString * gm_extra_param;
@property (nonatomic, strong) NSString * gm_referrer_tab_name;
@property (nonatomic, strong) NSString * gm_is_push;
@property (nonatomic, strong) NSString * gm_message_id;
@property (nonatomic, strong) NSString * gm_in_time_millis;
@property (nonatomic, strong) NSString * gm_out_time_millis;
@property (nonatomic, strong) NSString * gm_is_first;
+ (GMPhobosPageViewModel *)pageViewModelOfDict:(NSDictionary *)data
type:(NSString *)phobosType
urlApi:(NSString *)urlapi
tableName:(NSString *)name
immediately:(BOOL)status;
@end
//
// GMPhobosPageViewModel.m
// GMPhobos
//
// Created by edz on 2020/6/22.
//
#import "GMPhobosPageViewModel.h"
@implementation GMPhobosPageViewModel
+ (GMPhobosPageViewModel *)pageViewModelOfDict:(NSDictionary *)dict
type:(NSString *)phobosType
urlApi:(NSString *)urlapi
tableName:(NSString *)name
immediately:(BOOL)status {
GMPhobosPageViewModel *model = [[GMPhobosPageViewModel alloc] init];
//共有参数
model.table_name = name;
NSTimeInterval time = [[NSDate date] timeIntervalSince1970] * 1000;
model.message_item_id = [NSString stringWithFormat:@"%.f/%lld", time, mach_absolute_time()];
NSMutableDictionary *messageDict = [NSMutableDictionary dictionaryWithDictionary:dict];
[messageDict setValue:model.message_item_id forKey:@"message_item_id"];
model.data = [GMPhobosTool dictionaryToJsonString:messageDict];
model.status = PhobosDataSendStatus_wait;
model.phobos_type = phobosType;
model.api = urlapi;
model.immediately = status;
//私有参数
NSDictionary *data = dict[@"params"];
model.gm_out = data[@"out"];
model.gm_in = data[@"in"];
model.gm_page_name = data[@"page_name"];
model.gm_business_id = data[@"business_id"];
model.gm_referrer = data[@"referrer"];
model.gm_referrer_link = data[@"referrer_link"];
model.gm_referrer_id = data[@"referrer_id"];
model.gm_extra_param = data[@"extra_param"];
model.gm_referrer_tab_name = data[@"referrer_tab_name"];
model.gm_is_push = data[@"is_push"];
model.gm_message_id = data[@"message_id"];
model.gm_in_time_millis= data[@"in_time_millis"];
model.gm_out_time_millis = data[@"out_time_millis"];
model.gm_is_first = data[@"is_first"];
return model;
}
@end
//
// GMPhobosSqulitModel.h
// GMPhobos
//
// Created by edz on 2020/6/18.
//
#import <Foundation/Foundation.h>
#import "GMPhobosTool.h"
#import <mach/mach_time.h>
typedef NS_ENUM(int, PhobosDataSendStatus) {
PhobosDataSendStatus_wait = 1, // 待发送数据
PhobosDataSendStatus_send = 2, // 发送中数据
PhobosDataSendStatus_finish = 3, // 发送完成数据
PhobosDataSendStatus_error = 4, // 发送失败数据
};
@interface GMPhobosSqulitModel : NSObject
/// 唯一标识(用于筛选)
@property (nonatomic, strong) NSString *message_item_id;
/// 埋点类型
@property (nonatomic, strong) NSString *phobos_type;
/// 内容
@property (nonatomic, strong) NSString *data;
/// 路径
@property (nonatomic, strong) NSString *api;
///插入表格名称
@property (nonatomic, strong) NSString *table_name;
/// 数据状态
@property (nonatomic, assign) PhobosDataSendStatus status;
///是否是立刻发的埋点
@property (nonatomic, assign) BOOL immediately;
+ (GMPhobosSqulitModel *)modelOfDict:(NSDictionary *)data
type:(NSString *)phobosType
urlApi:(NSString *)urlapi
tableName:(NSString *)name
immediately:(BOOL)status;
@end
//
// GMPhobosSqulitModel.m
// GMPhobos
//
// Created by edz on 2020/6/18.
//
#import "GMPhobosSqulitModel.h"
@implementation GMPhobosSqulitModel
+ (GMPhobosSqulitModel *)modelOfDict:(NSDictionary *)data
type:(NSString *)phobosType
urlApi:(NSString *)urlapi
tableName:(NSString *)name
immediately:(BOOL)status{
GMPhobosSqulitModel *model = [GMPhobosSqulitModel new];
model.table_name = name;
NSTimeInterval time = [[NSDate date] timeIntervalSince1970] * 1000;
model.message_item_id = [NSString stringWithFormat:@"%.f/%lld", time, mach_absolute_time()];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:data];
[dict setValue:model.message_item_id forKey:@"message_item_id"];
model.data = [GMPhobosTool dictionaryToJsonString:dict];
model.status = PhobosDataSendStatus_wait;
model.phobos_type = phobosType;
model.api = urlapi;
model.immediately = status;
return model;
}
@end
//
// PhobosSendDataEntity+CoreDataClass.h
// GMPhobosThread.h
// GMPhobos
//
// Created by Locus on 2020/3/9.
//
// Created by edz on 2020/6/21.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
NS_ASSUME_NONNULL_BEGIN
@interface PhobosSendDataEntity : NSManagedObject
@interface GMPhobosThread : NSThread
@end
NS_ASSUME_NONNULL_END
#import "PhobosSendDataEntity+CoreDataProperties.h"
//
// GMPhobosThread.m
// GMPhobos
//
// Created by edz on 2020/6/21.
//
#import "GMPhobosThread.h"
@implementation GMPhobosThread
- (void)dealloc {
NSLog(@"%s", __func__);
}
@end
//
// GMPhobosTool.h
// GMPhobos
//
// Created by edz on 2020/6/23.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface GMPhobosTool : NSObject
/// 拆分数组
/// @param array 原数组
/// @param subSize 每个数组的长度
+ (NSArray *)splitArray:(NSArray *)array withSubSize:(int)subSize;
/// dictionary 转json
/// @param dict dict
+ (NSString *)dictionaryToJsonString:(NSDictionary *)dict;
@end
NS_ASSUME_NONNULL_END
//
// GMPhobosTool.m
// GMPhobos
//
// Created by edz on 2020/6/23.
//
#import "GMPhobosTool.h"
@implementation GMPhobosTool
#pragma mark - 把数组分割成二维数组
+ (NSArray *)splitArray:(NSArray *)array withSubSize:(int)subSize {
if (subSize < 1) return [NSArray new];
// 数组将被拆分成指定长度数组的个数
unsigned long count = array.count % subSize == 0 ? (array.count / subSize) : (array.count / subSize + 1);
// 用来保存指定长度数组的可变数组对象
NSMutableArray *arr = [[NSMutableArray alloc] init];
//利用总个数进行循环,将指定长度的元素加入数组
for (int i = 0; i < count; i ++) {
//数组下标
int index = i * subSize;
//保存拆分的固定长度的数组元素的可变数组
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
//移除子数组的所有元素
[arr1 removeAllObjects];
int j = index;
//将数组下标乘以1、2、3,得到拆分时数组的最大下标值,但最大不能超过数组的总大小
while (j < subSize*(i + 1) && j < array.count) {
[arr1 addObject:[array objectAtIndex:j]];
j += 1;
}
//将子数组添加到保存子数组的数组中
[arr addObject:[arr1 copy]];
}
return [arr copy];
}
+ (NSString *)dictionaryToJsonString:(NSDictionary *)dict
{
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
if (error) {
return nil;
}
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
@end
//
// GMSQliteManager.h
// GMSQlite
//
// Created by 卢悦明 on 2020/6/10.
// Copyright © 2020 卢悦明. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MJExtension/MJExtension.h>
// 数据库中常见的几种类型
#define SQL_TEXT @"TEXT" //文本
#define SQL_INTEGER @"INTEGER" //int long integer ...
#define SQL_REAL @"REAL" //浮点
#define SQL_BLOB @"BLOB" //data
@interface GMSQliteManager : NSObject
#pragma mark - 创建表
/// 创建表
/// @param tableName 名称
/// @param modelClass 类对象
- (BOOL)gm_createTable:(NSString *)tableName model:(Class)modelClass;
/// 创建表
/// @param tableName 名称
/// @param dict key 为键, value为存储类型
- (BOOL)gm_createTable:(NSString *)tableName dict:(NSDictionary *)dict;
#pragma mark - 插入操作
///字典插入
- (BOOL)gm_insertTable:(NSString *)tableName dict:(NSDictionary *)dict;
/// 模型插入
- (BOOL)gm_insertTable:(NSString *)tableName model:(NSObject *)model;
/**
批量插入或更改
@param dicOrModelArray 要insert/update数据的数组,也可以将model和dictionary混合装入array
@return 返回的数组存储未插入成功的下标,数组中元素类型为NSNumber
*/
- (NSArray *)gm_insertTable:(NSString *)tableName dicOrModelArray:(NSArray *)dicOrModelArray;
#pragma mark - 删除操作
/// 删除表中某些元素,
/// @param tableName 表的名称
/// @param format 条件语句, 如:@"where name = '小李'"
- (BOOL)gm_deleteTable:(NSString *)tableName whereFormat:(NSString *)format;
///删除表
- (BOOL)gm_deleteTable:(NSString *)tableName;
///清空表
- (BOOL)gm_deleteAllDataFromTable:(NSString *)tableName;
#pragma mark - 修改操作
/// 根据条件更改表中数据
/// @param tableName 名称
/// @param parameters 要更改的数据,可以是model或dictionary(格式:@{@"name":@"张三"})
/// @param format 条件语句, 如:@"where name = '小李'"
- (BOOL)gm_updateTable:(NSString *)tableName
dicOrModel:(id)parameters
whereFormat:(NSString *)format;
#pragma mark - 查找操作
/**
查找: 根据条件查找表中数据
@param tableName 表的名称
@param filterArray 过滤字段
@param cls [Persen class]
@param format 条件语句, 如:@"where name = '小李'",
@return 将结果存入array, @[@{@"age":@"", @"name":@""}]
*/
- (NSArray *)gm_lookupTable:(NSString *)tableName
filterArray:(NSArray *)filterArray
objectClass:(Class)cls
whereFormat:(NSString *)format;
- (NSArray *)gm_lookupTable:(NSString *)tableName
keyArray:(NSArray *)keyArray
whereFormat:(NSString *)format;
#pragma mark - 辅助接口
///是否存在表
- (BOOL)gm_isExistTable:(NSString *)tableName;
/// 表中共有多少条数据
/// @param tableName 表的名称
/// @param format 筛选条件(where name = '小李'), 如果没有条件可以传nil
- (int)gm_tableItemCount:(NSString *)tableName whereFormat:(NSString *)format;
/// 返回表中的字段名
- (NSArray *)gm_columnNameArray:(NSString *)tableName;
/// `关闭数据库
- (void)close;
/// 打开数据库 (每次shareDatabase系列操作时已经open,当调用close后若进行db操作需重新open或调用shareDatabase)
- (void)open;
/**
增加新字段, 在建表后还想新增字段,可以在原建表model或新model中新增对应属性,然后传入即可新增该字段,该操作已在事务中执行
@param tableName 表的名称
@param parameters dictionary格式为@{@"newname":@"TEXT"}
@return 是否成功
*/
- (BOOL)gm_alterTable:(NSString *)tableName keyDict:(NSDictionary *)parameters;
// ============================= 线程安全操作 ===============================
#pragma mark - 线程安全的处理
/**
将操作语句放入block中即可保证线程安全, 如:
Person *p = [[Person alloc] init];
p.name = @"小李";
[db gm_inDatabase:^{
[db gm_insertTable:@"users" dicOrModel:p];
}];
*/
- (void)gm_inDatabase:(void (^)(void))block;
/**
事务: 将操作语句放入block中可执行回滚操作(*rollback = YES;)
Person *p = [[Person alloc] init];
p.name = @"小李";
for (int i=0,i < 1000,i++) {
[db gm_inTransaction:^(BOOL *rollback) {
BOOL flag = [db gm_insertTable:@"users" dicOrModel:p];
if (!flag) {
*rollback = YES; //只要有一次不成功,则进行回滚操作
return;
}
}];
}
*/
- (void)gm_inTransaction:(void(^)(BOOL *rollback))block;
@end
This diff is collapsed.
//
// PhobosDataManager.h
// GMCache
//
// Created by Locus on 2020/1/21.
//
#import <Foundation/Foundation.h>
@interface PhobosDataManager : NSObject
/// 初始化方法(单利)
+ (PhobosDataManager *)sharedPhobosDataManager;
/// 插入数据的方法 (如果返回的是NO,就会直接把数据发送出去,不放到数据控中)
/// @param data 埋点数据dict
/// @param sendAPI 发送的url
/// @param phoboType 埋点类型
/// @param status 是否是立即发送的埋点
- (void)insertData:(NSDictionary *)data
sendAPI:(NSString *)sendAPI
phobosType:(NSString *)phoboType
immediately:(BOOL)status;
- (void)removeAll;
- (int)messageCount;
@end
//
// PhobosDataManager.m
// GMCache
//
// Created by Locus on 2020/1/21.
//
#import "PhobosDataManager.h"
#import "PhobosSendManager.h"
#import "PhobosConfig.h"
#import "PhobosUtil.h"
#import "GMSQliteManager.h"
#import "GMPhobosSqulitModel.h"
#import "GMPhobosPageViewModel.h"
#import <MJExtension/MJExtension.h>
#import "GMPhobosThread.h"
#import "GMPhobosTool.h"
#define KtableName @"phobosTable"
#define KPageViewTableName @"pageViewTable"
#define KName @"tableName"
#define KClass @"class"
@interface PhobosDataManager ()
//数据库操作对象(单利)
@property (nonatomic, strong) GMSQliteManager *squlitManager;
/// 记录没有发送的数据个数(大于50 就要发送数据)
@property (nonatomic, assign) NSInteger messageCont;
/// runloop线程,用来处理埋点的数据
@property (nonatomic, strong) GMPhobosThread *phobosThread;
@property (nonatomic, strong) NSArray *tableMessageArray;
@end
@implementation PhobosDataManager
static PhobosDataManager *dataManager;
+ (PhobosDataManager *)sharedPhobosDataManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataManager = [[PhobosDataManager alloc] init];
});
return dataManager;
}
- (instancetype)init {
self = [super init];
if (self) {
_tableMessageArray = @[
@{
KName:KtableName,
KClass:[GMPhobosSqulitModel class]
},
@{
KName:KPageViewTableName,
KClass:[GMPhobosPageViewModel class]
}
];
[self setupSDK];
}
return self;
}
- (void)removeAll {
[self performSelector:@selector(remove) onThread:_phobosThread withObject:nil waitUntilDone:YES];
}
- (void)remove {
bool status = [_squlitManager gm_deleteAllDataFromTable:KtableName];
bool status1 = [_squlitManager gm_deleteAllDataFromTable:KPageViewTableName];
NSLog(@"清空表格数状态-KtableName:%d KPageViewTableName:%d",status,status1);
}
- (int)messageCount {
int count = [_squlitManager gm_tableItemCount:KtableName whereFormat:nil];
int count1 = [_squlitManager gm_tableItemCount:KPageViewTableName whereFormat:nil];
NSLog(@"数据总数:%d - KtableName:%d KPageViewTableName:%d", count + count1, count, count1);
return count;
}
#pragma mark - 初始化
- (void)setupSDK {
//创建数据库和表格
_squlitManager = [[GMSQliteManager alloc] init];
for (NSDictionary *dict in _tableMessageArray) {
[_squlitManager gm_createTable:dict[KName] model:dict[KClass]];
}
//初始化线程和runloop
__weak typeof(self) weakSelf = self;
_phobosThread = [[GMPhobosThread alloc] initWithBlock:^{
[[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
while (weakSelf) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}];
_phobosThread.name = @"phobosThread";
[_phobosThread start];
//修改数据
[self performSelector:@selector(resetData) onThread:_phobosThread withObject:nil waitUntilDone:NO];
}
#pragma mark - 方法只用在APP启动的时候
- (void)resetData {
for (NSDictionary *dict in _tableMessageArray) {
/** 将上次没有获取到发送结果的数据的状态修改为发送失败,待下次重新发送 */
NSString *whereStr = [NSString stringWithFormat:@"where status = %d", PhobosDataSendStatus_send];
[_squlitManager gm_updateTable:dict[KName] dicOrModel:@{@"status":@(PhobosDataSendStatus_error)} whereFormat:whereStr];
/** 将发送成功的数据删除 */
NSString *whereDelet = [NSString stringWithFormat:@"where status = %d", PhobosDataSendStatus_finish];
[_squlitManager gm_deleteTable:dict[KName] whereFormat:whereDelet];
}
}
#pragma mark - 插入数据
- (void)insertData:(NSDictionary *)data
sendAPI:(NSString *)sendAPI
phobosType:(NSString *)phoboType
immediately:(BOOL)status {
if (!sendAPI || [sendAPI isEqualToString:@""] || !data) return;
if ([phoboType containsString:@"page_view"]) {
GMPhobosPageViewModel *squlitModel = [GMPhobosPageViewModel pageViewModelOfDict:data type:phoboType urlApi:sendAPI tableName:KPageViewTableName immediately:status];
[self performSelector:@selector(insertModel:) onThread:_phobosThread withObject:squlitModel waitUntilDone:NO];
} else {
GMPhobosSqulitModel *squlitModel = [GMPhobosSqulitModel modelOfDict:data type:phoboType urlApi:sendAPI tableName:KtableName immediately:status];
[self performSelector:@selector(insertModel:) onThread:_phobosThread withObject:squlitModel waitUntilDone:NO];
}
}
- (void)insertModel:(GMPhobosSqulitModel *)squlitModel {
BOOL insertType = [_squlitManager gm_insertTable:squlitModel.table_name model:squlitModel];
if (!insertType) {//如果插入失败,就直接发送给服务器
[self sendModelArray:@[squlitModel]];
} else if (squlitModel.immediately) {//需要立刻发送的埋点
[self disposeSendDataWithImmediately:YES];
} else {//插入到数据中
self.messageCont++;
[self disposeSendDataWithImmediately:NO];
}
NSLog(@"插入%@状态%d count:%d",squlitModel.phobos_type, insertType,_messageCont);
}
#pragma mark - 获取待发送数据并修改状态为“发送”
- (NSMutableArray *)fetchToBeSendDataEntitiesAndUpdateWithSendStatus {
NSString *where = [NSString stringWithFormat:@"where status = %d or status = %d", PhobosDataSendStatus_wait, PhobosDataSendStatus_error];
NSMutableArray *array = [NSMutableArray array];
for (NSDictionary *dict in _tableMessageArray) {
/**获取待发送的数据*/
NSArray *sub = [_squlitManager gm_lookupTable:dict[KName] filterArray:nil objectClass:dict[KClass] whereFormat:where];
[array addObjectsFromArray:sub];
/**将待发送的数据修改为“发送中”*/
[_squlitManager gm_updateTable:dict[KName] dicOrModel:@{@"status":@(PhobosDataSendStatus_send)} whereFormat:where];
}
return array;
}
//获取待发送的数据个数
- (int)getAllTabelNeedSendMessageCount {
int count = 0;
NSString *where = [NSString stringWithFormat:@"where status = %d or status = %d", PhobosDataSendStatus_wait, PhobosDataSendStatus_error];
for (NSDictionary *dict in _tableMessageArray) {
int tableCount = [_squlitManager gm_tableItemCount:dict[KName] whereFormat:where];
count += tableCount;
}
return count;
}
#pragma mark - 是否需要发送数据
- (void)disposeSendDataWithImmediately:(BOOL)status {
if (!status) {
_messageCont = [self getAllTabelNeedSendMessageCount];
if (_messageCont < PhobosShardCount) return;
}
/**
能走到下面说明“满足上报埋点条件 status == yes || _messageCont >= PhobosShardCount”
*/
NSMutableArray *entities = [self fetchToBeSendDataEntitiesAndUpdateWithSendStatus];
if (entities.count >= PhobosMaxSendCount) { //大于100条 要对数据进行拆分
//拆分数组
NSArray *array = [GMPhobosTool splitArray:entities withSubSize:PhobosShardCount];
for (NSArray *sub in array) {
[self sendModelArray:sub];
}
} else {
[self sendModelArray:entities];
}
}
- (void)sendModelArray:(NSArray<GMPhobosSqulitModel *> *)entities {
NSLog(@"发送*******%lld", entities.count);
[PhobosSendManager sendDataWithEntities:entities completion:^(NSArray<GMPhobosSqulitModel *> *finishEntities, NSInteger code) {
SEL selelct = code == 200 ? @selector(sendSuccess:) :@selector(sendError:);
[self performSelector:selelct onThread:_phobosThread withObject:finishEntities waitUntilDone:NO];
}];
}
#pragma mark - 上报数据成功
- (void)sendSuccess:(NSArray<GMPhobosSqulitModel*> *)entities {
for (GMPhobosSqulitModel *model in entities) {
NSString *whereStr = [NSString stringWithFormat:@"where message_item_id = '%@'", model.message_item_id];
bool status = [_squlitManager gm_deleteTable:model.table_name whereFormat:whereStr];
NSLog(@"发送数据成功-删除状态:%d", status);
}
}
#pragma mark - 上报数据失败
- (void)sendError:(NSArray<GMPhobosSqulitModel*> *)entities {
for (GMPhobosSqulitModel *model in entities) {
NSString *whereStr = [NSString stringWithFormat:@"where message_item_id = '%@'", model.message_item_id];
bool status = [_squlitManager gm_updateTable:model.table_name
dicOrModel: @{@"status":@(PhobosDataSendStatus_error)}
whereFormat:whereStr];
NSLog(@"发送失败后-修改状态:%d",status);
}
}
@end
......@@ -6,7 +6,7 @@
//
#import <Foundation/Foundation.h>
#import "PhobosDataManager.h"
#import "GMPhobosSqulitModel.h"
NS_ASSUME_NONNULL_BEGIN
......@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* 发送数据
*/
+ (void)sendDataWithEntities:(NSArray<PhobosSendDataEntity *> *)needSendData completion:(nullable void(^)(NSArray<PhobosSendDataEntity *> *finishEntities, NSInteger code))completion;
+ (void)sendDataWithEntities:(NSArray<GMPhobosSqulitModel *> *)needSendData completion:(nullable void(^)(NSArray<GMPhobosSqulitModel *> *finishEntities, NSInteger code))completion;
@end
......
......@@ -40,45 +40,35 @@
}];
}
NSString *exposureAPI = [GMExposureManager sharedManager].uploadExposureAPI;
NSArray *exposureArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:exposureAPI]];
if (exposureAPI) {
NSString *str = [PhobosUtil MD5String:exposureAPI];
NSArray *exposureArray = [GMCache fetchObjectAtDocumentPathWithkey:str];
if (exposureArray.count > 0) {
/** 获取非灰度下发送失败的埋点,进行发送 */
[self sendDataArray:exposureArray currentAPI:exposureAPI success:^(NSInteger code) {
if (code = 200) {
if (code == 200) {
[GMCache removeObjectAtDocumentPathWithkey:[PhobosUtil MD5String:exposureAPI]];
}
}];
}
}
}
+ (void)sendDataWithEntities:(NSArray<PhobosSendDataEntity *> *)sendDataEntities completion:(void (^)(NSArray<PhobosSendDataEntity *> * _Nonnull, NSInteger))completion {
if (sendDataEntities.count == 0) {
return;
} else if (sendDataEntities.count > PhobosMaxSendCount) {
/** 如果数据超过 PhobosMaxSendCount 数据规模,进行拆分,分批发送,默认100条 */
NSMutableArray *temp = [NSMutableArray arrayWithCapacity:PhobosMaxSendCount];
[sendDataEntities enumerateObjectsUsingBlock:^(PhobosSendDataEntity * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (temp.count >= PhobosMaxSendCount) {
// 会调用当前方法,但数据规模不会满足 > PhobosMaxSendCount,不会让数据走到下面的发送,拆分完成 会执行return
[self sendDataWithEntities:temp completion:completion];
[temp removeAllObjects];
}
[temp addObject:obj];
}];
return;
}
+ (void)sendDataWithEntities:(NSArray<GMPhobosSqulitModel *> *)sendDataEntities completion:(void (^)(NSArray<GMPhobosSqulitModel *> * _Nonnull, NSInteger))completion {
if (sendDataEntities.count == 0) return;
NSMutableDictionary *sendDataMap = [NSMutableDictionary new];
// 将相同api的数据合并
[sendDataEntities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[sendDataEntities enumerateObjectsUsingBlock:^(GMPhobosSqulitModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableArray *sendData = sendDataMap[obj.api] ?: [NSMutableArray new];
[sendData addObject:obj];
[sendDataMap setValue:sendData forKey:obj.api];
}];
// 将实体转为待发送数据,取出PhobosSendDataEntity中的data,并发送
[sendDataMap enumerateKeysAndObjectsUsingBlock:^(NSString *api, NSArray<PhobosSendDataEntity *> *entities, BOOL * _Nonnull stop) {
[sendDataMap enumerateKeysAndObjectsUsingBlock:^(NSString *api, NSArray<GMPhobosSqulitModel *> *entities, BOOL * _Nonnull stop) {
NSMutableArray *sendDatas = [NSMutableArray new];
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[entities enumerateObjectsUsingBlock:^(GMPhobosSqulitModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
id data = [obj.data mj_JSONObject];
if (data) {
[sendDatas addObject:data];
......
//
// PhobosSendDataEntity+CoreDataClass.m
// GMPhobos
//
// Created by Locus on 2020/3/9.
//
//
#import "PhobosSendDataEntity+CoreDataClass.h"
@implementation PhobosSendDataEntity
@end
//
// PhobosSendDataEntity+CoreDataProperties.h
// GMPhobos
//
// Created by Locus on 2020/3/9.
//
//
#import "PhobosSendDataEntity+CoreDataClass.h"
NS_ASSUME_NONNULL_BEGIN
@interface PhobosSendDataEntity (CoreDataProperties)
+ (NSFetchRequest<PhobosSendDataEntity *> *)fetchRequest;
@property (nonatomic) int64_t id;
@property (nullable, nonatomic, retain) NSData *data;
@property (nullable, nonatomic, copy) NSString *api;
@property (nonatomic) int16_t status;
@end
NS_ASSUME_NONNULL_END
//
// PhobosSendDataEntity+CoreDataProperties.m
// GMPhobos
//
// Created by Locus on 2020/3/9.
//
//
#import "PhobosSendDataEntity+CoreDataProperties.h"
@implementation PhobosSendDataEntity (CoreDataProperties)
+ (NSFetchRequest<PhobosSendDataEntity *> *)fetchRequest {
return [NSFetchRequest fetchRequestWithEntityName:@"PhobosSendDataEntity"];
}
@dynamic id;
@dynamic data;
@dynamic api;
@dynamic status;
@end
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15702" systemVersion="19C57" minimumToolsVersion="Automatic" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="PhobosSendDataEntity" representedClassName="PhobosSendDataEntity" syncable="YES">
<attribute name="api" optional="YES" attributeType="String"/>
<attribute name="data" optional="YES" attributeType="Binary"/>
<attribute name="id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="status" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
</entity>
<elements>
<element name="PhobosSendDataEntity" positionX="-54" positionY="-9" width="128" height="103"/>
</elements>
</model>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment