Commit 256e3a20 authored by 汪洋's avatar 汪洋

Merge branch 'jql/optimize' into 'master'

埋点库升级

See merge request !48
parents 0495bdd9 503cf24d
......@@ -21,6 +21,7 @@
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
6393936E24122A6A0090348B /* swiftVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6393936D24122A6A0090348B /* swiftVC.swift */; };
63EFAB1122658352005EEAC6 /* GMPhobos_ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63EFAB1022658352005EEAC6 /* GMPhobos_ExampleTests.m */; };
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
9822812B60126E270C6B388F /* Pods_GMPhobos_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3D30FF32AFC059EC87D69DA /* Pods_GMPhobos_Tests.framework */; };
......@@ -50,9 +51,11 @@
/* Begin PBXFileReference section */
259B47496C313B9EC720BD76 /* GMPhobos.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = GMPhobos.podspec; path = ../GMPhobos.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
307F0A9AE09C3400AA3E80C3 /* Pods_GMPhobos_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GMPhobos_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39F84A4B7451E3C570109001 /* Pods-GMPhobos_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Tests.release.xcconfig"; path = "Target Support Files/Pods-GMPhobos_Tests/Pods-GMPhobos_Tests.release.xcconfig"; sourceTree = "<group>"; };
3E2C3B0828BB1AA652517366 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
5973B392CD963C413ADE924A /* Pods-GMPhobos_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example.release.xcconfig"; sourceTree = "<group>"; };
5A925189F951EA5E99801E5F /* Pods-GMPhobos_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-GMPhobos_Tests/Pods-GMPhobos_Tests.release.xcconfig"; sourceTree = "<group>"; };
5BECCE13A9644D7FC0ABE491 /* Pods-GMPhobos_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Example.release.xcconfig"; path = "Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example.release.xcconfig"; sourceTree = "<group>"; };
5C8C0EC8AB1257BC31A5BCFC /* Pods-GMPhobos_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GMPhobos_Tests/Pods-GMPhobos_Tests.debug.xcconfig"; sourceTree = "<group>"; };
6003F58A195388D20070C39A /* GMPhobos_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GMPhobos_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
......@@ -73,9 +76,12 @@
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
6393936C24122A690090348B /* GMPhobos_Example-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GMPhobos_Example-Bridging-Header.h"; sourceTree = "<group>"; };
6393936D24122A6A0090348B /* swiftVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = swiftVC.swift; sourceTree = "<group>"; };
63EFAB0E22658352005EEAC6 /* GMPhobos_ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GMPhobos_ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
63EFAB1022658352005EEAC6 /* GMPhobos_ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GMPhobos_ExampleTests.m; sourceTree = "<group>"; };
63EFAB1222658352005EEAC6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
773D510F733436C849F61689 /* Pods-GMPhobos_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Example.debug.xcconfig"; path = "Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example.debug.xcconfig"; sourceTree = "<group>"; };
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
94F09197043C44CCA8756031 /* Pods-GMPhobos_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example.debug.xcconfig"; sourceTree = "<group>"; };
D321A04E1F4A8F4100A6B934 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
......@@ -86,6 +92,7 @@
E49977051C59F40000623ABA /* GMPhotoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GMPhotoTest.m; sourceTree = "<group>"; };
E4AF92BF1C71C6C700CF0B64 /* GMPhobosUtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GMPhobosUtilTest.m; sourceTree = "<group>"; };
E4AF92C31C71CCE600CF0B64 /* libz.1.2.5.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.1.2.5.tbd; path = usr/lib/libz.1.2.5.tbd; sourceTree = SDKROOT; };
EBFF902F7DDD31799747B1A0 /* Pods-GMPhobos_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMPhobos_Tests.debug.xcconfig"; path = "Target Support Files/Pods-GMPhobos_Tests/Pods-GMPhobos_Tests.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -130,7 +137,7 @@
63EFAB0F22658352005EEAC6 /* GMPhobos_ExampleTests */,
6003F58C195388D20070C39A /* Frameworks */,
6003F58B195388D20070C39A /* Products */,
F0A9B46EC6044F749D0CDBCA /* Pods */,
DD770357FB89002C494C140E /* Pods */,
);
sourceTree = "<group>";
};
......@@ -166,8 +173,10 @@
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
6003F5A5195388D20070C39A /* GMViewController.h */,
6003F5A6195388D20070C39A /* GMViewController.m */,
6393936D24122A6A0090348B /* swiftVC.swift */,
6003F5A8195388D20070C39A /* Images.xcassets */,
6003F594195388D20070C39A /* Supporting Files */,
6393936C24122A690090348B /* GMPhobos_Example-Bridging-Header.h */,
);
name = "Example for GMPhobos";
path = GMPhobos;
......@@ -204,6 +213,7 @@
6003F5B7195388D20070C39A /* Tests-Info.plist */,
6003F5B8195388D20070C39A /* InfoPlist.strings */,
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */,
F0A9B46EC6044F749D0CDBCA /* Pods */,
);
name = "Supporting Files";
sourceTree = "<group>";
......@@ -227,6 +237,17 @@
path = GMPhobos_ExampleTests;
sourceTree = "<group>";
};
DD770357FB89002C494C140E /* Pods */ = {
isa = PBXGroup;
children = (
773D510F733436C849F61689 /* Pods-GMPhobos_Example.debug.xcconfig */,
5BECCE13A9644D7FC0ABE491 /* Pods-GMPhobos_Example.release.xcconfig */,
EBFF902F7DDD31799747B1A0 /* Pods-GMPhobos_Tests.debug.xcconfig */,
39F84A4B7451E3C570109001 /* Pods-GMPhobos_Tests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
F0A9B46EC6044F749D0CDBCA /* Pods */ = {
isa = PBXGroup;
children = (
......@@ -236,6 +257,7 @@
5A925189F951EA5E99801E5F /* Pods-GMPhobos_Tests.release.xcconfig */,
);
name = Pods;
path = ..;
sourceTree = "<group>";
};
/* End PBXGroup section */
......@@ -309,6 +331,7 @@
TargetAttributes = {
6003F589195388D20070C39A = {
DevelopmentTeam = 86R4V3XFLU;
LastSwiftMigration = 1130;
};
6003F5AD195388D20070C39A = {
DevelopmentTeam = 86R4V3XFLU;
......@@ -417,19 +440,17 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GMPhobos_Example/Pods-GMPhobos_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/GMCache/GMCache.framework",
"${BUILT_PRODUCTS_DIR}/GMKit/GMKit.framework",
"${BUILT_PRODUCTS_DIR}/GMPhobos/GMPhobos.framework",
"${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.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}/GMCache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMPhobos.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.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;
......@@ -445,6 +466,7 @@
buildActionMask = 2147483647;
files = (
D3435C101E49662000A93ED8 /* GMPhobosController.m in Sources */,
6393936E24122A6A0090348B /* swiftVC.swift in Sources */,
6003F59E195388D20070C39A /* GMAppDelegate.m in Sources */,
6003F5A7195388D20070C39A /* GMViewController.m in Sources */,
6003F59A195388D20070C39A /* main.m in Sources */,
......@@ -601,20 +623,25 @@
};
6003F5C0195388D20070C39A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 94F09197043C44CCA8756031 /* Pods-GMPhobos_Example.debug.xcconfig */;
baseConfigurationReference = 773D510F733436C849F61689 /* Pods-GMPhobos_Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = 86R4V3XFLU;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "GMPhobos/GMPhobos-Prefix.pch";
INFOPLIST_FILE = "GMPhobos/GMPhobos-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "263a3bb1-1a96-42d8-9117-a6893cf835c9";
PROVISIONING_PROFILE_SPECIFIER = Wildcard;
SWIFT_OBJC_BRIDGING_HEADER = "GMPhobos/GMPhobos_Example-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
WRAPPER_EXTENSION = app;
};
......@@ -622,18 +649,24 @@
};
6003F5C1195388D20070C39A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5973B392CD963C413ADE924A /* Pods-GMPhobos_Example.release.xcconfig */;
baseConfigurationReference = 5BECCE13A9644D7FC0ABE491 /* Pods-GMPhobos_Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = 86R4V3XFLU;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "GMPhobos/GMPhobos-Prefix.pch";
INFOPLIST_FILE = "GMPhobos/GMPhobos-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "c7e6dc21-c52f-40e4-a435-5e942f0af080";
PROVISIONING_PROFILE_SPECIFIER = Wildcard;
SWIFT_OBJC_BRIDGING_HEADER = "GMPhobos/GMPhobos_Example-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
WRAPPER_EXTENSION = app;
};
......@@ -641,8 +674,9 @@
};
6003F5C3195388D20070C39A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5C8C0EC8AB1257BC31A5BCFC /* Pods-GMPhobos_Tests.debug.xcconfig */;
baseConfigurationReference = EBFF902F7DDD31799747B1A0 /* Pods-GMPhobos_Tests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = 86R4V3XFLU;
......@@ -668,8 +702,9 @@
};
6003F5C4195388D20070C39A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5A925189F951EA5E99801E5F /* Pods-GMPhobos_Tests.release.xcconfig */;
baseConfigurationReference = 39F84A4B7451E3C570109001 /* Pods-GMPhobos_Tests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_IDENTITY = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
......@@ -692,6 +727,7 @@
63EFAB1522658352005EEAC6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
......@@ -721,6 +757,7 @@
63EFAB1622658352005EEAC6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
......
......@@ -27,6 +27,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6003F589195388D20070C39A"
BuildableName = "GMPhobos_Example.app"
BlueprintName = "GMPhobos_Example"
ReferencedContainer = "container:GMPhobos.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
......@@ -54,17 +63,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6003F589195388D20070C39A"
BuildableName = "GMPhobos_Example.app"
BlueprintName = "GMPhobos_Example"
ReferencedContainer = "container:GMPhobos.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
......@@ -86,8 +84,6 @@
ReferencedContainer = "container:GMPhobos.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
......
......@@ -7,11 +7,15 @@
//
#import "GMAppDelegate.h"
#import <Phobos.h>
@implementation GMAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Phobos.sharedClient.getTopController = ^UIViewController * _Nonnull{
return [UIViewController new];
};
// Override point for customization after application launch.
return YES;
}
......
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
......@@ -9,6 +9,8 @@
#import "GMViewController.h"
#import <GMPhobos/Phobos.h>
#import <GMCache/GMCache.h>
#import "GMPhobos_Example-Swift.h"
//@import GMCache;
@import GMPhobos.PhobosUtil;
@import GMPhobos.Phobos;
......@@ -33,41 +35,56 @@ NSString *const MockCityId = @"beijing";
#ifdef POD_CONFIGURATION_APP_STORE
NSString *url = @"http://log.gmei.com/log/collect";
#else
NSString *url = @"http://log.test.gengmei.cc/log/collect";
NSString *url = @"http://log.test.igengmei.com/log/collect";
#endif
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
[Phobos clientWithAppName:MockAppName channelId:MockChannelId];
// [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PhobosGray];
Phobos *client = [Phobos clientWithAppName:MockAppName channelId:MockChannelId];
[Phobos setSharedClient:client];
Phobos.sharedClient.serverAPI = url;
[Phobos.sharedClient setLogEnabled:NO]; // 调试打Log模式,看情况开启
Phobos.sharedClient.signingType = PhobosSigningTypeDebug;
Phobos.sharedClient.userId = @"";
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"];
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"];
// [Phobos track:@"page_view" attributes:dict];
// NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//
//
// [Phobos track:@"page_view" attributes:dict];
// array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//
// [dict setObject:[PhobosUtil currentTime] forKey:@"in"];
// [dict setObject:[PhobosUtil currentTime] forKey:@"out"];
// [Phobos track:@"page_view" attributes:dict];
[dict setObject:[PhobosUtil currentTime] forKey:@"in"];
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[Phobos track:@"page_view" attributes:dict sendNow:YES];
// array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//
// [Phobos track:@"test" attributes:dict];
[Phobos track:@"test" attributes:dict sendNow:YES];
[Phobos track:@"test2" attributes:dict sendNow:YES];
[Phobos track:@"test3" attributes:dict sendNow:YES];
[Phobos track:@"test4" attributes:dict sendNow:YES];
[Phobos track:@"test3" attributes:dict sendNow:YES];
[Phobos track:@"test4" attributes:dict sendNow:YES];
[Phobos track:@"test3" attributes:dict sendNow:YES];
[Phobos track:@"test4" attributes:dict sendNow:YES];
// array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
swiftVC *vc = [swiftVC new];
[self presentViewController:vc animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
......
......@@ -84,6 +84,11 @@
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="whP-gf-Uak">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="whP-gf-Uak">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
......@@ -14,9 +16,9 @@
<viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="TpU-gO-2f1">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/>
......
//
// swiftVC.swift
// GMPhobos_Example
//
// Created by Locus on 2020/3/6.
// Copyright © 2020 licong. All rights reserved.
//
import Foundation
import GMPhobos
class swiftVC: UIViewController {
override func viewDidLoad() {
let attr = Dictionary<String, Any>.init()
Phobos.track("swift", attributes: attr, sendNow: true)
}
}
PODS:
- GMCache (0.2.3):
- GMCache (1.0.1):
- TMCache (= 2.1.0)
- GMKit (1.1.3):
- GMKit/Category (= 1.1.3)
- GMKit/Color (= 1.1.3)
- GMKit/Constant (= 1.1.3)
- GMKit/FDFullscreenPopGesture (= 1.1.3)
- GMKit/Kit (= 1.1.3)
- GMKit/Protocol (= 1.1.3)
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/Category (1.1.3):
- GMKit/Color (= 1.1.3)
- GMKit/Constant (= 1.1.3)
- GMKit/Protocol (= 1.1.3)
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/Color (1.1.3):
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/Constant (1.1.3):
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/FDFullscreenPopGesture (1.1.3):
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/Kit (1.1.3):
- GMKit/Category (= 1.1.3)
- GMKit/Color (= 1.1.3)
- GMKit/Constant (= 1.1.3)
- GMKit/Protocol (= 1.1.3)
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMKit/Protocol (1.1.3):
- Masonry (= 1.1.0)
- SDWebImage (= 3.7.6)
- GMPhobos (1.3.6):
- GMPhobos (2.0.0):
- GMCache
- GMKit
- Masonry (1.1.0)
- SDWebImage (3.7.6):
- SDWebImage/Core (= 3.7.6)
- SDWebImage/Core (3.7.6)
- MagicalRecord
- MJExtension
- MagicalRecord (2.3.2):
- MagicalRecord/Core (= 2.3.2)
- MagicalRecord/Core (2.3.2)
- MJExtension (3.2.1)
- TMCache (2.1.0)
DEPENDENCIES:
......@@ -50,10 +17,9 @@ DEPENDENCIES:
SPEC REPOS:
"git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git":
- GMCache
- GMKit
https://github.com/CocoaPods/Specs.git:
- Masonry
- SDWebImage
- MagicalRecord
- MJExtension
- TMCache
EXTERNAL SOURCES:
......@@ -61,11 +27,10 @@ EXTERNAL SOURCES:
:path: "../"
SPEC CHECKSUMS:
GMCache: 09a3029c96fe130e3a21faef70b3d9d2ce92d639
GMKit: 35f788243cceeddf3e13c5226b3ea0b5e08e2117
GMPhobos: 6623102d634ce5485e8d3e474da8bdce5891f419
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
SDWebImage: c325cf02c30337336b95beff20a13df489ec0ec9
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMPhobos: 3cad92cfa28da2b719ccef040a8fb4e33012b1ad
MagicalRecord: 53bed74b4323b930992a725be713e53b37d19755
MJExtension: 635f2c663dcb1bf76fa4b715b2570a5710aec545
TMCache: 95ebcc9b3c7e90fb5fd8fc3036cba3aa781c9bed
PODFILE CHECKSUM: ea0fac2144ac80baf8f21576cde49526c19991ad
......
......@@ -9,8 +9,8 @@
#import <XCTest/XCTest.h>
#import <GMPhobos/Phobos.h>
#import "GMPhobosController.h"
#define PhobosCacheKey @"PhobosCacheKey"
@import GMCache;
#import <GMCache/GMCache.h>
#import <MJExtension/MJExtension.h>
NSString *const MockAppName = @"gengmei_test";
NSString *const MockChannelId = @"AppStore";
......@@ -19,26 +19,28 @@ NSString *const MockUserId = @"1";
NSString *const MockCityId = @"beijing";
@interface GMPhotoTest : XCTestCase
@property Phobos *client;
@end
///[NSThread sleepForTimeInterval:0.2]; 因为是异步处理数据,所以需要延迟获取,进行单元测试
@implementation GMPhotoTest
- (void)setUp {
[super setUp];
_client = [Phobos clientWithAppName:MockAppName channelId:MockChannelId];
_client.serverAPI = @"http://log.test.igengmei.com/log/collect";
[_client setLogEnabled:NO]; // 调试打Log模式,看情况开启
_client.signingType = PhobosSigningTypeDebug;
_client.userId = @"";
[Phobos setSharedClient:_client];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:PhobosGray];
[Phobos clientWithAppName:MockAppName channelId:MockChannelId];
Phobos.sharedClient.serverAPI = @"http://log.test.igengmei.com/log/collect";
Phobos.sharedClient.logEnabled = NO; // 调试打Log模式,看情况开启
Phobos.sharedClient.signingType = PhobosSigningTypeDebug;
Phobos.sharedClient.userId = @"";
Phobos.sharedClient.getTopController = ^UIViewController * _Nonnull{
return [UIViewController new];
};
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKey];
[Phobos removeAllPhobosData];
}
/**
......@@ -47,12 +49,15 @@ NSString *const MockCityId = @"beijing";
* @since <#version number#>
*/
- (void)testClientWithUserId{
[_client setUserId:MockUserId];
[_client setCurrentCityId:MockCityId];
[self setUp];
[Phobos removeAllPhobosData];
[Phobos.sharedClient setUserId:MockUserId];
[Phobos.sharedClient setCurrentCityId:MockCityId];
[Phobos track:MockEventId];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
[NSThread sleepForTimeInterval:0.2];
NSArray<PhobosSendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
XCTAssertTrue(array.count == 1, @"array is empty");
NSDictionary *dict = [array objectAtIndex:0];
NSDictionary *dict = [array.firstObject.data mj_JSONObject];
[self verfiyDict:dict];
XCTAssertTrue([[dict objectForKey:@"user_id"] isEqualToString:MockUserId] , @"Invalid user_id value");
}
......@@ -64,9 +69,10 @@ NSString *const MockCityId = @"beijing";
*/
- (void)testTrackEventWithoutAttr{
[Phobos track:MockEventId];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
[NSThread sleepForTimeInterval:0.2];
NSArray<PhobosSendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
XCTAssertTrue(array.count == 1, @"array is empty");
NSDictionary *dict = [array objectAtIndex:0];
NSDictionary *dict = [array.firstObject.data mj_JSONObject];
[self verfiyDict:dict];
}
......@@ -79,9 +85,9 @@ NSString *const MockCityId = @"beijing";
- (void)testTrackEventWithAttr{
NSDictionary *attr = @{@"attr":@"track_attr"};
[Phobos track:MockEventId attributes:attr];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
NSArray<PhobosSendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
XCTAssertTrue(array.count == 1, @"array is empty");
NSDictionary *dict = [array objectAtIndex:0];
NSDictionary *dict = [array.firstObject.data mj_JSONObject];
[self verfiyDict:dict];
//验证Param的值是否正确
......@@ -95,17 +101,17 @@ NSString *const MockCityId = @"beijing";
* @since <#version number#>
*/
- (void)testTrackEventWithAttrAndSendNow{
[Phobos removeAllPhobosData];
// Given
NSDictionary *attr = @{@"attr":@"track_attr"};
// When
[Phobos track:MockEventId attributes:attr sendNow:YES];
// Then
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array should be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array should be empty");
}
/**
* @brief 测试立即发送带参数事件成功,不应该清除不立即发送的埋点
* @brief 测试立即发送带参数事件成功,应该把普通埋点也带上
*
* @since 1.1.4
*/
......@@ -117,9 +123,7 @@ NSString *const MockCityId = @"beijing";
[Phobos track:MockEventId attributes:attr sendNow:NO];
// When
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count != 0, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array should be empty");
}
/**
......@@ -132,19 +136,12 @@ NSString *const MockCityId = @"beijing";
[Phobos track:MockEventId attributes:attr sendNow:YES];
// 因为实时埋点是异步删除,所以这个位置暂时延时取数据,待优化 TODO
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr sendNow:YES];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
});
});
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr sendNow:YES];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr sendNow:YES];
}
/**
......@@ -153,23 +150,20 @@ NSString *const MockCityId = @"beijing";
* @since 1.1.4
*/
- (void)testTrackEventWithDoubleAttrAndNoSendNow {
[Phobos removeAllPhobosData];
NSDictionary *attr = @{@"attr":@"track_attr"};
//
[Phobos track:MockEventId attributes:attr];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
// PhobosCacheKey超过50条数据会自动上报,模拟此情况
for (int i = 0; i < 50; i++) {
[Phobos track:MockEventId attributes:attr];
}
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
}
/**
......@@ -178,70 +172,36 @@ NSString *const MockCityId = @"beijing";
* @since 1.1.4
*/
- (void)testTrackEventWithSendNowAndNoSendNowOne {
[Phobos removeAllPhobosData];
NSDictionary *attr = @{@"attr":@"track_attr"};
NSDictionary *sendNowAttr = @{@"attr":@"track_attr_send_now"};
for (int i = 0; i < 30; i++) {
[Phobos track:MockEventId attributes:attr];
}
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 30, @"array shouldn't be empty");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 30, @"array shouldn't be empty");
// PhobosCacheKey超过50条数据会自动上报,模拟此情况
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 30, @"array shouldn't be empty");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 30, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:sendNowAttr sendNow:NO];
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 30, @"array shouldn't be empty");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 31, @"array shouldn't be empty");
}
/**
* @brief 测试不实时和实时穿插 2
*
* @since 1.1.4
*/
- (void)testTrackEventWithSendNowAndNoSendNowTwo {
NSDictionary *attr = @{@"attr":@"track_attr"};
NSDictionary *sendNowAttr = @{@"attr":@"track_attr_send_now"};
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 2, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:sendNowAttr sendNow:YES];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 2, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 3, @"array shouldn't be empty");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
}
/**
......@@ -250,23 +210,22 @@ NSString *const MockCityId = @"beijing";
* @since 1.1.4
*/
- (void)testTrackEventWithSendNowAndNoSendNowThree {
[Phobos removeAllPhobosData];
NSDictionary *attr = @{@"attr":@"track_attr"};
//
[Phobos track:MockEventId attributes:attr];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"array shouldn't be empty");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
// PhobosCacheKey超过50条数据会自动上报,模拟此情况
for (int i = 0; i < 50; i++) {
[Phobos track:MockEventId attributes:attr];
}
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 0, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 0, @"array shouldn't be empty");
[Phobos track:MockEventId attributes:attr];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"array shouldn't be empty");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 1, @"array shouldn't be empty");
}
- (void)verfiyDict:(NSDictionary *)dict{
......@@ -287,7 +246,7 @@ NSString *const MockCityId = @"beijing";
}
- (void)testCatchNullInAttributes {
_client.captureNullExpection = ^(NSString *eventId, NSDictionary *att) {
Phobos.sharedClient.captureNullExpection = ^(NSString *eventId, NSDictionary *att) {
NSCAssert([att[@"bussness_id"] integerValue] == 1244, @"testCatchNullInAttributes 没有捕获到有用信息");
};
NSDictionary *attributes = @{@"key": [NSNull null],
......@@ -315,24 +274,19 @@ NSString *const MockCityId = @"beijing";
[controller viewWillAppear:true];
[controller viewWillDisappear:true];
[self paramUnNilCheck];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
NSArray<PhobosSendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
XCTAssertTrue(array.count != 0, @"PhobosCacheKey 下面应该有数据");
NSDictionary *dic = array[0][@"params"];
NSDictionary *dic = [array.firstObject.data mj_JSONObject][@"params"];
XCTAssertTrue([dic[@"referrer_id"] isEqualToString:@"rreferrerIdTest"], @"referrerId至少使用默认的空字符串");
}
- (void)testSimulativePageViewEvent {
[_client simulativePV:nil businessId:nil referer:nil];
[self paramUnNilCheck];
}
- (void)paramUnNilCheck {
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
NSArray<PhobosSendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
XCTAssertTrue(array.count != 0, @"PhobosCacheKey 下面应该有数据");
NSDictionary *dic = array[0][@"params"];
NSDictionary *dic = [array.firstObject.data mj_JSONObject][@"params"];
XCTAssertTrue(dic[@"page_name"] != nil, @"page_name至少使用默认的空字符串");
XCTAssertTrue([dic[@"referer"] integerValue] >= 0, @"referer至少使用默认的空字符串");
XCTAssertTrue(dic[@"business_id"] != nil, @"business_id至少使用默认的空字符串");
......@@ -350,8 +304,10 @@ NSString *const MockCityId = @"beijing";
XCTAssertFalse(controller.needLogPV, @"needLogPV赋值为NO时应该NO");
}
// 该单元测试暂时不用,因为过滤代码暂时不用,所以不需要跑通
/*
- (void)testCheckPVPhobos {
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
[Phobos removeAllPhobosData];
NSString *inDate = [PhobosUtil currentTime];
[NSThread sleepForTimeInterval:1];//模拟浏览页面,让out和in时间相差1s
......@@ -367,12 +323,12 @@ NSString *const MockCityId = @"beijing";
[dict setObject:@"" forKey:@"referrer_tab_name"];
[dict setObject:@(0) forKey:@"is_push"];
[Phobos track:@"page_view" attributes:dict];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
NSArray<SendDataEntity *> *array = [Phobos fetchToBeSendPhobosData];
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue(array.count == 1, @"PhobosCacheKey 下面应该有数据");
[Phobos track:@"page_view" attributes:dict];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 1, @"PhobosCacheKey 上条数据不应该发送");
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 2, @"PhobosCacheKey 上条数据不应该发送");
[NSThread sleepForTimeInterval:2];//模拟浏览页面,让第二次浏览和上一次时间相差2s
......@@ -380,15 +336,16 @@ NSString *const MockCityId = @"beijing";
[NSThread sleepForTimeInterval:1];//模拟浏览页面,让out和in时间相差1s
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[Phobos track:@"page_view" attributes:dict];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 2, @"PhobosCacheKey 上条数据应该发送");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount]== 2, @"PhobosCacheKey 上条数据应该发送");
[Phobos track:@"page_view" attributes:dict];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 2, @"PhobosCacheKey 上条数据不应该发送");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 2, @"PhobosCacheKey 上条数据不应该发送");
[Phobos track:@"test" attributes:dict];
array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
XCTAssertTrue(array.count == 3, @"PhobosCacheKey 上条数据应该发送");
[NSThread sleepForTimeInterval:0.2];
XCTAssertTrue([Phobos fetchToBeSendPhobosDataCount] == 3, @"PhobosCacheKey 上条数据应该发送");
}
*/
#pragma mark - 其它方法test
......
......@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = "GMPhobos"
s.version = "1.3.6"
s.version = "2.0.0"
s.summary = "GM statistic data sdk"
s.description = <<-DESC
......@@ -25,7 +25,9 @@ Pod::Spec.new do |s|
s.platform = :ios, '8.0'
s.source_files = 'GMPhobos/Classes/*.{h,m}'
s.dependency 'GMCache'
s.dependency 'GMKit'
s.dependency 'MJExtension'
s.dependency 'MagicalRecord'
s.library = 'z'
s.resource = 'GMPhobos/*.xcdatamodeld'
end
//
// Phobos.h
// GengmeiDoctor
// Data Statistic Client For Mars
// Created by Thierry on 16/1/26.
// Copyright © 2016年 wanmeizhensuo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "PhobosPVProtocol.h"
#import "PhobosConfig.h"
#import <CoreLocation/CLLocation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NewPhobos : NSObject
/**
* @brief 开启Phobos统计,默认以BATCH方式发送log.
*
* @param appName 通常由数据端与客户端一起确认的区分不同app的名字
* @param channelId 发布渠道
*
* @return Phobos实例
*
* @since 0.0.1
*/
+ (NewPhobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId;
+ (instancetype) alloc __attribute__((deprecated));
- (instancetype) init __attribute__((deprecated));
+ (instancetype) new __attribute__((deprecated));
#pragma mark - SDK配置
+ (instancetype)sharedClient;
/** 用于Phobos库从old更新到new使用,在全量之后删除相关逻辑 */
@property (nonatomic, assign) BOOL isGray;
// Phobos在处理业务端传递来的参数时会检查是否某个value为空,如果为空会调用这个block以通知业务层,业务层可以上报这个异常,以助解决问题
@property(nonatomic, copy) void (^captureNullExpection) (NSString *eventId, NSDictionary *info);
/**
网络状态 wifi=1, mobile=0, 不连通=-1
*/
@property (nonatomic, copy) NSString *netStatus;
/**
//没有网络连接
public static final String NETWORN_NONE = "none";
//wifi连接
public static final String NETWORN_WIFI = "wifi";
//手机网络数据连接类型
public static final String NETWORN_2G = "2G";
public static final String NETWORN_3G = "3G";
public static final String NETWORN_4G = "4G";
public static final String NETWORN_MOBILE = "other";
*/
@property (nonatomic, copy) NSString *networkStatus;
/**
* @brief 设置是否打印sdk的log信息,默认不开启
*
* @since 0.0.1
*/
@property (assign, nonatomic) BOOL logEnabled;
/**
* @brief 设置当前登录用户的ID,如果没有默认为@""
*
*
* @since 0.0.2
*/
@property (strong, nonatomic) NSString *userId;
/*!
* @author zhaiguojun, 16-05-31
*
* @brief 用户当前的城市id
*
*
* @since 0.2.7
*/
@property (strong, nonatomic) NSString *currentCityId;
@property (strong, nonatomic) CLLocation *gps;
/**
* 记录用户类型
*/
@property (strong, nonatomic) NSMutableDictionary *userType;
/**
数据接收的服务器API
*/
@property (copy, nonatomic) NSString *serverAPI;
/**
当前APP请求接口的 APIHOST(GMServerDomains.apiHost 主要用于flutter AppDelegate 中初始化需要传值
*/
@property (nonatomic, copy) NSString *apiHost;
/**
当前APP请求接口的 cookie(主要用于flutter) 获取到cookie 的时候穿过来 或者cookie 有变化的时候传过来
*/
@property (nonatomic, copy) NSString *cookie;
/**
灰度组, since 7.7.65
*/
@property (nonatomic, copy) NSString *greyType;
/**
包的类型:APPSTORE、RELEASE、DEBUG
*/
@property (nonatomic, assign) PhobosSigningType signingType;
/**
从主项目获取当前显示的controller
*/
@property (nonatomic, copy) UIViewController * (^getTopController) (void);
#pragma mark - 事件采集
/** 点击事件采集 */
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes;
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow;
/**
* @brief 自定义事件,数量统计.
*
* @param eventId 事件Id
* @attributes 参数
* @sendNow 是否实时发送,默认为NO
*
* @since 0.0.1
*/
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes;
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow;
+ (void)track:(NSString *)eventName;
/**
* @brief 自定义事件,数量统计 7730 精准曝光/数据链路.
*
* @param eventId 事件Id
* @attributes 参数
* @sendNow 是否实时发送,默认为NO
* @currentAPI 当前传过来的API
* @
*/
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventName currentAPI:(NSString *)currentAPI;
/**
* @brief PV事件开始。当controller viewWillAppear时调用
*/
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page;
/**
* @brief PV事件结束。当controller viewWillDisAppear时调用
*/
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page;
@end
@interface NewPhobos (UtilTest)
/** 获取所有非立即发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount;
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData;
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData;
@end
NS_ASSUME_NONNULL_END
//
// Phobos.m
// GengmeiDoctor
//
// Created by Thierry on 16/1/26.
// Copyright © 2016年 wanmeizhensuo. All rights reserved.
//
#import "NewPhobos.h"
#import <AdSupport/AdSupport.h>
#import "UIResponder+PhobosPV.h"
#import "PhobosUtil.h"
#import "PhobosCustomVisibleController.h"
#import <GMCache/GMCache.h>
#import <mach/mach_time.h>
#import "PhobosDataManager.h"
#import "PhobosSendManager.h"
static NewPhobos *_sharedClient;
static NSString *sdkVersion = @"2.0.0";
@interface NewPhobos ()
@property (strong, nonatomic) UIViewController *visibleController;
@property (strong, nonatomic) NSDateFormatter *dateFormatter;
@property (strong, nonatomic) NSString *appName;
@property (strong, nonatomic) NSString *channelId;
@property (strong, nonatomic) NSString *appVersion;
@property (strong, nonatomic) NSString *sessionId;
/* 每一条埋点数据的物理ID,自增,生命周期和sessionId相同。特别注意:在sessionOver的时候,要把他置为0 */
@property (assign, nonatomic) NSInteger serialId;
@end
@implementation NewPhobos
+ (NewPhobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId{
NewPhobos.sharedClient.appName = appName;
NewPhobos.sharedClient.channelId = channelId;
return NewPhobos.sharedClient;
}
- (instancetype)init {
if (self = [super init]) {
_appName = @"";
_channelId = @"";
_logEnabled = NO;
_userId = @"";
_netStatus = @"";
_currentCityId = @"";
_serverAPI = @"";
_greyType = @"";
_userType = [[NSMutableDictionary alloc] init];
_appVersion = [PhobosUtil getAppVersion];
_signingType = PhobosSigningTypeUndefined;
[self setupNotification];
[self handleSessionStart];
}
return self;
}
+ (id)allocWithZone:(struct _NSZone *)zone {
return NewPhobos.sharedClient;
}
- (id)copyWithZone:(struct _NSZone *)zone {
return NewPhobos.sharedClient;
}
+ (instancetype)sharedClient {// 使用单例设计模式,保证Phobos只有一个实例,并提供了全局访问点
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[super allocWithZone:NULL] init];
});
return _sharedClient;
}
- (void)dealloc{
if (self) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void)setUserType:(NSMutableDictionary *)userType {
if (userType == nil && userType.allKeys.count == 0) {
return;
}
NSArray *newKeys = userType.allKeys;
NSArray *oldKeys = _userType.allKeys;
for (NSString *newKey in newKeys) {
if ([oldKeys containsObject:newKey]) {
NSString *newValue = [[userType objectForKey:newKey] stringValue];
NSString *oldValue = [[_userType objectForKey:newKey] stringValue];
if (![newValue isEqualToString:oldValue]) {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
} else {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
}
}
/**
在APP启动、从后台到前台的时候需要记录device_opened埋点
*/
- (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],
};
[NewPhobos track:@"device_opened" attributes:dict sendNow:YES];
}
- (UIViewController *)visibleController {
if (self.getTopController) {
id target = self.getTopController();
if ([target conformsToProtocol:NSProtocolFromString(@"PhobosCustomVisibleController")]) {
target = [target performSelector:@selector(phobosVisibleController)];
}
return target;
}
return nil;
}
#pragma mark - notification handler
/**
* @brief 设置对APP的通知监听
*
* @since 0.0.1
*/
- (void)setupNotification{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppFinishLaunch:) name:UIApplicationDidFinishLaunchingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInBackgound:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
/**
* @brief 每次打开APP或返回前台,即Session开始的时候的处理
* @notification didFinishLaunch和willEnterForeground的时候都需要记录
*
* @since 0.0.1
*/
- (void)handleSessionStart{
_serialId = 0;
_sessionId = [[NSUUID UUID] UUIDString];
[GMCache storeObjectAtDocumentPathWithkey:PhobosBeginTime object:[PhobosUtil currentTime]];
}
/**
* @brief 应用打开时的处理
*
* @since 0.0.1
*/
- (void)handleAppFinishLaunch:(id)sender{
phobosLog(@"handleAppFinishLaunch");
[self handleSessionStart];
[self handleEventDeviceOpened];
}
/**
* @brief 应用进入前台的处理
*
* @since 0.0.1
*/
- (void)handleAppInForeground:(id)sender{
phobosLog(@"handleAppInForeground");
[self handleSessionStart];
[self handleEventDeviceOpened];
[NewPhobos disposeSendDataWithImmediately:NO];
[self handlePVEventAppInForeground];
}
/**
* @brief 应用进入后台的处理
*
* @since 0.0.1
*/
- (void)handleAppInBackgound:(id)sender{
phobosLog(@"handleAppInBackgound");
[self handlePVEventAppInBackgound];
[self handleSessionOver];
[NewPhobos disposeSendDataWithImmediately:NO];
}
/**
* @brief 会话结束时候的处理
*
* @since 0.0.1
*/
- (void)handleSessionOver{
//进入后台的同时,把记录时间同步到服务端,把已使用时间清空
double beginTime = [[GMCache fetchObjectAtDocumentPathWithkey:PhobosBeginTime] doubleValue];
if (beginTime == 0) {
return;
}
NSDate *date = [NSDate date];
double endTime = [date timeIntervalSince1970];
NSString *usedTime = [NSString stringWithFormat:@"%ld",(long)(endTime - beginTime)];
NSDictionary *dict = @{@"duration":usedTime,
@"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],
};
[NewPhobos track:@"on_app_session_over" attributes:dict];
[GMCache removeObjectAtDocumentPathWithkey:PhobosBeginTime];
//当前session结束之后,把id置为0
_serialId = 0;
}
/**
APP从后台到前台的时候,重新初始化pagename等信息
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInForeground {
if (self.visibleController != nil) {
[self onPVStart:self.visibleController];
}
}
/**
APP进到后台的时候,把当前pageview时间结束
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInBackgound {
if (self.visibleController != nil) {
[self onPVEnd:self.visibleController];
}
}
#pragma mark - PV
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page {
// 必须在此处调用一下referer,因为onControllerStart
[page initReferer];
[page initRefererLink];
[page initReferrerIdIfNil];
[page initReferrerTabName];
page.inTime = [PhobosUtil currentTime];
page.inTimeMillis = [PhobosUtil currentMMTime];
// 业务层更新
if (page.updatePVStartBlock) {
page.updatePVStartBlock();
}
}
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page {
if (![PhobosUtil isNonEmpty:page.pageName] || !page.needLogPV) {
return;
}
// 业务层更新
if (page.updatePVEndBlock) {
page.updatePVEndBlock();
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:page.inTime?:@"" forKey:@"in"];
[dict setObject:page.pageName forKey:@"page_name"];
[dict setObject:page.businessId?:@"" forKey:@"business_id"];
[dict setObject:page.referer?:@"" forKey:@"referrer"];
if ([page.referrerLink isKindOfClass:[NSArray class]] && page.referrerLink.count) {
[dict setObject:page.referrerLink forKey:@"referrer_link"];
} else {
[dict setObject:@[] forKey:@"referrer_link"];
}
[dict setObject:@(0) forKey:@"fake"];
[dict setObject:page.referrerId ? : @"" forKey:@"referrer_id"];
[dict setObject:page.extraParam ? : @"" forKey:@"extra_param"];
[dict setObject:page.referrerTabName ? : @"" forKey:@"referrer_tab_name"];
[dict setObject:page.isPush.intValue ? @(page.isPush.intValue) : @(0) forKey:@"is_push"];
[dict setObject:page.inTimeMillis?:@"" forKey:@"in_time_millis"];
[dict setObject:[PhobosUtil currentMMTime] forKey:@"out_time_millis"];
if (page.inTime.length > 0) {
// 页面显示时间为空时不记录页面pv事件
[NewPhobos track:@"page_view" attributes:dict];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
/**
* @brief 将埋点时间封装成词典数据
*
* @since 0.0.1
*/
- (NSDictionary *)prepareDictionaryForEvent:(NSString *)eventName attributes:(NSDictionary *)attributes {
NSArray *referrerLink = _sharedClient.visibleController.referrerLink;
// 对于埋点没有referrer_link的情况,在这里进行统一添加
if (![attributes.allKeys containsObject:@"referrer_link"]) {
NSMutableDictionary *attributesParams = [NSMutableDictionary dictionaryWithDictionary:attributes];
if ([referrerLink isKindOfClass:[NSArray class]] && referrerLink.count) {
[attributesParams setValue:referrerLink forKey:@"referrer_link"];
} else {
[attributesParams setValue:@[] forKey:@"referrer_link"];
}
attributes = attributesParams;
}
[self catchNullForEvent:eventName attributes:attributes];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
NSString *currentTime = [PhobosUtil currentTime];
NSMutableDictionary *deviceParams = [NSMutableDictionary new];
[deviceParams setValue:[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString] forKey:@"idfa"];
[deviceParams setValue:[[[UIDevice currentDevice] identifierForVendor] UUIDString] forKey:@"idfv"];
[deviceParams setValue:[PhobosUtil deviceId] forKey:@"device_id"];
[deviceParams setValue:@"ios" forKey:@"device_type"];
[deviceParams setValue:@"Apple" forKey:@"manufacturer"];
[deviceParams setValue:@(self.gps.coordinate.latitude) forKey:@"lat"];
[deviceParams setValue:@(self.gps.coordinate.longitude) forKey:@"lng"];
[deviceParams setValue:_netStatus forKey:@"is_WiFi"];
[deviceParams setValue:[PhobosUtil getIPAddress:YES] forKey:@"ip"];
[deviceParams setValue:_networkStatus forKey:@"net_type"];
[deviceParams setValue:[PhobosUtil platform] forKey:@"model"];
[deviceParams setValue:@(_isGray) forKey:@"isGray"];
[deviceParams setValue:[UIDevice currentDevice].systemVersion forKey:@"sys_version"];
NSMutableDictionary *appParams = [NSMutableDictionary new];
[appParams setValue:_greyType forKey:@"grey_type"];
[appParams setValue:_appName forKey:@"name"];
[appParams setValue:_appVersion forKey:@"version"];
[appParams setValue:_channelId forKey:@"channel"];
[appParams setValue:_userType forKey:@"user_type"];
[appParams setValue:_currentCityId forKey:@"current_city_id"];
[appParams setValue:@(_serialId++) forKey:@"serial_id"];
if (_signingType == PhobosSigningTypeDebug || _signingType == PhobosSigningTypeRelease) {
[dict setObject:@(0) forKey:@"is_release"];
}
NSString *nano_time = [NSString stringWithFormat:@"%lld",[[NSProcessInfo processInfo] systemUptime]];
[dict setObject:eventName forKey:@"type"];
[dict setObject:appParams forKey:@"app"];
[dict setObject:sdkVersion forKey:@"version"];
[dict setObject:deviceParams forKey:@"device"];
[dict setObject:_userId forKey:@"user_id"];
[dict setObject:currentTime forKey:@"create_at"];// 1584513842 当前时间(秒)
[dict setObject:nano_time?:@"" forKey:@"nano_time"];// 1657008897 系统启动后时长(秒)
[dict setObject:@(mach_absolute_time()) forKey:@"absolute_time"];// 148237263697318 系统启动后的 CPU 嘀嗒数(纳秒)
[dict setObject:[PhobosUtil currentMMTime] forKey:@"create_at_millis"];// 1584513842753 当前时间戳(毫秒)
[dict setObject:attributes forKey:@"params"];
[dict setObject:_sessionId forKey:@"app_session_id"];
}
@catch (NSException *exception) {
phobosLog(exception);
}
return dict;
}
#pragma mark - helpers
- (void)catchNullForEvent:(NSString *)eventName attributes:(NSDictionary *)attributes {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
@try {
for (NSString *key in attributes.allKeys) {
if ([attributes[key] isMemberOfClass:[NSNull class]]) {
if (self.captureNullExpection) {
self.captureNullExpection(eventName, attributes);
}
break;
}
}
} @catch (NSException *exception) {
}
});
}
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes {
[self track:@"on_cick_button" attributes:attributes];
}
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow {
[self track:@"on_cick_button" attributes:attributes sendNow:sendNow];
}
+ (void)track:(NSString *)eventName{
[self track:eventName attributes:@{} sendNow:NO currentAPI:_sharedClient.serverAPI];
}
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes{
[self track:eventName attributes:attributes sendNow:NO currentAPI:_sharedClient.serverAPI];
}
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow{
[self track:eventName attributes:attributes sendNow:sendNow currentAPI:_sharedClient.serverAPI];
}
+ (void)track:(NSString *)eventName currentAPI:(NSString *)currentAPI {
[self track:eventName attributes:@{} sendNow:NO currentAPI:currentAPI];
}
+ (void)track:(NSString *)eventName attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI {
[self track:eventName attributes:attributes sendNow:NO currentAPI:currentAPI];
}
+ (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];
} @catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
}
/**
* 处理发送数据
*/
+ (void)disposeSendDataWithImmediately:(BOOL)immediately {
NSArray<PhobosSendDataEntity *> *entities = [PhobosDataManager fetchToBeSendDataEntities];
if (immediately || entities.count > PhobosShardCount) {
[PhobosDataManager updateDataEntities:entities sendStatus:PhobosDataSendStatusSending];
[PhobosSendManager sendDataWithEntities:entities completion:^(NSArray<PhobosSendDataEntity *> * _Nonnull finishEntities, NSInteger code) {
if (code == 200) {
[PhobosDataManager deleteDataEntities:finishEntities];
[PhobosDataManager updateDataEntities:finishEntities sendStatus:PhobosDataSendStatusFinish];
} else {
[PhobosDataManager updateDataEntities:finishEntities sendStatus:PhobosDataSendStatusError];
}
}];
}
}
@end
@implementation NewPhobos (UtilTest)
/** 获取所有非立即发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount {
return [PhobosDataManager fetchCountOfToBeSendEntities];
}
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData {
return [PhobosDataManager fetchToBeSendDataEntities];
}
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData {
[PhobosDataManager deleteAllEntities];
}
@end
//
// Phobos.h
// GengmeiDoctor
// Data Statistic Client For Mars
// Created by Thierry on 16/1/26.
// Copyright © 2016年 wanmeizhensuo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "PhobosPVProtocol.h"
#import <CoreLocation/CLLocation.h>
#import "PhobosConfig.h"
NS_ASSUME_NONNULL_BEGIN
@interface OldPhobos : NSObject
/**
* @brief 开启Phobos统计,默认以BATCH方式发送log.
*
* @param appName 通常由数据端与客户端一起确认的区分不同app的名字
* @param channelId 发布渠道
*
* @return Phobos实例
*
* @since 0.0.1
*/
+ (OldPhobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId;
+ (instancetype)sharedClient;
+ (void)setSharedClient:(OldPhobos *)client;
#pragma mark - SDK配置
// Phobos在处理业务端传递来的参数时会检查是否某个value为空,如果为空会调用这个block以通知业务层,业务层可以上报这个异常,以助解决问题
@property(nonatomic, copy) void (^captureNullExpection) (NSString *eventId, NSDictionary *info);
/**
网络状态 wifi=1, mobile=0, 不连通=-1
*/
@property (nonatomic, copy) NSString *netStatus;
/**
//没有网络连接
public static final String NETWORN_NONE = "none";
//wifi连接
public static final String NETWORN_WIFI = "wifi";
//手机网络数据连接类型
public static final String NETWORN_2G = "2G";
public static final String NETWORN_3G = "3G";
public static final String NETWORN_4G = "4G";
public static final String NETWORN_MOBILE = "other";
*/
@property (nonatomic, copy) NSString *networkStatus;
/**
* @brief 设置是否打印sdk的log信息,默认不开启
*
* @since 0.0.1
*/
@property (assign, nonatomic) BOOL logEnabled;
/**
* @brief 设置当前登录用户的ID,如果没有默认为@""
*
*
* @since 0.0.2
*/
@property (strong, nonatomic) NSString *userId;
/*!
* @author zhaiguojun, 16-05-31
*
* @brief 用户当前的城市id
*
*
* @since 0.2.7
*/
@property (strong, nonatomic) NSString *currentCityId;
@property (strong, nonatomic) CLLocation *gps;
/**
* 记录用户类型
*/
@property (strong, nonatomic) NSMutableDictionary *userType;
/**
数据接收的服务器API
*/
@property (copy, nonatomic) NSString *serverAPI;
/**
当前APP请求接口的 APIHOST(GMServerDomains.apiHost 主要用于flutter AppDelegate 中初始化需要传值
*/
@property (nonatomic, copy) NSString *apiHost;
/**
当前APP请求接口的 cookie(主要用于flutter) 获取到cookie 的时候穿过来 或者cookie 有变化的时候传过来
*/
@property (nonatomic, copy) NSString *cookie;
/**
灰度组, since 7.7.65
*/
@property (nonatomic, copy) NSString *greyType;
/**
包的类型:APPSTORE、RELEASE、DEBUG
*/
@property (nonatomic, assign) PhobosSigningType signingType;
/**
从主项目获取当前显示的controller
*/
@property (nonatomic, copy) UIViewController * (^getTopController) (void);
#pragma mark - 事件采集
/**
* @brief 自定义事件,数量统计.
*
* @param eventId 事件Id
* @attributes 参数
* @sendNow 是否实时发送,默认为NO
*
* @since 0.0.1
*/
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes;
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow;
+ (void)track:(NSString *)eventId;
/**
* @brief 自定义事件,数量统计 7730 精准曝光.
*
* @param eventId 事件Id
* @attributes 参数
* @sendNow 是否实时发送,默认为NO
* @currentAPI 当前传过来的API
* @
*/
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventId currentAPI:(NSString *)currentAPI;
/**
* @author 翟国钧, 16-02-03 16:02:30
*
* @brief H5调用的埋点方法
*
* @param jsonString h5传过来的参数
*
* @since 0.0.1
*/
+ (void)trackJsEvent:(NSString *)jsonString;
/**
* @brief PV事件开始。当controller viewWillAppear时调用
*/
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page;
/**
* @brief PV事件结束。当controller viewWillDisAppear时调用
*/
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page;
/**
* @author 翟国钧, 16-03-08 11:03:45
*
* @brief 有些事件需要模拟pv事件,统一用该方法处理,in out 时间相同.点击一次即触发
*
* @param pageName 控件所在VC的pageName
* @param bid 业务id
* @param referer 上个月面的pagename
*
* @since 5.9.1
*/
- (void)simulativePV:(NSString *)pageName businessId:(NSString *)bid referer:(NSString *)referer;
@end
NS_ASSUME_NONNULL_END
//
// Phobos.m
// GengmeiDoctor
//
// Created by Thierry on 16/1/26.
// Copyright © 2016年 wanmeizhensuo. All rights reserved.
//
#import "OldPhobos.h"
#import <AdSupport/AdSupport.h>
#import "UIResponder+PhobosPV.h"
#import "PhobosUtil.h"
#import "PhobosCustomVisibleController.h"
#import <GMCache/GMCache.h>
#import <mach/mach_time.h>
static OldPhobos *sharedClient = nil;
static NSString *sdkVersion = @"2.0.0";
@interface OldPhobos ()
@property (strong, nonatomic) UIViewController *visibleController;
@property (strong, nonatomic) NSDateFormatter *dateFormatter;
@property (strong, nonatomic) NSString *appName;
@property (strong, nonatomic) NSString *channelId;
@property (strong, nonatomic) NSString *appVersion;
@property (strong, nonatomic) NSString *sessionId;
/* 每一条埋点数据的物理ID,自增,生命周期和sessionId相同。特别注意:在sessionOver的时候,要把他置为0 */
@property (assign, nonatomic) NSInteger serialId;
// 用来记录除serverAPI以外的API
@property (strong, nonatomic) NSMutableArray *APIArray;
@end
@implementation OldPhobos
+ (OldPhobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId{
return [[self alloc] initWithAppName:appName channelId:channelId];
}
+ (OldPhobos *)sharedClient{
return sharedClient;
}
+ (void)setSharedClient:(OldPhobos *)client{
sharedClient = client;
}
- (instancetype)initWithAppName:(NSString *)appName channelId:(NSString *)channelId{
self = [super init];
if (self) {
_appName = appName;
_channelId = channelId;
_logEnabled = NO;
_userId = @"";
_netStatus = @"";
_currentCityId = @"";
_serverAPI = @"";
_greyType = @"";
_userType = [[NSMutableDictionary alloc] initWithCapacity:0];
_appVersion = [PhobosUtil getAppVersion];
_APIArray = [NSMutableArray array];
_signingType = PhobosSigningTypeUndefined;
[self setupNotification];
[self handleSessionStart];
phobosLog(@"starts to orbit");
}
return self;
}
- (void)dealloc{
if (self) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void)setUserType:(NSMutableDictionary *)userType {
if (userType == nil && userType.count == 0) {
return;
}
NSArray *newKeys = userType.allKeys;
NSArray *oldKeys = _userType.allKeys;
for (NSString *newKey in newKeys) {
if ([oldKeys containsObject:newKey]) {
NSString *newValue = [[userType objectForKey:newKey] stringValue];
NSString *oldValue = [[_userType objectForKey:newKey] stringValue];
if (![newValue isEqualToString:oldValue]) {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
} else {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
}
}
/**
在APP启动、从后台到前台的时候需要记录device_opened埋点
*/
- (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],
};
[OldPhobos track:@"device_opened" attributes:dict sendNow:YES];
}
- (UIViewController *)visibleController {
if (self.getTopController) {
id target = self.getTopController();
if ([target conformsToProtocol:NSProtocolFromString(@"PhobosCustomVisibleController")]) {
target = [target performSelector:@selector(phobosVisibleController)];
}
return target;
}
return nil;
}
#pragma mark - notification handler
/**
* @brief 设置对APP的通知监听
*
* @since 0.0.1
*/
- (void)setupNotification{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppFinishLaunch:) name:UIApplicationDidFinishLaunchingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInBackgound:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
/**
* @brief 每次打开APP或返回前台,即Session开始的时候的处理
* @notification didFinishLaunch和willEnterForeground的时候都需要记录
*
* @since 0.0.1
*/
- (void)handleSessionStart{
_serialId = 0;
_sessionId = [[NSUUID UUID] UUIDString];
[GMCache storeObjectAtDocumentPathWithkey:PhobosBeginTime object:[PhobosUtil currentTime]];
}
/**
* @brief 应用打开时的处理
*
* @since 0.0.1
*/
- (void)handleAppFinishLaunch:(id)sender{
phobosLog(@"handleAppFinishLaunch");
[self handleSessionStart];
[self handleEventDeviceOpened];
}
/**
* @brief 应用进入前台的处理
*
* @since 0.0.1
*/
- (void)handleAppInForeground:(id)sender{
phobosLog(@"handleAppInForeground");
[self handleSessionStart];
[self handleEventDeviceOpened];
[self fetchDataAndSend];
[self handlePVEventAppInForeground];
}
/**
* @brief 应用进入后台的处理
*
* @since 0.0.1
*/
- (void)handleAppInBackgound:(id)sender{
phobosLog(@"handleAppInBackgound");
[self handlePVEventAppInBackgound];
[self handleSessionOver];
[self fetchDataAndSend];
}
/**
* @brief 会话结束时候的处理
*
* @since 0.0.1
*/
- (void)handleSessionOver{
//进入后台的同时,把记录时间同步到服务端,把已使用时间清空
double beginTime = [[GMCache fetchObjectAtDocumentPathWithkey:PhobosBeginTime] doubleValue];
if (beginTime == 0) {
return;
}
NSDate *date = [NSDate date];
double endTime = [date timeIntervalSince1970];
NSString *usedTime = [NSString stringWithFormat:@"%ld",(long)(endTime - beginTime)];
NSDictionary *dict = @{@"duration":usedTime,
@"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],
};
[OldPhobos track:@"on_app_session_over" attributes:dict];
[GMCache removeObjectAtDocumentPathWithkey:PhobosBeginTime];
//当前session结束之后,把id置为0
_serialId = 0;
}
/**
APP从后台到前台的时候,重新初始化pagename等信息
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInForeground {
if (self.visibleController != nil) {
[self onPVStart:self.visibleController];
}
}
/**
APP进到后台的时候,把当前pageview时间结束
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInBackgound {
if (self.visibleController != nil) {
[self onPVEnd:self.visibleController];
}
}
#pragma mark - track event handler
+ (void)track:(NSString *)eventId{
[OldPhobos track:eventId attributes:@{}];
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes{
[self track:eventId attributes:attributes sendNow:NO];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//超过一定数量的话,统一发送一次
if (array.count > PhobosShardCount) {
[sharedClient sendArray:array cleanCacheRightNow:YES];
}
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow{
NSDictionary *dict = [sharedClient prepareDictionaryForEvent:eventId attributes:attributes];
@try {
NSData *JSON = [PhobosUtil encodeJSON:dict];
if (sendNow) {
NSArray *array = @[dict];
// 实时发送的埋点,不能立即清楚缓存
[sharedClient sendArray:array cleanCacheRightNow:NO];
}else{
[sharedClient save:dict];
}
}
@catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI {
[self track:eventId attributes:attributes sendNow:NO currentAPI:currentAPI];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
//超过一定数量的话,统一发送一次
if (array.count > PhobosShardCount) {
[sharedClient sendArray:array currentAPI:currentAPI cleanCacheRightNow:YES];
}
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI {
[sharedClient addNewApi:currentAPI]; // 记录新的API
NSDictionary *dict = [sharedClient prepareDictionaryForEvent:eventId attributes:attributes];
@try {
NSData *JSON = [PhobosUtil encodeJSON:dict];
if (sendNow) {
NSArray *array = @[dict];
// 实时发送的埋点,不能立即清楚缓存
[sharedClient sendArray:array currentAPI:currentAPI cleanCacheRightNow:NO];
}else{
[sharedClient save:dict currentAPI:currentAPI];
}
}
@catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
}
+ (void)track:(NSString *)eventId currentAPI:(NSString *)currentAPI {
[OldPhobos track:eventId attributes:@{} currentAPI:currentAPI];
}
+ (void)trackJsEvent:(NSString *)jsonString{
@try {
NSData *data = [jsonString dataUsingEncoding:NSUnicodeStringEncoding];
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
id pa = dict[@"params"];
NSDictionary *json;
if ([pa isKindOfClass:[NSString class]]) {
NSError *jsonError;
NSData *objectData = [pa dataUsingEncoding:NSUTF8StringEncoding];
json = [NSJSONSerialization JSONObjectWithData:objectData
options:NSJSONReadingMutableContainers
error:&jsonError];
[OldPhobos track:dict[@"type"] attributes:json];
}else{
[OldPhobos track:dict[@"type"]];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
#pragma mark - PV
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page {
// 必须在此处调用一下referer,因为onControllerStart
[page initReferer];
[page initRefererLink];
[page initReferrerIdIfNil];
[page initReferrerTabName];
page.inTime = [PhobosUtil currentTime];
page.inTimeMillis = [PhobosUtil currentMMTime];
// 业务层更新
if (page.updatePVStartBlock) {
page.updatePVStartBlock();
}
}
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page {
if (![PhobosUtil isNonEmpty:page.pageName] || !page.needLogPV) {
return;
}
// 业务层更新
if (page.updatePVEndBlock) {
page.updatePVEndBlock();
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:page.inTime?:@"" forKey:@"in"];
[dict setObject:page.pageName forKey:@"page_name"];
[dict setObject:page.businessId?:@"" forKey:@"business_id"];
[dict setObject:page.referer?:@"" forKey:@"referrer"];
if ([page.referrerLink isKindOfClass:[NSArray class]] && page.referrerLink.count) {
[dict setObject:page.referrerLink forKey:@"referrer_link"];
} else {
[dict setObject:@[] forKey:@"referrer_link"];
}
[dict setObject:@(0) forKey:@"fake"];
[dict setObject:page.referrerId ? : @"" forKey:@"referrer_id"];
[dict setObject:page.extraParam ? : @"" forKey:@"extra_param"];
[dict setObject:page.referrerTabName ? : @"" forKey:@"referrer_tab_name"];
[dict setObject:page.isPush.intValue ? @(page.isPush.intValue) : @(0) forKey:@"is_push"];
[dict setObject:page.inTimeMillis?:@"" forKey:@"in_time_millis"];
[dict setObject:[PhobosUtil currentMMTime] forKey:@"out_time_millis"];
if (page.inTime.length > 0) {
// 页面显示时间为空时不记录页面pv事件
[OldPhobos track:@"page_view" attributes:dict];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
- (void)simulativePV:(NSString *)pageName businessId:(NSString *)bid referer:(NSString *)referer{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
// fake(模拟)的事件,所以in与out一样,就是这么规定的
[dict setObject:[PhobosUtil currentTime] forKey:@"in"];
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:pageName?:@"" forKey:@"page_name"];
[dict setObject:bid?:@"" forKey:@"business_id"];
[dict setObject:referer?:@"" forKey:@"referrer"];
[dict setObject:@(1) forKey:@"fake"];
[OldPhobos track:@"page_view" attributes:dict];
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
#pragma mark - 事件存储、发送
/**
* @brief 将埋点时间封装成词典数据
*
* @since 0.0.1
*/
- (NSDictionary *)prepareDictionaryForEvent:(NSString *)eventId attributes:(NSDictionary *)attributes{
NSArray *referrerLink = sharedClient.visibleController.referrerLink;
// 对于埋点没有referrer_link的情况,在这里进行统一添加
if (![attributes.allKeys containsObject:@"referrer_link"]) {
NSMutableDictionary *attributesParams = [NSMutableDictionary dictionaryWithDictionary:attributes];
if ([referrerLink isKindOfClass:[NSArray class]] && referrerLink.count) {
[attributesParams setValue:referrerLink forKey:@"referrer_link"];
} else {
[attributesParams setValue:@[] forKey:@"referrer_link"];
}
attributes = attributesParams;
}
[self catchNullForEvent:eventId attributes:attributes];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
NSString *currentTime = [PhobosUtil currentTime];
NSMutableDictionary *deviceParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString],@"idfa",
[[[UIDevice currentDevice] identifierForVendor] UUIDString],@"idfv",
[PhobosUtil deviceId],@"device_id",
@"ios",@"device_type",
@"Apple",@"manufacturer",
@(self.gps.coordinate.latitude),@"lat",
@(self.gps.coordinate.longitude),@"lng",
_netStatus,@"is_WiFi",
[PhobosUtil getIPAddress:YES],@"ip",nil];
[deviceParams setValue:_networkStatus forKey:@"net_type"];
[deviceParams setValue:[PhobosUtil platform] forKey:@"model"];
[deviceParams setValue:[UIDevice currentDevice].systemVersion forKey:@"sys_version"];
NSMutableDictionary *appParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
_greyType, @"grey_type",
self.appName, @"name",
self.appVersion, @"version",
self.channelId,@"channel",
_userType,@"user_type",
self.currentCityId,@"current_city_id",
@(_serialId++), @"serial_id",nil];
if (_signingType == PhobosSigningTypeDebug || _signingType == PhobosSigningTypeRelease) {
[dict setObject:@(0) forKey:@"is_release"];
}
NSString *nano_time = [NSString stringWithFormat:@"%lld",[[NSProcessInfo processInfo] systemUptime]];
[dict setObject:eventId forKey:@"type"];
[dict setObject:appParams forKey:@"app"];
[dict setObject:sdkVersion forKey:@"version"];
[dict setObject:deviceParams forKey:@"device"];
[dict setObject:_userId forKey:@"user_id"];
[dict setObject:currentTime forKey:@"create_at"];// 1584513842 当前时间(秒)
[dict setObject:nano_time?:@"" forKey:@"nano_time"];// 1657008897 系统启动后时长(秒)
[dict setObject:@(mach_absolute_time()) forKey:@"absolute_time"];// 148237263697318 系统启动后的 CPU 嘀嗒数(纳秒)
[dict setObject:[PhobosUtil currentMMTime] forKey:@"create_at_millis"];// 1584513842753 当前时间戳(毫秒)
[dict setObject:attributes forKey:@"params"];
[dict setObject:_sessionId forKey:@"app_session_id"];
}
@catch (NSException *exception) {
phobosLog(exception);
}
return dict;
}
/**
* @brief 保存数据到缓存层
*
* @param data 数据
*
* @since 0.0.1
*/
- (void)save:(NSDictionary *)data
{
if (_logEnabled) {
phobosLog([NSString stringWithFormat:@"save dictionary: %@",data]);
}
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
if (dataArray) {
#ifdef POD_CONFIGURATION_APP_STORE
[dataArray addObject:data];
#else
if (data[@"type"] && [data[@"type"] isEqualToString:@"page_view"]) {
NSDictionary *pageParams = data[@"params"];
long long pageInTime = [pageParams[@"in"] longLongValue];
long long pageOutTime = [pageParams[@"out"] longLongValue];
// phobosLog(@"pageInTime------%lld",pageInTime);
// phobosLog(@"pageOutTime------%lld",pageOutTime);
if (pageInTime && pageOutTime) {
__block BOOL checkTimeError;
for (int i = 0; i < dataArray.count; i++) {
NSDictionary *obj = dataArray[i];
if (obj[@"type"] && [obj[@"type"] isEqualToString:@"page_view"]) {
NSDictionary *params = obj[@"params"];
long long objInTime = [params[@"in"] longLongValue];
long long objOutTime = [params[@"out"] longLongValue];
if ( (fabsl(objInTime - pageInTime)) < 1 || (fabsl(objOutTime - pageOutTime)) < 1) {
phobosLog(@"两个埋点inTime 时间差------%f", (fabsl(objInTime - pageInTime)));
phobosLog(@"两个埋点outTime 时间差------%f", (fabsl(objOutTime - pageOutTime)));
checkTimeError = YES;
phobosLog(@"%s____数据校验失败,PV埋点可能重复", __func__);
/*
dispatch_async(dispatch_get_main_queue(), ^{
NSString *stringTitle = [NSString stringWithFormat:@"%@ PV埋点可能重复", data];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:stringTitle message:nil delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertView show];
});*/
break;
}
}
}
}
}
// 不管成功还是失败 给开发提示方便DEBUG
// phobosLog(@"%s____数据校验成功", __func__);
[dataArray addObject:data];
#endif
} else {
dataArray = [NSMutableArray arrayWithObject:data];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosCacheKey object:dataArray];
}
/**
* @brief 保存数据到缓存层
*
* @param data 数据
*
*/
- (void)save:(NSDictionary *)data currentAPI:(NSString *)currentAPI
{
if (_logEnabled) {
phobosLog([NSString stringWithFormat:@"save dictionary: %@",data]);
}
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
if (dataArray) {
[dataArray addObject:data];
}else{
dataArray = [NSMutableArray arrayWithObject:data];
}
[GMCache storeObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI] object:dataArray];
}
/**
* @brief 从缓存中获取数据,并发送
*
* @since 0.0.1
*/
- (void)fetchDataAndSend{
NSArray *paramsArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
if (paramsArray.count>0) {
[self sendArray:paramsArray cleanCacheRightNow:YES];
}
// 其他接口的埋点
for (NSString *newApi in self.APIArray) {
NSArray *paramsArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:newApi]];
if (paramsArray.count>0) {
[self sendArray:paramsArray currentAPI:newApi cleanCacheRightNow:YES];
}
}
}
/*
从缓存区获取数据,发给服务器,请求成功的时候,把缓存区的数据删除掉
*/
- (void)sendArray {
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
if (_logEnabled) {
NSData *data = [NSJSONSerialization dataWithJSONObject:dataArray options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
phobosLog([NSString stringWithFormat:@"array prepare to fly --✈: %@", jsonString]);
}
@try {
NSData *JSON = [PhobosUtil encodeJSON:dataArray];
NSData *compressedData = [PhobosUtil compressData:JSON];
if (compressedData) {
[PhobosUtil sendData:compressedData success:^(NSInteger code) {
if (code == 200) {
phobosLog(@"✈ ---------- ✈ data arrived Mars");
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKey];
}
}];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
/*
从缓存区获取数据,发给服务器,请求成功的时候,把缓存区的数据删除掉
*/
- (void)sendArrayWithCurrentAPI:(NSString *)currentAPI {
NSString *PhobosTempCacheKeyStr = [PhobosUtil MD5String:[PhobosUtil MD5String:currentAPI]]; // 两次加密作为key值,和缓存的key值作区分
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
if (_logEnabled) {
NSData *data = [NSJSONSerialization dataWithJSONObject:dataArray options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
phobosLog([NSString stringWithFormat:@"array prepare to fly --✈: %@", jsonString]);
}
@try {
NSData *JSON = [PhobosUtil encodeJSON:dataArray];
NSData *compressedData = [PhobosUtil compressData:JSON];
if (compressedData) {
[PhobosUtil sendData:compressedData currentAPI:currentAPI success:^(NSInteger code) {
if (code == 200) {
phobosLog(@"✈ ---------- ✈ data arrived Mars");
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
}
}];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
/**
该方法有改动,现在的逻辑是:当前方法只接受发送的请求,然后把数据转存到另一个缓存区,
让sendArray方法负责发送,数据一旦转移到缓存区,就把原有的数据干掉。
@author zhaiguojun 16-10-17 in (null)
@param array 参数
@param clean 是否立即清楚缓存
*/
- (void)sendArray:(NSArray *)array cleanCacheRightNow:(BOOL)clean {
@try {
//1.获取缓存区的数据,把新数据追加进去
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
if (dataArray) {
[dataArray addObjectsFromArray:array];
}else{
dataArray = [NSMutableArray arrayWithArray:array];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosTempCacheKey object:dataArray];
//2.把缓存区的数据发送给服务器
[self sendArray];
//3.把原有的数据删除
if (clean) {
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
/**
上边方法新加了一个API字段
*/
- (void)sendArray:(NSArray *)array currentAPI:(NSString *)currentAPI cleanCacheRightNow:(BOOL)clean {
@try {
//1.获取缓存区的数据,把新数据追加进去
NSString *PhobosTempCacheKeyStr = [PhobosUtil MD5String:[PhobosUtil MD5String:currentAPI]]; // 两次加密作为key值,和缓存的key值作区分
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
if (dataArray) {
[dataArray addObjectsFromArray:array];
}else{
dataArray = [NSMutableArray arrayWithArray:array];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr object:dataArray];
//2.把缓存区的数据发送给服务器
[self sendArrayWithCurrentAPI:currentAPI];
//3.把原有的数据删除
[GMCache removeObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
#pragma mark - helpers
- (void)catchNullForEvent:(NSString *)eventId attributes:(NSDictionary *)attributes {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
@try {
for (NSString *key in attributes.allKeys) {
if ([attributes[key] isMemberOfClass:[NSNull class]]) {
if (self.captureNullExpection) {
self.captureNullExpection(eventId, attributes);
}
break;
}
}
} @catch (NSException *exception) {
}
});
}
- (void)addNewApi:(NSString *)api {
for (NSString *item in self.APIArray) {
if ([api isEqualToString:item]) {
break;
}
[self.APIArray addObject:api];
}
}
@end
......@@ -8,17 +8,11 @@
#import <Foundation/Foundation.h>
#import "PhobosPVProtocol.h"
#import "PhobosConfig.h"
#import <CoreLocation/CLLocation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM (NSInteger, PhobosSigningType) {
PhobosSigningTypeUndefined = 0,
PhobosSigningTypeAppStore,
PhobosSigningTypeRelease,
PhobosSigningTypeDebug
};
@interface Phobos : NSObject
/**
......@@ -124,6 +118,10 @@ typedef NS_ENUM (NSInteger, PhobosSigningType) {
#pragma mark - 事件采集
/** 点击事件采集 */
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes;
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow;
/**
* @brief 自定义事件,数量统计.
*
......@@ -149,18 +147,6 @@ typedef NS_ENUM (NSInteger, PhobosSigningType) {
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI;
+ (void)track:(NSString *)eventId currentAPI:(NSString *)currentAPI;
/**
* @author 翟国钧, 16-02-03 16:02:30
*
* @brief H5调用的埋点方法
*
* @param jsonString h5传过来的参数
*
* @since 0.0.1
*/
+ (void)trackJsEvent:(NSString *)jsonString;
/**
* @brief PV事件开始。当controller viewWillAppear时调用
*/
......@@ -169,19 +155,19 @@ typedef NS_ENUM (NSInteger, PhobosSigningType) {
* @brief PV事件结束。当controller viewWillDisAppear时调用
*/
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page;
@end
/**
* @author 翟国钧, 16-03-08 11:03:45
*
* @brief 有些事件需要模拟pv事件,统一用该方法处理,in out 时间相同.点击一次即触发
*
* @param pageName 控件所在VC的pageName
* @param bid 业务id
* @param referer 上个月面的pagename
*
* @since 5.9.1
*/
- (void)simulativePV:(NSString *)pageName businessId:(NSString *)bid referer:(NSString *)referer;
@interface Phobos (UtilTest)
/** 获取待发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount;
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData;
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData;
@end
NS_ASSUME_NONNULL_END
//
// Phobos.m
// GengmeiDoctor
// GMCache
//
// Created by Thierry on 16/1/26.
// Copyright © 2016年 wanmeizhensuo. All rights reserved.
// Created by Locus on 2019/12/25.
//
#import "Phobos.h"
#import <AdSupport/AdSupport.h>
#import "PhobosUtil.h"
#import "PhobosConfig.h"
#import "UIResponder+PhobosPV.h"
#import "PhobosUtil.h"
#import "PhobosCustomVisibleController.h"
#import "UIDevice+Resolutions.h"
#import <GMCache/GMCache.h>
#import <mach/mach_time.h>
#import "OldPhobos.h"
#import "NewPhobos.h"
static Phobos *sharedClient = nil;
static NSString *sdkVersion = @"110";
static BOOL isGray = NO;
@interface Phobos ()
@property (strong, nonatomic) UIViewController *visibleController;
@property (strong, nonatomic) NSDateFormatter *dateFormatter;
@property (strong, nonatomic) NSString *appName;
@property (strong, nonatomic) NSString *channelId;
@property (strong, nonatomic) NSString *appVersion;
@property (strong, nonatomic) NSString *sessionId;
/* 每一条埋点数据的物理ID,自增,生命周期和sessionId相同。特别注意:在sessionOver的时候,要把他置为0 */
@property (assign, nonatomic) NSInteger serialId;
// 用来记录除serverAPI以外的API
@property (strong, nonatomic) NSMutableArray *APIArray;
@property (nonatomic, strong) OldPhobos *oldPhobos;
@property (nonatomic, strong) NewPhobos *rePhobos;
@end
@implementation Phobos
+ (Phobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId{
/**
* @brief 开启Phobos统计,默认以BATCH方式发送log.
*
* @param appName 通常由数据端与客户端一起确认的区分不同app的名字
* @param channelId 发布渠道
*
* @return Phobos实例
*
* @since 0.0.1
*/
+ (Phobos *)clientWithAppName:(NSString *)appName channelId:(NSString *)channelId {
return [[self alloc] initWithAppName:appName channelId:channelId];
}
+ (Phobos *)sharedClient{
+ (instancetype)sharedClient {
return sharedClient;
}
+ (void)setSharedClient:(Phobos *)client{
+ (void)setSharedClient:(Phobos *)client {
sharedClient = client;
}
- (instancetype)initWithAppName:(NSString *)appName channelId:(NSString *)channelId{
self = [super init];
if (self) {
_appName = appName;
_channelId = channelId;
_logEnabled = NO;
_userId = @"";
_netStatus = @"";
_currentCityId = @"";
_serverAPI = @"";
_greyType = @"";
_userType = [[NSMutableDictionary alloc] initWithCapacity:0];
_appVersion = [PhobosUtil getAppVersion];
_APIArray = [NSMutableArray array];
_signingType = PhobosSigningTypeUndefined;
[self setupNotification];
[self handleSessionStart];
[self synchronizePhobosKey];
phobosLog(@"starts to orbit");
if (self = [super init]) {
isGray = [[[NSUserDefaults standardUserDefaults] objectForKey:PhobosGray] boolValue];
if (isGray) {
_rePhobos = [NewPhobos clientWithAppName:appName channelId:channelId];
sharedClient = _rePhobos;
_rePhobos.isGray = YES;
} else {
_oldPhobos = [OldPhobos clientWithAppName:appName channelId:channelId];
[OldPhobos setSharedClient:_oldPhobos];
sharedClient = _oldPhobos;
}
}
return self;
}
/**
* disk下的PhobosHaveOpenApp只要存在,就把他取出来放到document下(注:当不支持7.6.16版本的时候,干掉这个方法)
*/
- (void)synchronizePhobosKey {
if ([GMCache fetchObjectAtDiskWithkey:PhobosHaveOpenApp]) {
NSString *prefePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
prefePath = [NSString stringWithFormat:@"%@/com.tumblr.TMDiskCache.WMCacheShared/%@",prefePath ,PhobosHaveOpenApp];
NSURL *fileUrl = [NSURL fileURLWithPathComponents:@[prefePath]];
BOOL written = [NSKeyedArchiver archiveRootObject:PhobosHaveOpenApp toFile:[fileUrl path]];
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes {
if (isGray) {
[NewPhobos onClickButtonWithAttributes:attributes];
} else {
[self track:@"on_cick_button" attributes:attributes];
}
}
- (void)dealloc{
if (self) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
+ (void)onClickButtonWithAttributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow {
if (isGray) {
[NewPhobos onClickButtonWithAttributes:attributes sendNow:sendNow];
} else {
[self track:@"on_cick_button" attributes:attributes sendNow:sendNow];
}
}
- (void)setUserType:(NSMutableDictionary *)userType {
if (userType == nil && userType.count == 0) {
return;
}
NSArray *newKeys = userType.allKeys;
NSArray *oldKeys = _userType.allKeys;
for (NSString *newKey in newKeys) {
if ([oldKeys containsObject:newKey]) {
NSString *newValue = [[userType objectForKey:newKey] stringValue];
NSString *oldValue = [[_userType objectForKey:newKey] stringValue];
if (![newValue isEqualToString:oldValue]) {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
} else {
[_userType setObject:[userType objectForKey:newKey] forKey:newKey];
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes {
if (isGray) {
[NewPhobos track:eventId attributes:attributes];
} else {
[OldPhobos track:eventId attributes:attributes];
}
}
/**
在APP启动、从后台到前台的时候需要记录device_opened埋点
*/
- (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],
@"build_model": [UIDevice deviceVersion],
};
[Phobos track:@"device_opened" attributes:dict sendNow:YES];
/** 第一次打开APP埋点 **/
// 当不再支持7.6.15版本时,只保留
if (![GMCache fetchObjectAtDocumentPathWithkey:PhobosHaveOpenApp]) {
[Phobos track:@"device_activated" attributes:@{} sendNow:YES];
[Phobos track:@"device_activated" attributes:@{} sendNow:NO];
[GMCache storeObjectAtDocumentPathWithkey:PhobosHaveOpenApp object:PhobosHaveOpenApp];
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow {
if (isGray) {
[NewPhobos track:eventId attributes:attributes sendNow:sendNow];
} else {
[OldPhobos track:eventId attributes:attributes sendNow:sendNow];
}
}
- (UIViewController *)visibleController {
if (self.getTopController) {
id target = self.getTopController();
if ([target conformsToProtocol:NSProtocolFromString(@"PhobosCustomVisibleController")]) {
target = [target performSelector:@selector(phobosVisibleController)];
}
return target;
+ (void)track:(NSString *)eventId {
if (isGray) {
[NewPhobos track:eventId];
} else {
[OldPhobos track:eventId];
}
return nil;
}
#pragma mark - notification handler
/**
* @brief 设置对APP的通知监听
*
* @since 0.0.1
*/
- (void)setupNotification{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppFinishLaunch:) name:UIApplicationDidFinishLaunchingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppInBackgound:) name:UIApplicationDidEnterBackgroundNotification object:nil];
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI {
if (isGray) {
[NewPhobos track:eventId attributes:attributes currentAPI:currentAPI];
} else {
[OldPhobos track:eventId attributes:attributes currentAPI:currentAPI];
}
}
/**
* @brief 每次打开APP或返回前台,即Session开始的时候的处理
* @notification didFinishLaunch和willEnterForeground的时候都需要记录
*
* @since 0.0.1
*/
- (void)handleSessionStart{
_serialId = 0;
_sessionId = [[NSUUID UUID] UUIDString];
[GMCache storeObjectAtDocumentPathWithkey:PhobosBeginTime object:[PhobosUtil currentTime]];
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI {
if (isGray) {
[NewPhobos track:eventId attributes:attributes sendNow:sendNow currentAPI:currentAPI];
} else {
[OldPhobos track:eventId attributes:attributes sendNow:sendNow currentAPI:currentAPI];
}
}
/**
* @brief 应用打开时的处理
*
* @since 0.0.1
*/
- (void)handleAppFinishLaunch:(id)sender{
phobosLog(@"handleAppFinishLaunch");
[self handleSessionStart];
[self handleEventDeviceOpened];
+ (void)track:(NSString *)eventId currentAPI:(NSString *)currentAPI {
if (isGray) {
[NewPhobos track:eventId currentAPI:currentAPI];
} else {
[OldPhobos track:eventId currentAPI:currentAPI];
}
}
/**
* @brief 应用进入前台的处理
*
* @since 0.0.1
* @brief PV事件开始。当controller viewWillAppear时调用
*/
- (void)handleAppInForeground:(id)sender{
phobosLog(@"handleAppInForeground");
[self handleSessionStart];
[self handleEventDeviceOpened];
[self fetchDataAndSend];
[self handlePVEventAppInForeground];
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page {
[_rePhobos onPVStart:page];
[_oldPhobos onPVStart:page];
}
/**
* @brief 应用进入后台的处理
*
* @since 0.0.1
* @brief PV事件结束。当controller viewWillDisAppear时调用
*/
- (void)handleAppInBackgound:(id)sender{
phobosLog(@"handleAppInBackgound");
[self handlePVEventAppInBackgound];
[self handleSessionOver];
[self fetchDataAndSend];
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page {
[_rePhobos onPVEnd:page];
[_oldPhobos onPVEnd:page];
}
/**
* @brief 会话结束时候的处理
*
* @since 0.0.1
*/
- (void)handleSessionOver{
//进入后台的同时,把记录时间同步到服务端,把已使用时间清空
double beginTime = [[GMCache fetchObjectAtDocumentPathWithkey:PhobosBeginTime] doubleValue];
if (beginTime == 0) {
return;
}
NSDate *date = [NSDate date];
double endTime = [date timeIntervalSince1970];
NSString *usedTime = [NSString stringWithFormat:@"%ld",(long)(endTime - beginTime)];
NSDictionary *dict = @{@"duration":usedTime,
@"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],
@"build_model": [UIDevice deviceVersion],
};
[Phobos track:@"on_app_session_over" attributes:dict];
[GMCache removeObjectAtDocumentPathWithkey:PhobosBeginTime];
//当前session结束之后,把id置为0
_serialId = 0;
- (void)setCaptureNullExpection:(void (^)(NSString * _Nonnull, NSDictionary * _Nonnull))captureNullExpection {
_rePhobos.captureNullExpection = captureNullExpection;
_oldPhobos.captureNullExpection = captureNullExpection;
}
/**
APP从后台到前台的时候,重新初始化pagename等信息
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInForeground {
if (self.visibleController != nil) {
[self onPVStart:self.visibleController];
}
- (void)setNetStatus:(NSString *)netStatus {
_rePhobos.netStatus = netStatus;
_oldPhobos.netStatus = netStatus;
}
/**
APP进到后台的时候,把当前pageview时间结束
@author zhaiguojun 16-10-11 in (null)
*/
- (void)handlePVEventAppInBackgound {
if (self.visibleController != nil) {
[self onPVEnd:self.visibleController];
}
- (void)setNetworkStatus:(NSString *)networkStatus {
_rePhobos.networkStatus = networkStatus;
_oldPhobos.networkStatus = networkStatus;
}
#pragma mark - track event handler
+ (void)track:(NSString *)eventId{
[Phobos track:eventId attributes:@{}];
- (void)setLogEnabled:(BOOL)logEnabled {
_rePhobos.logEnabled = logEnabled;
_oldPhobos.logEnabled = logEnabled;
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes{
[self track:eventId attributes:attributes sendNow:NO];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
//超过一定数量的话,统一发送一次
if (array.count > PhobosShardCount) {
[sharedClient sendArray:array cleanCacheRightNow:YES];
}
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow{
NSDictionary *dict = [sharedClient prepareDictionaryForEvent:eventId attributes:attributes];
@try {
NSData *JSON = [PhobosUtil encodeJSON:dict];
if (sendNow) {
NSArray *array = @[dict];
// 实时发送的埋点,不能立即清楚缓存
[sharedClient sendArray:array cleanCacheRightNow:NO];
}else{
[sharedClient save:dict];
}
}
@catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
- (void)setUserId:(NSString *)userId {
_rePhobos.userId = userId;
_oldPhobos.userId = userId;
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes currentAPI:(NSString *)currentAPI {
[self track:eventId attributes:attributes sendNow:NO currentAPI:currentAPI];
NSArray *array = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
//超过一定数量的话,统一发送一次
if (array.count > PhobosShardCount) {
[sharedClient sendArray:array currentAPI:currentAPI cleanCacheRightNow:YES];
}
- (void)setCurrentCityId:(NSString *)currentCityId {
_rePhobos.currentCityId = currentCityId;
_oldPhobos.currentCityId = currentCityId;
}
+ (void)track:(NSString *)eventId attributes:(NSDictionary *)attributes sendNow:(BOOL)sendNow currentAPI:(NSString *)currentAPI {
[sharedClient addNewApi:currentAPI]; // 记录新的API
NSDictionary *dict = [sharedClient prepareDictionaryForEvent:eventId attributes:attributes];
@try {
NSData *JSON = [PhobosUtil encodeJSON:dict];
if (sendNow) {
NSArray *array = @[dict];
// 实时发送的埋点,不能立即清楚缓存
[sharedClient sendArray:array currentAPI:currentAPI cleanCacheRightNow:NO];
}else{
[sharedClient save:dict currentAPI:currentAPI];
}
}
@catch (NSException *exception) {
NSAssert(NO, @"哎呀呀,VALUE不能为NSObject ");
}
- (void)setGps:(CLLocation *)gps {
_rePhobos.gps = gps;
_oldPhobos.gps = gps;
}
+ (void)track:(NSString *)eventId currentAPI:(NSString *)currentAPI {
[Phobos track:eventId attributes:@{} currentAPI:currentAPI];
}
+ (void)trackJsEvent:(NSString *)jsonString{
@try {
NSData *data = [jsonString dataUsingEncoding:NSUnicodeStringEncoding];
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
id pa = dict[@"params"];
NSDictionary *json;
if ([pa isKindOfClass:[NSString class]]) {
NSError *jsonError;
NSData *objectData = [pa dataUsingEncoding:NSUTF8StringEncoding];
json = [NSJSONSerialization JSONObjectWithData:objectData
options:NSJSONReadingMutableContainers
error:&jsonError];
[Phobos track:dict[@"type"] attributes:json];
}else{
[Phobos track:dict[@"type"]];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
- (void)setUserType:(NSMutableDictionary *)userType {
_rePhobos.userType = userType;
_oldPhobos.userType = userType;
}
#pragma mark - PV
- (void)onPVStart:(UIResponder<PhobosPVProtocol> *)page {
// 必须在此处调用一下referer,因为onControllerStart
[page initReferer];
[page initRefererLink];
[page initReferrerIdIfNil];
[page initReferrerTabName];
page.inTime = [PhobosUtil currentTime];
page.inTimeMillis = [PhobosUtil currentMMTime];
// 业务层更新
if (page.updatePVStartBlock) {
page.updatePVStartBlock();
}
- (void)setApiHost:(NSString *)apiHost {
_rePhobos.apiHost = apiHost;
_oldPhobos.apiHost = apiHost;
}
- (void)onPVEnd:(UIResponder<PhobosPVProtocol> *)page {
if (![PhobosUtil isNonEmpty:page.pageName] || !page.needLogPV) {
return;
}
// 业务层更新
if (page.updatePVEndBlock) {
page.updatePVEndBlock();
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:page.inTime?:@"" forKey:@"in"];
[dict setObject:page.pageName forKey:@"page_name"];
[dict setObject:page.businessId?:@"" forKey:@"business_id"];
[dict setObject:page.referer?:@"" forKey:@"referrer"];
if ([page.referrerLink isKindOfClass:[NSArray class]] && page.referrerLink.count) {
[dict setObject:page.referrerLink forKey:@"referrer_link"];
} else {
[dict setObject:@[] forKey:@"referrer_link"];
}
[dict setObject:@(0) forKey:@"fake"];
[dict setObject:page.referrerId ? : @"" forKey:@"referrer_id"];
[dict setObject:page.extraParam ? : @"" forKey:@"extra_param"];
[dict setObject:page.referrerTabName ? : @"" forKey:@"referrer_tab_name"];
[dict setObject:page.isPush.intValue ? @(page.isPush.intValue) : @(0) forKey:@"is_push"];
[dict setObject:page.inTimeMillis?:@"" forKey:@"in_time_millis"];
[dict setObject:[PhobosUtil currentMMTime] forKey:@"out_time_millis"];
if (page.inTime.length > 0) {
// 页面显示时间为空时不记录页面pv事件
[Phobos track:@"page_view" attributes:dict];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
- (void)setServerAPI:(NSString *)serverAPI {
_rePhobos.serverAPI = serverAPI;
_oldPhobos.serverAPI = serverAPI;
}
- (void)simulativePV:(NSString *)pageName businessId:(NSString *)bid referer:(NSString *)referer{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
// fake(模拟)的事件,所以in与out一样,就是这么规定的
[dict setObject:[PhobosUtil currentTime] forKey:@"in"];
[dict setObject:[PhobosUtil currentTime] forKey:@"out"];
[dict setObject:pageName?:@"" forKey:@"page_name"];
[dict setObject:bid?:@"" forKey:@"business_id"];
[dict setObject:referer?:@"" forKey:@"referrer"];
[dict setObject:@(1) forKey:@"fake"];
[Phobos track:@"page_view" attributes:dict];
}
@catch (NSException *exception) {
phobosLog(exception);
}
-(void)setCookie:(NSString *)cookie {
_rePhobos.cookie = cookie;
_oldPhobos.cookie = cookie;
}
#pragma mark - 事件存储、发送
/**
* @brief 将埋点时间封装成词典数据
*
* @since 0.0.1
*/
- (NSDictionary *)prepareDictionaryForEvent:(NSString *)eventId attributes:(NSDictionary *)attributes {
NSArray *referrerLink = sharedClient.visibleController.referrerLink;
// 对于埋点没有referrer_link的情况,在这里进行统一添加
if (![attributes.allKeys containsObject:@"referrer_link"]) {
NSMutableDictionary *attributesParams = [NSMutableDictionary dictionaryWithDictionary:attributes];
if ([referrerLink isKindOfClass:[NSArray class]] && referrerLink.count) {
[attributesParams setValue:referrerLink forKey:@"referrer_link"];
} else {
[attributesParams setValue:@[] forKey:@"referrer_link"];
}
attributes = attributesParams;
}
[self catchNullForEvent:eventId attributes:attributes];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
@try {
NSString *currentTime = [PhobosUtil currentTime];
NSMutableDictionary *deviceParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString],@"idfa",
[[[UIDevice currentDevice] identifierForVendor] UUIDString],@"idfv",
[PhobosUtil deviceId],@"device_id",
@"ios",@"device_type",
@"Apple",@"manufacturer",
@(self.gps.coordinate.latitude),@"lat",
@(self.gps.coordinate.longitude),@"lng",
_netStatus,@"is_WiFi",
[PhobosUtil getIPAddress:YES],@"ip",nil];
[deviceParams setValue:_networkStatus forKey:@"net_type"];
[deviceParams setValue:[UIDevice platform] forKey:@"model"];
[deviceParams setValue:[UIDevice currentDevice].systemVersion forKey:@"sys_version"];
NSMutableDictionary *appParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
_greyType, @"grey_type",
self.appName, @"name",
self.appVersion, @"version",
self.channelId,@"channel",
_userType,@"user_type",
self.currentCityId,@"current_city_id",
@(_serialId++), @"serial_id",nil];
if (_signingType == PhobosSigningTypeDebug || _signingType == PhobosSigningTypeRelease) {
[dict setObject:@(0) forKey:@"is_release"];
}
NSString *nano_time = [NSString stringWithFormat:@"%lld",[[NSProcessInfo processInfo] systemUptime]];
[dict setObject:eventId forKey:@"type"];
[dict setObject:appParams forKey:@"app"];
[dict setObject:sdkVersion forKey:@"version"];
[dict setObject:deviceParams forKey:@"device"];
[dict setObject:_userId forKey:@"user_id"];
[dict setObject:currentTime forKey:@"create_at"];// 1584513842 当前时间(秒)
[dict setObject:nano_time?:@"" forKey:@"nano_time"];// 1657008897 系统启动后时长(秒)
[dict setObject:@(mach_absolute_time()) forKey:@"absolute_time"];// 148237263697318 系统启动后的 CPU 嘀嗒数(纳秒)
[dict setObject:[PhobosUtil currentMMTime] forKey:@"create_at_millis"];// 1584513842753 当前时间戳(毫秒)
[dict setObject:attributes forKey:@"params"];
[dict setObject:_sessionId forKey:@"app_session_id"];
}
@catch (NSException *exception) {
phobosLog(exception);
}
return dict;
- (void)setGreyType:(NSString *)greyType {
_rePhobos.greyType = greyType;
_oldPhobos.greyType = greyType;
}
/**
* @brief 保存数据到缓存层
*
* @param data 数据
*
* @since 0.0.1
*/
- (void)save:(NSDictionary *)data
{
if (_logEnabled) {
phobosLog([NSString stringWithFormat:@"save dictionary: %@",data]);
}
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
if (dataArray) {
#ifdef POD_CONFIGURATION_APP_STORE
[dataArray addObject:data];
#else
if (data[@"type"] && [data[@"type"] isEqualToString:@"page_view"]) {
NSDictionary *pageParams = data[@"params"];
long long pageInTime = [pageParams[@"in"] longLongValue];
long long pageOutTime = [pageParams[@"out"] longLongValue];
// phobosLog(@"pageInTime------%lld",pageInTime);
// phobosLog(@"pageOutTime------%lld",pageOutTime);
if (pageInTime && pageOutTime) {
__block BOOL checkTimeError;
for (int i = 0; i < dataArray.count; i++) {
NSDictionary *obj = dataArray[i];
if (obj[@"type"] && [obj[@"type"] isEqualToString:@"page_view"]) {
NSDictionary *params = obj[@"params"];
long long objInTime = [params[@"in"] longLongValue];
long long objOutTime = [params[@"out"] longLongValue];
if ( (fabsl(objInTime - pageInTime)) < 1 || (fabsl(objOutTime - pageOutTime)) < 1) {
phobosLog(@"两个埋点inTime 时间差------%f", (fabsl(objInTime - pageInTime)));
phobosLog(@"两个埋点outTime 时间差------%f", (fabsl(objOutTime - pageOutTime)));
checkTimeError = YES;
phobosLog(@"%s____数据校验失败,PV埋点可能重复", __func__);
/*
dispatch_async(dispatch_get_main_queue(), ^{
NSString *stringTitle = [NSString stringWithFormat:@"%@ PV埋点可能重复", data];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:stringTitle message:nil delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertView show];
});*/
break;
}
}
}
}
}
// 不管成功还是失败 给开发提示方便DEBUG
// phobosLog(@"%s____数据校验成功", __func__);
[dataArray addObject:data];
#endif
} else {
dataArray = [NSMutableArray arrayWithObject:data];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosCacheKey object:dataArray];
- (void)setSigningType:(PhobosSigningType)signingType {
_rePhobos.signingType = signingType;
_oldPhobos.signingType = signingType;
}
/**
* @brief 保存数据到缓存层
*
* @param data 数据
*
*/
- (void)save:(NSDictionary *)data currentAPI:(NSString *)currentAPI
{
if (_logEnabled) {
phobosLog([NSString stringWithFormat:@"save dictionary: %@",data]);
}
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
if (dataArray) {
[dataArray addObject:data];
}else{
dataArray = [NSMutableArray arrayWithObject:data];
}
[GMCache storeObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI] object:dataArray];
}
/**
* @brief 从缓存中获取数据,并发送
*
* @since 0.0.1
*/
- (void)fetchDataAndSend{
NSArray *paramsArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
if (paramsArray.count>0) {
[self sendArray:paramsArray cleanCacheRightNow:YES];
}
// 其他接口的埋点
for (NSString *newApi in self.APIArray) {
NSArray *paramsArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:newApi]];
if (paramsArray.count>0) {
[self sendArray:paramsArray currentAPI:newApi cleanCacheRightNow:YES];
}
}
- (void)setGetTopController:(UIViewController * _Nonnull (^)(void))getTopController {
_rePhobos.getTopController = getTopController;
_oldPhobos.getTopController = getTopController;
}
/*
从缓存区获取数据,发给服务器,请求成功的时候,把缓存区的数据删除掉
*/
- (void)sendArray {
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
if (_logEnabled) {
NSData *data = [NSJSONSerialization dataWithJSONObject:dataArray options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
phobosLog([NSString stringWithFormat:@"array prepare to fly --✈: %@", jsonString]);
}
@try {
NSData *JSON = [PhobosUtil encodeJSON:dataArray];
NSData *compressedData = [PhobosUtil compressData:JSON];
if (compressedData) {
[PhobosUtil sendData:compressedData success:^(NSInteger code) {
phobosLog(@"✈ ---------- ✈ data arrived Mars");
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKey];
}];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
- (NSString *)serverAPI {
return isGray ? _rePhobos.serverAPI : _oldPhobos.serverAPI;
}
/*
从缓存区获取数据,发给服务器,请求成功的时候,把缓存区的数据删除掉
*/
- (void)sendArrayWithCurrentAPI:(NSString *)currentAPI {
NSString *PhobosTempCacheKeyStr = [PhobosUtil MD5String:[PhobosUtil MD5String:currentAPI]]; // 两次加密作为key值,和缓存的key值作区分
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
if (_logEnabled) {
NSData *data = [NSJSONSerialization dataWithJSONObject:dataArray options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
phobosLog([NSString stringWithFormat:@"array prepare to fly --✈: %@", jsonString]);
}
@try {
NSData *JSON = [PhobosUtil encodeJSON:dataArray];
NSData *compressedData = [PhobosUtil compressData:JSON];
if (compressedData) {
[PhobosUtil sendData:compressedData currentAPI:currentAPI success:^(NSInteger code) {
phobosLog(@"✈ ---------- ✈ data arrived Mars");
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
}];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
/**
该方法有改动,现在的逻辑是:当前方法只接受发送的请求,然后把数据转存到另一个缓存区,
让sendArray方法负责发送,数据一旦转移到缓存区,就把原有的数据干掉。
@author zhaiguojun 16-10-17 in (null)
@param array 参数
@param clean 是否立即清楚缓存
*/
- (void)sendArray:(NSArray *)array cleanCacheRightNow:(BOOL)clean {
@try {
//1.获取缓存区的数据,把新数据追加进去
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
if (dataArray) {
[dataArray addObjectsFromArray:array];
}else{
dataArray = [NSMutableArray arrayWithArray:array];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosTempCacheKey object:dataArray];
//2.把缓存区的数据发送给服务器
[self sendArray];
//3.把原有的数据删除
if (clean) {
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
}
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
@end
/**
上边方法新加了一个API字段
*/
- (void)sendArray:(NSArray *)array currentAPI:(NSString *)currentAPI cleanCacheRightNow:(BOOL)clean {
@try {
//1.获取缓存区的数据,把新数据追加进去
NSString *PhobosTempCacheKeyStr = [PhobosUtil MD5String:[PhobosUtil MD5String:currentAPI]]; // 两次加密作为key值,和缓存的key值作区分
NSMutableArray *dataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr];
if (dataArray) {
[dataArray addObjectsFromArray:array];
}else{
dataArray = [NSMutableArray arrayWithArray:array];
}
[GMCache storeObjectAtDocumentPathWithkey:PhobosTempCacheKeyStr object:dataArray];
//2.把缓存区的数据发送给服务器
[self sendArrayWithCurrentAPI:currentAPI];
//3.把原有的数据删除
[GMCache removeObjectAtDocumentPathWithkey:[PhobosUtil MD5String:currentAPI]];
}
@catch (NSException *exception) {
phobosLog(exception);
}
}
#pragma mark - helpers
- (void)catchNullForEvent:(NSString *)eventId attributes:(NSDictionary *)attributes {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
@try {
for (NSString *key in attributes.allKeys) {
if ([attributes[key] isMemberOfClass:[NSNull class]]) {
if (self.captureNullExpection) {
self.captureNullExpection(eventId, attributes);
}
break;
}
}
} @catch (NSException *exception) {
}
});
@implementation Phobos (UtilTest)
/** 获取待发送埋点数量 */
+ (NSUInteger)fetchToBeSendPhobosDataCount {
return isGray ? [NewPhobos fetchToBeSendPhobosDataCount] : 0;
}
/** 获取待发送埋点数据 */
+ (NSArray *)fetchToBeSendPhobosData {
return isGray ? [NewPhobos fetchToBeSendPhobosData] : @[];
}
- (void)addNewApi:(NSString *)api {
for (NSString *item in self.APIArray) {
if ([api isEqualToString:item]) {
break;
}
[self.APIArray addObject:api];
/** 清除待发送埋点数据缓存 */
+ (void)removeAllPhobosData {
if (isGray) {
[NewPhobos removeAllPhobosData];
}
}
......
......@@ -9,18 +9,28 @@
#ifndef PhobosConfig_h
#define PhobosConfig_h
typedef NS_ENUM (NSInteger, PhobosSigningType) {
PhobosSigningTypeUndefined = 0,
PhobosSigningTypeAppStore,
PhobosSigningTypeRelease,
PhobosSigningTypeDebug
};
#ifdef DEBUG
#define phobosLog(...) NSLog(@"[Phobos] %@",__VA_ARGS__)
#else
#define phobosLog(...)
#endif
#define PhobosHaveOpenApp @"PhobosHaveOpenApp" //是否打开过APP
#define PhobosGray @"PhobosGray"
#define PhobosBeginTime @"PhobosBeginTime" //记录APP打开|从后台启动时的时间戳
#define PhobosEndTime @"PhobosEndTime" //记录APP退出|退到后台时的时间戳
#define PhobosCacheKey @"PhobosCacheKey" //存放持久化埋点数据的key
#define PhobosTempCacheKey @"PhobosTempCacheKey" //临时存放待发送埋点数据的key
#define PhobosCacheKey @"PhobosCacheKey" //old 存放持久化埋点数据的key
#define PhobosTempCacheKey @"PhobosTempCacheKey" //old 临时存放待发送埋点数据的key
#define PhobosShardCount 50 //收集数据分段发送的个数
#define PhobosMaxSendCount 100 // 最大发送数量
#endif /* PhobosConfig_h */
//
// 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;
+ (NSArray<PhobosSendDataEntity *> *)fetchDataEntitiesWithPredicate:(NSPredicate *)searchFilter;
+ (NSUInteger)fetchCountOfToBeSendEntities;
+ (NSUInteger)fetchCountOfEntitiesWithPredicate:(NSPredicate *)searchFilter;
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI;
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus;
+ (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 *Phobos_defaultContext;
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Phobos_defaultContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
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];
Phobos_defaultContext.persistentStoreCoordinator = coordinator;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d", PhobosDataSendStatusSending];
NSArray<PhobosSendDataEntity *> *entities = [self fetchDataEntitiesWithPredicate:predicate];
[self updateDataEntities:entities sendStatus:PhobosDataSendStatusError];
});
}
+ (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:Phobos_defaultContext];
}
+ (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:Phobos_defaultContext] integerValue];
}
+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI {
if (!sendAPI || [sendAPI isEqualToString:@""] || !data) {
return;
}
PhobosSendDataEntity *entity = [PhobosSendDataEntity MR_createEntityInContext:Phobos_defaultContext];
entity.data = [data mj_JSONData];
entity.api = sendAPI;
entity.status = PhobosDataSendStatusToBeSend;
entity.id = mach_absolute_time();
[Phobos_defaultContext MR_saveOnlySelfWithCompletion:nil];
}
+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus {
if (entities.count > 0) {
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.status = sendStatus;
}];
[Phobos_defaultContext MR_saveOnlySelfWithCompletion:nil];
}
}
+ (void)deleteDataEntities:(NSArray<PhobosSendDataEntity *> *)entities {
if (entities.count > 0) {
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj MR_deleteEntityInContext:Phobos_defaultContext];
}];
[Phobos_defaultContext MR_saveOnlySelfWithCompletion:nil];
}
}
+ (void)deleteAllEntities {
[PhobosSendDataEntity MR_truncateAllInContext:Phobos_defaultContext];
[Phobos_defaultContext MR_saveOnlySelfWithCompletion:nil];
}
@end
......@@ -8,10 +8,10 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^PhobosUpdatePVBlock)(void);
@protocol PhobosPVProtocol <NSObject>
typedef void(^PhobosUpdatePVBlock)(void);
/**
* @author 翟国钧, 16-02-24 17:02:22
*
......
//
// PhobosSendDataEntity+CoreDataClass.h
// GMPhobos
//
// Created by Locus on 2020/3/9.
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
NS_ASSUME_NONNULL_BEGIN
@interface PhobosSendDataEntity : NSManagedObject
@end
NS_ASSUME_NONNULL_END
#import "PhobosSendDataEntity+CoreDataProperties.h"
//
// 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
//
// PhobosSendManager.h
// GMPhobos
//
// Created by Locus on 2020/3/3.
//
#import <Foundation/Foundation.h>
#import "PhobosDataManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface PhobosSendManager : NSObject
+ (void)sendDataWithEntities:(NSArray<PhobosSendDataEntity *> *)needSendData completion:(nullable void(^)(NSArray<PhobosSendDataEntity *> *finishEntities, NSInteger code))completion;
@end
NS_ASSUME_NONNULL_END
//
// PhobosSendManager.m
// GMPhobos
//
// Created by Locus on 2020/3/3.
//
#import "PhobosSendManager.h"
#import <GMCache/GMCache.h>
#import <MJExtension/MJExtension.h>
#import "PhobosConfig.h"
#import "Phobos.h"
#import "PhobosUtil.h"
#ifdef APPSTORE
#define GMExactExposureApi @"https://log.igengmei.com/log/precise_exposure"
#else
#define GMExactExposureApi @"http://log.test.igengmei.com/log/precise_exposure"
#endif
@implementation PhobosSendManager
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self disposeOldData];
});
}
// TODO: 全量以后,一定时间需要清除下面逻辑
+ (void)disposeOldData {
NSMutableArray *total = [NSMutableArray new];
NSArray *normalDataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosTempCacheKey];
NSArray *immiDataArray = [GMCache fetchObjectAtDocumentPathWithkey:PhobosCacheKey];
[total addObjectsFromArray:normalDataArray];
[total addObjectsFromArray:immiDataArray];
if (total.count > 0) {
[self sendDataArray:total currentAPI:Phobos.sharedClient.serverAPI success:^(NSInteger code) {
if (code == 200) {
[GMCache removeObjectAtDocumentPathWithkey:PhobosCacheKey];
[GMCache removeObjectAtDocumentPathWithkey:PhobosTempCacheKey];
}
}];
}
NSString *exposureAPI = GMExactExposureApi;
NSArray *exposureArray = [GMCache fetchObjectAtDocumentPathWithkey:[PhobosUtil MD5String:exposureAPI]];
if (exposureArray.count > 0) {
[self sendDataArray:exposureArray currentAPI:exposureAPI success:^(NSInteger code) {
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) {
NSMutableArray *temp = [NSMutableArray arrayWithCapacity:PhobosMaxSendCount];
[sendDataEntities enumerateObjectsUsingBlock:^(PhobosSendDataEntity * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (temp.count >= PhobosMaxSendCount) {
[self sendDataWithEntities:temp completion:completion];
[temp removeAllObjects];
}
[temp addObject:obj];
}];
return;
}
NSMutableDictionary *sendDataMap = [NSMutableDictionary new];
[sendDataEntities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableArray *sendData = sendDataMap[obj.api] ?: [NSMutableArray new];
[sendData addObject:obj];
[sendDataMap setValue:sendData forKey:obj.api];
}];
[sendDataMap enumerateKeysAndObjectsUsingBlock:^(NSString *api, NSArray<PhobosSendDataEntity *> *entities, BOOL * _Nonnull stop) {
// TODO: 如果数据量过大,
NSMutableArray *sendDatas = [NSMutableArray new];
[entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[sendDatas addObject:[obj.data mj_JSONObject]];
}];
if (sendDatas.count > 0) {
[self sendDataArray:sendDatas currentAPI:api success:^(NSInteger code) {
if (completion) {
completion(entities, code);
}
}];
}
}];
}
+ (void)sendDataArray:(NSArray *)dataArray currentAPI:(NSString *)currentAPI success:(SendDataSuccessBlock)success {
NSData *JSON = [PhobosUtil encodeJSON:dataArray];
NSData *compressedData = [PhobosUtil compressData:JSON];
[PhobosUtil sendData:compressedData currentAPI:currentAPI success:^(NSInteger code) {
if (success) {
success(code);
}
}];
}
@end
......@@ -53,6 +53,8 @@ typedef void (^SendDataSuccessBlock)(NSInteger code);
+ (BOOL)isNonEmpty:(NSString *)string;
+ (NSData *)encodeJSON:(id)obj;
+ (NSString *)deviceId;
/** 获取手机型号 */
+ (NSString *)platform;
/**
* 获取IP地址
*/
......
......@@ -116,16 +116,17 @@
+ (void)sendData:(NSData *)data success:(SendDataSuccessBlock)success {
@try {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[Phobos sharedClient].serverAPI]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:Phobos.sharedClient.serverAPI]];
[request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
request.HTTPBody = data;
request.HTTPMethod = @"POST";
// sendAsynchronousRequest 在iOS9以后y被废除了
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
//没有错误,返回正确;
if (success) {
if (success) {
if (error) {
success(error.code);
} else {
success(200);
}
}
......@@ -146,9 +147,10 @@
// sendAsynchronousRequest 在iOS9以后y被废除了
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
//没有错误,返回正确;
if (success) {
if (success) {
if (error) {
success(error.code);
} else {
success(200);
}
}
......@@ -357,6 +359,14 @@
return [NSString stringWithFormat:@"%ld", (long)count];
}
/** 获取手机型号 */
+ (NSString *)platform {
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
return platform;
}
/***
* 网卡地址
**/
......
......@@ -30,5 +30,4 @@
*/
- (void)initReferrerTabName;
@end
......@@ -261,6 +261,4 @@
PhobosUpdatePVBlock updatePVBlock = objc_getAssociatedObject(self, @selector(updatePVEndBlock));
return updatePVBlock;
}
@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