From 2a57b0bcb150bc701b4e465ea8d2669b78617082 Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Wed, 20 Sep 2023 12:13:13 +0530 Subject: [PATCH 1/9] content and service extension version tracking completed --- ...chPushNotificationViewController+Private.h | 3 ++ .../WEXRichPushNotificationViewController.m | 38 ++++++++++++++++++- .../WEXPushNotificationService.m | 7 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h index 655063d..0392260 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h @@ -28,6 +28,9 @@ - (NSAttributedString *)getHtmlParsedString:(NSString *)textString isTitle:(BOOL)isTitle bckColor:(NSString *)bckColor; +- (void)setExtensionDefaults; +- (NSUserDefaults *)getSharedUserDefaults; + #endif @end diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m index 29631e3..83896ad 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m @@ -16,6 +16,8 @@ #import #import "NSMutableAttributedString+Additions.h" +#define WEX_CONTENT_EXTENSION_VERSION @"1.0.2" + API_AVAILABLE(ios(10.0)) @interface WEXRichPushNotificationViewController () @@ -95,7 +97,7 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios self.notification = notification; self.isRendering = YES; [self updateDarkModeStatus]; - + [self setExtensionDefaults]; NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"WEX_APP_GROUP"]; if (!appGroup) { @@ -131,6 +133,40 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios } } +- (void)setExtensionDefaults { + NSUserDefaults *sharedDefaults = [self getSharedUserDefaults]; + // Write operation only if key is not present in the UserDefaults + if ([sharedDefaults valueForKey:@"WEG_Content_Extension_Version"] == nil) { + [sharedDefaults setValue:WEX_CONTENT_EXTENSION_VERSION forKey:@"WEG_Content_Extension_Version"]; + [sharedDefaults synchronize]; + } +} + +- (NSUserDefaults *)getSharedUserDefaults { + + NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"WEX_APP_GROUP"]; + + if (!appGroup) { + NSBundle *bundle = [NSBundle mainBundle]; + + if ([[bundle.bundleURL pathExtension] isEqualToString:@"appex"]) { + bundle = [NSBundle bundleWithURL:[[bundle.bundleURL URLByDeletingLastPathComponent] URLByDeletingLastPathComponent]]; + } + + NSString *bundleIdentifier = [bundle objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + + appGroup = [NSString stringWithFormat:@"group.%@.WEGNotificationGroup", bundleIdentifier]; + } + + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:appGroup]; + + if (!defaults) { + NSLog(@"Shared User Defaults could not be initialized. Ensure Shared App Groups have been enabled on Main App & Notification Service Extension Targets."); + } + + return defaults; +} + - (WEXRichPushLayout *)layoutForStyle:(NSString *)style { if (style && [style isEqualToString:@"CAROUSEL_V1"]) { diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m index 4ae81da..070544c 100644 --- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m +++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m @@ -9,6 +9,7 @@ #import "WEXPushNotificationService.h" #import +#define WEX_SERVICE_EXTENSION_VERSION @"1.0.2" @interface WEXPushNotificationService () @@ -16,8 +17,10 @@ @interface WEXPushNotificationService () @property (nonatomic) void (^contentHandler)(UNNotificationContent *contentToDeliver); @property (nonatomic) UNMutableNotificationContent *bestAttemptContent; @property (nonatomic) NSString *enviroment; +@property NSString *serviceExtensionVersion; @property NSDictionary *sharedUserDefaults; @property NSArray *customCategories; + #endif @end @@ -312,6 +315,10 @@ - (void)setExtensionDefaults { [sharedDefaults setValue:@"WEG" forKey:@"WEG_ServiceToApp"]; [sharedDefaults synchronize]; } + if ([sharedDefaults valueForKey:@"WEG_Service_Extension_Version"] == nil) { + [sharedDefaults setValue:WEX_SERVICE_EXTENSION_VERSION forKey:@"WEG_Service_Extension_Version"]; + [sharedDefaults synchronize]; + } } - (NSString *) getBaseURL{ From 294f80a8efb41702819852238424b95185134de7 Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Tue, 31 Oct 2023 13:06:16 +0530 Subject: [PATCH 2/9] initial commit for auth headers --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ Info.plist | 8 ++ WEGNetworkManager.h | 17 ++++ WEGNetworkManager.m | 98 +++++++++++++++++++ ...chPushNotificationViewController+Private.h | 2 + .../WEXPushNotificationService.m | 23 +++-- WebEngageBannerPush-Bridging-Header.h | 4 + 7 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Info.plist create mode 100644 WEGNetworkManager.h create mode 100644 WEGNetworkManager.m create mode 100644 WebEngageBannerPush-Bridging-Header.h diff --git a/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..4fa72e8 --- /dev/null +++ b/Info.plist @@ -0,0 +1,8 @@ + + + + + CFBundleShortVersionString + "1.0.2" + + diff --git a/WEGNetworkManager.h b/WEGNetworkManager.h new file mode 100644 index 0000000..47feaa5 --- /dev/null +++ b/WEGNetworkManager.h @@ -0,0 +1,17 @@ +// +// WEGNetworkManager.h +// WebEngageBannerPush +// +// Created by Uday Sharma on 30/10/23. +// + +#import + +@interface WEGNetworkManager : NSObject + ++ (instancetype)sharedManager; +- (NSURLRequest *)getModifiedUrl:(NSURLRequest *)request; +- (NSURLRequest *)getModifiedCommonRequest:(NSURLRequest *)request; +- (NSUserDefaults *)getSharedUserDefaults; + +@end diff --git a/WEGNetworkManager.m b/WEGNetworkManager.m new file mode 100644 index 0000000..f146b06 --- /dev/null +++ b/WEGNetworkManager.m @@ -0,0 +1,98 @@ +// +// WEGNetworkManager.m +// WebEngageBannerPush +// +// Created by Uday Sharma on 30/10/23. +// + +#import "WEGNetworkManager.h" + +@implementation WEGNetworkManager + ++ (instancetype)sharedManager { + static WEGNetworkManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + return self; +} + +- (NSURLRequest *)getModifiedUrl:(NSURLRequest *)request{ + NSString *regexPattern = @"https://[^/]*\\.webengage\\."; + + // Different regex, so have to check it individually + NSArray *uniqueRegexUrls = @[[NSURL URLWithString:@"https://s3.amazonaws.com/webengage-zfiles-gc/"]]; + + // Check if each base URL contains ".webengage" or ".webengage-zfiles-gc" using the regular expression + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexPattern options:0 error:&error]; + + if (error) { + // Handle the error here + return nil; + } + + for (NSURL *uniqueUrl in uniqueRegexUrls) { + if ([regex firstMatchInString:request.URL.absoluteString options:0 range:NSMakeRange(0, request.URL.absoluteString.length)]) { + return [self getModifiedCommonRequest:request]; + } + else if ([request.URL isEqual:uniqueUrl]) { + return [self getModifiedCommonRequest:request]; + } + else { + return request; + } + } + + return request; +} + +- (NSURLRequest *)getModifiedCommonRequest:(NSURLRequest *)request{ + + NSMutableURLRequest *urlRequest = [request mutableCopy]; + NSUserDefaults *defaults = [self getSharedUserDefaults]; + NSString *cuid = [defaults objectForKey:@"cuid"]; + NSString *license_code = [defaults objectForKey:@"license_code"]; + + if (cuid) { + [urlRequest addValue:cuid forHTTPHeaderField:@"cuid"]; + NSString *jwtToken = [defaults objectForKey:@"jwtToken"]; + [urlRequest addValue:[NSString stringWithFormat:@"Bearer %@", jwtToken ?: @""] forHTTPHeaderField:@"Authorization"]; + } + + [urlRequest addValue:license_code forHTTPHeaderField:@"lc"]; + return [urlRequest copy]; +} + +- (NSUserDefaults *)getSharedUserDefaults { + + NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"WEX_APP_GROUP"]; + + if (!appGroup) { + NSBundle *bundle = [NSBundle mainBundle]; + + if ([[bundle.bundleURL pathExtension] isEqualToString:@"appex"]) { + bundle = [NSBundle bundleWithURL:[[bundle.bundleURL URLByDeletingLastPathComponent] URLByDeletingLastPathComponent]]; + } + + NSString *bundleIdentifier = [bundle objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + + appGroup = [NSString stringWithFormat:@"group.%@.WEGNotificationGroup", bundleIdentifier]; + } + + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:appGroup]; + + if (!defaults) { + NSLog(@"Shared User Defaults could not be initialized. Ensure Shared App Groups have been enabled on Main App & Notification Service Extension Targets."); + } + + return defaults; +} + +@end diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h index 655063d..1eb30b6 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h @@ -27,6 +27,8 @@ - (NSTextAlignment)naturalTextAligmentForText:(NSString*) text; - (NSAttributedString *)getHtmlParsedString:(NSString *)textString isTitle:(BOOL)isTitle bckColor:(NSString *)bckColor; +- (void)setExtensionDefaults; +- (NSUserDefaults *)getSharedUserDefaults; #endif diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m index 4ae81da..7ae80b1 100644 --- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m +++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m @@ -8,6 +8,7 @@ #import "WEXPushNotificationService.h" #import +#import "WEGNetworkManager.h" @interface WEXPushNotificationService () @@ -224,11 +225,14 @@ - (void)fetchAttachmentFor:(NSString *)urlString @"Accept": @"image/webp" }; - [request setAllHTTPHeaderFields:headers]; - [request setHTTPMethod:@"GET"]; + NSMutableURLRequest *customRequest = [[[WEGNetworkManager sharedManager] getModifiedUrl:request] mutableCopy]; + + + [customRequest setAllHTTPHeaderFields:headers]; + [customRequest setHTTPMethod:@"GET"]; NSURLSession *session = [NSURLSession sharedSession]; - [[session downloadTaskWithRequest:request + [[session downloadTaskWithRequest:[customRequest copy] completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) { UNNotificationAttachment *attachment = nil; @@ -340,15 +344,16 @@ - (NSURLRequest *)getRequestForTracker:(NSString *)eventName { NSLog(@"Base url: %@", url); - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + NSURLRequest *request = [NSURLRequest requestWithURL:url]; - request.HTTPMethod = @"POST"; + NSMutableURLRequest *customRequest = [[[WEGNetworkManager sharedManager] getModifiedUrl:request] mutableCopy]; - [request setValue:@"application/transit+json" forHTTPHeaderField:@"Content-type"]; - [request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"]; - request.HTTPBody = [self getTrackerRequestBody:eventName]; + customRequest.HTTPMethod = @"POST"; + [customRequest setValue:@"application/transit+json" forHTTPHeaderField:@"Content-type"]; + [customRequest setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"]; + customRequest.HTTPBody = [self getTrackerRequestBody:eventName]; - return request; + return [customRequest copy]; } - (NSData *)getTrackerRequestBody:(NSString *)eventName { diff --git a/WebEngageBannerPush-Bridging-Header.h b/WebEngageBannerPush-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/WebEngageBannerPush-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + From bafa894c993e3e41974210cc01b83950629bd304 Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Tue, 31 Oct 2023 13:06:36 +0530 Subject: [PATCH 3/9] Revert "initial commit for auth headers" This reverts commit 294f80a8efb41702819852238424b95185134de7. --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -- Info.plist | 8 -- WEGNetworkManager.h | 17 ---- WEGNetworkManager.m | 98 ------------------- ...chPushNotificationViewController+Private.h | 2 - .../WEXPushNotificationService.m | 23 ++--- WebEngageBannerPush-Bridging-Header.h | 4 - 7 files changed, 9 insertions(+), 151 deletions(-) delete mode 100644 Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Info.plist delete mode 100644 WEGNetworkManager.h delete mode 100644 WEGNetworkManager.m delete mode 100644 WebEngageBannerPush-Bridging-Header.h diff --git a/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/Extension App/WEGExtensionApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Info.plist b/Info.plist deleted file mode 100644 index 4fa72e8..0000000 --- a/Info.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - CFBundleShortVersionString - "1.0.2" - - diff --git a/WEGNetworkManager.h b/WEGNetworkManager.h deleted file mode 100644 index 47feaa5..0000000 --- a/WEGNetworkManager.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// WEGNetworkManager.h -// WebEngageBannerPush -// -// Created by Uday Sharma on 30/10/23. -// - -#import - -@interface WEGNetworkManager : NSObject - -+ (instancetype)sharedManager; -- (NSURLRequest *)getModifiedUrl:(NSURLRequest *)request; -- (NSURLRequest *)getModifiedCommonRequest:(NSURLRequest *)request; -- (NSUserDefaults *)getSharedUserDefaults; - -@end diff --git a/WEGNetworkManager.m b/WEGNetworkManager.m deleted file mode 100644 index f146b06..0000000 --- a/WEGNetworkManager.m +++ /dev/null @@ -1,98 +0,0 @@ -// -// WEGNetworkManager.m -// WebEngageBannerPush -// -// Created by Uday Sharma on 30/10/23. -// - -#import "WEGNetworkManager.h" - -@implementation WEGNetworkManager - -+ (instancetype)sharedManager { - static WEGNetworkManager *sharedInstance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[self alloc] init]; - }); - return sharedInstance; -} - -- (instancetype)init { - self = [super init]; - return self; -} - -- (NSURLRequest *)getModifiedUrl:(NSURLRequest *)request{ - NSString *regexPattern = @"https://[^/]*\\.webengage\\."; - - // Different regex, so have to check it individually - NSArray *uniqueRegexUrls = @[[NSURL URLWithString:@"https://s3.amazonaws.com/webengage-zfiles-gc/"]]; - - // Check if each base URL contains ".webengage" or ".webengage-zfiles-gc" using the regular expression - NSError *error = nil; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexPattern options:0 error:&error]; - - if (error) { - // Handle the error here - return nil; - } - - for (NSURL *uniqueUrl in uniqueRegexUrls) { - if ([regex firstMatchInString:request.URL.absoluteString options:0 range:NSMakeRange(0, request.URL.absoluteString.length)]) { - return [self getModifiedCommonRequest:request]; - } - else if ([request.URL isEqual:uniqueUrl]) { - return [self getModifiedCommonRequest:request]; - } - else { - return request; - } - } - - return request; -} - -- (NSURLRequest *)getModifiedCommonRequest:(NSURLRequest *)request{ - - NSMutableURLRequest *urlRequest = [request mutableCopy]; - NSUserDefaults *defaults = [self getSharedUserDefaults]; - NSString *cuid = [defaults objectForKey:@"cuid"]; - NSString *license_code = [defaults objectForKey:@"license_code"]; - - if (cuid) { - [urlRequest addValue:cuid forHTTPHeaderField:@"cuid"]; - NSString *jwtToken = [defaults objectForKey:@"jwtToken"]; - [urlRequest addValue:[NSString stringWithFormat:@"Bearer %@", jwtToken ?: @""] forHTTPHeaderField:@"Authorization"]; - } - - [urlRequest addValue:license_code forHTTPHeaderField:@"lc"]; - return [urlRequest copy]; -} - -- (NSUserDefaults *)getSharedUserDefaults { - - NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"WEX_APP_GROUP"]; - - if (!appGroup) { - NSBundle *bundle = [NSBundle mainBundle]; - - if ([[bundle.bundleURL pathExtension] isEqualToString:@"appex"]) { - bundle = [NSBundle bundleWithURL:[[bundle.bundleURL URLByDeletingLastPathComponent] URLByDeletingLastPathComponent]]; - } - - NSString *bundleIdentifier = [bundle objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - - appGroup = [NSString stringWithFormat:@"group.%@.WEGNotificationGroup", bundleIdentifier]; - } - - NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:appGroup]; - - if (!defaults) { - NSLog(@"Shared User Defaults could not be initialized. Ensure Shared App Groups have been enabled on Main App & Notification Service Extension Targets."); - } - - return defaults; -} - -@end diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h index 1eb30b6..655063d 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h @@ -27,8 +27,6 @@ - (NSTextAlignment)naturalTextAligmentForText:(NSString*) text; - (NSAttributedString *)getHtmlParsedString:(NSString *)textString isTitle:(BOOL)isTitle bckColor:(NSString *)bckColor; -- (void)setExtensionDefaults; -- (NSUserDefaults *)getSharedUserDefaults; #endif diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m index 7ae80b1..4ae81da 100644 --- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m +++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m @@ -8,7 +8,6 @@ #import "WEXPushNotificationService.h" #import -#import "WEGNetworkManager.h" @interface WEXPushNotificationService () @@ -225,14 +224,11 @@ - (void)fetchAttachmentFor:(NSString *)urlString @"Accept": @"image/webp" }; - NSMutableURLRequest *customRequest = [[[WEGNetworkManager sharedManager] getModifiedUrl:request] mutableCopy]; - - - [customRequest setAllHTTPHeaderFields:headers]; - [customRequest setHTTPMethod:@"GET"]; + [request setAllHTTPHeaderFields:headers]; + [request setHTTPMethod:@"GET"]; NSURLSession *session = [NSURLSession sharedSession]; - [[session downloadTaskWithRequest:[customRequest copy] + [[session downloadTaskWithRequest:request completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) { UNNotificationAttachment *attachment = nil; @@ -344,16 +340,15 @@ - (NSURLRequest *)getRequestForTracker:(NSString *)eventName { NSLog(@"Base url: %@", url); - NSURLRequest *request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - NSMutableURLRequest *customRequest = [[[WEGNetworkManager sharedManager] getModifiedUrl:request] mutableCopy]; + request.HTTPMethod = @"POST"; - customRequest.HTTPMethod = @"POST"; - [customRequest setValue:@"application/transit+json" forHTTPHeaderField:@"Content-type"]; - [customRequest setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"]; - customRequest.HTTPBody = [self getTrackerRequestBody:eventName]; + [request setValue:@"application/transit+json" forHTTPHeaderField:@"Content-type"]; + [request setValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"]; + request.HTTPBody = [self getTrackerRequestBody:eventName]; - return [customRequest copy]; + return request; } - (NSData *)getTrackerRequestBody:(NSString *)eventName { diff --git a/WebEngageBannerPush-Bridging-Header.h b/WebEngageBannerPush-Bridging-Header.h deleted file mode 100644 index 1b2cb5d..0000000 --- a/WebEngageBannerPush-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - From 7fe7bb718922f33e8b6a728ec8929f54c11606ea Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Thu, 23 Nov 2023 17:40:30 +0530 Subject: [PATCH 4/9] gif support in content extension --- UIImage+animatedGIF.h | 32 +++++ UIImage+animatedGIF.m | 119 ++++++++++++++++++ .../WEXBannerPushNotificationViewController.m | 5 +- ...EXCarouselPushNotificationViewController.m | 3 +- .../WEXRatingPushNotificationViewController.m | 3 +- 5 files changed, 157 insertions(+), 5 deletions(-) create mode 100755 UIImage+animatedGIF.h create mode 100755 UIImage+animatedGIF.m diff --git a/UIImage+animatedGIF.h b/UIImage+animatedGIF.h new file mode 100755 index 0000000..1b58c7d --- /dev/null +++ b/UIImage+animatedGIF.h @@ -0,0 +1,32 @@ +#import + +/** + UIImage (animatedGIF) + + This category adds class methods to `UIImage` to create an animated `UIImage` from an animated GIF. +*/ +@interface UIImage (animatedGIF) + +/* + UIImage *animation = [UIImage animatedImageWithAnimatedGIFData:theData]; + + I interpret `theData` as a GIF. I create an animated `UIImage` using the source images in the GIF. + + The GIF stores a separate duration for each frame, in units of centiseconds (hundredths of a second). However, a `UIImage` only has a single, total `duration` property, which is a floating-point number. + + To handle this mismatch, I add each source image (from the GIF) to `animation` a varying number of times to match the ratios between the frame durations in the GIF. + + For example, suppose the GIF contains three frames. Frame 0 has duration 3. Frame 1 has duration 9. Frame 2 has duration 15. I divide each duration by the greatest common denominator of all the durations, which is 3, and add each frame the resulting number of times. Thus `animation` will contain frame 0 3/3 = 1 time, then frame 1 9/3 = 3 times, then frame 2 15/3 = 5 times. I set `animation.duration` to (3+9+15)/100 = 0.27 seconds. +*/ ++ (UIImage * _Nullable)animatedImageWithAnimatedGIFData:(NSData * _Nonnull)theData; + +/* + UIImage *image = [UIImage animatedImageWithAnimatedGIFURL:theURL]; + + I interpret the contents of `theURL` as a GIF. I create an animated `UIImage` using the source images in the GIF. + + I operate exactly like `+[UIImage animatedImageWithAnimatedGIFData:]`, except that I read the data from `theURL`. If `theURL` is not a `file:` URL, you probably want to call me on a background thread or GCD queue to avoid blocking the main thread. +*/ ++ (UIImage * _Nullable)animatedImageWithAnimatedGIFURL:(NSURL * _Nonnull)theURL; + +@end diff --git a/UIImage+animatedGIF.m b/UIImage+animatedGIF.m new file mode 100755 index 0000000..871d11e --- /dev/null +++ b/UIImage+animatedGIF.m @@ -0,0 +1,119 @@ +#import "UIImage+animatedGIF.h" +#import + +#if __has_feature(objc_arc) +#define toCF (__bridge CFTypeRef) +#define fromCF (__bridge id) +#else +#define toCF (CFTypeRef) +#define fromCF (id) +#endif + +@implementation UIImage (animatedGIF) + +static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) { + int delayCentiseconds = 1; + CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL); + if (properties) { + CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + if (gifProperties) { + NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime); + if (number == NULL || [number doubleValue] == 0) { + number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime); + } + if ([number doubleValue] > 0) { + // Even though the GIF stores the delay as an integer number of centiseconds, ImageIO “helpfully” converts that to seconds for us. + delayCentiseconds = (int)lrint([number doubleValue] * 100); + } + } + CFRelease(properties); + } + return delayCentiseconds; +} + +static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) { + for (size_t i = 0; i < count; ++i) { + imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL); + delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i); + } +} + +static int sum(size_t const count, int const *const values) { + int theSum = 0; + for (size_t i = 0; i < count; ++i) { + theSum += values[i]; + } + return theSum; +} + +static int pairGCD(int a, int b) { + if (a < b) + return pairGCD(b, a); + while (true) { + int const r = a % b; + if (r == 0) + return b; + a = b; + b = r; + } +} + +static int vectorGCD(size_t const count, int const *const values) { + int gcd = values[0]; + for (size_t i = 1; i < count; ++i) { + // Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element. By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments. + gcd = pairGCD(values[i], gcd); + } + return gcd; +} + +static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) { + int const gcd = vectorGCD(count, delayCentiseconds); + size_t const frameCount = totalDurationCentiseconds / gcd; + UIImage *frames[frameCount]; + for (size_t i = 0, f = 0; i < count; ++i) { + UIImage *const frame = [UIImage imageWithCGImage:images[i]]; + for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) { + frames[f++] = frame; + } + } + return [NSArray arrayWithObjects:frames count:frameCount]; +} + +static void releaseImages(size_t const count, CGImageRef const images[count]) { + for (size_t i = 0; i < count; ++i) { + CGImageRelease(images[i]); + } +} + +static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) { + size_t const count = CGImageSourceGetCount(source); + CGImageRef images[count]; + int delayCentiseconds[count]; // in centiseconds + createImagesAndDelays(source, count, images, delayCentiseconds); + int const totalDurationCentiseconds = sum(count, delayCentiseconds); + NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds); + UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0]; + releaseImages(count, images); + return animation; +} + +static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) { + if (source) { + UIImage *const image = animatedImageWithAnimatedGIFImageSource(source); + CFRelease(source); + return image; + } else { + return nil; + } +} + ++ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data { + return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL)); +} + ++ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url { + return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL)); +} + +@end diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m index a10c399..786c524 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m @@ -8,6 +8,7 @@ #import "WEXBannerPushNotificationViewController.h" #import "WEXRichPushNotificationViewController+Private.h" #import "UIColor+DarkMode.h" +#import "UIImage+animatedGIF.h" #define CONTENT_PADDING 10 #define TITLE_BODY_SPACE 5 @@ -69,10 +70,8 @@ - (void)setupBannerImageView { if ([attachment.URL startAccessingSecurityScopedResource]) { NSData *imageData = [NSData dataWithContentsOfFile:attachment.URL.path]; - UIImage *image = [UIImage imageWithData:imageData]; - + UIImage *image = [UIImage animatedImageWithAnimatedGIFData:imageData]; [attachment.URL stopAccessingSecurityScopedResource]; - if (image) { imageView.image = image; } else { diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m index ae427df..eaca549 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m @@ -9,6 +9,7 @@ #import "WEXCarouselPushNotificationViewController.h" #import "WEXRichPushNotificationViewController+Private.h" #import "UIColor+DarkMode.h" +#import "UIImage+animatedGIF.h" #define CONTENT_PADDING 10 #define TITLE_BODY_SPACE 5 @@ -81,7 +82,7 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios( NSString *imageURL = self.carouselItems[0][@"image"]; NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]; - UIImage *image = [UIImage imageWithData:imageData]; + UIImage *image = [UIImage animatedImageWithAnimatedGIFData:imageData]; if (image) { [self.images addObject:image]; diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m index c66666d..de53a0f 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m @@ -8,6 +8,7 @@ #import "WEXRatingPushNotificationViewController.h" #import "UIColor+DarkMode.h" +#import "UIImage+animatedGIF.h" //#define NO_OF_STARS 5 #define STAR_BAR_HEIGHT 50 @@ -146,7 +147,7 @@ - (void)initialiseViewHierarchy { if ([attachment.URL startAccessingSecurityScopedResource]) { NSData *imageData = [NSData dataWithContentsOfFile:attachment.URL.path]; - UIImage *image = [UIImage imageWithData:imageData]; + UIImage *image = [UIImage animatedImageWithAnimatedGIFData:imageData]; [attachment.URL stopAccessingSecurityScopedResource]; From 37b527bed5dabf7961674488a0fa408059d37279 Mon Sep 17 00:00:00 2001 From: Milind Keni Date: Fri, 1 Dec 2023 22:58:40 +0530 Subject: [PATCH 5/9] added ksa env for tracker --- .../Classes/NotificationService/WEXPushNotificationService.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m index 4ae81da..00d2e68 100644 --- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m +++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m @@ -329,6 +329,8 @@ - (NSString *) getBaseURL{ } else if ([self.enviroment.uppercaseString isEqualToString:@"UNL"]) { baseURL = @"https://c.unl.webengage.com/tracker"; + }else if ([self.enviroment.uppercaseString isEqualToString:@"KSA"]) { + baseURL = @"https://c.ksa.webengage.com/tracker"; } return baseURL; From b04cad3ee00b3e37eb311b103766b1ecd44b6017 Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Tue, 5 Dec 2023 12:05:14 +0530 Subject: [PATCH 6/9] gif support for a carousal edge case. --- .../WEXCarouselPushNotificationViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m index eaca549..e0675cb 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m @@ -129,7 +129,7 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios( if ([attachment.URL startAccessingSecurityScopedResource]) { NSData *imageData = [NSData dataWithContentsOfFile:attachment.URL.path]; - UIImage *image = [UIImage imageWithData:imageData]; + UIImage *image = [UIImage animatedImageWithAnimatedGIFData:imageData]; [attachment.URL stopAccessingSecurityScopedResource]; From d278f3d9b1d5bfc1961437958ca0a7f62bbc63ef Mon Sep 17 00:00:00 2001 From: Uday Sharma Date: Wed, 6 Dec 2023 14:26:49 +0530 Subject: [PATCH 7/9] file added to the root content folder. --- .../Classes/ContentExtension/UIImage+animatedGIF.h | 0 .../Classes/ContentExtension/UIImage+animatedGIF.m | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename UIImage+animatedGIF.h => WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.h (100%) rename UIImage+animatedGIF.m => WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.m (100%) diff --git a/UIImage+animatedGIF.h b/WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.h similarity index 100% rename from UIImage+animatedGIF.h rename to WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.h diff --git a/UIImage+animatedGIF.m b/WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.m similarity index 100% rename from UIImage+animatedGIF.m rename to WebEngageAppEx/Classes/ContentExtension/UIImage+animatedGIF.m From da0b280ea0fb5fb775227942455fb55a2a60384d Mon Sep 17 00:00:00 2001 From: Shubham Naidu Date: Tue, 19 Dec 2023 14:05:18 +0530 Subject: [PATCH 8/9] updated version to 1.0.3 --- .../ContentExtension/WEXRichPushNotificationViewController.m | 2 +- .../Classes/NotificationService/WEXPushNotificationService.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m index 83896ad..c480d16 100644 --- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m +++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m @@ -16,7 +16,7 @@ #import #import "NSMutableAttributedString+Additions.h" -#define WEX_CONTENT_EXTENSION_VERSION @"1.0.2" +#define WEX_CONTENT_EXTENSION_VERSION @"1.0.3" API_AVAILABLE(ios(10.0)) @interface WEXRichPushNotificationViewController () diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m index 58b34c1..20364a0 100644 --- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m +++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m @@ -9,7 +9,7 @@ #import "WEXPushNotificationService.h" #import -#define WEX_SERVICE_EXTENSION_VERSION @"1.0.2" +#define WEX_SERVICE_EXTENSION_VERSION @"1.0.3" @interface WEXPushNotificationService () From 1b3158618fdc2519701501e5f4709f6c9f3cd1cc Mon Sep 17 00:00:00 2001 From: Bhavesh Sarwar <> Date: Wed, 10 Jan 2024 17:04:54 +0530 Subject: [PATCH 9/9] version number changed --- WebEngageAppEx.podspec | 2 +- WebEngageBannerPush.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WebEngageAppEx.podspec b/WebEngageAppEx.podspec index 3228dbc..6619a04 100644 --- a/WebEngageAppEx.podspec +++ b/WebEngageAppEx.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |spec| spec.name = 'WebEngageAppEx' - spec.version = '1.0.2' + spec.version = '1.0.3' spec.summary = 'App Extension Target SDK for WebEngage for Rich Push Notifications support.' diff --git a/WebEngageBannerPush.podspec b/WebEngageBannerPush.podspec index 30b59a9..9c866ab 100644 --- a/WebEngageBannerPush.podspec +++ b/WebEngageBannerPush.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |spec| spec.name = 'WebEngageBannerPush' - spec.version = '1.0.2' + spec.version = '1.0.3' spec.summary = 'Extension Target SDK for adding WebEngage Rich Push Notifications support' spec.description = <<-DESC