From 265d78a0ce887504151d20e73b7f7366b81b302c Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Mon, 17 May 2021 19:33:34 +0530 Subject: [PATCH 01/22] Load and show html in-apps Download image and show image modal and slide-in Fixed close button to give priority to server value --- .../InApps/BlueShiftInAppNotification.h | 2 +- .../InApps/BlueShiftInAppNotification.m | 2 +- .../BlueShiftInAppNotificationManager.h | 6 +- .../BlueShiftInAppNotificationManager.m | 144 +++++++++++++----- .../BlueShiftNotificationViewController.h | 3 + .../BlueShiftNotificationViewController.m | 30 +++- .../BlueShiftNotificationWebViewController.h | 2 +- .../BlueShiftNotificationWebViewController.m | 11 +- 8 files changed, 147 insertions(+), 53 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.h index a05384f5..7cd11bcc 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.h @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign, readwrite) float height; @property (nonatomic, assign, readwrite) float width;; @property (nonatomic, assign, readwrite) BOOL enableBackgroundAction; -@property (nonatomic, assign, readwrite) BOOL enableCloseButton; +@property (nonatomic, assign, readwrite, nullable) NSNumber* enableCloseButton; @property (nonatomic, readwrite) BlueShiftInAppLayoutMargin *margin; @property (nonatomic, readwrite) BlueShiftInAppNotificationButton *closeButton; @property (nonatomic, assign, readwrite, nullable) NSNumber *backgroundDimAmount; diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m index 3e4f86c3..580741eb 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m @@ -217,7 +217,7 @@ - (instancetype)initFromDictionary: (NSDictionary *)templateStyleDictionary with } if ([templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey] != [NSNull null]){ - self.enableCloseButton = [[templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey] boolValue]; + self.enableCloseButton = (NSNumber*)[templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey]; } if ([templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundRadiusKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundRadiusKey] != [NSNull null]) { diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.h index f369f2af..1e4fb04d 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.h @@ -19,11 +19,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) double inAppNotificationTimeInterval; @property (nonatomic) NSString * _Nullable inAppNotificationDisplayOnPage; -- (void) load; -- (void) initializeInAppNotificationFromAPI:(NSMutableArray *)notificationArray handler:(void (^)(BOOL))handler; +- (void)load; +- (void)initializeInAppNotificationFromAPI:(NSMutableArray *)notificationArray handler:(void (^)(BOOL))handler; - (void)fetchInAppNotificationsFromDataStore: (BlueShiftInAppTriggerMode) triggerMode; - (void)fetchLastInAppMessageIDFromDB:(void (^)(BOOL, NSString *, NSString *))handler; -- (void) deleteExpireInAppNotificationFromDataStore; +- (void)deleteExpireInAppNotificationFromDataStore; - (void)markAsDisplayedForNotificationsViewedOnOtherDevice:(NSArray *)messageUUIDArray; @end diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index 682ce133..5a183dd9 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -174,15 +174,13 @@ - (void) addInAppNotificationToDataStore: (NSDictionary *) payload { } if(masterContext) { NSEntityDescription *entity; - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; @try { entity = [NSEntityDescription entityForName: kInAppNotificationEntityNameKey inManagedObjectContext:masterContext]; - [fetchRequest setEntity:entity]; } @catch (NSException *exception) { [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } - if(entity != nil && fetchRequest.entity != nil) { + if(entity != nil) { InAppNotificationEntity *inAppNotificationEntity = [[InAppNotificationEntity alloc] initWithEntity:entity insertIntoManagedObjectContext: masterContext]; if(inAppNotificationEntity != nil) { @@ -551,61 +549,125 @@ - (void)fetchNowAndUpcomingInAppMessageFromDB { } // Present ViewController -- (void)presentInAppNotification:(BlueShiftNotificationViewController*)notificationController { - if ([self inAppNotificationDisplayOnPage] && self.currentNotificationController == nil) { - self.currentNotificationController = notificationController; - [notificationController show:YES]; - } -} - - -- (void)createNotification:(BlueShiftInAppNotification*)notification { - BlueShiftNotificationViewController *notificationController; - NSString *errorString = nil; - - switch (notification.inAppType) { - case BlueShiftInAppTypeHTML: - notificationController = [[BlueShiftNotificationWebViewController alloc] initWithNotification:notification]; - break; - case BlueShiftInAppTypeModal: - notificationController = [[BlueShiftNotificationModalViewController alloc] initWithNotification:notification]; - break; - case BlueShiftNotificationSlideBanner: - notificationController = [[BlueShiftNotificationSlideBannerViewController alloc] initWithNotification:notification]; - break; - case BlueShiftNotificationRating: - [self displayReviewController]; - - /* delete this notification from coreData */ - [self removeInAppNotificationFromDB: notification.objectID]; +- (void)presentInAppViewController:(BlueShiftNotificationViewController*)notificationController forNotification:(BlueShiftInAppNotification*)notification { + if (notificationController.displayOnScreen && ![notificationController.displayOnScreen isEqual:@""]) { + if(![self.inAppNotificationDisplayOnPage isEqualToString:notificationController.displayOnScreen]) { return; - - - default: - errorString = [NSString stringWithFormat:@"Unhandled notification type: %lu", (unsigned long)notification.inAppType]; - break; + } } - if (notificationController) { + if (notificationController && [self inAppNotificationDisplayOnPage]) { notificationController.delegate = self; notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; - [self presentInAppNotification:notificationController]; - } - if (errorString) { - [BlueshiftLog logError:nil withDescription:errorString methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + [notificationController show:YES]; } } +- (void)createInAppNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + if (self.currentNotificationController != nil) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ + switch (notification.inAppType) { + case BlueShiftInAppTypeHTML: + [self processHTMLNotification:notification displayOnScreen:displayOnScreen]; + break; + + case BlueShiftInAppTypeModal: + [self processModalNotification:notification displayOnScreen:displayOnScreen]; + break; + + case BlueShiftNotificationSlideBanner: + [self processSlideInBannerNotification:notification displayOnScreen:displayOnScreen]; + break; + + case BlueShiftNotificationRating: + { + [self displayReviewController]; + [self removeInAppNotificationFromDB: notification.objectID]; + return;; + } + + default: + { + NSString* errorString = [NSString stringWithFormat:@"Unhandled notification type: %lu", (unsigned long)notification.inAppType]; + [BlueshiftLog logError:nil withDescription:errorString methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + } + break; + } + }); +} + - (void)displayReviewController { if (@available(iOS 10.3, *)) { [SKStoreReviewController requestReview]; } } +-(void)processSlideInBannerNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationSlideBannerViewController alloc] initWithNotification:notification]; + notificationVC.displayOnScreen = displayOnScreen; + self.currentNotificationController = notificationVC; + + BOOL isSlideInIconImagePresent = [self isSlideInIconImagePresent:notification]; + BOOL isBackgroundImagePresent = [self isBackgroundImagePresentForNotification:notification]; + if (isSlideInIconImagePresent || isBackgroundImagePresent) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *backgroundImageURL = nil; + if(isSlideInIconImagePresent) { + backgroundImageURL = notification.notificationContent.iconImage; + } else if (isBackgroundImagePresent) { + backgroundImageURL = notification.templateStyle.backgroundImage; + } + [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentInAppViewController:notificationVC forNotification:notification]; + }); + }); + } else { + [self presentInAppViewController:notificationVC forNotification:notification]; + } +} + +-(void)processModalNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationModalViewController alloc] initWithNotification:notification]; + notificationVC.displayOnScreen = displayOnScreen; + self.currentNotificationController = notificationVC; + if ([self isBackgroundImagePresentForNotification:notification]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *backgroundImageURL = notification.templateStyle.backgroundImage; + [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentInAppViewController:notificationVC forNotification:notification]; + }); + }); + } else { + [self presentInAppViewController:notificationVC forNotification:notification]; + } +} + +-(void)processHTMLNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationWebViewController alloc] initWithNotification:notification]; + notificationVC.displayOnScreen = displayOnScreen; + BlueShiftNotificationWebViewController *webViewController = (BlueShiftNotificationWebViewController*) notificationVC; + self.currentNotificationController = notificationVC; + [webViewController setupWebView:^{ + [self presentInAppViewController:notificationVC forNotification:notification]; + }]; +} + +- (BOOL)isBackgroundImagePresentForNotification:(BlueShiftInAppNotification*)notification { + return (notification.templateStyle && notification.templateStyle.backgroundImage && ![notification.templateStyle.backgroundImage isEqualToString:@""]); +} + +- (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification { + return (notification.notificationContent && notification.notificationContent.iconImage && ![notification.templateStyle.backgroundImage isEqualToString:@""]); +} + - (void)createNotificationFromDictionary:(InAppNotificationEntity *) inAppEntity { BlueShiftInAppNotification *inAppNotification = [[BlueShiftInAppNotification alloc] initFromEntity:inAppEntity]; [BlueshiftLog logInfo:@"Created in-app message to display, message Id: " withDetails:inAppEntity.id methodName:nil]; - [self createNotification: inAppNotification]; + [self createInAppNotification: inAppNotification displayOnScreen:inAppEntity.displayOn]; } // Notification Click Callbacks diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h index 2210ae7e..dbd4f818 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h @@ -28,6 +28,7 @@ controller; @property (nonatomic, assign) BOOL canTouchesPassThroughWindow; @property (nonatomic, weak) id delegate; @property (nonatomic, weak) id inAppNotificationDelegate; +@property (nonatomic, assign) NSString* _Nullable displayOnScreen; - (instancetype)initWithNotification:(BlueShiftInAppNotification *)notification; @@ -62,6 +63,8 @@ controller; /// @param inAppbutton nullable in-app notification clicked button object - (NSDictionary *)getInAppOpenURLOptions:(BlueShiftInAppNotificationButton * _Nullable)inAppbutton; +-(NSData*)loadAndCacheImageForURLString:(NSString*)urlString; + @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index 6079892e..4ec931c8 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -137,12 +137,18 @@ - (void)setBackgroundImageFromURL:(UIView *)notificationView { -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { NSData *imageData = [[NSData alloc] init]; + if(!urlString || [urlString isEqualToString:@""]) { + return imageData; + } if([cachedImageData valueForKey: urlString]) { imageData = [cachedImageData valueForKey:urlString]; } else { - imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: urlString]]; - if (imageData) { - [cachedImageData setObject:imageData forKey:urlString]; + NSURL *url = [NSURL URLWithString: urlString]; + if (url) { + imageData = [[NSData alloc] initWithContentsOfURL: url]; + if (imageData) { + [cachedImageData setObject:imageData forKey:urlString]; + } } } return imageData; @@ -174,8 +180,22 @@ - (void)setBackgroundDim { self.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent: backgroundDimAmount]; } +- (BOOL)checkDefaultCloseButtonStatusForInApp { + if((self.notification.inAppType == BlueShiftInAppTypeModal && self.notification.notificationContent.actions.count == 0) || self.notification.inAppType == BlueShiftInAppTypeHTML) { + return YES; + } + return NO; +} + +- (BOOL)shouldShowCloseButton { + if (self.notification.templateStyle.enableCloseButton) { + return [self.notification.templateStyle.enableCloseButton boolValue]; + } + return [self checkDefaultCloseButtonStatusForInApp]; +} + - (void)createCloseButton:(CGRect)frame { - BOOL showCloseButton = ((self.notification.inAppType == BlueShiftInAppTypeModal && self.notification.notificationContent.actions.count == 0) || self.notification.inAppType == BlueShiftInAppTypeHTML) ? YES : self.notification.templateStyle.enableCloseButton; + BOOL showCloseButton = [self shouldShowCloseButton]; if (self.notification.templateStyle && showCloseButton) { if ( self.notification.templateStyle.closeButton && self.notification.templateStyle.closeButton.text @@ -227,6 +247,8 @@ - (void)setButton:(UIButton *)button andString:(NSString *)value } if (backgroundColorCode != (id)[NSNull null] && backgroundColorCode.length > 0) { [button setBackgroundColor:[self colorWithHexString:backgroundColorCode]]; + } else { + [button setBackgroundColor:UIColor.clearColor]; } } } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h index edcd4668..644c9841 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN @interface BlueShiftNotificationWebViewController : BlueShiftNotificationViewController - +- (void)setupWebView:(void (^)(void))block; @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m index d250070d..e2ffc90a 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m @@ -18,6 +18,7 @@ @interface BlueShiftNotificationWebViewController ()didLoadWebView(); + [self resizeWebViewAsPerContent:webView]; } }]; } From 3cd1e0db4cb82afa45c0c5584ed627ef95907f29 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Wed, 19 May 2021 16:21:32 +0530 Subject: [PATCH 02/22] Added fix for slidein inapp bottom safearea view Added nil check for colorWithHexString --- ...iftNotificationSlideBannerViewController.m | 48 +++++++++++-------- .../BlueShiftNotificationViewController.m | 18 ++++--- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m index 425bb0f4..c9cdcd46 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m @@ -17,14 +17,12 @@ @interface BlueShiftNotificationSlideBannerViewController () { UIView *slideBannerView; + UIView *bottomSafeAreaView; } @property(nonatomic, assign) CGFloat initialHorizontalCenter; @property(nonatomic, assign) CGFloat initialTouchPositionX; @property(nonatomic, assign) CGFloat originalCenter; - -- (IBAction)onOkayButtonTapped:(id)sender; - @end @implementation BlueShiftNotificationSlideBannerViewController @@ -57,10 +55,8 @@ - (void) viewWillLayoutSubviews { } - (void)enableSingleTap { - UITapGestureRecognizer *singleFingerTap = - [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(onOkayButtonTapped:)]; - [slideBannerView addGestureRecognizer:singleFingerTap]; + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSlideInTap)]; + [slideBannerView addGestureRecognizer:tapGesture]; } -(void)setTapGestureForView { @@ -79,14 +75,17 @@ -(void)setSwipeGestureForBannerView { } - (void)presentAnimationView { + [slideBannerView.layer addAnimation:[self getAnimationTransition] forKey:nil]; + [self.view insertSubview:slideBannerView aboveSubview:self.view]; +} + +- (CATransition*)getAnimationTransition { CATransition *transition = [CATransition animation]; transition.duration = 1.0; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromLeft; [transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]]; - [slideBannerView.layer addAnimation:transition forKey:nil]; - - [self.view insertSubview:slideBannerView aboveSubview:self.view]; + return transition; } - (void)createNotificationView { @@ -351,18 +350,25 @@ - (UILabel *)createActionButtonLabel { return actionButtonlabel; } -- (void)createBottomSafeAreaView { - if([self getBottomSafeAreaHeight] > 0){ - CGRect frame = slideBannerView.frame; - frame.size.height = [self getBottomSafeAreaHeight]; - frame.origin.y = frame.origin.y; - UIView *bottomSafeAreaView = [[UIView alloc] initWithFrame: frame]; - if (self.notification.templateStyle && self.notification.templateStyle.bottomSafeAreaColor && ![self.notification.templateStyle.bottomSafeAreaColor isEqualToString: @""]) { +- (void)createBottomSafeAreaViewForFrame:(CGRect)slideInFrame { + if(slideInFrame.size.height > 0 && [self getBottomSafeAreaHeight] > 0 && self.notification.templateStyle) { + //Show safe area view only if bottom margin is zero and color is not empty/nil. + if (self.notification.templateStyle.margin.bottom == 0 && self.notification.templateStyle.bottomSafeAreaColor && ![self.notification.templateStyle.bottomSafeAreaColor isEqualToString: @""]) { + [bottomSafeAreaView removeFromSuperview]; + CGRect frame = slideInFrame; + frame.size.height = [self getBottomSafeAreaHeight]; + frame.origin.y = slideInFrame.origin.y + slideInFrame.size.height; + if (bottomSafeAreaView) { + bottomSafeAreaView.frame = frame; + } else { + bottomSafeAreaView = [[UIView alloc] initWithFrame: frame]; + [bottomSafeAreaView.layer addAnimation:[self getAnimationTransition] forKey:nil]; + [bottomSafeAreaView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSlideInTap)]]; + } UIColor *backgroundColor = [self colorWithHexString: self.notification.templateStyle.bottomSafeAreaColor]; [bottomSafeAreaView setBackgroundColor: backgroundColor]; + [self.view addSubview: bottomSafeAreaView]; } - - [self.view addSubview: bottomSafeAreaView]; } } @@ -385,7 +391,7 @@ -(void)hideAnimated { [self hideFromWindow:YES withDirection:UISwipeGestureRecognizerDirectionRight]; } -- (IBAction)onOkayButtonTapped:(id)sender { +- (void)handleSlideInTap { if (self.notification && self.notification.notificationContent && self.notification.notificationContent.actions && self.notification.notificationContent.actions.count > 0 && self.notification.notificationContent.actions[0]) { @@ -462,7 +468,7 @@ - (CGRect)positionNotificationView { } else if([position isEqual: kInAppNotificationModalPositionBottomKey]) { frame.origin.y = screenSize.height - (size.height + bottomMargin); slideBannerView.autoresizingMask = slideBannerView.autoresizingMask | UIViewAutoresizingFlexibleTopMargin; -// [self createBottomSafeAreaView]; + [self createBottomSafeAreaViewForFrame:frame]; } else { frame.origin.y = (screenSize.height - size.height) / 2.0f; } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index 4ec931c8..4150419b 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -105,13 +105,17 @@ - (void)configureBackground { } - (UIColor *)colorWithHexString:(NSString *)str { - unsigned char r, g, b; - const char *cStr = [str cStringUsingEncoding:NSASCIIStringEncoding]; - long x = strtol(cStr+1, NULL, 16); - b = x & 0xFF; - g = (x >> 8) & 0xFF; - r = (x >> 16) & 0xFF; - return [UIColor colorWithRed:(float)r/255.0f green:(float)g/255.0f blue:(float)b/255.0f alpha:1]; + if (str) { + unsigned char r, g, b; + const char *cStr = [str cStringUsingEncoding:NSASCIIStringEncoding]; + long x = strtol(cStr+1, NULL, 16); + b = x & 0xFF; + g = (x >> 8) & 0xFF; + r = (x >> 16) & 0xFF; + return [UIColor colorWithRed:(float)r/255.0f green:(float)g/255.0f blue:(float)b/255.0f alpha:1]; + } else { + return [UIColor clearColor]; + } } From 4b95f598b1e94d6b1af412e609ff5c3ace32cb81 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Thu, 20 May 2021 17:59:10 +0530 Subject: [PATCH 03/22] Added icon padding to slide in icon Added icon radius to slide in icon Added auto height - auto width support for modal background image --- .../BlueShiftInAppNotificationConstant.h | 2 +- ...BlueShiftNotificationModalViewController.m | 51 ++++++++++++++- ...iftNotificationSlideBannerViewController.m | 64 +++++++++++-------- 3 files changed, 89 insertions(+), 28 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index d38c2719..d3ab4a3a 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -110,7 +110,7 @@ #define KInAppNotificationModalCloseButtonHeight 32.0 #define kInAppNotificationDefaultWidth 90.0 -#define kInAppNotificationDefaultHeight 100.0 +#define kInAppNotificationDefaultHeight 90.0 #define kHTMLInAppNotificationMaximumWidthInPoints 470.0 #define kHTMLInAppNotificationMinimumHeight 25.0 diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index 8bf85dcc..f05dbc2d 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -439,9 +439,56 @@ - (CGFloat)getActionButtonXPosition:(UIView *)parentView childWidth:(CGFloat)wid : xPadding; } +- (CGSize)getAutoImageSizeForNotificationView { + float width = 0; + float height = 0; + + // Check if this modal is image modal + if (notificationView && self.notification.templateStyle && self.notification.templateStyle.backgroundImage && ![self.notification.templateStyle.backgroundImage isEqualToString:@""]) { + // Get max width & height in points which device can support + float maxWidthInPoints = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; + float maxHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; + NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; + UIImage* image = [[UIImage alloc] initWithData:imageData]; + // If image resolution is less than the device height and width, use the image dimention. + if (image.size.width < maxWidthInPoints && image.size.height < maxHeightInPoints) { + width = image.size.width; + height = image.size.height; + } else if (image.size.width > 0) { + // If image width & height is more than device width & height, modify the image height and width based on aspect ratio + float ratio = image.size.height/image.size.width; + width = maxWidthInPoints; + height = maxWidthInPoints * ratio; + if (height > maxHeightInPoints) { + width = maxHeightInPoints/ratio; + height = maxHeightInPoints; + } + } + } + return CGSizeMake(width, height); +} + - (CGRect)positionNotificationView { - float width = (self.notification.templateStyle && self.notification.templateStyle.width > 0) ? self.notification.templateStyle.width : self.notification.width; - float height = (self.notification.templateStyle && self.notification.templateStyle.height > 0) ? self.notification.templateStyle.height :[BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: notificationView.frame.size.height forWindow:self.window]; + CGSize imageSize = [self getAutoImageSizeForNotificationView]; + float width = 0; + if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { + width = self.notification.templateStyle.width; + } else if (imageSize.width > 0 && self.notification.templateStyle && self.notification.templateStyle.width < 0) { + // If auto width, get the adjusted height using image width. + width = [BlueShiftInAppNotificationHelper convertPointsWidthToPercentage: imageSize.width forWindow:self.window]; + } else { + width = self.notification.width; + } + + float height = 0; + if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { + height = self.notification.templateStyle.height; + } else if (imageSize.height > 0 && self.notification.templateStyle && self.notification.templateStyle.height < 0) { + // If auto height, get the adjusted height from the image height + height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: imageSize.height forWindow:self.window]; + } else { + height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: notificationView.frame.size.height forWindow:self.window]; + } float topMargin = 0.0; float bottomMargin = 0.0; diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m index c9cdcd46..22e2ab24 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationSlideBannerViewController.m @@ -160,10 +160,11 @@ - (void)initializeNotificationView { xPadding = iconLabel.frame.size.width; } - UIImageView *imageView; + UIView *iconView; if ([self isValidString: self.notification.notificationContent.iconImage]) { - imageView = [self createImageView]; - xPadding = xPadding + imageView.frame.size.width; + // get empty default width height view for calculating the padding + iconView = [self createIconViewWithHeight:0]; + xPadding = xPadding + iconView.frame.size.width; } UILabel *actionButtonLabel; @@ -201,8 +202,8 @@ - (void)initializeNotificationView { if (descriptionLabelHeight < kSlideInInAppNotificationMinimumHeight) { if (iconLabel.frame.size.height > 0) { descriptionLabelHeight = iconLabel.frame.size.height; - } else if (imageView.frame.size.height > 0) { - descriptionLabelHeight = imageView.frame.size.height; + } else if (iconView.frame.size.height > 0) { + descriptionLabelHeight = iconView.frame.size.height; } else { descriptionLabelHeight = kSlideInInAppNotificationMinimumHeight; } @@ -219,48 +220,61 @@ - (void)initializeNotificationView { [self createNotificationView]; } - imageView.frame = CGRectMake(0.0, 0.0, imageView.frame.size.width, slideBannerView.frame.size.height); - iconLabel.frame = CGRectMake(0.0, 0.0, iconLabel.frame.size.width, slideBannerView.frame.size.height); - + if ([self isValidString: self.notification.notificationContent.icon]) { + iconLabel.frame = CGRectMake(0.0, 0.0, iconLabel.frame.size.width, slideBannerView.frame.size.height); + [slideBannerView addSubview: iconLabel]; + } else if ([self isValidString: self.notification.notificationContent.iconImage]) { + // Recreate the icon view after getting exact size of the banner + iconView = [self createIconViewWithHeight:slideBannerView.frame.size.height]; + [slideBannerView addSubview: iconView]; + } + CGFloat actionXposition = slideBannerView.frame.size.width - actionButtonLabel.frame.size.width; actionButtonLabel.frame = CGRectMake(actionXposition, [self getCenterYPosition: actionButtonLabel.frame.size.height], actionButtonLabel.frame.size.width, actionButtonLabel.frame.size.height); - - [slideBannerView addSubview: iconLabel]; - [slideBannerView addSubview: imageView]; [slideBannerView addSubview: actionButtonLabel]; [slideBannerView addSubview: descriptionLabel]; } } -- (UIImageView *)createImageView { +- (UIView *)createIconViewWithHeight:(CGFloat)bannerHeight { BlueShiftInAppLayoutMargin *iconImagePadding = [self fetchNotificationIconImagePadding]; CGFloat leftPadding = (iconImagePadding && iconImagePadding.left > 0) ? iconImagePadding.left : 0.0; CGFloat topPadding = (iconImagePadding && iconImagePadding.top > 0) ? iconImagePadding.top : 0.0; CGFloat rightPadding = (iconImagePadding && iconImagePadding.right > 0) ? iconImagePadding.right : 0.0; CGFloat bottomPadding= (iconImagePadding && iconImagePadding.bottom > 0) ? iconImagePadding.bottom : 0.0; - CGFloat imageViewWidth = kInAppNotificationModalIconWidth + (leftPadding + rightPadding); - CGFloat imageViewHeight = kInAppNotificationModalIconHeight+ (topPadding + bottomPadding); - CGRect cgRect = CGRectMake(0.0, 0.0, imageViewWidth, imageViewHeight); + CGFloat iconImageWidth = kInAppNotificationModalIconWidth - (leftPadding + rightPadding); + CGFloat iconImageHeight = kInAppNotificationModalIconHeight - (topPadding + bottomPadding); - UIImageView *imageView = [[UIImageView alloc] initWithFrame: cgRect]; - if (self.notification.notificationContent.iconImage) { - [self loadImageFromURL:self.notification.notificationContent.iconImage forImageView:imageView]; + CGFloat iconViewHeight = bannerHeight == 0 ? kInAppNotificationModalIconHeight : bannerHeight; + // Create a container view for the image + UIView* iconView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, kInAppNotificationModalIconWidth, iconViewHeight)]; + // Return the iconView if bannerHeight is 0. + if (bannerHeight == 0) { + return iconView; } - if (self.notification.contentStyle && self.notification.contentStyle.iconImageBackgroundColor != (id)[NSNull null] && self.notification.contentStyle.iconImageBackgroundColor.length > 0) { - NSString *backgroundColorCode = self.notification.contentStyle.iconImageBackgroundColor; - imageView.backgroundColor = [self colorWithHexString:backgroundColorCode]; + // Create imageView and set the image, padding and corner radius + UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(leftPadding, topPadding, iconImageWidth, iconImageHeight)]; + // Set iconview center to show the image in the center when iconView height is more than the imageview height + imageView.center = iconView.center; + if (self.notification.notificationContent.iconImage) { + [self loadImageFromURL:self.notification.notificationContent.iconImage forImageView:imageView]; } - CGFloat backgroundRadius = (self.notification.contentStyle && self.notification.contentStyle.iconImageBackgroundRadius && self.notification.contentStyle.iconImageBackgroundRadius.floatValue > 0) ? self.notification.contentStyle.iconImageBackgroundRadius.floatValue : 0.0; - imageView.layer.cornerRadius = backgroundRadius; imageView.clipsToBounds = YES; imageView.contentMode = UIViewContentModeScaleAspectFit; - imageView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; + + // Set background color to the iconView + if (self.notification.contentStyle && self.notification.contentStyle.iconImageBackgroundColor != (id)[NSNull null] && self.notification.contentStyle.iconImageBackgroundColor.length > 0) { + NSString *backgroundColorCode = self.notification.contentStyle.iconImageBackgroundColor; + iconView.backgroundColor = [self colorWithHexString:backgroundColorCode]; + } - return imageView; + [iconView addSubview:imageView]; + iconView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin; + return iconView; } - (UILabel *)createIconLabel:(CGFloat)xPosition { From ba34255c64d5a99db268b151896e09034607ee48 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Thu, 20 May 2021 19:10:13 +0530 Subject: [PATCH 04/22] Added logs for the BlueShiftInAppNotificationConstant.h --- .../InApps/BlueShiftInAppNotification.m | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m index 580741eb..2d2b03f4 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m @@ -8,6 +8,7 @@ #import "BlueShiftInAppNotification.h" #import "BlueShiftInAppNotificationHelper.h" #import "BlueShiftInAppNotificationConstant.h" +#import "../BlueshiftLog.h" @implementation BlueShiftInAppNotificationButton @@ -57,8 +58,8 @@ - (instancetype)initFromDictionary: (NSDictionary *) payloadDictionary withType: break; } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return self; @@ -134,8 +135,8 @@ - (instancetype)initFromDictionary: (NSDictionary *) payloadDictionary withType: break; } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return self; @@ -165,8 +166,8 @@ - (instancetype)initFromDictionary: (NSDictionary *)marginDictionary { [marginDictionary objectForKey: kInAppNotificationModalLayoutMarginRightKey] != [NSNull null]) { self.right = [[marginDictionary objectForKey: kInAppNotificationModalLayoutMarginRightKey] floatValue]; } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } @@ -241,8 +242,8 @@ - (instancetype)initFromDictionary: (NSDictionary *)templateStyleDictionary with break; } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return self; @@ -384,8 +385,8 @@ - (instancetype)initFromDictionary: (NSDictionary *) contenStyletDictionary with break; } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return self; @@ -446,8 +447,8 @@ - (instancetype)initFromEntity: (InAppNotificationEntity *) appEntity { } } - } @catch (NSException *e) { - + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return self; From d1c6c2407fd0debb5547ea5daeb77c99c64f766d Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Mon, 31 May 2021 19:17:28 +0530 Subject: [PATCH 05/22] pass userinfo to the open url Added nil checks to the BlueshiftLog Rearranged the BlueshiftINAppNotificationManager methods Added checks for not showing in-app when its getting downloaded Increased show/hide animation for modal and html from 0.25 to 0.5 secs --- BlueShift-iOS-SDK/BlueShiftAppDelegate.m | 2 +- BlueShift-iOS-SDK/BlueshiftConstants.h | 1 + .../BlueshiftEventAnalyticsHelper.h | 5 + .../BlueshiftEventAnalyticsHelper.m | 8 +- BlueShift-iOS-SDK/BlueshiftLog.m | 4 +- .../BlueShiftInAppNotificationManager.m | 373 +++++++++--------- ...BlueShiftNotificationModalViewController.m | 12 +- .../BlueShiftNotificationViewController.h | 10 +- .../BlueShiftNotificationViewController.m | 39 +- .../BlueShiftNotificationWebViewController.m | 4 +- 10 files changed, 252 insertions(+), 206 deletions(-) diff --git a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m index 16d949be..3c7c9753 100755 --- a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m +++ b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m @@ -425,7 +425,7 @@ - (void)setupPushNotificationDeeplink:(NSDictionary *)userInfo { } if ([self.oldDelegate respondsToSelector:@selector(application:openURL:options:)]) { if (@available(iOS 9.0, *)) { - NSDictionary *pushOptions = @{openURLOptionsSource:openURLOptionsBlueshift,openURLOptionsChannel:openURLOptionsPush}; + NSDictionary *pushOptions = @{openURLOptionsSource:openURLOptionsBlueshift,openURLOptionsChannel:openURLOptionsPush,openURLOptionsPushUserInfo:userInfo}; [self.oldDelegate application:[UIApplication sharedApplication] openURL: deepLinkURL options:pushOptions]; [BlueshiftLog logInfo:[NSString stringWithFormat:@"%@ %@",@"Delivered push notification deeplink to AppDelegate openURL method, Deep link - ", [deepLinkURL absoluteString]] withDetails: pushOptions methodName:nil]; } diff --git a/BlueShift-iOS-SDK/BlueshiftConstants.h b/BlueShift-iOS-SDK/BlueshiftConstants.h index 5af43f83..82b84220 100644 --- a/BlueShift-iOS-SDK/BlueshiftConstants.h +++ b/BlueShift-iOS-SDK/BlueshiftConstants.h @@ -64,6 +64,7 @@ #define openURLOptionsInAppType @"inAppType" #define openURLOptionsButtonIndex @"clickedButtonIndex" #define openURLOptionsButtonText @"clickedButtonText" +#define openURLOptionsPushUserInfo @"userInfo" //Core data entities #define kHttpRequestOperationEntity @"HttpRequestOperationEntity" diff --git a/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.h b/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.h index be6703c7..cc1046e2 100644 --- a/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.h +++ b/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.h @@ -29,6 +29,11 @@ NS_ASSUME_NONNULL_BEGIN /// Check for nil and add the key value to the given dictionary + (void)addToDictionary:(NSMutableDictionary*)dictionary key:(NSString*)key value:(id)value; + +/// Returns true if string is not nil and not empty. +/// @param string string to perform check ++ (BOOL)isNotNilAndNotEmpty:(NSString*)string; + @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.m b/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.m index 9a254e6e..ce4abb8f 100644 --- a/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.m +++ b/BlueShift-iOS-SDK/BlueshiftEventAnalyticsHelper.m @@ -165,8 +165,12 @@ + (NSMutableDictionary *)getQueriesFromURL:(NSURL *)URL { } +(BOOL)isNotNilAndNotEmpty:(NSString*)string { - if (string && ![string isEqualToString:@""]) { - return YES; + @try { + if (string && ![string isEqualToString:@""]) { + return YES; + } + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } return NO; } diff --git a/BlueShift-iOS-SDK/BlueshiftLog.m b/BlueShift-iOS-SDK/BlueshiftLog.m index e43339ef..ff6bbb84 100644 --- a/BlueShift-iOS-SDK/BlueshiftLog.m +++ b/BlueShift-iOS-SDK/BlueshiftLog.m @@ -49,7 +49,7 @@ + (void)logException:(NSException*) exception withDescription:(NSString*)descrip } + (void)logInfo:(NSString*)info withDetails: (id) details methodName:(NSString*)method{ - if ([[BlueShift sharedInstance] config].debug) { + if ([BlueShift sharedInstance].config && [BlueShift sharedInstance].config.debug) { NSString* log = @"[Blueshift] info : "; @try { if (info) { @@ -69,7 +69,7 @@ + (void)logInfo:(NSString*)info withDetails: (id) details methodName:(NSString*) } +(void)logAPICallInfo:(NSString*)info withDetails: (NSDictionary*) details statusCode:(NSInteger)statusCode { - if ([[BlueShift sharedInstance] config].debug) { + if ([BlueShift sharedInstance].config && [BlueShift sharedInstance].config.debug) { NSString* log = @"[Blueshift] API call info : "; @try { if (info) { diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index 5a183dd9..163b10b6 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -28,6 +28,7 @@ @interface BlueShiftInAppNotificationManager() @implementation BlueShiftInAppNotificationManager +#pragma mark - Set up // init - (void)load { @@ -35,26 +36,26 @@ - (void)load { /* register for app background / foreground notification */ [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(OnApplicationEnteringBackground:) + selector:@selector(onApplicationEnteringBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(OnApplicationEnteringForeground:) + selector:@selector(onApplicationEnteringForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; [self deleteExpireInAppNotificationFromDataStore]; } -- (void) OnApplicationEnteringBackground:(NSNotification *)notification { +- (void)onApplicationEnteringBackground:(NSNotification *)notification { // stop the timer once app enters background. if ([[[BlueShift sharedInstance] config] inAppManualTriggerEnabled] == NO) { [self stopInAppMessageFetchTimer]; } } -- (void) OnApplicationEnteringForeground:(NSNotification *)notification { +- (void)onApplicationEnteringForeground:(NSNotification *)notification { // start the timer once app enters foreground. if ([[[BlueShift sharedInstance] config] inAppManualTriggerEnabled] == NO && [[BlueShiftAppData currentAppData] getCurrentInAppNotificationStatus] == YES) { [self fetchNowAndUpcomingInAppMessageFromDB]; @@ -63,21 +64,33 @@ - (void) OnApplicationEnteringForeground:(NSNotification *)notification { } } -- (void) initializeInAppNotificationFromAPI:(NSMutableArray *)notificationArray handler:(void (^)(BOOL))handler { - if (notificationArray !=nil && notificationArray.count > 0) { - for (int i = 0; i < notificationArray.count ; i++) { - [self addInAppNotificationToDataStore: [notificationArray objectAtIndex: i]]; - } - - handler(YES); - } else { - handler(YES); +- (void)startInAppMessageFetchTimer { + if (self.inAppMessageFetchTimer == nil) { + self.inAppMessageFetchTimer = [NSTimer scheduledTimerWithTimeInterval: [self inAppNotificationTimeInterval] + target:self + selector:@selector(fetchNowAndUpcomingInAppMessageFromDB) + userInfo:nil + repeats: YES]; + [BlueshiftLog logInfo:@"Started InAppMessageFetchTimer" withDetails:nil methodName:nil]; + } +} + +// Method to stop time gap b/w loading inAppNotification timer +- (void)stopInAppMessageFetchTimer { + if (self.inAppMessageFetchTimer != nil) { + [self.inAppMessageFetchTimer invalidate]; + self.inAppMessageFetchTimer = nil; + [BlueshiftLog logInfo:@"Stopped InAppMessageFetchTimer" withDetails:nil methodName:nil]; } } +- (void)fetchNowAndUpcomingInAppMessageFromDB { + [self fetchInAppNotificationsFromDataStore: BlueShiftInAppTriggerNowAndUpComing]; +} + //Remove the in-apps on receciving `in_app_mark_as_open` silent push which //are displayed on the other deivce for same user. --(void)markAsDisplayedForNotificationsViewedOnOtherDevice:(NSArray *)messageUUIDArray { +- (void)markAsDisplayedForNotificationsViewedOnOtherDevice:(NSArray *)messageUUIDArray { if (messageUUIDArray != nil && messageUUIDArray.count > 0) { for (int count = 0; count< messageUUIDArray.count; count++) { NSString *messageUUID = [messageUUIDArray objectAtIndex:count]; @@ -89,75 +102,19 @@ -(void)markAsDisplayedForNotificationsViewedOnOtherDevice:(NSArray *)messageUUID } } -- (void)checkInAppNotificationExist:(NSDictionary *)payload handler:(void (^)(BOOL))handler{ - BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; - NSManagedObjectContext *masterContext; - if (appDelegate) { - @try { - masterContext = appDelegate.managedObjectContext; - } - @catch (NSException *exception) { - [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; - } - } - - if (masterContext != nil) { - NSEntityDescription *entity; - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; - @try { - entity = [NSEntityDescription entityForName: kInAppNotificationEntityNameKey inManagedObjectContext:masterContext]; - [fetchRequest setEntity:entity]; - } - @catch (NSException *exception) { - [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; - } - - if(entity != nil && fetchRequest.entity != nil) { - NSString *notificationID = [self getInAppMessageID: payload]; - if (notificationID !=nil && ![notificationID isEqualToString:@""]) { - [InAppNotificationEntity fetchNotificationByID:masterContext forNotificatioID: notificationID request: fetchRequest handler:^(BOOL status, NSArray *result){ - if (status) { - handler(NO); - } else { - handler(YES); - } - }]; - } - } - } -} - --(NSString *)getInAppMessageID:(NSDictionary *)notificationPayload { - if ([notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]) { - return (NSString *)[notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]; - } else { - if([notificationPayload objectForKey:kInAppNotificationDataKey]) { - notificationPayload = [notificationPayload objectForKey:kInAppNotificationDataKey]; - if ([notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]) { - return (NSString *)[notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]; - } +#pragma mark - Insert, delete, update in-app notifications +- (void)initializeInAppNotificationFromAPI:(NSMutableArray *)notificationArray handler:(void (^)(BOOL))handler { + if (notificationArray !=nil && notificationArray.count > 0) { + for (int i = 0; i < notificationArray.count ; i++) { + [self addInAppNotificationToDataStore: [notificationArray objectAtIndex: i]]; } } - - return @""; -} - -- (double)checkInAppNotificationExpired:(double)createdTime { - double currentTime = [[NSDate date] timeIntervalSince1970]; - NSDate *createdDate = [self convertMillisecondToDate: createdTime]; - NSDate *currentDate = [self convertMillisecondToDate:currentTime]; - - NSTimeInterval timeDifference = [currentDate timeIntervalSinceDate: createdDate]; - return (timeDifference / (3600 * 24)); -} - -- (NSDate *)convertMillisecondToDate:(double)seconds { - return [NSDate dateWithTimeIntervalSince1970:seconds]; + handler(YES); } - (void) addInAppNotificationToDataStore: (NSDictionary *) payload { [self checkInAppNotificationExist: payload handler:^(BOOL status){ - if (status) { + if (status == NO) { if (nil == self.privateObjectContext) { self.privateObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; } @@ -200,7 +157,59 @@ - (void) addInAppNotificationToDataStore: (NSDictionary *) payload { }]; } -- (void) deleteExpireInAppNotificationFromDataStore { +/// Returns true if the In-App exists in the SDK database. +/// @param payload In-App notification payload +/// @param handler completion handler +- (void)checkInAppNotificationExist:(NSDictionary *)payload handler:(void (^)(BOOL))handler{ + BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; + NSManagedObjectContext *masterContext; + if (appDelegate) { + @try { + masterContext = appDelegate.managedObjectContext; + } + @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + } + } + + if (masterContext != nil) { + NSEntityDescription *entity; + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; + @try { + entity = [NSEntityDescription entityForName: kInAppNotificationEntityNameKey inManagedObjectContext:masterContext]; + [fetchRequest setEntity:entity]; + } + @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + } + + if(entity != nil && fetchRequest.entity != nil) { + NSString *notificationID = [self getInAppMessageID: payload]; + if (notificationID !=nil && ![notificationID isEqualToString:@""]) { + [InAppNotificationEntity fetchNotificationByID:masterContext forNotificatioID: notificationID request: fetchRequest handler:^(BOOL status, NSArray *result){ + handler(status); + }]; + } + } + } +} + +-(NSString *)getInAppMessageID:(NSDictionary *)notificationPayload { + if ([notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]) { + return (NSString *)[notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]; + } else { + if([notificationPayload objectForKey:kInAppNotificationDataKey]) { + notificationPayload = [notificationPayload objectForKey:kInAppNotificationDataKey]; + if ([notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]) { + return (NSString *)[notificationPayload objectForKey: kInAppNotificationModalMessageUDIDKey]; + } + } + } + + return @""; +} + +- (void)deleteExpireInAppNotificationFromDataStore { BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; NSManagedObjectContext *masterContext; if (appDelegate) { @@ -279,6 +288,19 @@ - (void)deleteNotification:(InAppNotificationEntity *)notification context:(NSMa } } +- (double)checkInAppNotificationExpired:(double)createdTime { + double currentTime = [[NSDate date] timeIntervalSince1970]; + NSDate *createdDate = [self convertMillisecondToDate: createdTime]; + NSDate *currentDate = [self convertMillisecondToDate:currentTime]; + + NSTimeInterval timeDifference = [currentDate timeIntervalSinceDate: createdDate]; + return (timeDifference / (3600 * 24)); +} + +- (NSDate *)convertMillisecondToDate:(double)seconds { + return [NSDate dateWithTimeIntervalSince1970:seconds]; +} + - (void)fetchLastInAppMessageIDFromDB:(void (^)(BOOL, NSString *, NSString *))handler { BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; NSManagedObjectContext *masterContext; @@ -398,7 +420,40 @@ - (void)removeInAppNotificationFromDB:(NSManagedObjectID *) entityItem { } } +- (void)updateInAppNotification:(NSDictionary *)notificationPayload { + BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; + NSManagedObjectContext *masterContext; + if (appDelegate) { + @try { + masterContext = appDelegate.managedObjectContext; + } + @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + } + } + if(masterContext) { + NSEntityDescription *entity; + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; + @try { + entity = [NSEntityDescription entityForName: kInAppNotificationEntityNameKey inManagedObjectContext:masterContext]; + [fetchRequest setEntity:entity]; + } + @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; + } + + NSString *notificationID = [self getInAppMessageID: notificationPayload]; + if (notificationID !=nil && ![notificationID isEqualToString:@""]) { + [InAppNotificationEntity updateInAppNotificationStatus: masterContext forNotificatioID: notificationID request: fetchRequest notificationStatus:@"Displayed" andAppDelegate: appDelegate handler:^(BOOL status){ + if (status) { + [BlueshiftLog logInfo:@"Marked in-app message in DB as Displayed, messageId : " withDetails:notificationID methodName:nil]; + } + }]; + } + } +} +#pragma mark - Fetch in-app from the Datastore, filter and process it to display notification - (void)fetchInAppNotificationsFromDataStore: (BlueShiftInAppTriggerMode) triggerMode { if([[BlueShiftAppData currentAppData] getCurrentInAppNotificationStatus] && [self inAppNotificationDisplayOnPage] && self.currentNotificationController == nil) { BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; @@ -411,6 +466,9 @@ - (void)fetchInAppNotificationsFromDataStore: (BlueShiftInAppTriggerMode) trigge [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } + if(masterContext == nil) { + return; + } [InAppNotificationEntity fetchAll:triggerMode forDisplayPage: [self inAppNotificationDisplayOnPage] context:masterContext withHandler:^(BOOL status, NSArray *results) { if (status) { NSArray *sortedArray = [self sortedInAppNotification: results]; @@ -419,9 +477,15 @@ - (void)fetchInAppNotificationsFromDataStore: (BlueShiftInAppTriggerMode) trigge InAppNotificationEntity *entity = [filteredResults objectAtIndex:0]; [BlueshiftLog logInfo:@"Fetched one in-app message from DB to display message id - " withDetails:entity.id methodName:nil]; [self createNotificationFromDictionary: entity]; + } else { + [BlueshiftLog logInfo:@"There are no pending in-apps to display at this moment for page." withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; } + } else { + [BlueshiftLog logInfo:@"There are no pending in-apps to display for page." withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; } }]; + } else { + [BlueshiftLog logInfo:@"In-app fetch from DB skipped due to one of the below reasons." withDetails:@" 1. In-App notifications are not enabled, 2. Screen is not registered to receive in-apps. 3. Active or in-progress In-app notification detected." methodName:nil]; } } @@ -449,40 +513,6 @@ - (NSArray *)sortedInAppNotification:(NSArray *)inAppNotificationArray { return sortedArrayList; } -- (void)updateInAppNotification:(NSDictionary *)notificationPayload { - BlueShiftAppDelegate *appDelegate = (BlueShiftAppDelegate *)[BlueShift sharedInstance].appDelegate; - NSManagedObjectContext *masterContext; - if (appDelegate) { - @try { - masterContext = appDelegate.managedObjectContext; - } - @catch (NSException *exception) { - [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; - } - } - if(masterContext) { - NSEntityDescription *entity; - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; - @try { - entity = [NSEntityDescription entityForName: kInAppNotificationEntityNameKey inManagedObjectContext:masterContext]; - [fetchRequest setEntity:entity]; - } - @catch (NSException *exception) { - [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; - } - - NSString *notificationID = [self getInAppMessageID: notificationPayload]; - if (notificationID !=nil && ![notificationID isEqualToString:@""]) { - [InAppNotificationEntity updateInAppNotificationStatus: masterContext forNotificatioID: notificationID request: fetchRequest notificationStatus:@"Displayed" andAppDelegate: appDelegate handler:^(BOOL status){ - if (status) { - [BlueshiftLog logInfo:@"Marked in-app message in DB as Displayed, messageId : " withDetails:notificationID methodName:nil]; - } - }]; - } - } -} - - - (NSArray *) filterInAppNotificationResults: (NSArray*) results { /* get the current time (since 1970) */ @@ -524,50 +554,20 @@ - (NSArray *) filterInAppNotificationResults: (NSArray*) results { return filteredResults; } -- (void)startInAppMessageFetchTimer { - if (self.inAppMessageFetchTimer == nil) { - self.inAppMessageFetchTimer = [NSTimer scheduledTimerWithTimeInterval: [self inAppNotificationTimeInterval] - target:self - selector:@selector(fetchNowAndUpcomingInAppMessageFromDB) - userInfo:nil - repeats: YES]; - [BlueshiftLog logInfo:@"Started InAppMessageFetchTimer" withDetails:nil methodName:nil]; - } -} - -// Method to stop time gap b/w loading inAppNotification timer -- (void) stopInAppMessageFetchTimer { - if (self.inAppMessageFetchTimer != nil) { - [self.inAppMessageFetchTimer invalidate]; - self.inAppMessageFetchTimer = nil; - [BlueshiftLog logInfo:@"Stopped InAppMessageFetchTimer" withDetails:nil methodName:nil]; - } -} - -- (void)fetchNowAndUpcomingInAppMessageFromDB { - [self fetchInAppNotificationsFromDataStore: BlueShiftInAppTriggerNowAndUpComing]; -} - -// Present ViewController -- (void)presentInAppViewController:(BlueShiftNotificationViewController*)notificationController forNotification:(BlueShiftInAppNotification*)notification { - if (notificationController.displayOnScreen && ![notificationController.displayOnScreen isEqual:@""]) { - if(![self.inAppNotificationDisplayOnPage isEqualToString:notificationController.displayOnScreen]) { - return; - } - } - if (notificationController && [self inAppNotificationDisplayOnPage]) { - notificationController.delegate = self; - notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; - [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; - [notificationController show:YES]; - } +#pragma mark - Display in-app notification +- (void)createNotificationFromDictionary:(InAppNotificationEntity *) inAppEntity { + BlueShiftInAppNotification *inAppNotification = [[BlueShiftInAppNotification alloc] initFromEntity:inAppEntity]; + [BlueshiftLog logInfo:@"Created in-app object from dictionary, message Id: " withDetails:inAppEntity.id methodName:nil]; + [self createInAppNotification: inAppNotification displayOnScreen:inAppEntity.displayOn]; } - (void)createInAppNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { - if (self.currentNotificationController != nil) { - return; - } dispatch_async(dispatch_get_main_queue(), ^{ + if (self.currentNotificationController != nil) { + [BlueshiftLog logInfo:@"Active In-app notification detected, skipped displaying current in-app." withDetails:nil methodName:nil]; + return; + } + switch (notification.inAppType) { case BlueShiftInAppTypeHTML: [self processHTMLNotification:notification displayOnScreen:displayOnScreen]; @@ -605,24 +605,24 @@ - (void)displayReviewController { } -(void)processSlideInBannerNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + [BlueshiftLog logInfo:@"Creating HTML in-app notification to display on screen name" withDetails:displayOnScreen methodName:nil]; BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationSlideBannerViewController alloc] initWithNotification:notification]; notificationVC.displayOnScreen = displayOnScreen; self.currentNotificationController = notificationVC; - BOOL isSlideInIconImagePresent = [self isSlideInIconImagePresent:notification]; - BOOL isBackgroundImagePresent = [self isBackgroundImagePresentForNotification:notification]; + BOOL isSlideInIconImagePresent = [notificationVC isSlideInIconImagePresent:notification]; + BOOL isBackgroundImagePresent = [notificationVC isBackgroundImagePresentForNotification:notification]; if (isSlideInIconImagePresent || isBackgroundImagePresent) { + NSString *backgroundImageURL = nil; + if(isSlideInIconImagePresent) { + backgroundImageURL = notification.notificationContent.iconImage; + } else if (isBackgroundImagePresent) { + backgroundImageURL = notification.templateStyle.backgroundImage; + } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSString *backgroundImageURL = nil; - if(isSlideInIconImagePresent) { - backgroundImageURL = notification.notificationContent.iconImage; - } else if (isBackgroundImagePresent) { - backgroundImageURL = notification.templateStyle.backgroundImage; - } [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self presentInAppViewController:notificationVC forNotification:notification]; - }); + [NSThread sleepForTimeInterval:1]; + [self presentInAppViewController:notificationVC forNotification:notification]; }); } else { [self presentInAppViewController:notificationVC forNotification:notification]; @@ -630,16 +630,17 @@ -(void)processSlideInBannerNotification:(BlueShiftInAppNotification*)notificatio } -(void)processModalNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + [BlueshiftLog logInfo:@"Creating Modal in-app notification to display on screen name" withDetails:displayOnScreen methodName:nil]; BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationModalViewController alloc] initWithNotification:notification]; notificationVC.displayOnScreen = displayOnScreen; self.currentNotificationController = notificationVC; - if ([self isBackgroundImagePresentForNotification:notification]) { + + if ([notificationVC isBackgroundImagePresentForNotification:notification]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *backgroundImageURL = notification.templateStyle.backgroundImage; [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self presentInAppViewController:notificationVC forNotification:notification]; - }); + [NSThread sleepForTimeInterval:1]; + [self presentInAppViewController:notificationVC forNotification:notification]; }); } else { [self presentInAppViewController:notificationVC forNotification:notification]; @@ -647,29 +648,41 @@ -(void)processModalNotification:(BlueShiftInAppNotification*)notification displa } -(void)processHTMLNotification:(BlueShiftInAppNotification*)notification displayOnScreen:(NSString*)displayOnScreen { + [BlueshiftLog logInfo:@"Creating HTML in-app notification to display on screen name" withDetails:displayOnScreen methodName:nil]; BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationWebViewController alloc] initWithNotification:notification]; notificationVC.displayOnScreen = displayOnScreen; - BlueShiftNotificationWebViewController *webViewController = (BlueShiftNotificationWebViewController*) notificationVC; self.currentNotificationController = notificationVC; + + BlueShiftNotificationWebViewController *webViewController = (BlueShiftNotificationWebViewController*) notificationVC; [webViewController setupWebView:^{ [self presentInAppViewController:notificationVC forNotification:notification]; }]; } -- (BOOL)isBackgroundImagePresentForNotification:(BlueShiftInAppNotification*)notification { - return (notification.templateStyle && notification.templateStyle.backgroundImage && ![notification.templateStyle.backgroundImage isEqualToString:@""]); -} - -- (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification { - return (notification.notificationContent && notification.notificationContent.iconImage && ![notification.templateStyle.backgroundImage isEqualToString:@""]); -} - -- (void)createNotificationFromDictionary:(InAppNotificationEntity *) inAppEntity { - BlueShiftInAppNotification *inAppNotification = [[BlueShiftInAppNotification alloc] initFromEntity:inAppEntity]; - [BlueshiftLog logInfo:@"Created in-app message to display, message Id: " withDetails:inAppEntity.id methodName:nil]; - [self createInAppNotification: inAppNotification displayOnScreen:inAppEntity.displayOn]; +// Present ViewController +- (void)presentInAppViewController:(BlueShiftNotificationViewController*)notificationController forNotification:(BlueShiftInAppNotification*)notification { + if (notificationController && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notificationController.displayOnScreen]) { + if(self.inAppNotificationDisplayOnPage == nil || ![self.inAppNotificationDisplayOnPage isEqualToString:notificationController.displayOnScreen]) { + self.currentNotificationController = nil; + [BlueshiftLog logInfo:@"Skipping preseting in-app notification as current screen is different than in-app notification display on screen" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + return; + } + } + if (notificationController && [self inAppNotificationDisplayOnPage]) { + [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + notificationController.delegate = self; + notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; + [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; + dispatch_async(dispatch_get_main_queue(), ^{ + [notificationController show:YES]; + }); + } else { + self.currentNotificationController = nil; + [BlueshiftLog logInfo:@"Skipping preseting in-app notification as screen is not registered to receive in-app notification" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + } } +#pragma mark - In App events // Notification Click Callbacks -(void)inAppDidDismiss:(NSDictionary *)notificationPayload fromViewController:(BlueShiftNotificationViewController *)controller { self.currentNotificationController = nil; diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index f05dbc2d..a5fd65db 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -85,7 +85,7 @@ - (void)showFromWindow:(BOOL)animated { } }; if (animated) { - [UIView animateWithDuration:0.25 animations:^{ + [UIView animateWithDuration:0.5 animations:^{ self.window.alpha = 1.0; } completion:^(BOOL finished) { completionBlock(); @@ -118,7 +118,7 @@ - (void)hideFromWindow:(BOOL)animated { }; if (animated) { - [UIView animateWithDuration:0.25 animations:^{ + [UIView animateWithDuration:0.5 animations:^{ self.window.alpha = 0; } completion:^(BOOL finished) { completionBlock(); @@ -444,7 +444,7 @@ - (CGSize)getAutoImageSizeForNotificationView { float height = 0; // Check if this modal is image modal - if (notificationView && self.notification.templateStyle && self.notification.templateStyle.backgroundImage && ![self.notification.templateStyle.backgroundImage isEqualToString:@""]) { + if ([self isBackgroundImagePresentForNotification:self.notification] && (self.notification.templateStyle.width < 0 || self.notification.templateStyle.height < 0)) { // Get max width & height in points which device can support float maxWidthInPoints = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; float maxHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; @@ -454,8 +454,8 @@ - (CGSize)getAutoImageSizeForNotificationView { if (image.size.width < maxWidthInPoints && image.size.height < maxHeightInPoints) { width = image.size.width; height = image.size.height; - } else if (image.size.width > 0) { - // If image width & height is more than device width & height, modify the image height and width based on aspect ratio + } else { + // If image width/height is more than device width & height, modify the image height and width based on aspect ratio float ratio = image.size.height/image.size.width; width = maxWidthInPoints; height = maxWidthInPoints * ratio; @@ -477,6 +477,7 @@ - (CGRect)positionNotificationView { // If auto width, get the adjusted height using image width. width = [BlueShiftInAppNotificationHelper convertPointsWidthToPercentage: imageSize.width forWindow:self.window]; } else { + // Default width width = self.notification.width; } @@ -487,6 +488,7 @@ - (CGRect)positionNotificationView { // If auto height, get the adjusted height from the image height height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: imageSize.height forWindow:self.window]; } else { + // Default width height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: notificationView.frame.size.height forWindow:self.window]; } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h index dbd4f818..6d76c423 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h @@ -28,7 +28,7 @@ controller; @property (nonatomic, assign) BOOL canTouchesPassThroughWindow; @property (nonatomic, weak) id delegate; @property (nonatomic, weak) id inAppNotificationDelegate; -@property (nonatomic, assign) NSString* _Nullable displayOnScreen; +@property (nonatomic, strong) NSString* _Nullable displayOnScreen; - (instancetype)initWithNotification:(BlueShiftInAppNotification *)notification; @@ -65,6 +65,14 @@ controller; -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString; +/// Check if the notification has a valid background image present. +/// @param notification notification object to perfor the check +- (BOOL)isBackgroundImagePresentForNotification:(BlueShiftInAppNotification*)notification; + +/// Check if the slide in notification has in icon background image present. +/// @param notification notification object to perfor the check +- (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification; + @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index 4150419b..c4b5456d 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -128,8 +128,7 @@ - (void)loadImageFromURL:(NSString *)imageURL forImageView:(UIImageView *)imageV } - (void)setBackgroundImageFromURL:(UIView *)notificationView { - if (notificationView && self.notification.templateStyle && self.notification.templateStyle.backgroundImage && - ![self.notification.templateStyle.backgroundImage isEqualToString:@""]) { + if (notificationView && [self isBackgroundImagePresentForNotification:self.notification]) { NSString *backgroundImageURL = self.notification.templateStyle.backgroundImage; UIImage *image = [[UIImage alloc] initWithData:[self loadAndCacheImageForURLString:backgroundImageURL]]; UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; @@ -141,19 +140,25 @@ - (void)setBackgroundImageFromURL:(UIView *)notificationView { -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { NSData *imageData = [[NSData alloc] init]; - if(!urlString || [urlString isEqualToString:@""]) { - return imageData; - } - if([cachedImageData valueForKey: urlString]) { - imageData = [cachedImageData valueForKey:urlString]; - } else { - NSURL *url = [NSURL URLWithString: urlString]; - if (url) { - imageData = [[NSData alloc] initWithContentsOfURL: url]; - if (imageData) { - [cachedImageData setObject:imageData forKey:urlString]; + @try { + if([BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:urlString]) { + if([cachedImageData valueForKey: urlString]) { + imageData = [cachedImageData valueForKey:urlString]; + [BlueshiftLog logInfo:@"Loading image from image cache for url" withDetails:urlString methodName:nil]; + } else { + NSURL *url = [NSURL URLWithString:urlString]; + if (url) { + [BlueshiftLog logInfo:@"Downloading image using url" withDetails:urlString methodName:nil]; + imageData = [[NSData alloc] initWithContentsOfURL:url]; + if (imageData) { + [cachedImageData setObject:imageData forKey:urlString]; + [BlueshiftLog logInfo:@"Downloaded image successfully with size in KB" withDetails:[NSNumber numberWithFloat:(imageData.length/1024.0f)] methodName:nil]; + } + } } } + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } return imageData; } @@ -490,4 +495,12 @@ - (BOOL)isDarkThemeEnabled { return NO; } +- (BOOL)isBackgroundImagePresentForNotification:(BlueShiftInAppNotification*)notification { + return (notification && notification.templateStyle && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notification.templateStyle.backgroundImage]); +} + +- (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification { + return (notification && notification.notificationContent && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notification.notificationContent.iconImage]); +} + @end diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m index e2ffc90a..798dff15 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m @@ -363,7 +363,7 @@ - (void)showFromWindow:(BOOL)animated { } }; if (animated) { - [UIView animateWithDuration:0.25 animations:^{ + [UIView animateWithDuration:0.5 animations:^{ self.window.alpha = 1.0; } completion:^(BOOL finished) { completionBlock(); @@ -389,7 +389,7 @@ -(void)hideFromWindow:(BOOL)animated { }; if (animated) { - [UIView animateWithDuration:0.25 animations:^{ + [UIView animateWithDuration:0.5 animations:^{ self.window.alpha = 0; } completion:^(BOOL finished) { completionBlock(); From 662ed9f08af946b31e5ba3fea7d079745040162e Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Mon, 7 Jun 2021 12:45:49 +0530 Subject: [PATCH 06/22] Added fix for fix one fixed + one auto dimension . --- .../BlueShiftInAppNotificationManager.m | 27 ++++++++------ ...BlueShiftNotificationModalViewController.m | 35 +++++++++++++------ .../BlueShiftNotificationViewController.h | 4 +++ .../BlueShiftNotificationViewController.m | 4 +++ 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index 163b10b6..22882747 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -613,14 +613,13 @@ -(void)processSlideInBannerNotification:(BlueShiftInAppNotification*)notificatio BOOL isSlideInIconImagePresent = [notificationVC isSlideInIconImagePresent:notification]; BOOL isBackgroundImagePresent = [notificationVC isBackgroundImagePresentForNotification:notification]; if (isSlideInIconImagePresent || isBackgroundImagePresent) { - NSString *backgroundImageURL = nil; - if(isSlideInIconImagePresent) { - backgroundImageURL = notification.notificationContent.iconImage; - } else if (isBackgroundImagePresent) { - backgroundImageURL = notification.templateStyle.backgroundImage; - } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; + if(isSlideInIconImagePresent) { + [notificationVC loadAndCacheImageForURLString:notification.notificationContent.iconImage]; + } + if (isBackgroundImagePresent) { + [notificationVC loadAndCacheImageForURLString:notification.templateStyle.backgroundImage]; + } [NSThread sleepForTimeInterval:1]; [self presentInAppViewController:notificationVC forNotification:notification]; }); @@ -634,11 +633,17 @@ -(void)processModalNotification:(BlueShiftInAppNotification*)notification displa BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationModalViewController alloc] initWithNotification:notification]; notificationVC.displayOnScreen = displayOnScreen; self.currentNotificationController = notificationVC; - - if ([notificationVC isBackgroundImagePresentForNotification:notification]) { + BOOL isBackgroundImagePresent = [notificationVC isBackgroundImagePresentForNotification:notification]; + BOOL isBannerImagePresent = [notificationVC isBannerImagePresentForNotification:notification]; + + if (isBackgroundImagePresent || isBannerImagePresent) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSString *backgroundImageURL = notification.templateStyle.backgroundImage; - [notificationVC loadAndCacheImageForURLString:backgroundImageURL]; + if (isBackgroundImagePresent) { + [notificationVC loadAndCacheImageForURLString:notification.templateStyle.backgroundImage]; + } + if (isBannerImagePresent) { + [notificationVC loadAndCacheImageForURLString:notification.notificationContent.banner]; + } [NSThread sleepForTimeInterval:1]; [self presentInAppViewController:notificationVC forNotification:notification]; }); diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index a5fd65db..0c6eaa00 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -445,9 +445,18 @@ - (CGSize)getAutoImageSizeForNotificationView { // Check if this modal is image modal if ([self isBackgroundImagePresentForNotification:self.notification] && (self.notification.templateStyle.width < 0 || self.notification.templateStyle.height < 0)) { + + float templateWidth = 0; + if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { + templateWidth = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:self.notification.templateStyle.width forWindow:self.window]; + } + float templateHeight = 0; + if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { + templateHeight = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: self.notification.templateStyle.height forWindow:self.window]; + } // Get max width & height in points which device can support - float maxWidthInPoints = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; - float maxHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; + float maxWidthInPoints = templateWidth > 0 ? templateWidth : [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; + float maxHeightInPoints = templateHeight > 0 ? templateHeight : [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; UIImage* image = [[UIImage alloc] initWithData:imageData]; // If image resolution is less than the device height and width, use the image dimention. @@ -469,24 +478,28 @@ - (CGSize)getAutoImageSizeForNotificationView { } - (CGRect)positionNotificationView { - CGSize imageSize = [self getAutoImageSizeForNotificationView]; + BOOL isBackgroundImageModal = [self isBackgroundImagePresentForNotification:self.notification]; + CGSize imageSize = CGSizeZero; + if (isBackgroundImageModal) { + imageSize = [self getAutoImageSizeForNotificationView]; + } float width = 0; - if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { - width = self.notification.templateStyle.width; - } else if (imageSize.width > 0 && self.notification.templateStyle && self.notification.templateStyle.width < 0) { - // If auto width, get the adjusted height using image width. + // If auto width, get the adjusted height using image width. + if (isBackgroundImageModal && imageSize.width > 0) { width = [BlueShiftInAppNotificationHelper convertPointsWidthToPercentage: imageSize.width forWindow:self.window]; + } else if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { + width = self.notification.templateStyle.width; } else { // Default width width = self.notification.width; } float height = 0; - if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { - height = self.notification.templateStyle.height; - } else if (imageSize.height > 0 && self.notification.templateStyle && self.notification.templateStyle.height < 0) { - // If auto height, get the adjusted height from the image height + // If auto height, get the adjusted height from the image height + if (isBackgroundImageModal && imageSize.height > 0) { height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: imageSize.height forWindow:self.window]; + } else if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { + height = self.notification.templateStyle.height; } else { // Default width height = [BlueShiftInAppNotificationHelper convertPointsHeightToPercentage: notificationView.frame.size.height forWindow:self.window]; diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h index 6d76c423..9df2357f 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h @@ -73,6 +73,10 @@ controller; /// @param notification notification object to perfor the check - (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification; +/// Check if the notification has a valid banner image present. +/// @param notification notification object to perfor the check +- (BOOL)isBannerImagePresentForNotification:(BlueShiftInAppNotification*)notification; + @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index c4b5456d..7c0d782d 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -499,6 +499,10 @@ - (BOOL)isBackgroundImagePresentForNotification:(BlueShiftInAppNotification*)not return (notification && notification.templateStyle && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notification.templateStyle.backgroundImage]); } +- (BOOL)isBannerImagePresentForNotification:(BlueShiftInAppNotification*)notification { + return (notification && notification.notificationContent && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notification.notificationContent.banner]); +} + - (BOOL)isSlideInIconImagePresent:(BlueShiftInAppNotification*)notification { return (notification && notification.notificationContent && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notification.notificationContent.iconImage]); } From 7f78803ab2395260db02a640a2524f4a7f5ed529 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Mon, 7 Jun 2021 19:29:50 +0530 Subject: [PATCH 07/22] Added image cache --- BlueShift-iOS-SDK/BlueShift.h | 3 +++ .../BlueShiftInAppNotificationManager.m | 23 ++++++++++--------- ...BlueShiftNotificationModalViewController.m | 4 ++-- .../BlueShiftNotificationViewController.m | 11 +++++---- .../BlueShiftNotificationWebViewController.m | 8 ++++--- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/BlueShift-iOS-SDK/BlueShift.h b/BlueShift-iOS-SDK/BlueShift.h index a818b3cc..fb9b0bb4 100644 --- a/BlueShift-iOS-SDK/BlueShift.h +++ b/BlueShift-iOS-SDK/BlueShift.h @@ -47,6 +47,9 @@ NS_ASSUME_NONNULL_BEGIN @property BlueShiftAppDelegate * _Nullable appDelegate; @property BlueShiftUserNotificationCenterDelegate * _Nullable userNotificationDelegate; +/// Image cache for storing downloaded images from the in-app notifications. The cache will be cleared when in-app gets dismissed. +@property (nonatomic, strong) NSCache *inAppImageDataCache; + + (instancetype _Nullable)sharedInstance; /// Initialise the SDK using BlueShiftConfig diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index 22882747..acb64fd7 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -673,24 +673,25 @@ - (void)presentInAppViewController:(BlueShiftNotificationViewController*)notific return; } } - if (notificationController && [self inAppNotificationDisplayOnPage]) { - [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; - notificationController.delegate = self; - notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; - [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + if (notificationController && [self inAppNotificationDisplayOnPage]) { + [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + notificationController.delegate = self; + notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; + [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; [notificationController show:YES]; - }); - } else { - self.currentNotificationController = nil; - [BlueshiftLog logInfo:@"Skipping preseting in-app notification as screen is not registered to receive in-app notification" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; - } + } else { + self.currentNotificationController = nil; + [BlueshiftLog logInfo:@"Skipping preseting in-app notification as screen is not registered to receive in-app notification" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + } + }); } #pragma mark - In App events // Notification Click Callbacks -(void)inAppDidDismiss:(NSDictionary *)notificationPayload fromViewController:(BlueShiftNotificationViewController *)controller { self.currentNotificationController = nil; + [[BlueShift sharedInstance].inAppImageDataCache removeAllObjects]; if ([[[BlueShift sharedInstance] config] inAppManualTriggerEnabled] == NO) { [self startInAppMessageFetchTimer]; } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index 0c6eaa00..3a681a36 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -85,7 +85,7 @@ - (void)showFromWindow:(BOOL)animated { } }; if (animated) { - [UIView animateWithDuration:0.5 animations:^{ + [UIView animateWithDuration:0.25 animations:^{ self.window.alpha = 1.0; } completion:^(BOOL finished) { completionBlock(); @@ -118,7 +118,7 @@ - (void)hideFromWindow:(BOOL)animated { }; if (animated) { - [UIView animateWithDuration:0.5 animations:^{ + [UIView animateWithDuration:0.25 animations:^{ self.window.alpha = 0; } completion:^(BOOL finished) { completionBlock(); diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index 7c0d782d..c2184a55 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -16,7 +16,6 @@ @interface BlueShiftNotificationViewController () { BlueShiftNotificationCloseButton *_closeButton; - NSMutableDictionary *cachedImageData; } @end @@ -28,7 +27,6 @@ - (instancetype)initWithNotification:(BlueShiftInAppNotification *)notification notification.contentStyle = ([self isDarkThemeEnabled] && notification.contentStyleDark) ? notification.contentStyleDark : notification.contentStyle; notification.templateStyle = ([self isDarkThemeEnabled] && notification.templateStyleDark) ? notification.templateStyleDark : notification.templateStyle; _notification = notification; - cachedImageData = [[NSMutableDictionary alloc] init]; } return self; } @@ -142,8 +140,8 @@ -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { NSData *imageData = [[NSData alloc] init]; @try { if([BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:urlString]) { - if([cachedImageData valueForKey: urlString]) { - imageData = [cachedImageData valueForKey:urlString]; + if([BlueShift sharedInstance].inAppImageDataCache && [[BlueShift sharedInstance].inAppImageDataCache objectForKey: urlString]) { + imageData = [[BlueShift sharedInstance].inAppImageDataCache objectForKey:urlString]; [BlueshiftLog logInfo:@"Loading image from image cache for url" withDetails:urlString methodName:nil]; } else { NSURL *url = [NSURL URLWithString:urlString]; @@ -151,7 +149,10 @@ -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { [BlueshiftLog logInfo:@"Downloading image using url" withDetails:urlString methodName:nil]; imageData = [[NSData alloc] initWithContentsOfURL:url]; if (imageData) { - [cachedImageData setObject:imageData forKey:urlString]; + if ([BlueShift sharedInstance].inAppImageDataCache == nil) { + [BlueShift sharedInstance].inAppImageDataCache = [[NSCache alloc] init]; + } + [[BlueShift sharedInstance].inAppImageDataCache setObject:imageData forKey:urlString]; [BlueshiftLog logInfo:@"Downloaded image successfully with size in KB" withDetails:[NSNumber numberWithFloat:(imageData.length/1024.0f)] methodName:nil]; } } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m index 798dff15..b056825e 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m @@ -291,8 +291,10 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { [webView evaluateJavaScript:@"document.readyState" completionHandler:^(id _Nullable complete, NSError * _Nullable error) { if (complete) { - self->didLoadWebView(); + self->didLoadWebView(); + dispatch_async(dispatch_get_main_queue(), ^{ [self resizeWebViewAsPerContent:webView]; + }); } }]; } @@ -363,7 +365,7 @@ - (void)showFromWindow:(BOOL)animated { } }; if (animated) { - [UIView animateWithDuration:0.5 animations:^{ + [UIView animateWithDuration:0.25 animations:^{ self.window.alpha = 1.0; } completion:^(BOOL finished) { completionBlock(); @@ -389,7 +391,7 @@ -(void)hideFromWindow:(BOOL)animated { }; if (animated) { - [UIView animateWithDuration:0.5 animations:^{ + [UIView animateWithDuration:0.25 animations:^{ self.window.alpha = 0; } completion:^(BOOL finished) { completionBlock(); From ec2504978e2e70bd7e8b30f494ad6d191486888f Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Tue, 8 Jun 2021 13:17:18 +0530 Subject: [PATCH 08/22] Added margin for close button changed close button key to show --- BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m | 7 +++---- .../InApps/BlueShiftInAppNotificationConstant.h | 2 +- .../InApps/BlueShiftNotificationViewController.m | 9 +++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m index 2d2b03f4..0ab894ad 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m @@ -216,10 +216,6 @@ - (instancetype)initFromDictionary: (NSDictionary *)templateStyleDictionary with if ([templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundImageKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundImageKey] != [NSNull null]) { self.backgroundImage = (NSString *)[templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundImageKey]; } - if ([templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey] && - [templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey] != [NSNull null]){ - self.enableCloseButton = (NSNumber*)[templateStyleDictionary objectForKey: kInAppNotificationModalEnableCloseButtonKey]; - } if ([templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundRadiusKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundRadiusKey] != [NSNull null]) { self.backgroundRadius = (NSNumber *)[templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundRadiusKey]; @@ -227,6 +223,9 @@ - (instancetype)initFromDictionary: (NSDictionary *)templateStyleDictionary with if ([templateStyleDictionary objectForKey: kInAppNotificationModalCloseButtonKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalCloseButtonKey] != [NSNull null]) { NSDictionary *closeButtonPayload = [templateStyleDictionary objectForKey: kInAppNotificationModalCloseButtonKey]; self.closeButton = [[BlueShiftInAppNotificationButton alloc] initFromDictionary: closeButtonPayload withType: inAppType]; + if ([closeButtonPayload objectForKey: kInAppNotificationModalEnableCloseButtonKey]){ + self.enableCloseButton = (NSNumber*)[closeButtonPayload objectForKey: kInAppNotificationModalEnableCloseButtonKey]; + } } if ([templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundDimAmountKey] && [templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundDimAmountKey] != [NSNull null]) { self.backgroundDimAmount = (NSNumber *)[templateStyleDictionary objectForKey: kInAppNotificationModalBackgroundDimAmountKey]; diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index d3ab4a3a..9c8515eb 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -54,7 +54,7 @@ #define kInAppNotificationModalHeightKey @"height" #define kInAppNotificationModalBackgroundColorKey @"background_color" #define kInAppNotificationModalBackgroundImageKey @"background_image" -#define kInAppNotificationModalEnableCloseButtonKey @"enable_close_button" +#define kInAppNotificationModalEnableCloseButtonKey @"show" #define kInAppNotificationModalBackgroundActionKey @"enable_background_action" #define kInAppNotificationModalCloseButtonKey @"close_button" #define kInAppNotificationModalBackgroundDimAmountKey @"background_dim_amount" diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index c2184a55..ae9d2bde 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -206,12 +206,13 @@ - (BOOL)shouldShowCloseButton { - (void)createCloseButton:(CGRect)frame { BOOL showCloseButton = [self shouldShowCloseButton]; + CGFloat margin = 5; if (self.notification.templateStyle && showCloseButton) { if ( self.notification.templateStyle.closeButton && self.notification.templateStyle.closeButton.text && ![self.notification.templateStyle.closeButton.text isEqualToString:@""]) { - CGFloat xPosition = frame.origin.x + frame.size.width - KInAppNotificationModalCloseButtonWidth - 5; - CGRect cgRect = CGRectMake(xPosition, frame.origin.y + 5, KInAppNotificationModalCloseButtonWidth, KInAppNotificationModalCloseButtonHeight); + CGFloat xPosition = frame.origin.x + frame.size.width - KInAppNotificationModalCloseButtonWidth - margin; + CGRect cgRect = CGRectMake(xPosition, frame.origin.y + margin, KInAppNotificationModalCloseButtonWidth, KInAppNotificationModalCloseButtonHeight); UIButton *closeButtonLabel = [[UIButton alloc] initWithFrame:cgRect]; BlueShiftInAppNotificationButton *closeButton = self.notification.templateStyle.closeButton; CGFloat closeButtonFontSize = (closeButton && closeButton.textSize && closeButton.textSize.floatValue > 0) @@ -235,8 +236,8 @@ - (void)createCloseButton:(CGRect)frame { [closeButtonLabel.titleLabel setTextAlignment: NSTextAlignmentCenter]; [self.view addSubview: closeButtonLabel]; } else { - CGFloat xPosition = frame.origin.x + frame.size.width - KInAppNotificationModalCloseButtonWidth; - CGRect cgRect = CGRectMake(xPosition, frame.origin.y, KInAppNotificationModalCloseButtonWidth, KInAppNotificationModalCloseButtonHeight); + CGFloat xPosition = frame.origin.x + frame.size.width - KInAppNotificationModalCloseButtonWidth - margin; + CGRect cgRect = CGRectMake(xPosition, frame.origin.y + margin, KInAppNotificationModalCloseButtonWidth, KInAppNotificationModalCloseButtonHeight); _closeButton = [BlueShiftNotificationCloseButton new]; [_closeButton addTarget:self action:@selector(closeButtonDidTapped) forControlEvents:UIControlEventTouchUpInside]; _closeButton.frame = cgRect; From 56e01917e247397b63d2d2e508accc223be7f581 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Wed, 9 Jun 2021 18:31:00 +0530 Subject: [PATCH 09/22] Added "browser_platform" in the tracking api Added dedupe for push click processing Added fix to handle silent push notifications Fixed unsubscribed handling Added "icon_image_corner_radius" for slide in image corner radius --- .../BlueShiftPushAnalytics.m | 2 ++ .../BlueshiftExtensionConstants.h | 2 ++ BlueShift-iOS-SDK/BlueShift.m | 7 +++-- BlueShift-iOS-SDK/BlueShiftAppDelegate.m | 27 ++++++++++++++----- .../BlueShiftNotificationConstants.h | 1 + BlueShift-iOS-SDK/BlueShiftUserInfo.h | 3 ++- BlueShift-iOS-SDK/BlueShiftUserInfo.m | 6 +++-- BlueShift-iOS-SDK/BlueshiftConstants.h | 1 + .../InApps/BlueShiftInAppNotification.m | 5 ++++ .../BlueShiftInAppNotificationConstant.h | 1 + .../BlueShiftNotificationViewController.m | 2 -- 11 files changed, 43 insertions(+), 14 deletions(-) diff --git a/BlueShift-iOS-Extension-SDK/BlueShiftPushAnalytics.m b/BlueShift-iOS-Extension-SDK/BlueShiftPushAnalytics.m index 595e0aa6..3807b4d3 100644 --- a/BlueShift-iOS-Extension-SDK/BlueShiftPushAnalytics.m +++ b/BlueShift-iOS-Extension-SDK/BlueShiftPushAnalytics.m @@ -25,6 +25,8 @@ + (void)sendPushAnalytics:(NSString *)type withParams:(NSDictionary *)userInfo { [parameterMutableDictionary addEntriesFromDictionary:pushTrackParameterDictionary]; } [parameterMutableDictionary setObject:type forKey:@"a"]; + NSString *browserPlatform = [NSString stringWithFormat:@"%@ %@", kiOS, [[UIDevice currentDevice] systemVersion]]; + [parameterMutableDictionary setObject:browserPlatform forKey:kBrowserPlatform]; NSString *url = [NSString stringWithFormat:@"%@%@", kBaseURL, kPushEventsUploadURL]; [self fireAPICallWithURL:url data:parameterMutableDictionary andRetryCount:3]; } diff --git a/BlueShift-iOS-Extension-SDK/BlueshiftExtensionConstants.h b/BlueShift-iOS-Extension-SDK/BlueshiftExtensionConstants.h index 7087195d..99e9226a 100755 --- a/BlueShift-iOS-Extension-SDK/BlueshiftExtensionConstants.h +++ b/BlueShift-iOS-Extension-SDK/BlueshiftExtensionConstants.h @@ -51,5 +51,7 @@ #define kAppName @"app_name" #define kDeviceID @"device_id" +#define kBrowserPlatform @"browser_platform" +#define kiOS @"iOS" #endif diff --git a/BlueShift-iOS-SDK/BlueShift.m b/BlueShift-iOS-SDK/BlueShift.m index 01a82fd1..acb86e79 100644 --- a/BlueShift-iOS-SDK/BlueShift.m +++ b/BlueShift-iOS-SDK/BlueShift.m @@ -110,10 +110,11 @@ - (void) setupWithConfiguration:(BlueShiftConfig *)config { } if (config.enablePushNotification == YES) { [blueShiftAppDelegate registerForNotification]; - [blueShiftAppDelegate handleRemoteNotificationOnLaunchWithLaunchOptions:config.applicationLaunchOptions]; } else if (config.enableSilentPushNotification == YES) { [blueShiftAppDelegate registerForSilentPushNotification]; } + [blueShiftAppDelegate handleRemoteNotificationOnLaunchWithLaunchOptions:config.applicationLaunchOptions]; + // Initialize In App Manager _inAppNotificationMananger = [[BlueShiftInAppNotificationManager alloc] init]; if (config.inAppNotificationDelegate) { @@ -666,7 +667,9 @@ - (void)performRequestQueue:(NSMutableDictionary *)parameters canBatchThisEvent: if([self validateSDKTrackingRequirements] == false) { return; } - + + parameters[kBrowserPlatform] = [BlueShiftDeviceData currentDeviceData].operatingSystem; + if (parameters != nil) { NSString *url = [NSString stringWithFormat:@"%@%@", kBaseURL, kPushEventsUploadURL]; BlueShiftRequestOperation *requestOperation = [[BlueShiftRequestOperation alloc] initWithRequestURL:url andHttpMethod:BlueShiftHTTPMethodGET andParameters:[parameters copy] andRetryAttemptsCount:kRequestTryMaximumLimit andNextRetryTimeStamp:0 andIsBatchEvent:isBatchEvent]; diff --git a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m index 3c7c9753..767ec473 100755 --- a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m +++ b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m @@ -16,7 +16,9 @@ #define SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) -@implementation BlueShiftAppDelegate +@implementation BlueShiftAppDelegate { + NSString *lastProcessedPushNotificationUUID; +} - (id) init { self = [super init]; @@ -78,12 +80,11 @@ - (void)registerForSilentPushNotification { // Handles the push notification payload when the app is killed and lauched from push notification tray ... - (BOOL)handleRemoteNotificationOnLaunchWithLaunchOptions:(NSDictionary *)launchOptions { - NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; - - if (userInfo) { - // Handling the push notification if we get the userInfo from launchOptions ... - // It's the only way to track notification payload while app is on launch (i.e after the app is killed) ... - [self handleRemoteNotification:userInfo]; + if (launchOptions) { + NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; + if (userInfo) { + [self handleRemoteNotification:userInfo]; + } } return YES; @@ -378,7 +379,12 @@ - (void)handleRemoteNotification:(NSDictionary *)userInfo { if ([BlueshiftEventAnalyticsHelper isSilenPushNotificationPayload: userInfo]) { [[BlueShift sharedInstance] handleSilentPushNotification: userInfo forApplicationState: UIApplicationStateActive]; } else { + NSString *pushUUID = [userInfo valueForKey:kInAppNotificationModalMessageUDIDKey]; NSString *pushCategory = [[userInfo objectForKey: kNotificationAPSIdentifierKey] objectForKey: kNotificationCategoryIdentifierKey]; + if ([pushCategory isEqualToString:kNotificationCategorySilentPushIdentifier] || [pushUUID isEqualToString:lastProcessedPushNotificationUUID]) { + [BlueshiftLog logInfo:@"Skipped processing notification due to following reasons" withDetails:@"1. The push notification is silent push notification 2. The push notification click is already processed." methodName:nil]; + return; + } self.pushAlertDictionary = [userInfo objectForKey: kNotificationAPSIdentifierKey]; self.userInfo = userInfo; NSDictionary *pushTrackParameterDictionary = [BlueshiftEventAnalyticsHelper pushTrackParameterDictionaryForPushDetailsDictionary:userInfo]; @@ -416,6 +422,8 @@ - (void)setupPushNotificationDeeplink:(NSDictionary *)userInfo { [[[BlueShift sharedInstance].config blueShiftPushDelegate] pushNotificationDidClick:userInfo]; } + lastProcessedPushNotificationUUID = [userInfo valueForKey:kInAppNotificationModalMessageUDIDKey]; + [self trackAppOpenWithParameters:userInfo]; if (userInfo != nil && ([userInfo objectForKey: kPushNotificationDeepLinkURLKey] || [userInfo objectForKey: kNotificationURLElementKey])) { @@ -473,6 +481,11 @@ - (void)handleRemoteNotification:(NSDictionary *)userInfo forApplicationState:(U } else if([BlueshiftEventAnalyticsHelper isSchedulePushNotification:userInfo]) { [self validateAndScheduleLocalNotification:userInfo]; } else { + NSString *pushUUID = [userInfo valueForKey:kInAppNotificationModalMessageUDIDKey]; + if ([pushCategory isEqualToString:kNotificationCategorySilentPushIdentifier] || [pushUUID isEqualToString:lastProcessedPushNotificationUUID]) { + [BlueshiftLog logInfo:@"Skipped processing notification due to following reasons" withDetails:@"1. The push notification is silent push notification 2. The push notification click is already processed." methodName:nil]; + return; + } // Handle push notification when the app is in inactive or background state ... if ([pushCategory isEqualToString:kNotificationCategoryBuyIdentifier]) { [self handleCategoryForBuyUsingPushDetailsDictionary:userInfo]; diff --git a/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h b/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h index 667389af..97bfd0ba 100755 --- a/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h +++ b/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h @@ -33,6 +33,7 @@ #define kNotificationCategoryViewCartIdentifier @"view_cart" #define kNotificationActionOpenCartIdentifier @"open_cart" +#define kNotificationCategorySilentPushIdentifier @"silent_push" #define kNotificationCategoryOfferIdentifier @"promotion" #define kNotificationProductIDIdenfierKey @"product_id" #define kNotificationSelectedIndexKey @"selected_index" diff --git a/BlueShift-iOS-SDK/BlueShiftUserInfo.h b/BlueShift-iOS-SDK/BlueShiftUserInfo.h index 0f856086..9a8e068b 100644 --- a/BlueShift-iOS-SDK/BlueShiftUserInfo.h +++ b/BlueShift-iOS-SDK/BlueShiftUserInfo.h @@ -31,7 +31,8 @@ @property (nonatomic, strong) NSString *facebookID; /// Unsubscribe from the push notifications. -@property BOOL unsubscribed; +/// Set this flag to true if you want to stop receiving push notifications for that user. +@property NSNumber* unsubscribed; /// The data stored in the additionalUserInfo will be populated on server with `additional_user_info__` prefix to every key name. /// If key is stored as `profession`, then server will popluate it as `additional_user_info__profession` in the events. diff --git a/BlueShift-iOS-SDK/BlueShiftUserInfo.m b/BlueShift-iOS-SDK/BlueShiftUserInfo.m index 3d6a9868..425c490d 100644 --- a/BlueShift-iOS-SDK/BlueShiftUserInfo.m +++ b/BlueShift-iOS-SDK/BlueShiftUserInfo.m @@ -58,7 +58,9 @@ - (NSMutableDictionary *)convertToDictionary { } [BlueshiftEventAnalyticsHelper addToDictionary:sharedUserInfoMutableDictionary key:kBSUserFacebookId value:self.facebookID]; [BlueshiftEventAnalyticsHelper addToDictionary:sharedUserInfoMutableDictionary key:kBSUserEducation value:self.education]; - [BlueshiftEventAnalyticsHelper addToDictionary:sharedUserInfoMutableDictionary key:kBSUserUnsubscribedPush value:[NSNumber numberWithBool:self.unsubscribed]]; + if (self.unsubscribed != nil) { + [BlueshiftEventAnalyticsHelper addToDictionary:sharedUserInfoMutableDictionary key:kBSUserUnsubscribedPush value:self.unsubscribed]; + } [BlueshiftEventAnalyticsHelper addToDictionary:sharedUserInfoMutableDictionary key:kBSUserAdditionalInfo value:self.additionalUserInfo]; if (self.dateOfBirth) { NSNumber *dateOfBirthTimeStamp = [NSNumber numberWithDouble:[self.dateOfBirth timeIntervalSinceReferenceDate]]; @@ -137,7 +139,7 @@ + (BlueShiftUserInfo *)parseUserInfoDictionary:(NSDictionary *)currentUserInfoDi blueShiftUserInfo.facebookID = [currentUserInfoDictionary objectForKey:kBSUserFacebookId]; blueShiftUserInfo.gender = [currentUserInfoDictionary objectForKey:kBSUserGender]; if([currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush]) { - blueShiftUserInfo.unsubscribed = [[currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush] boolValue]; + blueShiftUserInfo.unsubscribed = (NSNumber*)[currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush]; } NSTimeInterval joinedAtTimeStamp = [[currentUserInfoDictionary objectForKey:kBSUserJoinedAt] doubleValue]; diff --git a/BlueShift-iOS-SDK/BlueshiftConstants.h b/BlueShift-iOS-SDK/BlueshiftConstants.h index 82b84220..e0e8b774 100644 --- a/BlueShift-iOS-SDK/BlueshiftConstants.h +++ b/BlueShift-iOS-SDK/BlueshiftConstants.h @@ -23,6 +23,7 @@ #define kDeviceID @"device_id" #define kApple @"apple" #define kiOS @"iOS" +#define kBrowserPlatform @"browser_platform" //App Data #define kEnablePush @"enable_push" diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m index 0ab894ad..a5182a5e 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m @@ -378,6 +378,11 @@ - (instancetype)initFromDictionary: (NSDictionary *) contenStyletDictionary with self.iconImageBackgroundRadius =(NSNumber *)[contenStyletDictionary objectForKey:kInAppNotificationModalIconImageBackgroundRadiusKey]; } + if ([contenStyletDictionary objectForKey: kInAppNotificationIconImageCornerRadiusKey] && + [contenStyletDictionary objectForKey: kInAppNotificationIconImageCornerRadiusKey] != [NSNull null] ) { + self.iconImageBackgroundRadius = (NSNumber *)[contenStyletDictionary objectForKey:kInAppNotificationIconImageCornerRadiusKey]; + } + break; default: diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index 9c8515eb..22fadc9b 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -46,6 +46,7 @@ #define kInAppNotificationModalSecondaryIconRadiusKey @"secondary_icon_background_color" #define kInAppNotificationModalIconImageBackgroundColorKey @"icon_image_background_color" #define kInAppNotificationModalIconImageBackgroundRadiusKey @"icon_image_background_radius" +#define kInAppNotificationIconImageCornerRadiusKey @"icon_image_corner_radius" #define kInAppNotificationModalTemplateStyleKey @"template_style" #define kInAppNotificationModalTemplateStyleDarkKey @"template_style_dark" diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index ae9d2bde..a9801e11 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -258,8 +258,6 @@ - (void)setButton:(UIButton *)button andString:(NSString *)value } if (backgroundColorCode != (id)[NSNull null] && backgroundColorCode.length > 0) { [button setBackgroundColor:[self colorWithHexString:backgroundColorCode]]; - } else { - [button setBackgroundColor:UIColor.clearColor]; } } } From 56ff0df6feedbb162f6afa6cd4098259ed5305bc Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Thu, 10 Jun 2021 22:41:08 +0530 Subject: [PATCH 10/22] removed icon_image_corner_radius --- BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m | 5 ----- .../InApps/BlueShiftInAppNotificationConstant.h | 1 - 2 files changed, 6 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m index a5182a5e..0ab894ad 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotification.m @@ -378,11 +378,6 @@ - (instancetype)initFromDictionary: (NSDictionary *) contenStyletDictionary with self.iconImageBackgroundRadius =(NSNumber *)[contenStyletDictionary objectForKey:kInAppNotificationModalIconImageBackgroundRadiusKey]; } - if ([contenStyletDictionary objectForKey: kInAppNotificationIconImageCornerRadiusKey] && - [contenStyletDictionary objectForKey: kInAppNotificationIconImageCornerRadiusKey] != [NSNull null] ) { - self.iconImageBackgroundRadius = (NSNumber *)[contenStyletDictionary objectForKey:kInAppNotificationIconImageCornerRadiusKey]; - } - break; default: diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index 22fadc9b..9c8515eb 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -46,7 +46,6 @@ #define kInAppNotificationModalSecondaryIconRadiusKey @"secondary_icon_background_color" #define kInAppNotificationModalIconImageBackgroundColorKey @"icon_image_background_color" #define kInAppNotificationModalIconImageBackgroundRadiusKey @"icon_image_background_radius" -#define kInAppNotificationIconImageCornerRadiusKey @"icon_image_corner_radius" #define kInAppNotificationModalTemplateStyleKey @"template_style" #define kInAppNotificationModalTemplateStyleDarkKey @"template_style_dark" From a4302b3aebdd4d3f5a6703c24b317dcc7378fefc Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 10:50:17 +0530 Subject: [PATCH 11/22] Added md5 hash for image caching key --- .../InApps/BlueShiftInAppNotificationHelper.h | 3 +++ .../InApps/BlueShiftInAppNotificationHelper.m | 15 +++++++++++++++ .../InApps/BlueShiftNotificationViewController.m | 7 ++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.h index 8d486a65..955c7f4a 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.h @@ -48,6 +48,9 @@ NS_ASSUME_NONNULL_BEGIN /// @warning In the sceneDelegate enabled apps, In order to access multiple windows to find the keyWindow, this function needs to be executed on the main thread + (UIWindow *)getApplicationKeyWindow; +/// Returns MD5 hash for the given string ++ (NSString *)getMD5ForString:(NSString*)string; + @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.m index ef049cf9..5952754e 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationHelper.m @@ -4,6 +4,7 @@ // // Created by shahas kp on 11/07/19. // +#import #import "BlueShiftInAppNotificationHelper.h" #import "BlueShiftInAppNotificationConstant.h" @@ -168,4 +169,18 @@ + (BOOL)isIpadDevice { return NO; } ++ (NSString *)getMD5ForString:(NSString*)string { + const char *cStr = [string UTF8String]; + unsigned char result[CC_MD5_DIGEST_LENGTH]; + CC_MD5( cStr, (CC_LONG)strlen(cStr), result ); + + return [NSString stringWithFormat: + @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + result[0], result[1], result[2], result[3], + result[4], result[5], result[6], result[7], + result[8], result[9], result[10], result[11], + result[12], result[13], result[14], result[15] + ]; +} + @end diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m index a9801e11..933cda3a 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.m @@ -140,8 +140,9 @@ -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { NSData *imageData = [[NSData alloc] init]; @try { if([BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:urlString]) { - if([BlueShift sharedInstance].inAppImageDataCache && [[BlueShift sharedInstance].inAppImageDataCache objectForKey: urlString]) { - imageData = [[BlueShift sharedInstance].inAppImageDataCache objectForKey:urlString]; + NSString *urlMD5Hash = [BlueShiftInAppNotificationHelper getMD5ForString: urlString]; + if([BlueShift sharedInstance].inAppImageDataCache && [[BlueShift sharedInstance].inAppImageDataCache objectForKey: urlMD5Hash]) { + imageData = [[BlueShift sharedInstance].inAppImageDataCache objectForKey:urlMD5Hash]; [BlueshiftLog logInfo:@"Loading image from image cache for url" withDetails:urlString methodName:nil]; } else { NSURL *url = [NSURL URLWithString:urlString]; @@ -152,7 +153,7 @@ -(NSData*)loadAndCacheImageForURLString:(NSString*)urlString { if ([BlueShift sharedInstance].inAppImageDataCache == nil) { [BlueShift sharedInstance].inAppImageDataCache = [[NSCache alloc] init]; } - [[BlueShift sharedInstance].inAppImageDataCache setObject:imageData forKey:urlString]; + [[BlueShift sharedInstance].inAppImageDataCache setObject:imageData forKey:urlMD5Hash]; [BlueshiftLog logInfo:@"Downloaded image successfully with size in KB" withDetails:[NSNumber numberWithFloat:(imageData.length/1024.0f)] methodName:nil]; } } From f32c86a8b10a6d1ef88ffb87f821c826b194d10b Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 10:57:33 +0530 Subject: [PATCH 12/22] Dispatch queue optimisation for the in app display and push delivered event --- .../BlueShiftPushNotification.m | 2 +- .../InApps/BlueShiftInAppNotificationManager.m | 18 ++++++++++++------ .../BlueShiftNotificationWebViewController.m | 6 ++++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/BlueShift-iOS-Extension-SDK/BlueShiftPushNotification.m b/BlueShift-iOS-Extension-SDK/BlueShiftPushNotification.m index 9da21bd1..d977f442 100644 --- a/BlueShift-iOS-Extension-SDK/BlueShiftPushNotification.m +++ b/BlueShift-iOS-Extension-SDK/BlueShiftPushNotification.m @@ -46,7 +46,7 @@ - (NSArray *)integratePushNotificationWithMediaAttachementsForRequest:(UNNotific NSLog(@"[Blueshift] Error - Please set the api key in the Notification Service Extension, otherwise push notification delivered events will not reflect on the dashboard"); } - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ [self trackPushViewedWithRequest:request]; }); diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index acb64fd7..9c6796b4 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -613,14 +613,13 @@ -(void)processSlideInBannerNotification:(BlueShiftInAppNotification*)notificatio BOOL isSlideInIconImagePresent = [notificationVC isSlideInIconImagePresent:notification]; BOOL isBackgroundImagePresent = [notificationVC isBackgroundImagePresentForNotification:notification]; if (isSlideInIconImagePresent || isBackgroundImagePresent) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ if(isSlideInIconImagePresent) { [notificationVC loadAndCacheImageForURLString:notification.notificationContent.iconImage]; } if (isBackgroundImagePresent) { [notificationVC loadAndCacheImageForURLString:notification.templateStyle.backgroundImage]; } - [NSThread sleepForTimeInterval:1]; [self presentInAppViewController:notificationVC forNotification:notification]; }); } else { @@ -637,14 +636,13 @@ -(void)processModalNotification:(BlueShiftInAppNotification*)notification displa BOOL isBannerImagePresent = [notificationVC isBannerImagePresentForNotification:notification]; if (isBackgroundImagePresent || isBannerImagePresent) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ if (isBackgroundImagePresent) { [notificationVC loadAndCacheImageForURLString:notification.templateStyle.backgroundImage]; } if (isBannerImagePresent) { [notificationVC loadAndCacheImageForURLString:notification.notificationContent.banner]; } - [NSThread sleepForTimeInterval:1]; [self presentInAppViewController:notificationVC forNotification:notification]; }); } else { @@ -673,7 +671,7 @@ - (void)presentInAppViewController:(BlueShiftNotificationViewController*)notific return; } } - dispatch_async(dispatch_get_main_queue(), ^{ + void(^ presentInAppBlock)(void) = ^{ if (notificationController && [self inAppNotificationDisplayOnPage]) { [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; notificationController.delegate = self; @@ -684,7 +682,15 @@ - (void)presentInAppViewController:(BlueShiftNotificationViewController*)notific self.currentNotificationController = nil; [BlueshiftLog logInfo:@"Skipping preseting in-app notification as screen is not registered to receive in-app notification" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; } - }); + }; + + if ([NSThread isMainThread] == YES) { + presentInAppBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + presentInAppBlock(); + }); + } } #pragma mark - In App events diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m index b056825e..f309cd12 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m @@ -291,8 +291,9 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { [webView evaluateJavaScript:@"document.readyState" completionHandler:^(id _Nullable complete, NSError * _Nullable error) { if (complete) { - self->didLoadWebView(); - dispatch_async(dispatch_get_main_queue(), ^{ + [BlueshiftLog logInfo:@"Webview loaded the content successfully." withDetails:nil methodName:nil]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + self->didLoadWebView(); [self resizeWebViewAsPerContent:webView]; }); } @@ -305,6 +306,7 @@ - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView * //resize webview as per content height & width when all the content/media is loaded - (void)resizeWebViewAsPerContent:(WKWebView *)webView { + [BlueshiftLog logInfo:@"Resizing the in-app webview size based on the loaded content." withDetails:nil methodName:nil]; [webView evaluateJavaScript:@"document.body.scrollHeight" completionHandler:^(id _Nullable height, NSError * _Nullable error) { [webView evaluateJavaScript:@"document.body.scrollWidth" completionHandler:^(id _Nullable width, NSError * _Nullable error) { dispatch_async(dispatch_get_main_queue(), ^{ From f0bc966b7f41b39b0f50c14777165f9b6c98b5d3 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 10:59:20 +0530 Subject: [PATCH 13/22] Added backward compatibility for image modals --- .../InApps/BlueShiftInAppNotificationConstant.h | 1 + .../InApps/BlueShiftNotificationModalViewController.m | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index 9c8515eb..fc0afc35 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -111,6 +111,7 @@ #define kInAppNotificationDefaultWidth 90.0 #define kInAppNotificationDefaultHeight 90.0 +#define kInAppNotificationImageModalDefaultHeight 100.0 #define kHTMLInAppNotificationMaximumWidthInPoints 470.0 #define kHTMLInAppNotificationMinimumHeight 25.0 diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index 3a681a36..6fde8594 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -444,7 +444,8 @@ - (CGSize)getAutoImageSizeForNotificationView { float height = 0; // Check if this modal is image modal - if ([self isBackgroundImagePresentForNotification:self.notification] && (self.notification.templateStyle.width < 0 || self.notification.templateStyle.height < 0)) { + if ([self isBackgroundImagePresentForNotification:self.notification]) { + //&& (self.notification.templateStyle.width < 0 || self.notification.templateStyle.height < 0)) { //for auto width & height float templateWidth = 0; if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { @@ -456,7 +457,7 @@ - (CGSize)getAutoImageSizeForNotificationView { } // Get max width & height in points which device can support float maxWidthInPoints = templateWidth > 0 ? templateWidth : [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; - float maxHeightInPoints = templateHeight > 0 ? templateHeight : [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; + float maxHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationImageModalDefaultHeight forWindow:self.window]; NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; UIImage* image = [[UIImage alloc] initWithData:imageData]; // If image resolution is less than the device height and width, use the image dimention. From 588aa17edb1019c848bf35d8374d80e2d7cc79c1 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 11:01:09 +0530 Subject: [PATCH 14/22] Fixed warning for the rechability class --- BlueShift-iOS-SDK/NetworkReachability.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BlueShift-iOS-SDK/NetworkReachability.m b/BlueShift-iOS-SDK/NetworkReachability.m index 19d249a1..f22c3d59 100755 --- a/BlueShift-iOS-SDK/NetworkReachability.m +++ b/BlueShift-iOS-SDK/NetworkReachability.m @@ -467,8 +467,8 @@ -(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags - (NSString *) description { - NSString *description = [NSString stringWithFormat:@"<%@: %#x (%@)>", - NSStringFromClass([self class]), (unsigned int) self, [self currentReachabilityFlags]]; + NSString *description = [NSString stringWithFormat:@"<%@: %#lx (%@)>", + NSStringFromClass([self class]), (long int) self, [self currentReachabilityFlags]]; return description; } From 7600316db71ddfa015c0b6d205983cbae323bc3e Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 11:12:34 +0530 Subject: [PATCH 15/22] added nil check --- BlueShift-iOS-SDK/BlueShiftUserInfo.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueShift-iOS-SDK/BlueShiftUserInfo.m b/BlueShift-iOS-SDK/BlueShiftUserInfo.m index 425c490d..7db4a39d 100644 --- a/BlueShift-iOS-SDK/BlueShiftUserInfo.m +++ b/BlueShift-iOS-SDK/BlueShiftUserInfo.m @@ -138,7 +138,7 @@ + (BlueShiftUserInfo *)parseUserInfoDictionary:(NSDictionary *)currentUserInfoDi blueShiftUserInfo.education = [currentUserInfoDictionary objectForKey:kBSUserEducation]; blueShiftUserInfo.facebookID = [currentUserInfoDictionary objectForKey:kBSUserFacebookId]; blueShiftUserInfo.gender = [currentUserInfoDictionary objectForKey:kBSUserGender]; - if([currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush]) { + if([currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush] != nil) { blueShiftUserInfo.unsubscribed = (NSNumber*)[currentUserInfoDictionary objectForKey:kBSUserUnsubscribedPush]; } NSTimeInterval joinedAtTimeStamp = [[currentUserInfoDictionary objectForKey:kBSUserJoinedAt] doubleValue]; From eaa6cd85465f4b2f5680aeb8e4984fe523b0be5c Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 15:14:25 +0530 Subject: [PATCH 16/22] fixed image modal rendering for automatic and fixed dimension rendering --- ...BlueShiftNotificationModalViewController.m | 84 +++++++++++++------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index 6fde8594..d862bf82 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -12,6 +12,7 @@ #import "BlueShiftInAppNotificationConstant.h" #import "BlueShiftInAppNotificationDelegate.h" #import "BlueShiftInAppNotificationHelper.h" +#import "../BlueshiftLog.h" @interface BlueShiftNotificationModalViewController (){ UIView *notificationView; @@ -445,34 +446,63 @@ - (CGSize)getAutoImageSizeForNotificationView { // Check if this modal is image modal if ([self isBackgroundImagePresentForNotification:self.notification]) { - //&& (self.notification.templateStyle.width < 0 || self.notification.templateStyle.height < 0)) { //for auto width & height - - float templateWidth = 0; - if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { - templateWidth = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:self.notification.templateStyle.width forWindow:self.window]; - } - float templateHeight = 0; - if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { - templateHeight = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: self.notification.templateStyle.height forWindow:self.window]; - } - // Get max width & height in points which device can support - float maxWidthInPoints = templateWidth > 0 ? templateWidth : [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; - float maxHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationImageModalDefaultHeight forWindow:self.window]; - NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; - UIImage* image = [[UIImage alloc] initWithData:imageData]; - // If image resolution is less than the device height and width, use the image dimention. - if (image.size.width < maxWidthInPoints && image.size.height < maxHeightInPoints) { - width = image.size.width; - height = image.size.height; - } else { - // If image width/height is more than device width & height, modify the image height and width based on aspect ratio - float ratio = image.size.height/image.size.width; - width = maxWidthInPoints; - height = maxWidthInPoints * ratio; - if (height > maxHeightInPoints) { - width = maxHeightInPoints/ratio; - height = maxHeightInPoints; + @try { + BOOL isAutoHeight = NO; + BOOL isAutoWidth = NO; + + // Get width from template + float templateWidthInPoints = 0; + if (self.notification.templateStyle && self.notification.templateStyle.width > 0) { + templateWidthInPoints = [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:self.notification.templateStyle.width forWindow:self.window]; + } else { + isAutoWidth = YES; + } + + // Get height from template + float templateHeightInPoints = 0; + if(self.notification.templateStyle && self.notification.templateStyle.height > 0) { + templateHeightInPoints = [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: self.notification.templateStyle.height forWindow:self.window]; + } else { + isAutoHeight = YES; + } + + // Set max width in points which device can support + float maxWidthInPoints = templateWidthInPoints > 0 ? templateWidthInPoints : [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; + // Set max width in points to default height except when width is automatic and height is fixed + float maxHeightInPoints = (isAutoWidth == YES && templateHeightInPoints > 0) ? templateHeightInPoints : [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationImageModalDefaultHeight forWindow:self.window]; + + NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; + UIImage* image = [[UIImage alloc] initWithData:imageData]; + + // If auto height and auto width is set for image modal + // and image resolution is less than the device height and width, use the image dimention. + if (isAutoWidth == YES && isAutoHeight == YES && image.size.width < maxWidthInPoints && image.size.height < maxHeightInPoints) { + width = image.size.width; + height = image.size.height; + } else { + float ratio = image.size.height/image.size.width; + + // For fixed height and auto width, + // Resize the image using the maxHeight based on the image aspect ratio + if (isAutoWidth == YES && isAutoHeight == NO) { + height = maxHeightInPoints; + width = maxHeightInPoints/ratio; + if (width > maxWidthInPoints) { + width = maxWidthInPoints; + height = maxWidthInPoints * ratio; + } + } else { + // Resize the image using the maxWidth based on the image aspect ratio + width = maxWidthInPoints; + height = maxWidthInPoints * ratio; + if (height > maxHeightInPoints) { + height = maxHeightInPoints; + width = maxHeightInPoints/ratio; + } + } } + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } } return CGSizeMake(width, height); From 7d4e40cef1bfbfc9628d7d9b29336ab347d9ac15 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Fri, 11 Jun 2021 18:40:36 +0530 Subject: [PATCH 17/22] Set in-app max height to 90% Added logs --- .../InApps/BlueShiftInAppNotificationConstant.h | 1 - .../InApps/BlueShiftNotificationModalViewController.m | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h index fc0afc35..9c8515eb 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationConstant.h @@ -111,7 +111,6 @@ #define kInAppNotificationDefaultWidth 90.0 #define kInAppNotificationDefaultHeight 90.0 -#define kInAppNotificationImageModalDefaultHeight 100.0 #define kHTMLInAppNotificationMaximumWidthInPoints 470.0 #define kHTMLInAppNotificationMinimumHeight 25.0 diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index d862bf82..50978f55 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -469,16 +469,18 @@ - (CGSize)getAutoImageSizeForNotificationView { // Set max width in points which device can support float maxWidthInPoints = templateWidthInPoints > 0 ? templateWidthInPoints : [BlueShiftInAppNotificationHelper convertPercentageWidthToPoints:kInAppNotificationDefaultWidth forWindow:self.window]; // Set max width in points to default height except when width is automatic and height is fixed - float maxHeightInPoints = (isAutoWidth == YES && templateHeightInPoints > 0) ? templateHeightInPoints : [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationImageModalDefaultHeight forWindow:self.window]; + float maxHeightInPoints = (isAutoWidth == YES && templateHeightInPoints > 0) ? templateHeightInPoints : [BlueShiftInAppNotificationHelper convertPercentageHeightToPoints: kInAppNotificationDefaultHeight forWindow:self.window]; NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; UIImage* image = [[UIImage alloc] initWithData:imageData]; + [BlueshiftLog logInfo:@"Downloaded Image size is" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",image.size.height,image.size.width] methodName:nil]; // If auto height and auto width is set for image modal // and image resolution is less than the device height and width, use the image dimention. if (isAutoWidth == YES && isAutoHeight == YES && image.size.width < maxWidthInPoints && image.size.height < maxHeightInPoints) { width = image.size.width; height = image.size.height; + [BlueshiftLog logInfo:@"Image size using auto height and auto width" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",height,width] methodName:nil]; } else { float ratio = image.size.height/image.size.width; @@ -491,6 +493,7 @@ - (CGSize)getAutoImageSizeForNotificationView { width = maxWidthInPoints; height = maxWidthInPoints * ratio; } + [BlueshiftLog logInfo:@"Image size using fixed height and auto width" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",height,width] methodName:nil]; } else { // Resize the image using the maxWidth based on the image aspect ratio width = maxWidthInPoints; @@ -499,6 +502,7 @@ - (CGSize)getAutoImageSizeForNotificationView { height = maxHeightInPoints; width = maxHeightInPoints/ratio; } + [BlueshiftLog logInfo:@"Image size using fixed width and auto height" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",height,width] methodName:nil]; } } } @catch (NSException *exception) { From 530bba4d51e7667bbd4c217e7ecf2670d6dd06eb Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Mon, 14 Jun 2021 09:55:01 +0530 Subject: [PATCH 18/22] Modified log statement --- BlueShift-iOS-SDK/BlueShiftAppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m index 767ec473..f9c03dde 100755 --- a/BlueShift-iOS-SDK/BlueShiftAppDelegate.m +++ b/BlueShift-iOS-SDK/BlueShiftAppDelegate.m @@ -382,7 +382,7 @@ - (void)handleRemoteNotification:(NSDictionary *)userInfo { NSString *pushUUID = [userInfo valueForKey:kInAppNotificationModalMessageUDIDKey]; NSString *pushCategory = [[userInfo objectForKey: kNotificationAPSIdentifierKey] objectForKey: kNotificationCategoryIdentifierKey]; if ([pushCategory isEqualToString:kNotificationCategorySilentPushIdentifier] || [pushUUID isEqualToString:lastProcessedPushNotificationUUID]) { - [BlueshiftLog logInfo:@"Skipped processing notification due to following reasons" withDetails:@"1. The push notification is silent push notification 2. The push notification click is already processed." methodName:nil]; + [BlueshiftLog logInfo:@"Skipped processing notification due to one of the following reasons." withDetails:@"1. The push notification is silent push notification 2. The push notification click is already processed." methodName:nil]; return; } self.pushAlertDictionary = [userInfo objectForKey: kNotificationAPSIdentifierKey]; From 3227aa16dc39b32255c0f1fd8aacf3bcbc46fd26 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Tue, 15 Jun 2021 12:18:46 +0530 Subject: [PATCH 19/22] created mutable dictionary for adding browser platform Fixed memory leak issue for the html inapp --- BlueShift-iOS-SDK/BlueShift.m | 9 ++- .../BlueShiftInAppNotificationManager.m | 55 ++++++++++++------- ...BlueShiftNotificationModalViewController.m | 2 +- .../BlueShiftNotificationViewController.h | 4 +- .../BlueShiftNotificationWebViewController.h | 2 +- .../BlueShiftNotificationWebViewController.m | 8 +-- 6 files changed, 47 insertions(+), 33 deletions(-) diff --git a/BlueShift-iOS-SDK/BlueShift.m b/BlueShift-iOS-SDK/BlueShift.m index acb86e79..85b47c02 100644 --- a/BlueShift-iOS-SDK/BlueShift.m +++ b/BlueShift-iOS-SDK/BlueShift.m @@ -667,12 +667,11 @@ - (void)performRequestQueue:(NSMutableDictionary *)parameters canBatchThisEvent: if([self validateSDKTrackingRequirements] == false) { return; } - - parameters[kBrowserPlatform] = [BlueShiftDeviceData currentDeviceData].operatingSystem; - - if (parameters != nil) { + NSMutableDictionary* mutableParams = [parameters mutableCopy]; + [mutableParams setValue:[BlueShiftDeviceData currentDeviceData].operatingSystem forKey:kBrowserPlatform]; + if (mutableParams != nil) { NSString *url = [NSString stringWithFormat:@"%@%@", kBaseURL, kPushEventsUploadURL]; - BlueShiftRequestOperation *requestOperation = [[BlueShiftRequestOperation alloc] initWithRequestURL:url andHttpMethod:BlueShiftHTTPMethodGET andParameters:[parameters copy] andRetryAttemptsCount:kRequestTryMaximumLimit andNextRetryTimeStamp:0 andIsBatchEvent:isBatchEvent]; + BlueShiftRequestOperation *requestOperation = [[BlueShiftRequestOperation alloc] initWithRequestURL:url andHttpMethod:BlueShiftHTTPMethodGET andParameters:[mutableParams copy] andRetryAttemptsCount:kRequestTryMaximumLimit andNextRetryTimeStamp:0 andIsBatchEvent:isBatchEvent]; [BlueShiftRequestQueue addRequestOperation:requestOperation]; } } diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m index 9c6796b4..90e614e5 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftInAppNotificationManager.m @@ -654,33 +654,32 @@ -(void)processHTMLNotification:(BlueShiftInAppNotification*)notification display [BlueshiftLog logInfo:@"Creating HTML in-app notification to display on screen name" withDetails:displayOnScreen methodName:nil]; BlueShiftNotificationViewController* notificationVC = [[BlueShiftNotificationWebViewController alloc] initWithNotification:notification]; notificationVC.displayOnScreen = displayOnScreen; + notificationVC.delegate = self; self.currentNotificationController = notificationVC; - + BlueShiftNotificationWebViewController *webViewController = (BlueShiftNotificationWebViewController*) notificationVC; - [webViewController setupWebView:^{ - [self presentInAppViewController:notificationVC forNotification:notification]; - }]; + [webViewController setupWebView]; } // Present ViewController - (void)presentInAppViewController:(BlueShiftNotificationViewController*)notificationController forNotification:(BlueShiftInAppNotification*)notification { - if (notificationController && [BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:notificationController.displayOnScreen]) { - if(self.inAppNotificationDisplayOnPage == nil || ![self.inAppNotificationDisplayOnPage isEqualToString:notificationController.displayOnScreen]) { - self.currentNotificationController = nil; - [BlueshiftLog logInfo:@"Skipping preseting in-app notification as current screen is different than in-app notification display on screen" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; - return; - } - } void(^ presentInAppBlock)(void) = ^{ - if (notificationController && [self inAppNotificationDisplayOnPage]) { - [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; - notificationController.delegate = self; - notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; - [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; - [notificationController show:YES]; - } else { - self.currentNotificationController = nil; - [BlueshiftLog logInfo:@"Skipping preseting in-app notification as screen is not registered to receive in-app notification" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + @try { + if (notificationController && [self shouldDisplayInAppNotification:notificationController.displayOnScreen] == YES) { + [BlueshiftLog logInfo:@"Presenting in-app notification on the screen name" withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + if(notificationController.delegate == nil) { + notificationController.delegate = self; + } + notificationController.inAppNotificationDelegate = self.inAppNotificationDelegate; + [notificationController setTouchesPassThroughWindow: notification.templateStyle.enableBackgroundAction]; + [notificationController show:YES]; + } else { + self.currentNotificationController = nil; + [BlueshiftLog logInfo:@"Skipped preseting in-app notification as screen is not registered to receive in-app notification or current screen is different than in-app notification display on screen." withDetails:[self inAppNotificationDisplayOnPage] methodName:nil]; + } + + } @catch (NSException *exception) { + [BlueshiftLog logException:exception withDescription:nil methodName:[NSString stringWithUTF8String:__PRETTY_FUNCTION__]]; } }; @@ -693,6 +692,22 @@ - (void)presentInAppViewController:(BlueShiftNotificationViewController*)notific } } + +/// Check if the notification is eligible to display on the current screen. +/// @param displayOnScreen Name of screen where notification should be displayed +- (BOOL)shouldDisplayInAppNotification:(NSString*)displayOnScreen { + if ([self inAppNotificationDisplayOnPage] == nil) { + return false; + } else if ([BlueshiftEventAnalyticsHelper isNotNilAndNotEmpty:displayOnScreen]) { + if(![[self inAppNotificationDisplayOnPage] isEqualToString:displayOnScreen]) { + return false; + } else { + return true; + } + } + return true; +} + #pragma mark - In App events // Notification Click Callbacks -(void)inAppDidDismiss:(NSDictionary *)notificationPayload fromViewController:(BlueShiftNotificationViewController *)controller { diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m index 50978f55..de4d6449 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationModalViewController.m @@ -473,7 +473,7 @@ - (CGSize)getAutoImageSizeForNotificationView { NSData* imageData = [self loadAndCacheImageForURLString:self.notification.templateStyle.backgroundImage]; UIImage* image = [[UIImage alloc] initWithData:imageData]; - [BlueshiftLog logInfo:@"Downloaded Image size is" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",image.size.height,image.size.width] methodName:nil]; + [BlueshiftLog logInfo:@"Image size is" withDetails:[NSString stringWithFormat:@"H:%f, W:%f",image.size.height,image.size.width] methodName:nil]; // If auto height and auto width is set for image modal // and image resolution is less than the device height and width, use the image dimention. diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h index 9df2357f..70a18ed2 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationViewController.h @@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN @protocol BlueShiftNotificationDelegate @optional - (void)inAppDidDismiss:(NSDictionary *)notificationPayload fromViewController:(BlueShiftNotificationViewController*)controller; -- (void)inAppActionDidTapped:(NSDictionary *)notificationActionButtonPayload fromViewController:(BlueShiftNotificationViewController *) -controller; +- (void)inAppActionDidTapped:(NSDictionary *)notificationActionButtonPayload fromViewController:(BlueShiftNotificationViewController *)controller; - (void)inAppDidShow:(NSDictionary *)notification fromViewController:(BlueShiftNotificationViewController*)controller; +- (void)presentInAppViewController:(BlueShiftNotificationViewController*)notificationController forNotification:(BlueShiftInAppNotification*)notification; @end @interface BlueShiftNotificationViewController : UIViewController diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h index 644c9841..e112fdd7 100644 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN @interface BlueShiftNotificationWebViewController : BlueShiftNotificationViewController -- (void)setupWebView:(void (^)(void))block; +- (void)setupWebView; @end NS_ASSUME_NONNULL_END diff --git a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m index f309cd12..fd85b579 100755 --- a/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m +++ b/BlueShift-iOS-SDK/InApps/BlueShiftNotificationWebViewController.m @@ -18,7 +18,6 @@ @interface BlueShiftNotificationWebViewController ()didLoadWebView(); + if ([self delegate] && [[self delegate] respondsToSelector:@selector(presentInAppViewController:forNotification:)]) { + [[self delegate] presentInAppViewController:self forNotification:self.notification]; + } [self resizeWebViewAsPerContent:webView]; }); } From 4f131ea650ac97d7acaebd46820ce2ab6102475c Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Tue, 15 Jun 2021 13:27:52 +0530 Subject: [PATCH 20/22] set useinfo attributes as nullable --- BlueShift-iOS-SDK/BlueShiftUserInfo.h | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/BlueShift-iOS-SDK/BlueShiftUserInfo.h b/BlueShift-iOS-SDK/BlueShiftUserInfo.h index 9a8e068b..60642db3 100644 --- a/BlueShift-iOS-SDK/BlueShiftUserInfo.h +++ b/BlueShift-iOS-SDK/BlueShiftUserInfo.h @@ -12,37 +12,37 @@ /// Set user email id. /// Make sure you call BlueShiftUserInfo.sharedInstance()?.save() after setting/modifying any property of user info. -@property (nonatomic, strong) NSString *email; +@property (nonatomic, strong) NSString* _Nullable email; /// Set user customer id. /// Make sure you call BlueShiftUserInfo.sharedInstance()?.save() after setting/modifying any property of user info. -@property (nonatomic, strong) NSString *retailerCustomerID; +@property (nonatomic, strong) NSString* _Nullable retailerCustomerID; -@property (nonatomic, strong) NSString *name; -@property (nonatomic, strong) NSString *firstName; -@property (nonatomic, strong) NSString *lastName; +@property (nonatomic, strong) NSString* _Nullable name; +@property (nonatomic, strong) NSString* _Nullable firstName; +@property (nonatomic, strong) NSString* _Nullable lastName; -@property (nonatomic, strong) NSDate *dateOfBirth; -@property (nonatomic, strong) NSString *gender; -@property (nonatomic, strong) NSString *education; +@property (nonatomic, strong) NSDate* _Nullable dateOfBirth; +@property (nonatomic, strong) NSString* _Nullable gender; +@property (nonatomic, strong) NSString* _Nullable education; -@property (nonatomic, strong) NSDate *joinedAt; +@property (nonatomic, strong) NSDate* _Nullable joinedAt; -@property (nonatomic, strong) NSString *facebookID; +@property (nonatomic, strong) NSString* _Nullable facebookID; /// Unsubscribe from the push notifications. /// Set this flag to true if you want to stop receiving push notifications for that user. -@property NSNumber* unsubscribed; +@property NSNumber* _Nullable unsubscribed; /// The data stored in the additionalUserInfo will be populated on server with `additional_user_info__` prefix to every key name. /// If key is stored as `profession`, then server will popluate it as `additional_user_info__profession` in the events. /// Make sure you call BlueShiftUserInfo.sharedInstance()?.save() after setting/modifying the user info. -@property NSDictionary *additionalUserInfo; +@property NSMutableDictionary* _Nullable additionalUserInfo; /// The data stored in the extras will be sent to server as it is as part of every event. /// If key is stored as `profession`, then server will populate it as `profession` in the events. /// Make sure you call BlueShiftUserInfo.sharedInstance()?.save() after setting/modifying the user info. -@property NSDictionary *extras; +@property NSMutableDictionary* _Nullable extras; /// Call save method after making any change in the BlueshiftUserInfo data to store the data. - (void)save; @@ -50,10 +50,10 @@ /// Use this method to erase the stored data. + (void)removeCurrentUserInfo; -+ (instancetype) sharedInstance; ++ (instancetype _Nullable) sharedInstance; /// Returns saved User info as dictionary of key value pairs -- (NSDictionary *)toDictionary; +- (NSDictionary *_Nonnull)toDictionary; @end From d4e7e45435e6c800e0d1e05017c276612aba07cb Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Tue, 15 Jun 2021 13:50:37 +0530 Subject: [PATCH 21/22] Modified silent push category name --- BlueShift-iOS-SDK/BlueShiftNotificationConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h b/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h index 97bfd0ba..b52d68e9 100755 --- a/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h +++ b/BlueShift-iOS-SDK/BlueShiftNotificationConstants.h @@ -33,7 +33,7 @@ #define kNotificationCategoryViewCartIdentifier @"view_cart" #define kNotificationActionOpenCartIdentifier @"open_cart" -#define kNotificationCategorySilentPushIdentifier @"silent_push" +#define kNotificationCategorySilentPushIdentifier @"silent push" #define kNotificationCategoryOfferIdentifier @"promotion" #define kNotificationProductIDIdenfierKey @"product_id" #define kNotificationSelectedIndexKey @"selected_index" From 43664d3b1fd681c541ea874af24799eec92f0584 Mon Sep 17 00:00:00 2001 From: Ketan Shikhare Date: Tue, 15 Jun 2021 14:17:38 +0530 Subject: [PATCH 22/22] Added nil check for parameters attribute --- BlueShift-iOS-SDK/BlueShift.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BlueShift-iOS-SDK/BlueShift.m b/BlueShift-iOS-SDK/BlueShift.m index 85b47c02..b5338668 100644 --- a/BlueShift-iOS-SDK/BlueShift.m +++ b/BlueShift-iOS-SDK/BlueShift.m @@ -667,9 +667,9 @@ - (void)performRequestQueue:(NSMutableDictionary *)parameters canBatchThisEvent: if([self validateSDKTrackingRequirements] == false) { return; } - NSMutableDictionary* mutableParams = [parameters mutableCopy]; - [mutableParams setValue:[BlueShiftDeviceData currentDeviceData].operatingSystem forKey:kBrowserPlatform]; - if (mutableParams != nil) { + if (parameters != nil) { + NSMutableDictionary* mutableParams = [parameters mutableCopy]; + [mutableParams setValue:[BlueShiftDeviceData currentDeviceData].operatingSystem forKey:kBrowserPlatform]; NSString *url = [NSString stringWithFormat:@"%@%@", kBaseURL, kPushEventsUploadURL]; BlueShiftRequestOperation *requestOperation = [[BlueShiftRequestOperation alloc] initWithRequestURL:url andHttpMethod:BlueShiftHTTPMethodGET andParameters:[mutableParams copy] andRetryAttemptsCount:kRequestTryMaximumLimit andNextRetryTimeStamp:0 andIsBatchEvent:isBatchEvent]; [BlueShiftRequestQueue addRequestOperation:requestOperation];