[M] sync n3
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Thinking</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f0912fc584a54fccb105f957cec170d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b010dd865139b4ea8b8fe65c815bf3da
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3aa65556739d487581dcbc33f001e23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f4211ddaee63483da2cf08a3b9dbed6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TDAPPPushParams.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Charles on 6.5.23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern id __td_get_userNotificationCenter(void);
|
||||
extern id __td_get_userNotificationCenter_delegate(void);
|
||||
extern NSDictionary * __td_get_userNotificationCenterResponse(id response);
|
||||
extern NSString * __td_get_userNotificationCenterRequestContentTitle(id response);
|
||||
extern NSString * __td_get_userNotificationCenterRequestContentBody(id response);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d606670f7a7c24e1d86b03c1fc6251ac
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// TDAPPPushParams.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Charles on 6.5.23.
|
||||
//
|
||||
|
||||
#import "TDAPPPushParams.h"
|
||||
|
||||
id __td_get_userNotificationCenter(void) {
|
||||
Class cls = NSClassFromString(@"UNUserNotificationCenter");
|
||||
SEL sel = NSSelectorFromString(@"currentNotificationCenter");
|
||||
if ([cls respondsToSelector:sel]) {
|
||||
id (*getUserNotificationCenterIMP)(id, SEL) = (NSString * (*)(id, SEL))[cls methodForSelector:sel];
|
||||
return getUserNotificationCenterIMP(cls, sel);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
id __td_get_userNotificationCenter_delegate(void) {
|
||||
Class cls = NSClassFromString(@"UNUserNotificationCenter");
|
||||
SEL sel = NSSelectorFromString(@"currentNotificationCenter");
|
||||
SEL delegateSel = NSSelectorFromString(@"delegate");
|
||||
if ([cls respondsToSelector:sel]) {
|
||||
id (*getUserNotificationCenterIMP)(id, SEL) = (id (*)(id, SEL))[cls methodForSelector:sel];
|
||||
id center = getUserNotificationCenterIMP(cls, sel);
|
||||
if (center) {
|
||||
id (*getUserNotificationCenterDelegateIMP)(id, SEL) = (id (*)(id, SEL))[center methodForSelector:delegateSel];
|
||||
id delegate = getUserNotificationCenterDelegateIMP(center, delegateSel);
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary * __td_get_userNotificationCenterResponse(id response) {
|
||||
|
||||
@try {
|
||||
if ([response isKindOfClass:[NSClassFromString(@"UNNotificationResponse") class]]) {
|
||||
return [response valueForKeyPath:@"notification.request.content.userInfo"];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString * __td_get_userNotificationCenterRequestContentTitle(id response) {
|
||||
|
||||
@try {
|
||||
if ([response isKindOfClass:[NSClassFromString(@"UNNotificationResponse") class]]) {
|
||||
return [response valueForKeyPath:@"notification.request.content.title"];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString * __td_get_userNotificationCenterRequestContentBody(id response) {
|
||||
|
||||
@try {
|
||||
if ([response isKindOfClass:[NSClassFromString(@"UNNotificationResponse") class]]) {
|
||||
return [response valueForKeyPath:@"notification.request.content.body"];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08ddbde4b0bb44a2781691f28d329404
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDAppDelegateProxyManager : NSObject
|
||||
|
||||
+ (instancetype)defaultManager;
|
||||
|
||||
- (void)proxyNotifications;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ad802e76f93c418c9419315b8a3d275
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
#import "TDAppDelegateProxyManager.h"
|
||||
#import "TDApplicationDelegateProxy.h"
|
||||
#import "TDNewSwizzle.h"
|
||||
#import "UIApplication+TDPushClick.h"
|
||||
#import "TDMethodHelper.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
#import "TDUNUserNotificationCenterDelegateProxy.h"
|
||||
#endif
|
||||
|
||||
@implementation TDAppDelegateProxyManager
|
||||
|
||||
+ (instancetype)defaultManager {
|
||||
static dispatch_once_t onceToken;
|
||||
static TDAppDelegateProxyManager *manager = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
manager = [[TDAppDelegateProxyManager alloc] init];
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
|
||||
- (void)proxyNotifications NS_EXTENSION_UNAVAILABLE_IOS(""){
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[TDMethodHelper swizzleRespondsToSelector];
|
||||
|
||||
[TDApplicationDelegateProxy resolveOptionalSelectorsForDelegate:[UIApplication sharedApplication].delegate];
|
||||
[TDApplicationDelegateProxy proxyDelegate:[UIApplication sharedApplication].delegate selectors:[NSSet setWithArray:@[@"application:didReceiveLocalNotification:",
|
||||
@"application:didReceiveRemoteNotification:fetchCompletionHandler:",
|
||||
@"application:handleOpenURL:",
|
||||
@"application:openURL:options:",
|
||||
@"application:continueUserActivity:restorationHandler:",
|
||||
@"application:performActionForShortcutItem:completionHandler:"]]];
|
||||
if (@available(iOS 10.0, *)) {
|
||||
if ([UNUserNotificationCenter currentNotificationCenter].delegate) {
|
||||
[TDUNUserNotificationCenterDelegateProxy proxyDelegate:[UNUserNotificationCenter currentNotificationCenter].delegate selectors:[NSSet setWithArray:@[@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:"]]];
|
||||
}
|
||||
NSError *error = NULL;
|
||||
[UNUserNotificationCenter td_new_swizzleMethod:@selector(setDelegate:) withMethod:@selector(thinkingdata_setDelegate:) error:&error];
|
||||
if (error) {
|
||||
NSLog(@"proxy notification delegate error: %@", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed11ab70d6d6943019d6d3995eeaadc2
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
#import "TDDelegateProxy.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDApplicationDelegateProxy : TDDelegateProxy
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47013b120f73c4885845dbb7dd840189
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,119 @@
|
||||
|
||||
#import "TDApplicationDelegateProxy.h"
|
||||
#import "TDClassHelper.h"
|
||||
#import "NSObject+TDDelegateProxy.h"
|
||||
#import "UIApplication+TDPushClick.h"
|
||||
#import <objc/message.h>
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
#import "TDAppLaunchReason.h"
|
||||
#import "TDCommonUtil.h"
|
||||
|
||||
@implementation TDApplicationDelegateProxy
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
SEL selector = @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
|
||||
[TDApplicationDelegateProxy invokeWithTarget:self selector:selector, application, userInfo, completionHandler];
|
||||
[TDApplicationDelegateProxy trackEventWithTarget:self application:application remoteNotification:userInfo];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
|
||||
SEL selector = @selector(application:didReceiveLocalNotification:);
|
||||
[TDApplicationDelegateProxy invokeWithTarget:self selector:selector, application, notification];
|
||||
[TDApplicationDelegateProxy trackEventWithTarget:self application:application localNotification:notification];
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
||||
SEL selector = @selector(application:continueUserActivity:restorationHandler:);
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": [TDCommonUtil string: userActivity.webpageURL.absoluteString],@"data":@{}};
|
||||
}
|
||||
return [TDApplicationDelegateProxy invokeReturnBOOLWithTarget:self selector:selector arg1:application arg2:userActivity arg3:restorationHandler];
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
SEL selector = @selector(application:openURL:options:);
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": [TDCommonUtil string:url.absoluteString],@"data":@{}};
|
||||
}
|
||||
return [TDApplicationDelegateProxy invokeReturnBOOLWithTarget:self selector:selector arg1:app arg2:url arg3:options];
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
|
||||
SEL selector = @selector(application:handleOpenURL:);
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": [TDCommonUtil string:url.absoluteString], @"data":@{}};
|
||||
}
|
||||
return [TDApplicationDelegateProxy invokeReturnBOOLWithTarget:self selector:selector arg1:application arg2:url];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler{
|
||||
SEL selector = @selector(application:performActionForShortcutItem:completionHandler:);
|
||||
[TDApplicationDelegateProxy invokeWithTarget:self selector:selector, application, shortcutItem, completionHandler];
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": @"",@"data": [TDCommonUtil dictionary:shortcutItem.userInfo]};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (void)trackEventWithTarget:(NSObject *)target application:(UIApplication *)application remoteNotification:(NSDictionary *)userInfo {
|
||||
|
||||
if (target != application.delegate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
|
||||
NSLog(@"iOS version >= 10.0, callback for %@ was ignored.", @"application:didReceiveRemoteNotification:fetchCompletionHandler:");
|
||||
return;
|
||||
}
|
||||
|
||||
if (application.applicationState != UIApplicationStateInactive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": @"", @"data": [TDCommonUtil dictionary:userInfo]};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ (void)trackEventWithTarget:(NSObject *)target application:(UIApplication *)application localNotification:(UILocalNotification *)notification {
|
||||
|
||||
if (target != application.delegate) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL isValidPushClick = NO;
|
||||
if (application.applicationState == UIApplicationStateInactive) {
|
||||
isValidPushClick = YES;
|
||||
}
|
||||
|
||||
if (!isValidPushClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
|
||||
properties[@"alertBody"] = notification.alertBody;
|
||||
if (@available(iOS 8.2, *)) {
|
||||
properties[@"alertTitle"] = notification.alertTitle;
|
||||
}
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": @"", @"data": [TDCommonUtil dictionary:properties]};
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)optionalSelectors {
|
||||
return [NSSet setWithArray:@[@"application:didReceiveLocalNotification:",
|
||||
@"application:didReceiveRemoteNotification:fetchCompletionHandler:",
|
||||
@"application:handleOpenURL:",
|
||||
@"application:openURL:options:",
|
||||
@"application:continueUserActivity:restorationHandler:",
|
||||
@"application:performActionForShortcutItem:completionHandler:"]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2eec12b437e64f6886ebe51d6680b83
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#import "TDDelegateProxy.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDUNUserNotificationCenterDelegateProxy : TDDelegateProxy
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd9eda5b6572748ecaa3313c288c9e16
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#import "TDUNUserNotificationCenterDelegateProxy.h"
|
||||
#import "TDClassHelper.h"
|
||||
#import "NSObject+TDDelegateProxy.h"
|
||||
#import <objc/message.h>
|
||||
#import "TDAPPPushParams.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
#import "TDAppLaunchReason.h"
|
||||
#import "TDCommonUtil.h"
|
||||
|
||||
@implementation TDUNUserNotificationCenterDelegateProxy
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)){
|
||||
SEL selector = @selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:);
|
||||
[TDUNUserNotificationCenterDelegateProxy invokeWithTarget:self selector:selector, center, response, completionHandler];
|
||||
[TDUNUserNotificationCenterDelegateProxy trackEventWithTarget:self notificationCenter:center notificationResponse:response];
|
||||
}
|
||||
|
||||
+ (void)trackEventWithTarget:(NSObject *)target notificationCenter:(UNUserNotificationCenter *)center notificationResponse:(UNNotificationResponse *)response API_AVAILABLE(ios(10.0)){
|
||||
|
||||
if (target != center.delegate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
|
||||
NSDictionary *userInfo = __td_get_userNotificationCenterResponse(response);
|
||||
if (userInfo) {
|
||||
[properties addEntriesFromDictionary:userInfo];
|
||||
}
|
||||
properties[@"title"] = __td_get_userNotificationCenterRequestContentTitle(response);
|
||||
properties[@"body"] = __td_get_userNotificationCenterRequestContentBody(response);
|
||||
|
||||
[[TDAppLaunchReason sharedInstance] clearAppLaunchParams];
|
||||
[TDAppLaunchReason sharedInstance].appLaunchParams = @{@"url": @"", @"data": [TDCommonUtil dictionary:properties]};
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableOpsReceiptProperties]) {
|
||||
@try {
|
||||
if ([response isKindOfClass:[NSClassFromString(@"UNNotificationResponse") class]]) {
|
||||
NSDictionary *userInfo = [response valueForKeyPath:@"notification.request.content.userInfo"];
|
||||
[TDAppLaunchReason td_ops_push_click:userInfo];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)optionalSelectors {
|
||||
return [NSSet setWithArray:@[@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:"]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8c262d70355c46f38a4fce70eb95cc5
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIApplication (TDPushClick)
|
||||
|
||||
- (void)thinkingdata_setDelegate:(id <UIApplicationDelegate>)delegate;
|
||||
@property (nonatomic, copy, nullable) NSDictionary *thinkingdata_launchOptions;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b039553b9411c4e30b4fc767b7c2714d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
#import "UIApplication+TDPushClick.h"
|
||||
#import "TDApplicationDelegateProxy.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static void *const kSALaunchOptions = (void *)&kSALaunchOptions;
|
||||
|
||||
@implementation UIApplication (TDPushClick)
|
||||
|
||||
- (void)thinkingdata_setDelegate:(id<UIApplicationDelegate>)delegate {
|
||||
[TDApplicationDelegateProxy resolveOptionalSelectorsForDelegate:delegate];
|
||||
|
||||
[self thinkingdata_setDelegate:delegate];
|
||||
|
||||
if (!self.delegate) {
|
||||
return;
|
||||
}
|
||||
[TDApplicationDelegateProxy proxyDelegate:self.delegate selectors:[NSSet setWithArray:@[@"application:didReceiveLocalNotification:", @"application:didReceiveRemoteNotification:fetchCompletionHandler:"]]];
|
||||
}
|
||||
|
||||
- (NSDictionary *)thinkingdata_launchOptions {
|
||||
return objc_getAssociatedObject(self, kSALaunchOptions);
|
||||
}
|
||||
|
||||
- (void)setThinkingdata_launchOptions:(NSDictionary *)thinkingdata_launchOptions {
|
||||
objc_setAssociatedObject(self, kSALaunchOptions, thinkingdata_launchOptions, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17463cb6f209545bcbc20aad5129804d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UNUserNotificationCenter (TDPushClick)
|
||||
|
||||
- (void)thinkingdata_setDelegate:(id <UNUserNotificationCenterDelegate>)delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd78c300cef5f4507a13b638ce74c1e5
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
#import "UNUserNotificationCenter+TDPushClick.h"
|
||||
#import "TDUNUserNotificationCenterDelegateProxy.h"
|
||||
|
||||
@implementation UNUserNotificationCenter (TDPushClick)
|
||||
|
||||
- (void)thinkingdata_setDelegate:(id<UNUserNotificationCenterDelegate>)delegate {
|
||||
|
||||
[TDUNUserNotificationCenterDelegateProxy resolveOptionalSelectorsForDelegate:delegate];
|
||||
|
||||
[self thinkingdata_setDelegate:delegate];
|
||||
if (!self.delegate) {
|
||||
return;
|
||||
}
|
||||
[TDUNUserNotificationCenterDelegateProxy proxyDelegate:self.delegate selectors:[NSSet setWithArray:@[@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:"]]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73166a65f020c46e8a3c53cfa301c5f2
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0aa41df3a429a4fd8915122407b7001a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TDDelegateProxyObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (TDDelegateProxy)
|
||||
|
||||
@property (nonatomic, copy, nullable) NSSet<NSString *> *thinkingdata_optionalSelectors;
|
||||
@property (nonatomic, strong, nullable) TDDelegateProxyObject *thinkingdata_delegateObject;
|
||||
|
||||
/// hook respondsToSelector to resolve optional selectors
|
||||
/// @param aSelector selector
|
||||
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSProxy (TDDelegateProxy)
|
||||
|
||||
@property (nonatomic, copy, nullable) NSSet<NSString *> *thinkingdata_optionalSelectors;
|
||||
@property (nonatomic, strong, nullable) TDDelegateProxyObject *thinkingdata_delegateObject;
|
||||
|
||||
/// hook respondsToSelector to resolve optional selectors
|
||||
/// @param aSelector selector
|
||||
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c165be5fc3eea4ab0bd9ff520104d3d8
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#import "NSObject+TDDelegateProxy.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static void *const kTDNSObjectDelegateOptionalSelectorsKey = (void *)&kTDNSObjectDelegateOptionalSelectorsKey;
|
||||
static void *const kTDNSObjectDelegateObjectKey = (void *)&kTDNSObjectDelegateObjectKey;
|
||||
|
||||
static void *const kTDNSProxyDelegateOptionalSelectorsKey = (void *)&kTDNSProxyDelegateOptionalSelectorsKey;
|
||||
static void *const kTDNSProxyDelegateObjectKey = (void *)&kTDNSProxyDelegateObjectKey;
|
||||
|
||||
@implementation NSObject (TDDelegateProxy)
|
||||
|
||||
- (NSSet<NSString *> *)thinkingdata_optionalSelectors {
|
||||
return objc_getAssociatedObject(self, kTDNSObjectDelegateOptionalSelectorsKey);
|
||||
}
|
||||
|
||||
- (void)setThinkingdata_optionalSelectors:(NSSet<NSString *> *)thinkingdata_optionalSelectors {
|
||||
objc_setAssociatedObject(self, kTDNSObjectDelegateOptionalSelectorsKey, thinkingdata_optionalSelectors, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
- (TDDelegateProxyObject *)thinkingdata_delegateObject {
|
||||
return objc_getAssociatedObject(self, kTDNSObjectDelegateObjectKey);
|
||||
}
|
||||
|
||||
- (void)setThinkingdata_delegateObject:(TDDelegateProxyObject *)thinkingdata_delegateObject {
|
||||
objc_setAssociatedObject(self, kTDNSObjectDelegateObjectKey, thinkingdata_delegateObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector {
|
||||
if ([self thinkingdata_respondsToSelector:aSelector]) {
|
||||
return YES;
|
||||
}
|
||||
if ([self.thinkingdata_optionalSelectors containsObject:NSStringFromSelector(aSelector)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSProxy (TDDelegateProxy)
|
||||
|
||||
- (NSSet<NSString *> *)thinkingdata_optionalSelectors {
|
||||
return objc_getAssociatedObject(self, kTDNSProxyDelegateOptionalSelectorsKey);
|
||||
}
|
||||
|
||||
- (void)setThinkingdata_optionalSelectors:(NSSet<NSString *> *)thinkingdata_optionalSelectors {
|
||||
objc_setAssociatedObject(self, kTDNSProxyDelegateOptionalSelectorsKey, thinkingdata_optionalSelectors, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
- (TDDelegateProxyObject *)thinkingdata_delegateObject {
|
||||
return objc_getAssociatedObject(self, kTDNSProxyDelegateObjectKey);
|
||||
}
|
||||
|
||||
- (void)setThinkingdata_delegateObject:(TDDelegateProxyObject *)thinkingdata_delegateObject {
|
||||
objc_setAssociatedObject(self, kTDNSProxyDelegateObjectKey, thinkingdata_delegateObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector {
|
||||
if ([self thinkingdata_respondsToSelector:aSelector]) {
|
||||
return YES;
|
||||
}
|
||||
if ([self.thinkingdata_optionalSelectors containsObject:NSStringFromSelector(aSelector)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 852dc5d94530d4aff8a96973c9986ad2
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDClassHelper : NSObject
|
||||
|
||||
+ (Class _Nullable)allocateClassWithObject:(id)object className:(NSString *)className;
|
||||
|
||||
+ (void)registerClass:(Class)cla;
|
||||
|
||||
+ (BOOL)setObject:(id)object toClass:(Class)cla;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b05b7c406ad1f43d0bb4f1be994d8765
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
#import "TDClassHelper.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation TDClassHelper
|
||||
|
||||
+ (Class _Nullable)allocateClassWithObject:(id)object className:(NSString *)className {
|
||||
if (!object || className.length <= 0) {
|
||||
return nil;
|
||||
}
|
||||
Class originalClass = object_getClass(object);
|
||||
Class subclass = NSClassFromString(className);
|
||||
if (subclass) {
|
||||
return nil;
|
||||
}
|
||||
subclass = objc_allocateClassPair(originalClass, className.UTF8String, 0);
|
||||
if (class_getInstanceSize(originalClass) != class_getInstanceSize(subclass)) {
|
||||
return nil;
|
||||
}
|
||||
return subclass;
|
||||
}
|
||||
|
||||
+ (void)registerClass:(Class)cla {
|
||||
if (cla) {
|
||||
objc_registerClassPair(cla);
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)setObject:(id)object toClass:(Class)cla {
|
||||
if (cla && object && object_getClass(object) != cla) {
|
||||
return object_setClass(object, cla);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aec2711162866493884cdef2cc925bb0
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol TDHookDelegateProtocol <NSObject>
|
||||
@optional
|
||||
+ (NSSet<NSString *> *)optionalSelectors;
|
||||
|
||||
@end
|
||||
|
||||
@interface TDDelegateProxy : NSObject <TDHookDelegateProtocol>
|
||||
|
||||
+ (void)proxyDelegate:(id)delegate selectors:(NSSet<NSString *>*)selectors;
|
||||
|
||||
+ (void)invokeWithTarget:(NSObject *)target selector:(SEL)selector, ...;
|
||||
|
||||
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2;
|
||||
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 arg3:(id)arg3;
|
||||
|
||||
+ (void)resolveOptionalSelectorsForDelegate:(id)delegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d844d7614eae8439c904288502d39b52
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
#import "TDDelegateProxy.h"
|
||||
#import "TDClassHelper.h"
|
||||
#import "TDMethodHelper.h"
|
||||
#import "NSObject+TDDelegateProxy.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
static NSString * const kTDNSObjectRemoveObserverSelector = @"removeObserver:forKeyPath:";
|
||||
static NSString * const kTDNSObjectAddObserverSelector = @"addObserver:forKeyPath:options:context:";
|
||||
static NSString * const kTDNSObjectClassSelector = @"class";
|
||||
|
||||
@implementation TDDelegateProxy
|
||||
|
||||
+ (void)proxyDelegate:(id)delegate selectors:(NSSet<NSString *> *)selectors {
|
||||
if (object_isClass(delegate) || selectors.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class proxyClass = [self class];
|
||||
NSMutableSet *delegateSelectors = [NSMutableSet setWithSet:selectors];
|
||||
|
||||
TDDelegateProxyObject *object = [delegate thinkingdata_delegateObject];
|
||||
if (!object) {
|
||||
object = [[TDDelegateProxyObject alloc] initWithDelegate:delegate proxy:proxyClass];
|
||||
[delegate setThinkingdata_delegateObject:object];
|
||||
}
|
||||
|
||||
[delegateSelectors minusSet:object.selectors];
|
||||
if (delegateSelectors.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.thinkingClass) {
|
||||
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:object.thinkingClass];
|
||||
[object.selectors unionSet:delegateSelectors];
|
||||
|
||||
if (![object_getClass(delegate) isSubclassOfClass:object.thinkingClass]) {
|
||||
[TDClassHelper setObject:delegate toClass:object.thinkingClass];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.kvoClass) {
|
||||
if ([delegate isKindOfClass:NSObject.class] && ![object.selectors containsObject:kTDNSObjectRemoveObserverSelector]) {
|
||||
[delegateSelectors addObject:kTDNSObjectRemoveObserverSelector];
|
||||
}
|
||||
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:object.kvoClass];
|
||||
[object.selectors unionSet:delegateSelectors];
|
||||
return;
|
||||
}
|
||||
|
||||
Class thinkingClass = [TDClassHelper allocateClassWithObject:delegate className:object.thinkingClassName];
|
||||
[TDClassHelper registerClass:thinkingClass];
|
||||
|
||||
if ([delegate isKindOfClass:NSObject.class] && ![object.selectors containsObject:kTDNSObjectAddObserverSelector]) {
|
||||
[delegateSelectors addObject:kTDNSObjectAddObserverSelector];
|
||||
}
|
||||
|
||||
if (![object.selectors containsObject:kTDNSObjectClassSelector]) {
|
||||
[delegateSelectors addObject:kTDNSObjectClassSelector];
|
||||
}
|
||||
|
||||
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:thinkingClass];
|
||||
[object.selectors unionSet:delegateSelectors];
|
||||
|
||||
[TDClassHelper setObject:delegate toClass:thinkingClass];
|
||||
}
|
||||
|
||||
+ (void)addInstanceMethodWithSelectors:(NSSet<NSString *> *)selectors fromClass:(Class)fromClass toClass:(Class)toClass {
|
||||
for (NSString *selector in selectors) {
|
||||
SEL sel = NSSelectorFromString(selector);
|
||||
[TDMethodHelper addInstanceMethodWithSelector:sel fromClass:fromClass toClass:toClass];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 arg3:(id)arg3 {
|
||||
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
|
||||
|
||||
struct objc_super targetSuper = {
|
||||
.receiver = target,
|
||||
.super_class = originalClass
|
||||
};
|
||||
|
||||
BOOL returnValue = NO;
|
||||
@try {
|
||||
returnValue = ((BOOL (*)(struct objc_super *, SEL, id, id, id))objc_msgSendSuper)(&targetSuper, selector, arg1, arg2, arg3);
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"msgSendSuper with exception: %@", exception);
|
||||
} @finally {
|
||||
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 {
|
||||
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
|
||||
|
||||
struct objc_super targetSuper = {
|
||||
.receiver = target,
|
||||
.super_class = originalClass
|
||||
};
|
||||
|
||||
BOOL returnValue = NO;
|
||||
@try {
|
||||
returnValue = ((BOOL (*)(struct objc_super *, SEL, id, id))objc_msgSendSuper)(&targetSuper, selector, arg1, arg2);
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"msgSendSuper with exception: %@", exception);
|
||||
} @finally {
|
||||
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
+ (void)invokeWithTarget:(NSObject *)target selector:(SEL)selector, ... {
|
||||
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
|
||||
|
||||
va_list args;
|
||||
va_start(args, selector);
|
||||
id arg1 = nil, arg2 = nil, arg3 = nil, arg4 = nil;
|
||||
NSInteger count = [NSStringFromSelector(selector) componentsSeparatedByString:@":"].count - 1;
|
||||
for (NSInteger i = 0; i < count; i++) {
|
||||
i == 0 ? (arg1 = va_arg(args, id)) : nil;
|
||||
i == 1 ? (arg2 = va_arg(args, id)) : nil;
|
||||
i == 2 ? (arg3 = va_arg(args, id)) : nil;
|
||||
i == 3 ? (arg4 = va_arg(args, id)) : nil;
|
||||
}
|
||||
struct objc_super targetSuper = {
|
||||
.receiver = target,
|
||||
.super_class = originalClass
|
||||
};
|
||||
|
||||
@try {
|
||||
void (*func)(struct objc_super *, SEL, id, id, id, id) = (void *)&objc_msgSendSuper;
|
||||
func(&targetSuper, selector, arg1, arg2, arg3, arg4);
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"msgSendSuper with exception: %@", exception);
|
||||
} @finally {
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (void)resolveOptionalSelectorsForDelegate:(id)delegate {
|
||||
if (object_isClass(delegate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSSet *currentOptionalSelectors = ((NSObject *)delegate).thinkingdata_optionalSelectors;
|
||||
NSMutableSet *optionalSelectors = [[NSMutableSet alloc] init];
|
||||
if (currentOptionalSelectors) {
|
||||
[optionalSelectors unionSet:currentOptionalSelectors];
|
||||
}
|
||||
|
||||
if ([self respondsToSelector:@selector(optionalSelectors)] &&[self optionalSelectors]) {
|
||||
[optionalSelectors unionSet:[self optionalSelectors]];
|
||||
}
|
||||
((NSObject *)delegate).thinkingdata_optionalSelectors = [optionalSelectors copy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Class
|
||||
@implementation TDDelegateProxy (Class)
|
||||
|
||||
- (Class)class {
|
||||
if (self.thinkingdata_delegateObject.delegateClass) {
|
||||
return self.thinkingdata_delegateObject.delegateClass;
|
||||
}
|
||||
return [super class];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - KVO
|
||||
@implementation TDDelegateProxy (KVO)
|
||||
|
||||
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
|
||||
[super addObserver:observer forKeyPath:keyPath options:options context:context];
|
||||
if (self.thinkingdata_delegateObject) {
|
||||
[TDMethodHelper replaceInstanceMethodWithDestinationSelector:@selector(class) sourceSelector:@selector(class) fromClass:TDDelegateProxy.class toClass:object_getClass(self)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
|
||||
BOOL oldClassIsKVO = [TDDelegateProxyObject isKVOClass:object_getClass(self)];
|
||||
[super removeObserver:observer forKeyPath:keyPath];
|
||||
BOOL newClassIsKVO = [TDDelegateProxyObject isKVOClass:object_getClass(self)];
|
||||
|
||||
if (oldClassIsKVO && !newClassIsKVO) {
|
||||
Class delegateProxy = self.thinkingdata_delegateObject.delegateProxy;
|
||||
NSSet *selectors = [self.thinkingdata_delegateObject.selectors copy];
|
||||
|
||||
[self.thinkingdata_delegateObject removeKVO];
|
||||
if ([delegateProxy respondsToSelector:@selector(proxyDelegate:selectors:)]) {
|
||||
[delegateProxy proxyDelegate:self selectors:selectors];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 814fa739d0a0447259f0fda304b44e4e
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDDelegateProxyObject : NSObject
|
||||
|
||||
@property (nonatomic, strong) Class delegateISA;
|
||||
|
||||
@property (nonatomic, strong, nullable) Class kvoClass;
|
||||
|
||||
@property (nonatomic, copy, nullable) NSString *thinkingClassName;
|
||||
|
||||
@property (nonatomic, strong, readonly, nullable) Class thinkingClass;
|
||||
|
||||
@property (nonatomic, strong) id delegateClass;
|
||||
|
||||
@property (nonatomic, strong) Class delegateProxy;
|
||||
|
||||
@property (nonatomic, strong) NSMutableSet *selectors;
|
||||
|
||||
- (instancetype)initWithDelegate:(id)delegate proxy:(id)proxy;
|
||||
|
||||
- (void)removeKVO;
|
||||
|
||||
@end
|
||||
|
||||
@interface TDDelegateProxyObject (Utils)
|
||||
|
||||
+ (BOOL)isKVOClass:(Class _Nullable)cls;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b66965aa8d4f84c9fbcab5bb32c159a6
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#import "TDDelegateProxyObject.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
NSString * const kTDDelegateClassThinkingSuffix = @"_TD.THINKINGDATA";
|
||||
NSString * const kTDDelegateClassKVOPrefix = @"KVONotifying_";
|
||||
|
||||
@implementation TDDelegateProxyObject
|
||||
|
||||
- (instancetype)initWithDelegate:(id)delegate proxy:(id)proxy {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_delegateProxy = proxy;
|
||||
|
||||
_selectors = [NSMutableSet set];
|
||||
_delegateClass = [delegate class];
|
||||
|
||||
Class cla = object_getClass(delegate);
|
||||
NSString *name = NSStringFromClass(cla);
|
||||
|
||||
if ([name containsString:kTDDelegateClassKVOPrefix]) {
|
||||
_delegateISA = class_getSuperclass(cla);
|
||||
_kvoClass = cla;
|
||||
} else if ([name containsString:kTDDelegateClassThinkingSuffix]) {
|
||||
_delegateISA = class_getSuperclass(cla);
|
||||
_thinkingClassName = name;
|
||||
} else {
|
||||
_delegateISA = cla;
|
||||
_thinkingClassName = [NSString stringWithFormat:@"%@%@", name, kTDDelegateClassThinkingSuffix];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (Class)thinkingClass {
|
||||
return NSClassFromString(self.thinkingClassName);
|
||||
}
|
||||
|
||||
- (void)removeKVO {
|
||||
self.kvoClass = nil;
|
||||
self.thinkingClassName = [NSString stringWithFormat:@"%@%@", self.delegateISA, kTDDelegateClassThinkingSuffix];
|
||||
[self.selectors removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Utils
|
||||
|
||||
@implementation TDDelegateProxyObject (Utils)
|
||||
|
||||
+ (BOOL)isKVOClass:(Class _Nullable)cls {
|
||||
return [NSStringFromClass(cls) containsString:kTDDelegateClassKVOPrefix];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6c49449459eb4a92bf83ab85a7be1e7
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDMethodHelper : NSObject
|
||||
|
||||
+ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass;
|
||||
|
||||
+ (void)addInstanceMethodWithSelector:(SEL)methodSelector fromClass:(Class)fromClass toClass:(Class)toClass;
|
||||
|
||||
+ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
|
||||
|
||||
+ (void)addClassMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
|
||||
|
||||
+ (IMP _Nullable)replaceInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
|
||||
|
||||
/// swizzle respondsToSelector 方法
|
||||
/// 用于处理未实现代理方法也能采集事件的逻辑
|
||||
+ (void)swizzleRespondsToSelector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1cc9da14eecc4d23b345a15404edcab
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#import "TDMethodHelper.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "TDNewSwizzle.h"
|
||||
#import "NSObject+TDDelegateProxy.h"
|
||||
|
||||
@implementation TDMethodHelper
|
||||
|
||||
+ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass {
|
||||
Method aMethod = class_getInstanceMethod(aClass, selector);
|
||||
return method_getImplementation(aMethod);
|
||||
}
|
||||
|
||||
+ (void)addInstanceMethodWithSelector:(SEL)methodSelector fromClass:(Class)fromClass toClass:(Class)toClass {
|
||||
[self addInstanceMethodWithDestinationSelector:methodSelector sourceSelector:methodSelector fromClass:fromClass toClass:toClass];
|
||||
}
|
||||
|
||||
+ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
|
||||
Method method = class_getInstanceMethod(fromClass, sourceSelector);
|
||||
if (!method) {
|
||||
return;
|
||||
}
|
||||
IMP methodIMP = method_getImplementation(method);
|
||||
const char *types = method_getTypeEncoding(method);
|
||||
if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
|
||||
IMP destinationIMP = [self implementationOfMethodSelector:destinationSelector fromClass:toClass];
|
||||
if (destinationIMP == methodIMP) {
|
||||
return;
|
||||
}
|
||||
class_replaceMethod(toClass, destinationSelector, methodIMP, types);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)addClassMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
|
||||
Method method = class_getClassMethod(fromClass, sourceSelector);
|
||||
IMP methodIMP = method_getImplementation(method);
|
||||
const char *types = method_getTypeEncoding(method);
|
||||
if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
|
||||
class_replaceMethod(toClass, destinationSelector, methodIMP, types);
|
||||
}
|
||||
}
|
||||
|
||||
+ (IMP _Nullable)replaceInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
|
||||
Method method = class_getInstanceMethod(fromClass, sourceSelector);
|
||||
IMP methodIMP = method_getImplementation(method);
|
||||
const char *types = method_getTypeEncoding(method);
|
||||
return class_replaceMethod(toClass, destinationSelector, methodIMP, types);
|
||||
}
|
||||
|
||||
+ (void)swizzleRespondsToSelector {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[NSObject td_new_swizzleMethod:@selector(respondsToSelector:)
|
||||
withMethod:@selector(thinkingdata_respondsToSelector:)
|
||||
error:NULL];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 009c284b5153443e8bff5c9ca6ba32e8
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b294828e3aa214401ad6a0db7ebd8a63
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (TDNewSwizzle)
|
||||
|
||||
+ (BOOL)td_new_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError **)error_;
|
||||
+ (BOOL)td_new_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError **)error_;
|
||||
+ (BOOL)td_new_swizzleMethod:(SEL)origSel_ withClass:(Class)altCla_ withMethod:(SEL)altSel_ error:(NSError **)error_;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2a9df7cedc0046aaad72584161c53f8
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,155 @@
|
||||
|
||||
#import "TDNewSwizzle.h"
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#else
|
||||
#import <objc/objc-class.h>
|
||||
#endif
|
||||
|
||||
#define TDSetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \
|
||||
if (ERROR_VAR) { \
|
||||
NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \
|
||||
*ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \
|
||||
code:-1 \
|
||||
userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \
|
||||
}
|
||||
#define TDSetNSError(ERROR_VAR, FORMAT,...) TDSetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__)
|
||||
|
||||
#if OBJC_API_VERSION >= 2
|
||||
#define TDGetClass(obj) object_getClass(obj)
|
||||
#else
|
||||
#define TDGetClass(obj) (obj ? obj->isa : Nil)
|
||||
#endif
|
||||
|
||||
@implementation NSObject (TDNewSwizzle)
|
||||
|
||||
+ (BOOL)td_new_swizzleMethod:(SEL)origSel_ withClass:(Class)altCla_ withMethod:(SEL)altSel_ error:(NSError **)error_ {
|
||||
Method origMethod = class_getInstanceMethod(self, origSel_);
|
||||
if (!origMethod) {
|
||||
TDSetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]);
|
||||
return NO;
|
||||
}
|
||||
|
||||
Method altMethod = class_getInstanceMethod(altCla_, altSel_);
|
||||
if (!altMethod) {
|
||||
TDSetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [altCla_ class]);
|
||||
return NO;
|
||||
}
|
||||
|
||||
class_addMethod(self,
|
||||
origSel_,
|
||||
class_getMethodImplementation(self, origSel_),
|
||||
method_getTypeEncoding(origMethod));
|
||||
class_addMethod(altCla_,
|
||||
altSel_,
|
||||
class_getMethodImplementation(altCla_, altSel_),
|
||||
method_getTypeEncoding(altMethod));
|
||||
|
||||
//交换之前,先对自定义方法进行添加
|
||||
BOOL didAddMethod = class_addMethod(self,
|
||||
altSel_,
|
||||
method_getImplementation(altMethod),
|
||||
method_getTypeEncoding(altMethod));
|
||||
if (didAddMethod) {
|
||||
method_exchangeImplementations(origMethod, class_getInstanceMethod(self, altSel_));
|
||||
}
|
||||
return didAddMethod;
|
||||
}
|
||||
|
||||
+ (BOOL)td_new_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError **)error_ {
|
||||
#if OBJC_API_VERSION >= 2
|
||||
Method origMethod = class_getInstanceMethod(self, origSel_);
|
||||
if (!origMethod) {
|
||||
TDSetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]);
|
||||
return NO;
|
||||
}
|
||||
|
||||
Method altMethod = class_getInstanceMethod(self, altSel_);
|
||||
if (!altMethod) {
|
||||
TDSetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]);
|
||||
return NO;
|
||||
}
|
||||
|
||||
class_addMethod(self,
|
||||
origSel_,
|
||||
class_getMethodImplementation(self, origSel_),
|
||||
method_getTypeEncoding(origMethod));
|
||||
class_addMethod(self,
|
||||
altSel_,
|
||||
class_getMethodImplementation(self, altSel_),
|
||||
method_getTypeEncoding(altMethod));
|
||||
|
||||
method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));
|
||||
return YES;
|
||||
#else
|
||||
// Scan for non-inherited methods.
|
||||
Method directOriginalMethod = NULL, directAlternateMethod = NULL;
|
||||
|
||||
void *iterator = NULL;
|
||||
struct objc_method_list *mlist = class_nextMethodList(self, &iterator);
|
||||
while (mlist) {
|
||||
int method_index = 0;
|
||||
for (; method_index < mlist->method_count; method_index++) {
|
||||
if (mlist->method_list[method_index].method_name == origSel_) {
|
||||
assert(!directOriginalMethod);
|
||||
directOriginalMethod = &mlist->method_list[method_index];
|
||||
}
|
||||
if (mlist->method_list[method_index].method_name == altSel_) {
|
||||
assert(!directAlternateMethod);
|
||||
directAlternateMethod = &mlist->method_list[method_index];
|
||||
}
|
||||
}
|
||||
mlist = class_nextMethodList(self, &iterator);
|
||||
}
|
||||
|
||||
// If either method is inherited, copy it up to the target class to make it non-inherited.
|
||||
if (!directOriginalMethod || !directAlternateMethod) {
|
||||
Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL;
|
||||
if (!directOriginalMethod) {
|
||||
inheritedOriginalMethod = class_getInstanceMethod(self, origSel_);
|
||||
if (!inheritedOriginalMethod) {
|
||||
TDSetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (!directAlternateMethod) {
|
||||
inheritedAlternateMethod = class_getInstanceMethod(self, altSel_);
|
||||
if (!inheritedAlternateMethod) {
|
||||
TDSetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1;
|
||||
struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1)));
|
||||
hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind
|
||||
hoisted_method_list->method_count = hoisted_method_count;
|
||||
Method hoisted_method = hoisted_method_list->method_list;
|
||||
|
||||
if (!directOriginalMethod) {
|
||||
bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method));
|
||||
directOriginalMethod = hoisted_method++;
|
||||
}
|
||||
if (!directAlternateMethod) {
|
||||
bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method));
|
||||
directAlternateMethod = hoisted_method;
|
||||
}
|
||||
class_addMethods(self, hoisted_method_list);
|
||||
}
|
||||
|
||||
// Swizzle.
|
||||
IMP temp = directOriginalMethod->method_imp;
|
||||
directOriginalMethod->method_imp = directAlternateMethod->method_imp;
|
||||
directAlternateMethod->method_imp = temp;
|
||||
|
||||
return YES;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (BOOL)td_new_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError **)error_ {
|
||||
return [TDGetClass((id)self) td_new_swizzleMethod:origSel_ withMethod:altSel_ error:error_];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8ab506fca17c4ec1815a15a2b7eb5f7
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// TDAppLaunchReason.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/11/17.
|
||||
// Copyright © 2021 thinkingdata. All rights reserved.
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSDictionary *appPushClickDic;
|
||||
|
||||
@interface TDAppLaunchReason : NSObject
|
||||
|
||||
@property(nonatomic, copy) NSDictionary *appLaunchParams;
|
||||
|
||||
+ (TDAppLaunchReason *)sharedInstance;
|
||||
|
||||
- (void)clearAppLaunchParams;
|
||||
|
||||
+ (void)td_ops_push_click:(NSDictionary *)userInfo;
|
||||
|
||||
+ (NSDictionary*)getAppPushDic;
|
||||
|
||||
+ (void)clearAppPushParams;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f37b994396cdc4d7780bcb516fcc6d51
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// TDAppLaunchReason.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/11/17.
|
||||
// Copyright © 2021 thinkingdata. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TDAppLaunchReason.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "TDCommonUtil.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
#import "TDAppState.h"
|
||||
#import "ThinkingAnalyticsSDKPrivate.h"
|
||||
#import "TDAppDelegateProxyManager.h"
|
||||
#import "TAPushClickEvent.h"
|
||||
|
||||
@implementation TDAppLaunchReason
|
||||
|
||||
|
||||
+ (void)load {
|
||||
|
||||
[TDPresetProperties disPresetProperties];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:[TDAppLaunchReason sharedInstance] selector:@selector(_applicationDidFinishLaunchingNotification:) name:UIApplicationDidFinishLaunchingNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:[TDAppLaunchReason sharedInstance] selector:@selector(_applicationDidEnterBackgroundNotification:) name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
}
|
||||
|
||||
+ (void)td_ops_push_click:(NSDictionary *)userInfo {
|
||||
|
||||
@try {
|
||||
if ([userInfo.allKeys containsObject:@"te_extras"] && [userInfo[@"te_extras"] isKindOfClass:[NSString class]]) {
|
||||
NSData *jsonData = [userInfo[@"te_extras"] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *err;
|
||||
NSDictionary *responseDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
|
||||
NSDictionary *opsReceiptProperties = responseDic[@"#ops_receipt_properties"];
|
||||
if ([opsReceiptProperties isKindOfClass:[NSString class]]) {
|
||||
NSString *opsStr = (NSString *)opsReceiptProperties;
|
||||
opsReceiptProperties = [NSJSONSerialization JSONObjectWithData:[opsStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&err];
|
||||
}
|
||||
if (opsReceiptProperties && [opsReceiptProperties isKindOfClass:[NSDictionary class]]) {
|
||||
NSMutableDictionary *dic = [ThinkingAnalyticsSDK _getAllInstances];
|
||||
if(dic == nil || dic.count == 0){
|
||||
appPushClickDic = opsReceiptProperties;
|
||||
}else{
|
||||
for (NSString *instanceToken in dic.allKeys) {
|
||||
ThinkingAnalyticsSDK *instance = dic[instanceToken];
|
||||
TAPushClickEvent *pushEvent = [[TAPushClickEvent alloc]initWithName: @"ops_push_click"];
|
||||
pushEvent.ops = opsReceiptProperties;
|
||||
[instance autoTrackWithEvent:pushEvent properties:@{}];
|
||||
[instance flush];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)getAppPushDic{
|
||||
return appPushClickDic;
|
||||
}
|
||||
|
||||
+ (void)clearAppPushParams{
|
||||
appPushClickDic = nil;
|
||||
}
|
||||
|
||||
+ (TDAppLaunchReason *)sharedInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TDAppLaunchReason *appLaunchManager;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
appLaunchManager = [TDAppLaunchReason new];
|
||||
});
|
||||
return appLaunchManager;
|
||||
}
|
||||
|
||||
- (void)clearAppLaunchParams {
|
||||
self.appLaunchParams = @{@"url":@"",
|
||||
@"data":@{}};
|
||||
}
|
||||
|
||||
- (void)_applicationDidEnterBackgroundNotification:(NSNotification *)notification {
|
||||
[self clearAppLaunchParams];
|
||||
}
|
||||
|
||||
// 拦截冷启动和热启动的参数
|
||||
- (void)_applicationDidFinishLaunchingNotification:(NSNotification *)notification {
|
||||
|
||||
__weak TDAppLaunchReason *weakSelf = self;
|
||||
|
||||
NSDictionary *launchOptions = notification.userInfo;
|
||||
NSString *url = [self getInitDeeplink:launchOptions];
|
||||
NSDictionary *data = [self getInitData:launchOptions];
|
||||
|
||||
// 发送推送事件
|
||||
if (![TDPresetProperties disableOpsReceiptProperties] && launchOptions) {
|
||||
NSDictionary *remoteNotification = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
|
||||
[TDAppLaunchReason td_ops_push_click:remoteNotification];
|
||||
}
|
||||
|
||||
// 记录冷启动启动原因
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
|
||||
if (!launchOptions) {
|
||||
[weakSelf clearAppLaunchParams];
|
||||
} else if ([url isKindOfClass:[NSString class]] && url.length) {
|
||||
self.appLaunchParams = @{@"url": [TDCommonUtil string:url],
|
||||
@"data": @{}};
|
||||
} else {
|
||||
self.appLaunchParams = @{@"url": @"",
|
||||
@"data": [TDCommonUtil dictionary:data]};
|
||||
}
|
||||
}
|
||||
|
||||
UIApplication *application = [TDAppState sharedApplication];
|
||||
id applicationDelegate = [application delegate];
|
||||
if (applicationDelegate == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
[[TDAppDelegateProxyManager defaultManager] proxyNotifications];
|
||||
}
|
||||
|
||||
if (![TDPresetProperties disableOpsReceiptProperties]) {
|
||||
[[TDAppDelegateProxyManager defaultManager] proxyNotifications];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)getInitDeeplink:(NSDictionary *)launchOptions {
|
||||
|
||||
if (!launchOptions || ![launchOptions isKindOfClass:[NSDictionary class]]) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
if ([launchOptions isKindOfClass:[NSDictionary class]] &&
|
||||
[launchOptions.allKeys containsObject:UIApplicationLaunchOptionsURLKey]) {
|
||||
|
||||
return launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
|
||||
} else if ([launchOptions isKindOfClass:[NSDictionary class]] &&
|
||||
[launchOptions.allKeys containsObject:UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
|
||||
|
||||
NSDictionary *userActivityDictionary = launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
|
||||
NSString *type = userActivityDictionary[UIApplicationLaunchOptionsUserActivityTypeKey];
|
||||
if ([type isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||
NSUserActivity *userActivity = userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"];
|
||||
return userActivity.webpageURL.absoluteString;
|
||||
}
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSDictionary *)getInitData:(NSDictionary *)launchOptions {
|
||||
|
||||
if (!launchOptions || ![launchOptions isKindOfClass:[NSDictionary class]]) {
|
||||
return @{};
|
||||
}
|
||||
|
||||
if ([launchOptions.allKeys containsObject:UIApplicationLaunchOptionsLocalNotificationKey]) {
|
||||
// 本地推送可能会解析不出alertbody,这里特殊处理一下
|
||||
UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
|
||||
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
|
||||
properties[@"alertBody"] = notification.alertBody;
|
||||
if (@available(iOS 8.2, *)) {
|
||||
properties[@"alertTitle"] = notification.alertTitle;
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
return launchOptions;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2153a11937bd248f793246e3f848aaab
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20131090d388c4844a66a22ba19bcf58
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// TAAppLifeCycle.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/28.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// APP life cycle
|
||||
typedef NS_ENUM(NSUInteger, TAAppLifeCycleState) {
|
||||
TAAppLifeCycleStateInit = 1, // init status
|
||||
TAAppLifeCycleStateBackgroundStart,
|
||||
TAAppLifeCycleStateStart,
|
||||
TAAppLifeCycleStateEnd,
|
||||
TAAppLifeCycleStateTerminate,
|
||||
};
|
||||
|
||||
/// When the life cycle status is about to change, this notification will be sent
|
||||
/// object: The object is the current life cycle object
|
||||
/// userInfo: Contains two keys kTAAppLifeCycleNewStateKey and kTAAppLifeCycleOldStateKey
|
||||
extern NSNotificationName const kTAAppLifeCycleStateWillChangeNotification;
|
||||
|
||||
/// When the life cycle status changes, this notification will be sent
|
||||
/// object: The object is the current lifecycle object
|
||||
/// userInfo: Contains two keys kTAAppLifeCycleNewStateKey and kTAAppLifeCycleOldStateKey
|
||||
extern NSNotificationName const kTAAppLifeCycleStateDidChangeNotification;
|
||||
|
||||
/// In the status change notification, get the new status
|
||||
extern NSString * const kTAAppLifeCycleNewStateKey;
|
||||
|
||||
/// In the status change notification, get the status before the change
|
||||
extern NSString * const kTAAppLifeCycleOldStateKey;
|
||||
|
||||
@interface TAAppLifeCycle : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) TAAppLifeCycleState state;
|
||||
|
||||
+ (void)startMonitor;
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 885238a5636ac43b7a9be0bfdd0537b2
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// TAAppLifeCycle.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/28.
|
||||
//
|
||||
|
||||
#import "TAAppLifeCycle.h"
|
||||
#import "TDAppState.h"
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<ThinkingSDK/TDLogging.h>)
|
||||
#import <ThinkingSDK/TDLogging.h>
|
||||
#else
|
||||
#import "TDLogging.h"
|
||||
#endif
|
||||
|
||||
NSNotificationName const kTAAppLifeCycleStateWillChangeNotification = @"cn.thinkingdata.TAAppLifeCycleStateWillChange";
|
||||
NSNotificationName const kTAAppLifeCycleStateDidChangeNotification = @"cn.thinkingdata.TAAppLifeCycleStateDidChange";
|
||||
NSString * const kTAAppLifeCycleNewStateKey = @"new";
|
||||
NSString * const kTAAppLifeCycleOldStateKey = @"old";
|
||||
|
||||
|
||||
@interface TAAppLifeCycle ()
|
||||
/// status
|
||||
@property (nonatomic, assign) TAAppLifeCycleState state;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TAAppLifeCycle
|
||||
|
||||
+ (void)startMonitor {
|
||||
[TAAppLifeCycle shareInstance];
|
||||
}
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TAAppLifeCycle *appLifeCycle = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
appLifeCycle = [[TAAppLifeCycle alloc] init];
|
||||
});
|
||||
return appLifeCycle;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_state = TAAppLifeCycleStateInit;
|
||||
[self registerListeners];
|
||||
[self setupLaunchedState];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)registerListeners {
|
||||
if ([TDAppState runningInAppExtension]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
#if TARGET_OS_IOS
|
||||
[notificationCenter addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive:)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
[notificationCenter addObserver:self
|
||||
selector:@selector(applicationDidEnterBackground:)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
|
||||
[notificationCenter addObserver:self
|
||||
selector:@selector(applicationWillTerminate:)
|
||||
name:UIApplicationWillTerminateNotification
|
||||
object:nil];
|
||||
|
||||
#elif TARGET_OS_OSX
|
||||
|
||||
// [notificationCenter addObserver:self
|
||||
// selector:@selector(applicationDidFinishLaunching:)
|
||||
// name:NSApplicationDidFinishLaunchingNotification
|
||||
// object:nil];
|
||||
//
|
||||
// [notificationCenter addObserver:self
|
||||
// selector:@selector(applicationDidBecomeActive:)
|
||||
// name:NSApplicationDidBecomeActiveNotification
|
||||
// object:nil];
|
||||
// [notificationCenter addObserver:self
|
||||
// selector:@selector(applicationDidResignActive:)
|
||||
// name:NSApplicationDidResignActiveNotification
|
||||
// object:nil];
|
||||
//
|
||||
// [notificationCenter addObserver:self
|
||||
// selector:@selector(applicationWillTerminate:)
|
||||
// name:NSApplicationWillTerminateNotification
|
||||
// object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setupLaunchedState {
|
||||
if ([TDAppState runningInAppExtension]) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_block_t mainThreadBlock = ^(){
|
||||
#if TARGET_OS_IOS
|
||||
UIApplication *application = [TDAppState sharedApplication];
|
||||
BOOL isAppStateBackground = application.applicationState == UIApplicationStateBackground;
|
||||
#else
|
||||
BOOL isAppStateBackground = NO;
|
||||
#endif
|
||||
[TDAppState shareInstance].relaunchInBackground = isAppStateBackground;
|
||||
|
||||
self.state = isAppStateBackground ? TAAppLifeCycleStateBackgroundStart : TAAppLifeCycleStateStart;
|
||||
};
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// The reason why iOS 13 and above modify the status in the block of the asynchronous main queue:+
|
||||
// 1. Make sure that the initialization of the SDK has been completed before sending the appstatus change notification. This can ensure that the public properties have been set when the automatic collection management class sends the app_start event (in fact, it can also be achieved by listening to UIApplicationDidFinishLaunchingNotification)
|
||||
// 2. In a project that contains SceneDelegate, it is accurate to delay obtaining applicationState (obtaining by listening to UIApplicationDidFinishLaunchingNotification is inaccurate)
|
||||
dispatch_async(dispatch_get_main_queue(), mainThreadBlock);
|
||||
} else {
|
||||
// iOS 13 and below handle background wakeup and cold start (non-delayed initialization) by listening to the notification of UIApplicationDidFinishLaunchingNotification:
|
||||
// 1. When iOS 13 or later wakes up in the background, the block of the asynchronous main queue will not be executed. So you need to listen to UIApplicationDidFinishLaunchingNotification at the same time
|
||||
// 2. iOS 13 and below will not contain SceneDelegate
|
||||
#if TARGET_OS_IOS
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidFinishLaunching:)
|
||||
name:UIApplicationDidFinishLaunchingNotification
|
||||
object:nil];
|
||||
#endif
|
||||
// Handle cold start below iOS 13, where the client delays initialization. UIApplicationDidFinishLaunchingNotification notification has been missed when lazy initialization
|
||||
dispatch_async(dispatch_get_main_queue(), mainThreadBlock);
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Notification Action
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
#if TARGET_OS_IOS
|
||||
UIApplication *application = [TDAppState sharedApplication];
|
||||
BOOL isAppStateBackground = application.applicationState == UIApplicationStateBackground;
|
||||
#else
|
||||
BOOL isAppStateBackground = NO;
|
||||
#endif
|
||||
|
||||
[TDAppState shareInstance].relaunchInBackground = isAppStateBackground;
|
||||
|
||||
self.state = isAppStateBackground ? TAAppLifeCycleStateBackgroundStart : TAAppLifeCycleStateStart;
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
TDLogDebug(@"application did become active");
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
if (![notification.object isKindOfClass:[UIApplication class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIApplication *application = (UIApplication *)notification.object;
|
||||
if (application.applicationState != UIApplicationStateActive) {
|
||||
return;
|
||||
}
|
||||
#elif TARGET_OS_OSX
|
||||
if (![notification.object isKindOfClass:[NSApplication class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSApplication *application = (NSApplication *)notification.object;
|
||||
if (!application.isActive) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
[TDAppState shareInstance].relaunchInBackground = NO;
|
||||
|
||||
self.state = TAAppLifeCycleStateStart;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
- (void)applicationDidEnterBackground:(NSNotification *)notification {
|
||||
TDLogDebug(@"application did enter background");
|
||||
|
||||
if (![notification.object isKindOfClass:[UIApplication class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIApplication *application = (UIApplication *)notification.object;
|
||||
if (application.applicationState != UIApplicationStateBackground) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.state = TAAppLifeCycleStateEnd;
|
||||
}
|
||||
|
||||
#elif TARGET_OS_OSX
|
||||
- (void)applicationDidResignActive:(NSNotification *)notification {
|
||||
TDLogDebug(@"application did resignActive");
|
||||
|
||||
if (![notification.object isKindOfClass:[NSApplication class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSApplication *application = (NSApplication *)notification.object;
|
||||
if (application.isActive) {
|
||||
return;
|
||||
}
|
||||
self.state = TAAppLifeCycleStateEnd;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)notification {
|
||||
TDLogDebug(@"application will terminate");
|
||||
|
||||
self.state = TAAppLifeCycleStateTerminate;
|
||||
}
|
||||
|
||||
//MARK: - Setter
|
||||
|
||||
- (void)setState:(TAAppLifeCycleState)state {
|
||||
|
||||
if (_state == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
[TDAppState shareInstance].isActive = (state == TAAppLifeCycleStateStart);
|
||||
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
userInfo[kTAAppLifeCycleNewStateKey] = @(state);
|
||||
userInfo[kTAAppLifeCycleOldStateKey] = @(_state);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kTAAppLifeCycleStateWillChangeNotification object:self userInfo:userInfo];
|
||||
|
||||
_state = state;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kTAAppLifeCycleStateDidChangeNotification object:self userInfo:userInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90a768aa97d9f4a67a459208b6dc419f
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// TDAppState.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/9/24.
|
||||
// Copyright © 2021 thinkingdata. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDAppState : NSObject
|
||||
/// Whether to start in the background. When the app is woken up by silently pushing the background, or when the location change wakes up the app, value = YES. (thread safe)
|
||||
@property (atomic, assign) BOOL relaunchInBackground;
|
||||
|
||||
/// Whether the current app is in the foreground
|
||||
@property (atomic, assign) BOOL isActive;
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
+ (id)sharedApplication;
|
||||
|
||||
+ (BOOL)runningInAppExtension;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfe06ac7bb20d44f4b38427283e52402
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// TDAppState.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/9/24.
|
||||
// Copyright © 2021 thinkingdata. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TDAppState.h"
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
NSString *_td_lastKnownState;
|
||||
|
||||
@implementation TDAppState
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TDAppState *appState;
|
||||
dispatch_once(&onceToken, ^{
|
||||
appState = [TDAppState new];
|
||||
});
|
||||
return appState;
|
||||
}
|
||||
|
||||
+ (id)sharedApplication {
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
|
||||
if ([self runningInAppExtension]) {
|
||||
return nil;
|
||||
}
|
||||
return [[UIApplication class] performSelector:@selector(sharedApplication)];
|
||||
|
||||
#endif
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (BOOL)runningInAppExtension {
|
||||
#if TARGET_OS_IOS
|
||||
return [[[[NSBundle mainBundle] bundlePath] pathExtension] isEqualToString:@"appex"];
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 439283b9eaf2e4d26883e97a319af143
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1b5729d7c0b24bddbf39df25636523b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60e81b49c2ab941b48f1746f0b7f409d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TAAppEndEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/17.
|
||||
//
|
||||
|
||||
#import "TAAutoTrackEvent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAAppEndEvent : TAAutoTrackEvent
|
||||
@property (nonatomic, copy) NSString *screenName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab91a24abdc494f7b8c0862a2b45cce3
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TAAppEndEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/17.
|
||||
//
|
||||
|
||||
#import "TAAppEndEvent.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TAAppEndEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
|
||||
if (![TDPresetProperties disableScreenName]) {
|
||||
self.properties[@"#screen_name"] = self.screenName ?: @"";
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 294d54bcf09bf453c8bf7febc52d1dcb
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// TAAppStartEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/17.
|
||||
//
|
||||
|
||||
#import "TAAutoTrackEvent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAAppStartEvent : TAAutoTrackEvent
|
||||
@property (nonatomic, copy) NSString *startReason;
|
||||
@property (nonatomic, assign) BOOL resumeFromBackground;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77af5449a173c4d05aa967435187b647
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// TAAppStartEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/17.
|
||||
//
|
||||
|
||||
#import "TAAppStartEvent.h"
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TAAppStartEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
|
||||
if (![TDPresetProperties disableResumeFromBackground]) {
|
||||
self.properties[@"#resume_from_background"] = @(self.resumeFromBackground);
|
||||
}
|
||||
if (![TDPresetProperties disableStartReason]) {
|
||||
self.properties[@"#start_reason"] = self.startReason;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1294c9d002c2c4f879fcc49269cbc7e9
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// TAAutoClickEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TAAutoTrackEvent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAAutoClickEvent : TAAutoTrackEvent
|
||||
@property (nonatomic, copy) NSString *elementId;
|
||||
@property (nonatomic, copy) NSString *elementContent;
|
||||
@property (nonatomic, copy) NSString *elementType;
|
||||
@property (nonatomic, copy) NSString *elementPosition;
|
||||
@property (nonatomic, copy) NSString *pageTitle;
|
||||
@property (nonatomic, copy) NSString *screenName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0b6e9b4fa84e40ffa4799dd7aed576d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// TAAutoClickEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TAAutoClickEvent.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TAAutoClickEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
|
||||
if (![TDPresetProperties disableScreenName]) {
|
||||
self.properties[@"#screen_name"] = self.screenName;
|
||||
}
|
||||
if (![TDPresetProperties disableElementId]) {
|
||||
self.properties[@"#element_id"] = self.elementId;
|
||||
}
|
||||
if (![TDPresetProperties disableElementType]) {
|
||||
self.properties[@"#element_type"] = self.elementType;
|
||||
}
|
||||
if (![TDPresetProperties disableElementContent]) {
|
||||
self.properties[@"#element_content"] = self.elementContent;
|
||||
}
|
||||
if (![TDPresetProperties disableElementPosition]) {
|
||||
self.properties[@"#element_position"] = self.elementPosition;
|
||||
}
|
||||
if (![TDPresetProperties disableTitle]) {
|
||||
self.properties[@"#title"] = self.pageTitle;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22c8f205dbc9a492db570c08357cab4f
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TAAutoPageViewEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TAAutoTrackEvent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAAutoPageViewEvent : TAAutoTrackEvent
|
||||
@property (nonatomic, copy) NSString *pageUrl;
|
||||
@property (nonatomic, copy) NSString *referrer;
|
||||
@property (nonatomic, copy) NSString *pageTitle;
|
||||
@property (nonatomic, copy) NSString *screenName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfeb4b3d07e4d4c0e89b139b8d7e4184
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// TAAutoPageViewEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TAAutoPageViewEvent.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TAAutoPageViewEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
|
||||
if (![TDPresetProperties disableScreenName]) {
|
||||
self.properties[@"#screen_name"] = self.screenName;
|
||||
}
|
||||
if (![TDPresetProperties disableTitle]) {
|
||||
self.properties[@"#title"] = self.pageTitle;
|
||||
}
|
||||
if (![TDPresetProperties disableUrl]) {
|
||||
self.properties[@"#url"] = self.pageUrl;
|
||||
}
|
||||
if (![TDPresetProperties disableReferrer]) {
|
||||
self.properties[@"#referrer"] = self.referrer;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c0bed1add07542e6bcf1fda661ce0d5
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// TAAutoTrackEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TATrackEvent.h"
|
||||
#import "TDConstant.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAAutoTrackEvent : TATrackEvent
|
||||
|
||||
/// It is used to record the dynamic public properties of automatic collection events. The dynamic public properties need to be obtained in the current thread where the event occurs
|
||||
@property (nonatomic, strong) NSDictionary *autoDynamicSuperProperties;
|
||||
|
||||
/// Static public property for logging autocollection events
|
||||
@property (nonatomic, strong) NSDictionary *autoSuperProperties;
|
||||
|
||||
/// Returns the automatic collection type
|
||||
- (ThinkingAnalyticsAutoTrackEventType)autoTrackEventType;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: debe332a658c34f4a97564ba712921a6
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// TAAutoTrackEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/6/15.
|
||||
//
|
||||
|
||||
#import "TAAutoTrackEvent.h"
|
||||
#import "ThinkingAnalyticsSDKPrivate.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TAAutoTrackEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
// Reprocess the duration of automatic collection events, mainly app_start, app_end
|
||||
// app_start app_end events are collected by the automatic collection management class. There are the following problems: the automatic collection management class and the timeTracker event duration management class are processed by listening to appLifeCycle notifications, so they are not at a precise and unified time point. There will be small errors that need to be eliminated.
|
||||
// After testing, the error is less than 0.01s.
|
||||
CGFloat minDuration = 0.01;
|
||||
if (![TDPresetProperties disableDuration]) {
|
||||
if (self.foregroundDuration > minDuration) {
|
||||
self.properties[@"#duration"] = @([NSString stringWithFormat:@"%.3f", self.foregroundDuration].floatValue);
|
||||
}
|
||||
}
|
||||
if (![TDPresetProperties disableBackgroundDuration]) {
|
||||
if (self.backgroundDuration > minDuration) {
|
||||
self.properties[@"#background_duration"] = @([NSString stringWithFormat:@"%.3f", self.backgroundDuration].floatValue);
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
- (ThinkingAnalyticsAutoTrackEventType)autoTrackEventType {
|
||||
if ([self.eventName isEqualToString:TD_APP_START_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppStart;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_START_BACKGROUND_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppStart;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_END_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppEnd;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_VIEW_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppViewScreen;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_CLICK_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppClick;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_CRASH_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppViewCrash;
|
||||
} else if ([self.eventName isEqualToString:TD_APP_INSTALL_EVENT]) {
|
||||
return ThinkingAnalyticsEventTypeAppInstall;
|
||||
} else {
|
||||
return ThinkingAnalyticsEventTypeNone;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ta_validateKey:(NSString *)key value:(id)value error:(NSError *__autoreleasing _Nullable *)error {
|
||||
[TAPropertyValidator validateAutoTrackEventPropertyKey:key value:value error:error];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 457a15183a12f43288ad47022c24f21d
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// TAPushClickEvent.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by liulongbing on 2023/5/31.
|
||||
//
|
||||
#import "TAAutoTrackEvent.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TAPushClickEvent : TAAutoTrackEvent
|
||||
|
||||
@property (nonatomic, strong) NSDictionary *ops;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5da924cd82c7e49b6a2d9eafec038882
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// TAPushClickEvent.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by liulongbing on 2023/5/31.
|
||||
//
|
||||
|
||||
#import "TAPushClickEvent.h"
|
||||
|
||||
@implementation TAPushClickEvent
|
||||
|
||||
- (NSMutableDictionary *)jsonObject {
|
||||
NSMutableDictionary *dict = [super jsonObject];
|
||||
self.properties[@"#ops_receipt_properties"] = self.ops;
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70ccea408f557438a9f8be087342eab3
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// TAAutoTrackProtocol.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/7/1.
|
||||
//
|
||||
|
||||
#ifndef TAAutoTrackProtocol_h
|
||||
#define TAAutoTrackProtocol_h
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol TDUIViewAutoTrackDelegate
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
UITableView event properties
|
||||
|
||||
@return event properties
|
||||
*/
|
||||
- (NSDictionary *)thinkingAnalytics_tableView:(UITableView *)tableView autoTrackPropertiesAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/**
|
||||
APPID UITableView event properties
|
||||
|
||||
@return event properties
|
||||
*/
|
||||
- (NSDictionary *)thinkingAnalyticsWithAppid_tableView:(UITableView *)tableView autoTrackPropertiesAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
UICollectionView event properties
|
||||
|
||||
@return event properties
|
||||
*/
|
||||
- (NSDictionary *)thinkingAnalytics_collectionView:(UICollectionView *)collectionView autoTrackPropertiesAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/**
|
||||
APPID UICollectionView event properties
|
||||
|
||||
@return event properties
|
||||
*/
|
||||
- (NSDictionary *)thinkingAnalyticsWithAppid_collectionView:(UICollectionView *)collectionView autoTrackPropertiesAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol TDAutoTracker
|
||||
|
||||
@optional
|
||||
|
||||
- (NSDictionary *)getTrackProperties;
|
||||
|
||||
|
||||
- (NSDictionary *)getTrackPropertiesWithAppid;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
Automatically track the page
|
||||
*/
|
||||
@protocol TDScreenAutoTracker <TDAutoTracker>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
Attributes for custom page view events
|
||||
*/
|
||||
- (NSString *)getScreenUrl;
|
||||
|
||||
/**
|
||||
Configure the properties of the APPID custom page view event
|
||||
*/
|
||||
- (NSDictionary *)getScreenUrlWithAppid;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* TAAutoTrackProtocol_h */
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18165eaf66907443c93552539b274cd0
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// TAAutoTrackPublicHeader.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by Yangxiongon 2022/7/1.
|
||||
//
|
||||
|
||||
#ifndef TAAutoTrackPublicHeader_h
|
||||
#define TAAutoTrackPublicHeader_h
|
||||
|
||||
#if __has_include(<ThinkingSDK/TAAutoTrackProtocol.h>)
|
||||
#import <ThinkingSDK/TAAutoTrackProtocol.h>
|
||||
#else
|
||||
#import "TAAutoTrackProtocol.h"
|
||||
#endif
|
||||
|
||||
#if __has_include(<ThinkingSDK/UIView+ThinkingAnalytics.h>)
|
||||
#import <ThinkingSDK/UIView+ThinkingAnalytics.h>
|
||||
#else
|
||||
#import "UIView+ThinkingAnalytics.h"
|
||||
#endif
|
||||
|
||||
#endif /* TAAutoTrackPublicHeader_h */
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0346fe03091074a4ab4c1763dc7d6d5f
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
#import "ThinkingAnalyticsSDK.h"
|
||||
#import "TDColdStartTracker.h"
|
||||
#import "TDHotStartTracker.h"
|
||||
#import "TDInstallTracker.h"
|
||||
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_TITLE;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_URL_PROPERTY;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_REFERRER_URL;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_SCREEN_NAME;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_ELEMENT_ID;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_ELEMENT_TYPE;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_ELEMENT_CONTENT;
|
||||
FOUNDATION_EXTERN NSString * const TD_EVENT_PROPERTY_ELEMENT_POSITION;
|
||||
|
||||
@interface TDAutoTrackManager : NSObject
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
- (void)trackEventView:(UIView *)view;
|
||||
|
||||
- (void)trackEventView:(UIView *)view withIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (void)trackWithAppid:(NSString *)appid withOption:(ThinkingAnalyticsAutoTrackEventType)type;
|
||||
|
||||
- (void)viewControlWillAppear:(UIViewController *)controller;
|
||||
|
||||
+ (UIViewController *)topPresentedViewController;
|
||||
|
||||
#pragma mark - UNAVAILABLE
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1625f60723f8542a69466be0231920f5
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user