Skip to content

Commit

Permalink
Merge pull request #239 from CleverTap/develop
Browse files Browse the repository at this point in the history
Release v4.2.1
  • Loading branch information
AishwaryaNanna authored Mar 22, 2023
2 parents 7d0858a + 25deb74 commit b3066ed
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 51 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Change Log
All notable changes to this project will be documented in this file.

### [Version 4.2.1](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/4.2.1) (March 22, 2023)

#### Added
- Adds a public method `dismissAppInbox` to dismiss App Inbox.
- Adds a public method `enableLocation` for enabling location API in case of SPM.
- Adds a public method `markReadInboxMessagesForIDs` for marking multiple App Inbox messages as read by passing a collection of `messageID`s.
- Fixes a bug where CoreData would crash with threading inconsistency exceptions.
- Fixes a bug where the method `deleteInboxMessagesForIDs` would cause a crash when the message ID was null or invalid.

### [Version 4.2.0](https://github.com/CleverTap/clevertap-ios-sdk/releases/tag/4.2.0) (December 13, 2022)

#### Added
Expand Down
2 changes: 1 addition & 1 deletion CleverTap-iOS-SDK.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CleverTap-iOS-SDK"
s.version = "4.2.0"
s.version = "4.2.1"
s.summary = "The CleverTap iOS SDK for App Analytics and Engagement."
s.homepage = "https://github.com/CleverTap/clevertap-ios-sdk"
s.license = { :type => "MIT" }
Expand Down
2 changes: 0 additions & 2 deletions CleverTapSDK/CTLocationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

@interface CTLocationManager : NSObject

#if defined(CLEVERTAP_LOCATION)
+ (void)getLocationWithSuccess:(void (^)(CLLocationCoordinate2D location))success andError:(void (^)(NSString *reason))error;
#endif

@end
4 changes: 0 additions & 4 deletions CleverTapSDK/CTLocationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ @interface CleverTapLocationRequest : NSObject
@implementation CleverTapLocationRequest
@end

#if defined(CLEVERTAP_LOCATION)
NSString *const kLocationTimeoutError = @"Location Request Timed Out: Have You Set NSLocationWhenInUseUsageDescription in Your Info.plist?";
NSString *const kLocationServicesNotEnabled = @"Location Services Not Enabled";
NSString *const kLocationPermissionDenied = @"Location Permission Denied";
Expand All @@ -26,11 +25,9 @@ @implementation CleverTapLocationRequest
static NSMutableArray<CleverTapLocationRequest *> *pendingRequests;

static NSObject *requestsLockObject;
#endif

@implementation CTLocationManager

#if defined(CLEVERTAP_LOCATION)
/**
NOTE: If NSLocationWhenInUseUsageDescription is not set in the app's Info.plist, calls to the CLLocationManager instance will fail silently. Rely on the location timeout to stop updating and return an error in this case.
*/
Expand Down Expand Up @@ -201,6 +198,5 @@ + (void)stopUpdatingLocation {
locationManager.delegate = nil;
[self cancelLocationTimeout];
}
#endif

@end
16 changes: 16 additions & 0 deletions CleverTapSDK/CleverTap+Inbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ typedef void (^CleverTapInboxUpdatedBlock)(void);

- (void)markReadInboxMessageForID:(NSString * _Nonnull)messageId;

/*!
@method
@abstract
This method marks the `CleverTapInboxMessage` object as read for given 'Message Ids` as Collection.
*/

- (void)markReadInboxMessagesForIDs:(NSArray<NSString *> *_Nonnull)messageIds;

/*!
@method
Expand Down Expand Up @@ -242,5 +251,12 @@ typedef void (^CleverTapInboxUpdatedBlock)(void);
*/
- (void)recordInboxNotificationClickedEventForID:(NSString * _Nonnull)messageId;

/*!
@method
@abstract
This method dismisses the inbox controller
*/
- (void)dismissAppInbox;

@end
11 changes: 11 additions & 0 deletions CleverTapSDK/CleverTap.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,17 @@ typedef NS_ENUM(int, CTSignedCallEvent) {
*/
extern NSString * _Nonnull const CleverTapGeofencesDidUpdateNotification;

/*!
@method
@abstract
Enables the location API
@discussion
Call this method (typically once at app launch) to enable the location API.
*/
+ (void)enableLocation:(BOOL)enabled;

/*!
@method
Expand Down
39 changes: 38 additions & 1 deletion CleverTapSDK/CleverTap.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@

static const void *const kQueueKey = &kQueueKey;
static const void *const kNotificationQueueKey = &kNotificationQueueKey;
static BOOL isLocationEnabled;

static NSRecursiveLock *instanceLock;
static const int kMaxBatchSize = 49;
Expand Down Expand Up @@ -4078,11 +4079,22 @@ - (BOOL)geofenceLocation {
return _geofenceLocation;
}

+ (void)enableLocation:(BOOL)enabled{
isLocationEnabled = enabled;
}

+ (void)getLocationWithSuccess:(void (^)(CLLocationCoordinate2D location))success andError:(void (^)(NSString *reason))error; {
#if defined(CLEVERTAP_LOCATION)
[CTLocationManager getLocationWithSuccess:success andError:error];
#else
CleverTapLogStaticInfo(@"To Enable CleverTap Location services/apis please build the SDK with the CLEVERTAP_LOCATION macro");
if (isLocationEnabled){
[CTLocationManager getLocationWithSuccess:success andError:error];
}
else {
NSString *errorMsg = @"To Enable CleverTap Location services/apis please build the SDK with the CLEVERTAP_LOCATION macro or use enableLocation method";
CleverTapLogStaticDebug(@"%@",errorMsg);
error(errorMsg);
}
#endif
}

Expand Down Expand Up @@ -4354,6 +4366,18 @@ - (void)markReadInboxMessageForID:(NSString *)messageId{
[self.inboxController markReadMessageWithId:messageId];
}

- (void)markReadInboxMessagesForIDs:(NSArray<NSString *> *_Nonnull)messageIds{
if (![self _isInboxInitialized]) {
return;
}
if (messageIds != nil && [messageIds count] > 0) {
[self.inboxController markReadMessagesWithId:messageIds];
}
else {
CleverTapLogStaticDebug(@"App Inbox Message IDs array is null or empty");
}
}

- (void)registerInboxUpdatedBlock:(CleverTapInboxUpdatedBlock)block {
if (!_inboxUpdateBlocks) {
_inboxUpdateBlocks = [NSMutableArray new];
Expand All @@ -4372,6 +4396,19 @@ - (CleverTapInboxViewController * _Nullable)newInboxViewControllerWithConfig:(Cl
return [[CleverTapInboxViewController alloc] initWithMessages:messages config:config delegate:delegate analyticsDelegate:self];
}

- (void)dismissAppInbox {
[[self class] runSyncMainQueue:^{
UIApplication *application = [[self class] getSharedApplication];
UIWindow *window = [[application delegate] window];
UIViewController *presentedViewcontoller = [[window rootViewController] presentedViewController];
if ([presentedViewcontoller isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)[[window rootViewController] presentedViewController];
if ([navigationController.topViewController isKindOfClass:[CleverTapInboxViewController class]]) {
[[window rootViewController] dismissViewControllerAnimated:YES completion:nil];
}
}
}];
}

#pragma mark Private

Expand Down
2 changes: 1 addition & 1 deletion CleverTapSDK/CleverTapBuildInfo.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

#define WR_SDK_REVISION @"40200"
#define WR_SDK_REVISION @"40201"

1 change: 1 addition & 0 deletions CleverTapSDK/Inbox/controllers/CTInboxController.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)deleteMessageWithId:(NSString *)messageId;
- (void)deleteMessagesWithId:(NSArray *_Nonnull)messageIds;
- (void)markReadMessageWithId:(NSString *)messageId;
- (void)markReadMessagesWithId:(NSArray *_Nonnull)messageIds;

@end

Expand Down
131 changes: 89 additions & 42 deletions CleverTapSDK/Inbox/controllers/CTInboxController.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,19 @@ - (void)deleteMessageWithId:(NSString *)messageId {
- (void)deleteMessagesWithId:(NSArray *_Nonnull)messageIds {
NSMutableArray *toDeleteInboxMessages = [NSMutableArray new];
for (NSString *ids in messageIds) {
CTMessageMO *msg = [self _messageForId:ids];
[toDeleteInboxMessages addObject:msg];
if (ids != nil && ![ids isEqualToString:@""]){
CTMessageMO *msg = [self _messageForId:ids];
if (msg) {
[toDeleteInboxMessages addObject:msg];
}
else {
CleverTapLogStaticDebug(@"Cannot delete App Inbox Message because Message ID %@ is invalid.", ids)
}
}
else {
CleverTapLogStaticDebug(@"Cannot delete App Inbox Message because Message ID is null or not a string.");
}
}
if ([toDeleteInboxMessages count] > 0) {
[self _deleteMessages:toDeleteInboxMessages];
}
Expand All @@ -122,6 +132,27 @@ - (void)markReadMessageWithId:(NSString *)messageId {
}];
}

- (void)markReadMessagesWithId:(NSArray *_Nonnull)messageIds {
[privateContext performBlock:^{
for (NSString *ids in messageIds) {
if (ids != nil && ![ids isEqualToString:@""]){
CTMessageMO *message = [self _messageForId:ids];
if (message) {
[message setValue:@YES forKey:@"isRead"];
}
else {
CleverTapLogStaticDebug(@"Cannot mark App Inbox Message as read because Message ID %@ is invalid.", ids);
}
}
else {
CleverTapLogStaticDebug(@"Cannot mark App Inbox Message as read because Message ID is null or not a string.");
}
}
[self _save];
[self notifyUpdate];
}];
}

- (NSDictionary *)messageForId:(NSString *)messageId {
if (!self.isInitialized) return nil;
CTMessageMO *msg = [self _messageForId:messageId];
Expand Down Expand Up @@ -150,21 +181,24 @@ - (NSInteger)unreadCount {
BOOL hasMessages = ([[self.user.entity propertiesByName] objectForKey:@"messages"] != nil);
if (!hasMessages) return nil;

for (CTMessageMO *msg in self.user.messages) {
int ttl = (int)msg.expires;
if (ttl > 0 && now >= ttl) {
CleverTapLogStaticInternal(@"%@: message expires: %@, deleting", self, msg);
[toDelete addObject:msg];
} else {
[messages addObject:[msg toJSON]];
[privateContext performBlockAndWait:^{
for (CTMessageMO *msg in self.user.messages) {
int ttl = (int)msg.expires;
if (ttl > 0 && now >= ttl) {
CleverTapLogStaticInternal(@"%@: message expires: %@, deleting", self, msg);
[toDelete addObject:msg];
} else {
[messages addObject:[msg toJSON]];
}
}
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[messages sortUsingDescriptors:@[sortDescriptor]];

if ([toDelete count] > 0) {
[self _deleteMessages:toDelete];
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[messages sortUsingDescriptors:@[sortDescriptor]];

if ([toDelete count] > 0) {
[self _deleteMessages:toDelete];
}

}];
return messages;
}

Expand All @@ -177,22 +211,26 @@ - (NSInteger)unreadCount {
BOOL hasMessages = ([[self.user.entity propertiesByName] objectForKey:@"messages"] != nil);
if (!hasMessages) return nil;

NSOrderedSet *results = [self.user.messages filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"isRead == NO"]]];
for (CTMessageMO *msg in results) {
int ttl = (int)msg.expires;
if (ttl > 0 && now >= ttl) {
CleverTapLogStaticInternal(@"%@: message expires: %@, deleting", self, msg);
[toDelete addObject:msg];
} else {
[messages addObject:[msg toJSON]];
[privateContext performBlockAndWait:^{
NSOrderedSet *results = [self.user.messages filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"isRead == NO"]]];
for (CTMessageMO *msg in results) {
int ttl = (int)msg.expires;
if (ttl > 0 && now >= ttl) {
CleverTapLogStaticInternal(@"%@: message expires: %@, deleting", self, msg);
[toDelete addObject:msg];
} else {
[messages addObject:[msg toJSON]];
}
}
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[messages sortUsingDescriptors:@[sortDescriptor]];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[messages sortUsingDescriptors:@[sortDescriptor]];

if ([toDelete count] > 0) {
[self _deleteMessages:toDelete];
}
}];


if ([toDelete count] > 0) {
[self _deleteMessages:toDelete];
}
return messages;
}

Expand All @@ -204,8 +242,12 @@ - (CTMessageMO *)_messageForId:(NSString *)messageId {

BOOL hasMessages = ([[self.user.entity propertiesByName] objectForKey:@"messages"] != nil);
if (!hasMessages) return nil;

NSOrderedSet *results = [self.user.messages filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:@"id == %@", messageId]];
__block NSOrderedSet *results;

[privateContext performBlockAndWait:^{
results = [self.user.messages filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:@"id == %@", messageId]];
}];

BOOL existing = results && [results count] > 0;
return existing ? results[0] : nil;
}
Expand All @@ -222,16 +264,21 @@ - (void)_deleteMessages:(NSArray<CTMessageMO*>*)messages {

// always call from inside privateContext performBlock
- (BOOL)_save {
NSError *error = nil;
BOOL res = YES;
res = [privateContext save:&error];
if (!res) {
CleverTapLogStaticDebug(@"Error saving core data private context: %@\n%@", [error localizedDescription], [error userInfo]);
}
res = [mainContext save:&error];
if (!res) {
CleverTapLogStaticDebug(@"Error saving core data main context: %@\n%@", [error localizedDescription], [error userInfo]);
}
__block BOOL res = YES;
[privateContext performBlockAndWait:^{
NSError *error = nil;
res = [privateContext save:&error];
if (!res) {
CleverTapLogStaticDebug(@"Error saving core data main context: %@\n%@", [error localizedDescription], [error userInfo]);
}
}];
[mainContext performBlockAndWait:^{
NSError *error = nil;
res = [mainContext save:&error];
if (!res) {
CleverTapLogStaticDebug(@"Error saving core data main context: %@\n%@", [error localizedDescription], [error userInfo]);
}
}];
return res;
}

Expand Down

0 comments on commit b3066ed

Please sign in to comment.