Skip to content

Commit

Permalink
In-app feature parity (#308)
Browse files Browse the repository at this point in the history
* Add InApp Trigger and Limit Adapters and Matchers, ImpressionManager

* Remove event name from matchCharged

* Add sample test

* Added trigger match evaluations and tests

* added charged tests and trigger logic

* Use ordinal for CTTriggerOperator

* Add test for event without props

* Add TriggerManager

* Add BatchSentDelegate, implement todos in EvaluationManager

* added whenlimits and tests

* Fix sorting, add tests

* modified onEvery and onExact limits to use triggers instead of impressions

* Refactor CTInAppFCManager WIP

* modified days/weeks whenLimits

* Use excludeGlobalFCaps and efc

* Refactor CTInAppFCManager WIP 2

* Remove dismissedThisSession, fix inAppCounts

* Refactor CTInAppFCManager, use current storage keys since legacy are migrated

* added fetchInapps api

* added extra checks in trigger matches and unit tests

* Add InApp store

* Evaluate triggers and limits

* added storage methods for inapp store

* added encryption test

* added plaintext and encryption inapp store getters/setters

* Attach to batch header using a delegate, EvaluationManager improvements

* added completion block for fetchInApps

* Create CTInAppDisplayManager and move all in-apps logic from CleverTap

* Initialize managers

* Remove unused methods

* Improvements and refactoring

* added swizzle and queue managers

* moved private methods to an internal file. added push primer manager. fixed xcode analyser warnings

* Move in-apps parse response in category, refactor CleverTapInternal

* Move params and keys to Constants

* Add response handler to project

* Add values to Constants

* Use new limits

* Improvements

* Check daily limits as is

* Organize in-app imports and usages

* removed duplicate notification queue

* added test cases

* removed some todos

* Improve In App managers initialisation, add CTDelegateManager, refactoring and improvements.

* Fix tests

* Fix CTInAppStore

* added session manager and tests

* updated tests

* fixed inappfcmanager being nil in display manager

* fixed incorrect calls to "runningInsideAppExtension"

* fixed wrong method being called for inapp store

* ImpressionManager abstract time and date

* Fix ImpressionManager and add tests

* ImpressionManager perWeek fix and more tests

* Use constants for evtName, evtData and Items

* Rename DelegateManager, move App Launched check in a helper

* Update name

* Format campaign ti to string

* Add LimitsMatcher tests for minute, hour, day, week

* Rewrite InAppStore and add tests

* Add trigger geoRadius part1

* Add trigger geoRadius

* Do not evaluate events without eventName

* Add geoRadius tests

* Added CTInAppImagePrefetchManager class to handling preloading of images
Added logic for prefetch and clear images on disk cache

* Match triggers when value is numerical string and handle arrays

* Fix trigger evaluations and refactor tests

* Move inapp_notifs to InAppStore

* Add nullability specifiers for InAppStore

* Update storage keys format to match others

* Fix locale for scanner

* Send inapp_evals only with events queue

* Send inapp_evals only with events queue cont

* Fix limits matching for empty limits, tests for empty and multiple

* Streamline InApp notification ti parsing

* TriggerManager storage per deviceId

* Fix suppression error if cgId is nil

* Add InAppHelper for tests

* Add EvaluationManager tests

* Use InAppHelper in tests

* Move encryption test

* Add evaluated campaign ids as numbers

* Prevent out of bounds when removing elements in EvaluationManager

* Add EvaluationManager tests

* Fix SessionManager test

* Move the tests extensions into separate files

* Use deviceId for inapp_notifs storage

* Add InAppFCManager tests

* Add pragma marks

* Set the inAppStore

* Rename value to propertyValue

* Use long value for impression timestamp

* Bump version to 60000

* moved the observer handling for Push notification center delegate back to shared instance to prevent crashes

* Fix pending notifications

* Get actual prop value to support campaign properties

* Updated SDWebImage to v5.18.5

* Fix mdc session limit

* Evaluate App Launched properties and map keys to System Props

* minor bug fixes and improvements. removed duplicate and redundant code.

* Refactor event evaluation from queueEvent

* Use constants for app fields

* Remove campaign type - not supported for in-apps

* Evaluate contains operator for numbers and arrays

* Add tests for app launched, system, and notification properties

* fixed build errors Swift Package Manager apps

* Linting

* Refactor fetchInAppsBlock and handle in InAppsResponseHandler

* Fix event property name validation (#303)

* Revert "Updated SDWebImage to v5.18.5"

This reverts commit 3db772e.

* Updated prefetch manager to use prefetchURLs API.

* Added test case for image preloading

* Added support to prefetch landscape image urls.

* added more allowed class types to fix unarchive errors.

* Added support to render images from disk for each in-app templates.

* Fix equals boolean

* Image interstitial preview (#306)

* Handle image interstitial preview notification

* Add html to cocoapods

* Use constants

* Cache evaluated server-side in-app ids and suppressed client-side in-apps

* - Added support for storing multi user images.
- Updated logic for downloading and removing images.
- Updated logic for sliding time expiry.
- Updated test cases to resolve build failure.

* Add delegate manager to InAppStore

* - Added public api to delete images from disk cache.
- Refactored code changes.

* Fix InAppStore initialization

* Make default init unavailable

* Add unit tests to ensure delegates are added and behave correctly

* Fix inactive image assets and add tests

* Remove impressions and triggers for stale inapps

* Fix update of last deleted ts and ensure cleanup ts is expired

* Updated storing image assets with accountID only

* feat(inApps): Add display condition for HTML in-apps to prevent showing when there is no network.

* Used deviceInfo class to check network is reachable or not.

* Add isOnline to DeviceInfo and use it in HTML template

* fixed tvos errors

* Update storage key formats

* Fix duplicate header and use path directly

* Unit tests improvements

* Add more InAppFCManager tests

* Update CHANGELOG.md

* tvos compatibility fixes

* Fix display controller presented before scene became active (#309)

---------

Co-authored-by: Akash Malhotra <>
Co-authored-by: Akash Malhotra <carljohnson.akash@gmail.com>
Co-authored-by: Nishant Kumar <nishant.kumar@clevertap.com>
Co-authored-by: nishant-clevertap <96819882+nishant-clevertap@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 15, 2024
1 parent 79bc797 commit 8e8f05c
Showing 126 changed files with 11,151 additions and 1,742 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Change Log
All notable changes to this project will be documented in this file.

### [Version 6.0.0](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/6.0.0) (January 15, 2024)

#### Added
- Adds support for client-side in-apps.

### [Version 5.2.2](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/5.2.2) (November 21, 2023)

#### Fixed
7 changes: 3 additions & 4 deletions CleverTap-iOS-SDK.podspec
Original file line number Diff line number Diff line change
@@ -10,14 +10,13 @@ s.requires_arc = true
s.module_name = 'CleverTapSDK'
s.resources = 'CleverTapSDK/*.cer'
s.ios.dependency 'SDWebImage', '~> 5.11'
s.ios.resource_bundle = {'CleverTapSDK' => ['CleverTapSDK/**/*.{png,xib}', 'CleverTapSDK/**/*.xcdatamodeld']}
s.ios.resource_bundle = {'CleverTapSDK' => ['CleverTapSDK/**/*.{png,xib,html}', 'CleverTapSDK/**/*.xcdatamodeld']}
s.ios.deployment_target = '9.0'
s.ios.source_files = 'CleverTapSDK/**/*.{h,m}'
s.ios.exclude_files = 'CleverTapSDK/include/**/*.h'
s.ios.public_header_files = 'CleverTapSDK/CleverTap.h', 'CleverTapSDK/CleverTap+SSLPinning.h','CleverTapSDK/CleverTap+Inbox.h', 'CleverTapSDK/CleverTapInstanceConfig.h', 'CleverTapSDK/CleverTapBuildInfo.h', 'CleverTapSDK/CleverTapEventDetail.h', 'CleverTapSDK/CleverTapInAppNotificationDelegate.h', 'CleverTapSDK/CleverTapSyncDelegate.h', 'CleverTapSDK/CleverTapTrackedViewController.h', 'CleverTapSDK/CleverTapUTMDetail.h', 'CleverTapSDK/CleverTapJSInterface.h', 'CleverTapSDK/CleverTap+DisplayUnit.h', 'CleverTapSDK/CleverTap+FeatureFlags.h', 'CleverTapSDK/CleverTap+ProductConfig.h', 'CleverTapSDK/CleverTapPushNotificationDelegate.h', 'CleverTapSDK/CleverTapURLDelegate.h', 'CleverTapSDK/CleverTap+InAppNotifications.h', 'CleverTapSDK/CleverTap+SCDomain.h', 'CleverTapSDK/CleverTap+PushPermission.h', 'CleverTapSDK/InApps/CTLocalInApp.h', 'CleverTapSDK/CleverTap+CTVar.h', 'CleverTapSDK/ProductExperiences/CTVar.h', 'CleverTapSDK/LeanplumCT.h'
s.tvos.deployment_target = '9.0'
s.tvos.source_files = 'CleverTapSDK/*.{h,m}', 'CleverTapSDK/ProductConfig/**/*.{h,m}', 'CleverTapSDK/FeatureFlags/**/*.{h,m}', 'CleverTapSDK/ProductExperiences/*.{h,m}'
s.tvos.exclude_files = 'CleverTapSDK/include/**/*.h'
s.tvos.exclude_files = 'CleverTapSDK/CleverTapJSInterface.{h,m}'
s.tvos.source_files = 'CleverTapSDK/*.{h,m}', 'CleverTapSDK/ProductConfig/**/*.{h,m}', 'CleverTapSDK/FeatureFlags/**/*.{h,m}', 'CleverTapSDK/ProductExperiences/*.{h,m}', 'CleverTapSDK/Swizzling/*.{h,m}', 'CleverTapSDK/Session/*.{h,m}'
s.tvos.exclude_files = 'CleverTapSDK/include/**/*.h', 'CleverTapSDK/CleverTapJSInterface.{h,m}', 'CleverTapSDK/CTInAppNotification.{h,m}', 'CleverTapSDK/CTPushPrimerManager.{h,m}', 'CleverTapSDK/InApps/*.{h,m}', 'CleverTapSDK/InApps/**/*.{h,m}', 'CleverTapSDK/CTInAppFCManager.{h,m}', 'CleverTapSDK/CTInAppDisplayViewController.{h,m}'
s.tvos.public_header_files = 'CleverTapSDK/CleverTap.h', 'CleverTapSDK/CleverTap+SSLPinning.h', 'CleverTapSDK/CleverTapInstanceConfig.h', 'CleverTapSDK/CleverTapBuildInfo.h', 'CleverTapSDK/CleverTapEventDetail.h', 'CleverTapSDK/CleverTapSyncDelegate.h', 'CleverTapSDK/CleverTapTrackedViewController.h', 'CleverTapSDK/CleverTapUTMDetail.h', 'CleverTapSDK/CleverTap+FeatureFlags.h', 'CleverTapSDK/CleverTap+ProductConfig.h', 'CleverTapSDK/CleverTap+CTVar.h', 'CleverTapSDK/ProductExperiences/CTVar.h'
end
483 changes: 427 additions & 56 deletions CleverTapSDK.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion CleverTapSDK/CTAES.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import <Foundation/Foundation.h>
#import "CleverTap.h"

@interface CTAES : NSObject<NSSecureCoding>
@interface CTAES : NSObject <NSSecureCoding>

/**
* Returns AES128 encrypted string using the crypto framework.
@@ -15,4 +15,10 @@

- (instancetype)initWithAccountID:(NSString *)accountID encryptionLevel:(CleverTapEncryptionLevel)encryptionLevel isDefaultInstance:(BOOL)isDefaultInstance;

- (NSString *)getEncryptedBase64String:(id)objectToEncrypt;

- (id)getDecryptedObject:(NSString *)encryptedString;

- (instancetype)initWithAccountID:(NSString *)accountID;

@end
46 changes: 41 additions & 5 deletions CleverTapSDK/CTAES.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#import <CommonCrypto/CommonCryptor.h>
#import "CTAES.h"
#import <CommonCrypto/CommonCryptor.h>
#import "CTConstants.h"
#import "CTPreferences.h"
#import "CTUtils.h"
@@ -28,10 +28,11 @@ - (instancetype)initWithAccountID:(NSString *)accountID
return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject: _accountID forKey:@"accountID"];
[coder encodeBool: _isDefaultInstance forKey:@"isDefaultInstance"];
[coder encodeInt: _encryptionLevel forKey:@"encryptionLevel"];
- (instancetype)initWithAccountID:(NSString *)accountID {
if (self = [super init]) {
_accountID = accountID;
}
return self;
}

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
@@ -43,6 +44,12 @@ - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject: _accountID forKey:@"accountID"];
[coder encodeBool: _isDefaultInstance forKey:@"isDefaultInstance"];
[coder encodeInt: _encryptionLevel forKey:@"encryptionLevel"];
}

+ (BOOL)supportsSecureCoding {
return YES;
}
@@ -194,4 +201,33 @@ - (NSString *)generateKeyPassword {
return keyPassword;
}

- (NSString *)getEncryptedBase64String:(id)objectToEncrypt {
@try {
NSData *dataValue = [NSKeyedArchiver archivedDataWithRootObject:objectToEncrypt];
NSData *encryptedData = [self convertData:dataValue withOperation:kCCEncrypt];
if (encryptedData) {
return [encryptedData base64EncodedStringWithOptions:kNilOptions];
}
} @catch (NSException *e) {
CleverTapLogStaticInternal(@"Error: %@ while encrypting object: %@", e.debugDescription, objectToEncrypt);
return nil;
}
return nil;
}

- (id)getDecryptedObject:(NSString *)encryptedString {
if (!encryptedString) return nil;
@try {
NSData *dataValue = [[NSData alloc] initWithBase64EncodedString:encryptedString options:kNilOptions];
NSData *decryptedData = [self convertData:dataValue withOperation:kCCDecrypt];
if (decryptedData && decryptedData.length > 0) {
return [NSKeyedUnarchiver unarchiveObjectWithData:decryptedData];
}
} @catch (NSException *e) {
CleverTapLogStaticInternal(@"Error: %@ while decrypting string: %@", e.debugDescription, encryptedString);
return nil;
}
return nil;
}

@end
22 changes: 22 additions & 0 deletions CleverTapSDK/CTAttachToBatchHeaderDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CTAttachToBatchHeaderDelegate.h
// CleverTapSDK
//
// Created by Nikola Zagorchev on 29.09.23.
// Copyright © 2023 CleverTap. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "CTQueueType.h"

NS_ASSUME_NONNULL_BEGIN

typedef NSDictionary<NSString *, id> * _Nonnull BatchHeaderKeyPathValues;

@protocol CTAttachToBatchHeaderDelegate <NSObject>

- (BatchHeaderKeyPathValues)onBatchHeaderCreationForQueue:(CTQueueType)queueType;

@end

NS_ASSUME_NONNULL_END
19 changes: 19 additions & 0 deletions CleverTapSDK/CTBatchSentDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// CTBatchSentDelegate.h
// CleverTapSDK
//
// Created by Nikola Zagorchev on 12.09.23.
// Copyright © 2023 CleverTap. All rights reserved.
//

#import <Foundation/Foundation.h>

@protocol CTBatchSentDelegate <NSObject>

@optional
- (void)onBatchSent:(NSArray *)batchWithHeader withSuccess:(BOOL)success;

@optional
- (void)onAppLaunchedWithSuccess:(BOOL)success;

@end
19 changes: 19 additions & 0 deletions CleverTapSDK/CTBatchSentDelegateHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// CTBatchSentDelegateHelper.h
// CleverTapSDK
//
// Created by Nikola Zagorchev on 1.11.23.
// Copyright © 2023 CleverTap. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface CTBatchSentDelegateHelper : NSObject

+ (BOOL)isBatchWithAppLaunched:(NSArray *)batchWithHeader;

@end

NS_ASSUME_NONNULL_END
24 changes: 24 additions & 0 deletions CleverTapSDK/CTBatchSentDelegateHelper.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CTBatchSentDelegateHelper.m
// CleverTapSDK
//
// Created by Nikola Zagorchev on 1.11.23.
// Copyright © 2023 CleverTap. All rights reserved.
//

#import "CTBatchSentDelegateHelper.h"
#import "CTConstants.h"

@implementation CTBatchSentDelegateHelper

+ (BOOL)isBatchWithAppLaunched:(NSArray *)batchWithHeader {
// Find the event with evtName == "App Launched"
for (NSDictionary *event in batchWithHeader) {
if ([event[CLTAP_EVENT_NAME] isEqualToString:CLTAP_APP_LAUNCHED_EVENT]) {
return YES;
}
}
return NO;
}

@end
17 changes: 17 additions & 0 deletions CleverTapSDK/CTClock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// CTClock.h
// CleverTapSDK
//
// Created by Nikola Zagorchev on 27.10.23.
// Copyright © 2023 CleverTap. All rights reserved.
//

#ifndef CTClock_h
#define CTClock_h

@protocol CTClock <NSObject>
- (NSNumber *)timeIntervalSince1970;
- (NSDate *)currentDate;
@end

#endif /* CTClock_h */
Loading

0 comments on commit 8e8f05c

Please sign in to comment.