-
Notifications
You must be signed in to change notification settings - Fork 66
SDK-5440: Implement InAction inApps and Refactor in-app notification scheduling with CTInAppScheduler #511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
…for swift-obj c interoperability
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the
WalkthroughThis PR refactors the in-app notification scheduling system, replacing the legacy CTInAppDelayManager with a new modular CTInAppScheduler framework. It introduces duration-based partitioning, timer-based scheduling with multiple storage and data extraction strategies, adds fresh app launch tracking, and enables in-action in-app fetch capabilities. Changes
Sequence DiagramsequenceDiagram
participant Client as App/Client
participant Scheduler as CTInAppScheduler
participant Timer as InAppTimerManager
participant Storage as StorageStrategy
participant Extractor as DataExtractor
participant Callback as Completion Handler
Client->>Scheduler: schedule(inApps:onComplete:)
Scheduler->>Storage: prepareForScheduling(inApps:)
Storage-->>Scheduler: prepared (true/false)
loop For each in-app with delay > 0
Scheduler->>Timer: scheduleTimer(id:delay:callback:)
Timer-->>Scheduler: DispatchWorkItem
end
Note over Timer: Wait for delay...
Timer->>Storage: retrieveAfterTimer(id:)
Storage-->>Timer: in-app data (or nil)
Timer->>Extractor: createSuccessResult(id:data:)<br/>or createErrorResult(id:)<br/>or createDiscardedResult(id:)
Extractor-->>Timer: CTTimerResult / CTDelayedInAppResult / CTInActionResult
Timer->>Callback: callback(result)
Callback-->>Client: onComplete with result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Important Action Needed: IP Allowlist UpdateIf your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:
Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
CleverTapSDK/InApps/CTInAppEvaluationManager.m (1)
144-150: Fix server-side queueing and align TTL intent.
_addInAppNotificationsToQueue:is passed@[ssInApps], which nests the array and likely enqueues a single array element instead of in-app dictionaries.- The comment says server-side should not update TTL, but
withTTL:truecan still update TTL depending on strategy.🔧 Proposed fix
- NSMutableArray *ssInApps = [self selectAndProcessEligibleInApps: eligibleInApps withStrategy:ImmediateInAppSelectionStrategy.shared withTTL: true]; - [self.inAppDisplayManager _addInAppNotificationsToQueue:@[ssInApps]]; + NSArray<NSDictionary *> *ssInApps = [self selectAndProcessEligibleInApps:eligibleInApps + withStrategy:ImmediateInAppSelectionStrategy.shared + withTTL:NO]; + [self.inAppDisplayManager _addInAppNotificationsToQueue:ssInApps];
🤖 Fix all issues with AI agents
In `@CleverTapSDK/InApps/CleverTap`+InAppsResponseHandler.m:
- Around line 93-111: The second storeClientSideInApps: call overwrites the
first; instead, when partitionImmediateDelayedInApps (ImmediateAndDelayed)
returns both immediate and delayed in-apps, merge the arrays (e.g., concatenate
partitionedClientSideInApps.immediateInApps and .delayedInApps preserving
desired order) into a single NSArray and call [self.inAppStore
storeClientSideInApps:mergedArray] once; keep the separate downloadMediaURLs:
and downloadCustomTemplatesFileURLs: invocations for each group but remove the
second storeClientSideInApps: call so storeClientSideInApps: (which assigns
_clientSideInApps) receives the combined list.
In `@CleverTapSDK/InApps/CTInAppEvaluationManager.m`:
- Around line 196-202: The server-side path in
evaluateOnAppLaunchedInActionServerSide: creates ssInAppsCopy using a shallow
mutableCopy so its NSDictionary payloads stay immutable; change the code to
deep-copy each NSDictionary into NSMutableDictionary (same approach as the
delayed path) after receiving ssInApps from
selectAndProcessEligibleInApps:withStrategy:withTTL:, then pass that array of
NSMutableDictionary objects to scheduleInActionInApps: to avoid mutation crashes
at runtime.
In `@CleverTapSDK/InApps/CTInAppStore.m`:
- Around line 438-459: The method storeServerSideInactionInApps: incorrectly
assigns the payload to _serverSideInApps, overwriting the regular server-side
in-apps cache; change the assignment to the intended in-action metadata property
(_serverSideInActionInAppsMetaData) before encrypting and persisting using
storageKeyWithSuffix:CLTAP_PREFS_INACTION_INAPP_KEY_SS, keeping the existing
encryption (cryptManager) and CTPreferences putString flow and preserving the
exception handling and logging in the same method.
- Around line 299-329: The function dequeueDelayedInAppWithCampaignId: currently
returns the matched inApp from inside the for-loop before removing it from the
delayedInAppsQueue; modify the logic in dequeueDelayedInAppWithCampaignId: so
that when a matching queuedCampaignId is found you remove the item from the
mutable delayedInAppsQueue and call storeDelayedInApps: to persist the updated
queue (using the same delayedInAppsQueue NSMutableArray), then return the
removed inApp; ensure these changes are inside the `@synchronized`(self) block and
reference the existing symbols delayedInAppsQueue, storeDelayedInApps:, and
CLTAP_INAPP_ID so the item is actually removed before returning.
In `@CleverTapSDK/InApps/InAppsScheduler/CTTimerResult.h`:
- Around line 1-14: Add the missing Foundation import and nullability
annotations to the CTTimerResult.h header: include `#import`
<Foundation/Foundation.h> at the top of the file and wrap the public
declarations (the CTTimerResultType enum) with NS_ASSUME_NONNULL_BEGIN and
NS_ASSUME_NONNULL_END to match other headers (e.g., CTInActionResult.h) so
NS_ENUM and other Foundation symbols resolve correctly.
In `@CleverTapSDK/InApps/InAppsScheduler/InactionInAppStorageStrategy.swift`:
- Around line 17-43: prepareForScheduling currently writes to inActionCache
without synchronization causing data races with retrieveAfterTimer; wrap the
write loop into cacheQueue.sync(flags: .barrier) to ensure exclusive access and
that the method only returns after caching completes, keeping the weak self
guard (guard let self = self else { return true }) and updating
cachedCount/inActionCache inside that barrier block while preserving the same
inActionId logic.
In `@CleverTapSDK/InApps/InAppsScheduler/InAppDataExtractor.swift`:
- Around line 61-71: In InAppDataExtractor.extractDelay the code claims the
stored value is milliseconds but returns it unchanged; update extractDelay to
convert milliseconds to seconds before returning (divide the extracted
Int/Double by 1000.0), and handle numeric types robustly (Int, Double, NSNumber)
so the method returns a TimeInterval in seconds consistent with
DelayedInAppDataExtractor; reference the InAppDataExtractor.extractDelay method
to locate and change the conversion logic.
In `@CleverTapSDK/InApps/InAppsScheduler/InAppScheduler.swift`:
- Around line 67-71: The loop over newInApps uses the wrong key ("id") when
extracting the in-app identifier which causes nil/incorrect IDs to be passed to
dataExtractor?.createErrorResult(id:message:) and onComplete(result); update the
guard in the loop that currently reads let id = inApp["id"] to use the
consistent key "ti" (i.e., guard let id = inApp["ti"] as? String else { continue
}) so the error callback receives the correct identifier (ensure you update the
extraction in the for-in loop where newInApps,
dataExtractor?.createErrorResult(id:message:), and onComplete(result) are
referenced).
In `@CleverTapSDK/InApps/InAppsScheduler/InAppSelectionStrategy.swift`:
- Around line 137-138: The constant INAPP_DELAY_AFTER_TRIGGER in
InAppSelectionStrategy (currently set to "delay") mismatches
InAppDelayConstants.INAPP_DELAY_AFTER_TRIGGER (which is "delayAfterTrigger"),
causing key inconsistencies; update INAPP_DELAY_AFTER_TRIGGER to use the exact
same key ("delayAfterTrigger") as InAppDelayConstants.INAPP_DELAY_AFTER_TRIGGER,
or refactor usages to reference InAppDelayConstants.INAPP_DELAY_AFTER_TRIGGER
directly (search for INAPP_DELAY_AFTER_TRIGGER, InAppSelectionStrategy, and
InAppDurationPartitioner to align all usages).
In `@CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift`:
- Around line 114-120: Remove all leftover commented-out code blocks in
InAppTimerManager (e.g., the commented Thread.current.isCancelled check and
other commented sections around timer handling and job storage). Clean up
comments near symbols like InAppTimerManager,
storeCancelledJob(id:delay:scheduledAt:callback:), removeActiveJob(id:), and any
prints referencing self.tag so only relevant inline comments remain; ensure no
functional change is introduced—only delete the commented-out code fragments
mentioned in the review.
- Around line 157-168: cancelAllTimers() currently unlocks before cancelling,
which allows scheduleTimer() to add new timers that might be incorrectly
cancelled and leaves stale entries; fix by acquiring lock, copying the current
workItems from activeJobs (e.g., map values' workItem), clearing activeJobs
(activeJobs.removeAll()) while still holding the lock, then release the lock and
iterate to cancel the copied workItems (workItem.cancel()), and finally log the
cancelledCount; update the method to reference cancelAllTimers(), activeJobs,
workItem, scheduleTimer(), and cleanup() accordingly.
🟡 Minor comments (13)
CleverTapSDK.xcodeproj/project.pbxproj-332-342 (1)
332-342: Confirm header visibility for new InApp result types.Lines 339-341 and 2317-2319 add the new headers without
ATTRIBUTES, so they default to Project visibility. The codebase convention is to explicitly set header visibility (as seen in other header entries withsettings = {ATTRIBUTES = (Public, ); }orATTRIBUTES = (Private, ); }). If these types are meant to be visible to Swift or exposed in the framework module map, set the visibility explicitly.🔧 Suggested update if these headers must be exposed
-57B7E7772F2B33C000CF22E1 /* CTInActionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E7702F2B33C000CF22E1 /* CTInActionResult.h */; }; -57B7E7782F2B33C000CF22E1 /* CTTimerResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E7722F2B33C000CF22E1 /* CTTimerResult.h */; }; -57B7E7792F2B33C000CF22E1 /* CTDelayedInAppResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E76E2F2B33C000CF22E1 /* CTDelayedInAppResult.h */; }; +57B7E7772F2B33C000CF22E1 /* CTInActionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E7702F2B33C000CF22E1 /* CTInActionResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; +57B7E7782F2B33C000CF22E1 /* CTTimerResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E7722F2B33C000CF22E1 /* CTTimerResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; +57B7E7792F2B33C000CF22E1 /* CTDelayedInAppResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7E76E2F2B33C000CF22E1 /* CTDelayedInAppResult.h */; settings = {ATTRIBUTES = (Public, ); }; };CleverTapSDK/InApps/InAppDurationPartitioner.swift-1-7 (1)
1-7: File header comment doesn't match filename.The header comment says
InAppDelayConstants.swiftbut the actual filename isInAppDurationPartitioner.swift.✏️ Suggested fix
// -// InAppDelayConstants.swift +// InAppDurationPartitioner.swift // CleverTapSDK //CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift-1-7 (1)
1-7: File header comment doesn't match filename.The header says
InAppSchedulingStrategy.swiftbut the actual filename isInAppTimerManager.swift.✏️ Suggested fix
// -// InAppSchedulingStrategy.swift +// InAppTimerManager.swift // CleverTapSDK //CleverTapSDK/InApps/InAppDurationPartitioner.swift-43-50 (1)
43-50: Documentation lists methods that don't exist.The class documentation mentions
partitionLegacyInApps,partitionClientSideInApps, andpartitionAppLaunchServerSideInAppsbut the actual method names arepartitionImmediateDelayedInApps,partitionLegacyMetaInApps,partitionServerSideMetaInApps, andpartitionAppLaunchServerSideMetaInApps.✏️ Suggested fix
* Provides specialized partition functions for different in-app sources: - * - `partitionLegacyInApps`: immediate + delayed + * - `partitionImmediateDelayedInApps`: immediate + delayed (used for legacy, CS, and app-launch SS) * - `partitionLegacyMetaInApps`: inAction only - * - `partitionClientSideInApps`: immediate + delayed * - `partitionServerSideMetaInApps`: unknown + inAction - * - `partitionAppLaunchServerSideInApps`: immediate + delayed * - `partitionAppLaunchServerSideMetaInApps`: inAction onlyCleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift-387-402 (1)
387-402: Remove unusedCTCancelledJobDataclass.
CTCancelledJobDataduplicates the privateCancelledJobDatastruct and is not used anywhere in the codebase. Despite the@objcannotation suggesting Objective-C interop, the complete absence of references indicates it is dead code.CleverTapSDK/CleverTap.m-145-146 (1)
145-146: Add synchronization to prevent concurrent writes to the fresh‑launch flag.
freshAppLaunchSentis a file-static variable shared across all CleverTap instances, butisFreshAppLaunchis an instance method with no synchronization. Since multiple SDK instances can exist and call this method concurrently,freshAppLaunchSentcan be read and written without ordering guarantees, violating the one-shot-per-process intent. Wrap the read-modify-write with@synchronized([CleverTap class]).Fix
- (BOOL)isFreshAppLaunch { - BOOL isInitialTimeRecorded = (initialAppEnteredForegroundTime > 0); - BOOL result = isInitialTimeRecorded && !freshAppLaunchSent; - freshAppLaunchSent = isInitialTimeRecorded; - return result; -} + (BOOL)isFreshAppLaunch { + `@synchronized`([CleverTap class]) { + BOOL isInitialTimeRecorded = (initialAppEnteredForegroundTime > 0); + BOOL result = isInitialTimeRecorded && !freshAppLaunchSent; + freshAppLaunchSent = isInitialTimeRecorded; + return result; + } +}Also applies to: 839-841, 856-861
CleverTapSDK/CleverTap.m-3696-3703 (1)
3696-3703: Add input validation tofetchInactionInApps:to handle non-numeric campaign IDs.The
integerValuemethod returns0for non-numeric strings, which silently enqueues a fetch for campaign ID0instead of failing or logging the issue. Consider validating thatinAppIdis numeric before conversion, or short-circuit with an early return for invalid inputs.✅ Input validation + safe conversion
- (void)fetchInactionInApps:(NSString *)inAppId { - NSNumber *campaignId = @([inAppId integerValue]); - NSDictionary *eventData = @{ - @"t": @(6), - @"tgtId": campaignId // Use inAppId directly if it's already NSNumber or typecast to NSString - }; - [self queueEvent:@{CLTAP_EVENT_NAME: CLTAP_WZRK_FETCH_EVENT, CLTAP_EVENT_DATA: eventData} withType:CleverTapEventTypeFetch]; -} + (void)fetchInactionInApps:(NSString *)inAppId { + if (inAppId.length == 0) { + CleverTapLogDebug(self.config.logLevel, @"%@: fetchInactionInApps called with empty inAppId", self); + return; + } + NSScanner *scanner = [NSScanner scannerWithString:inAppId]; + NSInteger campaignValue; + if (![scanner scanInteger:&campaignValue] || !scanner.isAtEnd) { + CleverTapLogDebug(self.config.logLevel, @"%@: fetchInactionInApps called with non-numeric inAppId: %@", self, inAppId); + return; + } + NSDictionary *eventData = @{ + @"t": @(6), + @"tgtId": @(campaignValue) + }; + [self queueEvent:@{CLTAP_EVENT_NAME: CLTAP_WZRK_FETCH_EVENT, CLTAP_EVENT_DATA: eventData} withType:CleverTapEventTypeFetch]; +}CleverTapSDK/InApps/InAppsScheduler/CTInActionResult.m-12-18 (1)
12-18: Missing[inActionId copy]inreadyToFetchWithId:data:.The
inActionIdis assigned directly without copying, unlike themessageproperty in other factory methods (lines 24, 32, 40). For consistency and safety with NSString properties, use[inActionId copy].🐛 Proposed fix
+ (instancetype)readyToFetchWithId:(NSString *)inActionId data:(NSDictionary<NSString *, id> *)data { CTInActionResult *result = [[CTInActionResult alloc] init]; result->_type = CTInActionResultTypeReadyToFetch; - result->_inActionId = inActionId; + result->_inActionId = [inActionId copy]; result->_data = data; return result; }CleverTapSDK/InApps/InAppsScheduler/CTInActionResult.m-20-42 (1)
20-42: InconsistentinActionIdhandling across factory methods.
errorWithId:,discardedWithId:, andcancelledWithId:also assigninActionIddirectly without[copy]. Apply the same fix to all factory methods for consistency.🐛 Proposed fix for all factory methods
+ (instancetype)errorWithId:(NSString *)inActionId message:(NSString *)message { CTInActionResult *result = [[CTInActionResult alloc] init]; result->_type = CTInActionResultTypeError; - result->_inActionId = inActionId; + result->_inActionId = [inActionId copy]; result->_message = [message copy]; return result; } + (instancetype)discardedWithId:(NSString *)inActionId message:(NSString *)message { CTInActionResult *result = [[CTInActionResult alloc] init]; result->_type = CTInActionResultTypeDiscarded; - result->_inActionId = inActionId; + result->_inActionId = [inActionId copy]; result->_message = [message copy]; return result; } + (instancetype)cancelledWithId:(NSString *)inActionId message:(NSString *)message { CTInActionResult *result = [[CTInActionResult alloc] init]; result->_type = CTInActionResultTypeCancelled; - result->_inActionId = inActionId; + result->_inActionId = [inActionId copy]; result->_message = [message copy]; return result; }CleverTapSDK/InApps/InAppsScheduler/InAppScheduler.swift-123-136 (1)
123-136: Potential nil assignment whendataExtractoris nil.When
dataExtractoris nil,createErrorResultandcreateSuccessResultreturn nil via optional chaining. The localresultvariable is typed asAny(non-optional) but will receive nil, which then gets passed toonComplete. This could cause unexpected behavior downstream.Consider adding a guard or providing a fallback result when
dataExtractoris unavailable.🛡️ Proposed fix with guard
case .completed: // Timer completed, retrieve and process - let result: Any guard let resultId = timerResult.resultId else { - result = self.dataExtractor?.createErrorResult(id: id, message: "Data not found") - onComplete(result) + if let errorResult = self.dataExtractor?.createErrorResult(id: id, message: "Data not found") { + onComplete(errorResult) + } return } let data = self.storageStrategy?.retrieveAfterTimer(id: resultId) + let result: Any? if let data = data as? [String: Any] { result = self.dataExtractor?.createSuccessResult(id: resultId, data: data) } else { result = self.dataExtractor?.createErrorResult(id: resultId, message: "Data not found") } - onComplete(result) + if let result = result { + onComplete(result) + }CleverTapSDK/InApps/CTInAppDisplayManager.m-206-223 (1)
206-223: Dead statement and redundantmutableCopycalls.Line 214
[result.data mutableCopy];is a dead statement with no effect. Lines 216-217 each create a new mutable copy of the same data. This is both wasteful and potentially error-prone if modifications are expected to persist.🐛 Proposed fix
switch (result.type) { case CTDelayedInAppResultTypeSuccess: - [result.data mutableCopy]; - NSLog(@"Updating TTL"); - [strongSelf.inAppStore updateTTL:[result.data mutableCopy]]; - [strongSelf _addInAppNotificationsToQueue:@[[result.data mutableCopy]]]; + { + NSMutableDictionary *inAppData = [result.data mutableCopy]; + CleverTapLogInternal(strongSelf.config.logLevel, @"%@: Updating TTL for delayed in-app", strongSelf); + [strongSelf.inAppStore updateTTL:inAppData]; + [strongSelf _addInAppNotificationsToQueue:@[inAppData]]; + } break; case CTDelayedInAppResultTypeError: break; case CTDelayedInAppResultTypeDiscarded: break; }CleverTapSDK/InApps/CTInAppStore.m-480-501 (1)
480-501:storeServerSideInActionMetaData:is not declared in the header and appears to be dead code.The method is defined at line 480 in the implementation but has no declaration in
CTInAppStore.hand is never called anywhere in the codebase. Consider removing this unused method. Note: the header does contain a similarly-named methodstoreServerSideInactionInApps:which may have been intended here instead.CleverTapSDK/InApps/InAppsScheduler/InAppDataExtractor.swift-26-36 (1)
26-36: Correct the misleading variable naming and comment — delayAfterTrigger is already in seconds.According to CleverTap documentation,
delayAfterTriggeris specified in seconds, not milliseconds. The code is correct, but the variable namedelayMsand the comment "Assuming delay is stored in milliseconds, convert to seconds" are misleading. RenamedelayMstodelay(ordelaySecs) and update the comment to reflect that the value is already in seconds.`@objc` public func extractDelay(inApp: [String: Any]) -> TimeInterval { // Extract delay from in-app dictionary - // Assuming delay is stored in milliseconds, convert to seconds - if let delayMs = inApp["delayAfterTrigger"] as? Int { - return TimeInterval(delayMs) + // Delay is specified in seconds by CleverTap + if let delay = inApp["delayAfterTrigger"] as? Int { + return TimeInterval(delay) } - if let delayMs = inApp["delayAfterTrigger"] as? Double { - return TimeInterval(delayMs) + if let delay = inApp["delayAfterTrigger"] as? Double { + return TimeInterval(delay) } return 0 }
🧹 Nitpick comments (18)
CleverTapSDK/InApps/CTInAppDisplayManager.h (1)
47-48: Add element typing (and clarify nil semantics) for new public APIs.Because
NSArray * _Nullablemaps to[Any]?in Swift, callers can pass unexpected payloads silently. Consider documenting the expected element type and (optionally) using Objective‑C generics; also clarify whethernilis valid or if callers should pass an empty array.♻️ Suggested header refinement (adjust element type as appropriate)
- - (void)scheduleInActionInApps:(NSArray * _Nullable)inappNotifs; - - (void)scheduleDelayedInAppsForAllModes:(NSArray * _Nullable)inappNotifs; +/// Schedules in-app payloads; replace NSDictionary with the concrete payload type if different. +- (void)scheduleInActionInApps:(NSArray<NSDictionary *> * _Nullable)inappNotifs; +/// Schedules delayed in-app payloads for all display modes. +- (void)scheduleDelayedInAppsForAllModes:(NSArray<NSDictionary *> * _Nullable)inappNotifs;CleverTapSDK.xcodeproj/project.pbxproj (1)
1244-1245: Consider nestingInAppDurationPartitioner.swiftunder the new scheduler group for consistency.Right now it sits alongside the
InAppsSchedulergroup, while the rest of the scheduler files are grouped together. Moving it underInAppsSchedulerkeeps the structure coherent.🧭 Suggested group placement
children = ( 57B7E7542F220A9300CF22E1 /* InAppsScheduler */, - 57CDEE402F163C4E001161F5 /* InAppDurationPartitioner.swift */, 6BB727102B8E455B009CE7D0 /* CustomTemplates */, @@ 57B7E7542F220A9300CF22E1 /* InAppsScheduler */ = { isa = PBXGroup; children = ( + 57CDEE402F163C4E001161F5 /* InAppDurationPartitioner.swift */, 57B7E76E2F2B33C000CF22E1 /* CTDelayedInAppResult.h */,Also applies to: 1592-1607
CleverTapSDK/InApps/CleverTap+InAppsResponseHandler.m (1)
83-91: Minor: Inconsistent comment indentation.Line 85 comment has extra indentation that doesn't align with surrounding code.
✏️ Suggested fix
// SS in-apps (inapp_notifs_ss -> IN-ACTION + NORMAL in-app campaigns WITH advance display rules) UnknownAndInAction *partitionedServerSideInAppsMeta = [InAppDurationPartitioner partitionServerSideMetaInApps:jsonResp[CLTAP_INAPP_SS_JSON_RESPONSE_KEY]]; - // delayAfterTrigger only comes within inapp_notifs(Legacy SS, with in-app content) + // delayAfterTrigger only comes within inapp_notifs(Legacy SS, with in-app content) if ([partitionedServerSideInAppsMeta hasUnknownDurationInApps]) {CleverTapSDK/InApps/InAppsScheduler/CTDelayedInAppResult.h (1)
16-20: Consider prefixing the enum to avoid naming conflicts.
CTErrorReasonis a generic name that could conflict with other error enums in the codebase or when integrating with other libraries. Consider a more specific prefix likeCTDelayedInAppErrorReason.✏️ Suggested rename
-typedef NS_ENUM(NSInteger, CTErrorReason) { - CTErrorReasonUnknown, - CTErrorReasonPreparationFailed, - CTErrorReasonDataNotFound +typedef NS_ENUM(NSInteger, CTDelayedInAppErrorReason) { + CTDelayedInAppErrorReasonUnknown, + CTDelayedInAppErrorReasonPreparationFailed, + CTDelayedInAppErrorReasonDataNotFound };Then update Line 31:
-@property (nonatomic, readonly) CTErrorReason reason; +@property (nonatomic, readonly) CTDelayedInAppErrorReason reason;CleverTapSDK/InApps/InAppsScheduler/CTDelayedInAppResult.m (1)
11-17: Consider copying the data dictionary for safety.The
datadictionary is assigned directly without copying. If the caller mutates the dictionary after creating the result, it could lead to unexpected behavior.✏️ Suggested fix
+ (instancetype)successWithId:(NSString *)resultId data:(NSDictionary<NSString *, id> *)data { CTDelayedInAppResult *result = [[CTDelayedInAppResult alloc] init]; result->_type = CTDelayedInAppResultTypeSuccess; result->_resultId = [resultId copy]; - result->_data = data; + result->_data = [data copy]; return result; }CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift (1)
89-89: ReplaceDebug output uses
print()statements throughout the file. For consistency with the rest of the SDK and to support log levels, consider usingCleverTapLogDebugor the SDK's logging infrastructure.Also applies to: 105-105, 135-135, 152-152, 167-167, 212-212, 221-221, 266-266, 278-278, 296-298, 318-318
CleverTapSDK/InApps/InAppsScheduler/InAppSelectionStrategy.swift (2)
114-129: Non-deterministic iteration order over dictionary.The iteration over
delayedInAppsByDelaydictionary (Line 114) has no guaranteed order in Swift. While this may not affect correctness since each delay group is independent, it could lead to non-deterministic logging output and potentially affect debugging.✏️ Suggested fix for deterministic iteration
- for (delay, inAppsWithSameDelay) in delayedInAppsByDelay { + for delay in delayedInAppsByDelay.keys.sorted() { + guard let inAppsWithSameDelay = delayedInAppsByDelay[delay] else { continue } print( "\(DelayedInAppSelectionStrategy.TAG), message: Processing \(inAppsWithSameDelay.count) in-apps with delay: \(delay)s")
115-115: ReplaceDebug output should use the SDK's logging infrastructure for consistency and to respect log level settings.
Also applies to: 127-127
CleverTapSDK/InApps/DurationPartitionedInApps.swift (1)
42-45: Align initializer visibility with the public API.These classes are
publicbut their initializers are internal, which prevents SDK consumers from constructing non-empty instances. If external construction is intended, make the initializerspublic; otherwise consider reducing the class visibility to internal.♻️ Suggested visibility alignment
- init(immediateInApps: NSArray, delayedInApps: NSArray) { + `@objc` public init(immediateInApps: NSArray, delayedInApps: NSArray) { self.immediateInApps = immediateInApps self.delayedInApps = delayedInApps super.init() } @@ - init(unknownDurationInApps: NSArray, inActionInApps: NSArray) { + `@objc` public init(unknownDurationInApps: NSArray, inActionInApps: NSArray) { self.unknownDurationInApps = unknownDurationInApps self.inActionInApps = inActionInApps super.init() } @@ - init(inActionInApps: NSArray) { + `@objc` public init(inActionInApps: NSArray) { self.inActionInApps = inActionInApps super.init() }Also applies to: 72-75, 103-105
CleverTapSDK/InApps/InAppsScheduler/InAppSchedulingStrategy.swift (1)
11-17: Clean up the commented‑out doc block.The
// / ...lines look like accidental comment remnants. Consider converting them to proper doc comments or removing for clarity.📝 Tidy doc comments
-// / Prepare data before scheduling (e.g., save to DB) -// / - Parameter inApps: Array of in-app dictionaries -// / - Returns: true if preparation successful, false otherwise + /// Prepare data before scheduling (e.g., save to DB) + /// - Parameter inApps: Array of in-app dictionaries + /// - Returns: true if preparation successful, false otherwiseCleverTapSDK/InApps/InAppsScheduler/DelayedInAppStorageStrategy.swift (2)
34-35: Redundant and incorrect optional cast.The cast
(inApp as? [String : Any]?) ?? nilis unnecessarily complex. IfdequeueDelayedInAppreturnsAny?, you should cast directly to the expected type.♻️ Proposed fix
- let inApp = store.dequeueDelayedInApp(withCampaignId: id) - return (inApp as? [String : Any]?) ?? nil + return store.dequeueDelayedInApp(withCampaignId: id) as? [String: Any]
38-40: Emptyclear(id:)method may be intentional but warrants clarification.The method body is empty while
InactionInAppStorageStrategy.clear(id:)actually removes items from cache. If this is intentional becausedequeueDelayedInAppalready removes the item from storage, consider adding a comment to clarify this design decision.📝 Suggested documentation
public func clear(id: String) { - + // No-op: dequeueDelayedInApp already removes the item from persistent storage }CleverTapSDK/InApps/InAppsScheduler/InAppScheduler.swift (1)
147-148: Discarded return values fromretrieveAfterTimerin error/discarded cases.In the
erroranddiscardedcases,retrieveAfterTimeris called but its return value is ignored. If the intent is to clean up storage by dequeuing, consider adding a comment to clarify. If actual cleanup is needed, uncomment theclear(id:)calls or use_ =to explicitly discard the value.Also applies to: 154-155
CleverTapSDK/InApps/InAppsScheduler/CTInActionResult.h (1)
22-22: Consider addingcopyattribute toinActionIdproperty.For consistency with
CTTimerResult.hwhereresultIdis declared withcopy, and following Objective-C best practices forNSStringproperties,inActionIdshould also use thecopyattribute to prevent unexpected mutation if a mutable string is passed.♻️ Proposed fix
-@property (nonatomic, readonly) NSString* inActionId; +@property (nonatomic, readonly, copy) NSString *inActionId;CleverTapSDK/InApps/InAppsScheduler/InactionInAppStorageStrategy.swift (2)
45-57: Redundant cast on Line 56.
resultis already typed as[String: Any]?, so the castas? [String : Any]is unnecessary.♻️ Proposed fix
- return result as? [String : Any] + return result
18-18: Consider using CleverTap's logging system instead ofThe
CleverTapLogInternalor similar) which respects log levels and can be disabled in production.Also applies to: 38-38, 41-41, 51-51, 53-53, 63-63, 72-72
CleverTapSDK/InApps/InAppsScheduler/InAppDataExtractor.swift (1)
85-87:createCancelledResultduplicatescreateDiscardedResultlogic.Both methods return
CTInActionResult.discardedwith the same message. If "cancelled" has different semantics than "discarded", consider using a distinct message or result type. If they're truly equivalent, consider removing one or havingcreateCancelledResultcallcreateDiscardedResult.CleverTapSDK/InApps/CTInAppDisplayManager.m (1)
208-208: UseCleverTapLogInternalinstead ofNSLogfor consistency.Multiple
NSLogstatements are used throughout the new scheduling methods. For consistency with the rest of the SDK and to respect log-level configuration, these should useCleverTapLogInternalor appropriate CleverTap logging macros.Also applies to: 227-227, 237-237, 240-240, 243-243, 249-249
| - (void)evaluateOnAppLaunchedInActionServerSide:(NSArray *)appLaunchedNotifs { | ||
| CTEventAdapter *event = [[CTEventAdapter alloc] initWithEventName:CLTAP_APP_LAUNCHED_EVENT eventProperties:self.appLaunchedProperties andLocation:self.location]; | ||
| NSMutableArray *eligibleInApps = [self evaluate:event withInApps:appLaunchedNotifs]; | ||
| // Server-side evaluations do **NOT** update TTL | ||
| NSMutableArray *ssInApps = [self selectAndProcessEligibleInApps: eligibleInApps withStrategy:ImmediateInAppSelectionStrategy.shared withTTL: true]; | ||
| NSMutableArray<NSMutableDictionary *> *ssInAppsCopy = [ssInApps mutableCopy]; | ||
| [self.inAppDisplayManager scheduleInActionInApps: ssInAppsCopy]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure in-action scheduling receives mutable dictionaries.
ssInAppsCopy is only a shallow array copy; the dictionaries remain immutable. If scheduleInActionInApps: mutates payloads (as the delayed path suggests), this can throw at runtime. Consider deep-copying the dictionaries as done in the delayed path.
🔧 Proposed fix
- NSMutableArray<NSMutableDictionary *> *ssInAppsCopy = [ssInApps mutableCopy];
- [self.inAppDisplayManager scheduleInActionInApps: ssInAppsCopy];
+ NSMutableArray<NSMutableDictionary *> *ssInAppsCopy = [NSMutableArray arrayWithCapacity:ssInApps.count];
+ for (NSDictionary *inApp in ssInApps) {
+ [ssInAppsCopy addObject:[inApp mutableCopy]];
+ }
+ [self.inAppDisplayManager scheduleInActionInApps:ssInAppsCopy];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - (void)evaluateOnAppLaunchedInActionServerSide:(NSArray *)appLaunchedNotifs { | |
| CTEventAdapter *event = [[CTEventAdapter alloc] initWithEventName:CLTAP_APP_LAUNCHED_EVENT eventProperties:self.appLaunchedProperties andLocation:self.location]; | |
| NSMutableArray *eligibleInApps = [self evaluate:event withInApps:appLaunchedNotifs]; | |
| // Server-side evaluations do **NOT** update TTL | |
| NSMutableArray *ssInApps = [self selectAndProcessEligibleInApps: eligibleInApps withStrategy:ImmediateInAppSelectionStrategy.shared withTTL: true]; | |
| NSMutableArray<NSMutableDictionary *> *ssInAppsCopy = [ssInApps mutableCopy]; | |
| [self.inAppDisplayManager scheduleInActionInApps: ssInAppsCopy]; | |
| - (void)evaluateOnAppLaunchedInActionServerSide:(NSArray *)appLaunchedNotifs { | |
| CTEventAdapter *event = [[CTEventAdapter alloc] initWithEventName:CLTAP_APP_LAUNCHED_EVENT eventProperties:self.appLaunchedProperties andLocation:self.location]; | |
| NSMutableArray *eligibleInApps = [self evaluate:event withInApps:appLaunchedNotifs]; | |
| // Server-side evaluations do **NOT** update TTL | |
| NSMutableArray *ssInApps = [self selectAndProcessEligibleInApps: eligibleInApps withStrategy:ImmediateInAppSelectionStrategy.shared withTTL: true]; | |
| NSMutableArray<NSMutableDictionary *> *ssInAppsCopy = [NSMutableArray arrayWithCapacity:ssInApps.count]; | |
| for (NSDictionary *inApp in ssInApps) { | |
| [ssInAppsCopy addObject:[inApp mutableCopy]]; | |
| } | |
| [self.inAppDisplayManager scheduleInActionInApps:ssInAppsCopy]; |
🤖 Prompt for AI Agents
In `@CleverTapSDK/InApps/CTInAppEvaluationManager.m` around lines 196 - 202, The
server-side path in evaluateOnAppLaunchedInActionServerSide: creates
ssInAppsCopy using a shallow mutableCopy so its NSDictionary payloads stay
immutable; change the code to deep-copy each NSDictionary into
NSMutableDictionary (same approach as the delayed path) after receiving ssInApps
from selectAndProcessEligibleInApps:withStrategy:withTTL:, then pass that array
of NSMutableDictionary objects to scheduleInActionInApps: to avoid mutation
crashes at runtime.
| - (NSDictionary *)dequeueDelayedInAppWithCampaignId:(NSString *)campaignId { | ||
| if (!campaignId) return nil; | ||
|
|
||
| @synchronized(self) { | ||
| NSMutableArray *delayedInAppsQueue = [[NSMutableArray alloc] initWithArray:[self delayedInAppsQueue]]; | ||
|
|
||
| NSUInteger indexToRemove = NSNotFound; | ||
| for (NSUInteger i = 0; i < delayedInAppsQueue.count; i++) { | ||
| NSDictionary *inApp = delayedInAppsQueue[i]; | ||
| NSString *queuedCampaignId = inApp[CLTAP_NOTIFICATION_ID_TAG]; | ||
|
|
||
| if ([queuedCampaignId isEqualToString:campaignId]) { | ||
| id queuedCampaignIdObj = inApp[CLTAP_INAPP_ID]; | ||
| NSString *queuedCampaignId; | ||
|
|
||
| if ([queuedCampaignIdObj isKindOfClass:[NSNumber class]]) { | ||
| queuedCampaignId = [(NSNumber *)queuedCampaignIdObj stringValue]; | ||
| } else if ([queuedCampaignIdObj isKindOfClass:[NSString class]]) { | ||
| queuedCampaignId = (NSString *)queuedCampaignIdObj; | ||
| } else { | ||
| queuedCampaignId = [queuedCampaignIdObj description]; | ||
| } | ||
| if ([queuedCampaignId isEqualToString:campaignId]) { | ||
| indexToRemove = i; | ||
| break; | ||
| return inApp; | ||
| } | ||
| } | ||
|
|
||
| if (indexToRemove != NSNotFound) { | ||
| [delayedInAppsQueue removeObjectAtIndex:indexToRemove]; | ||
| [self storeDelayedInApps:delayedInAppsQueue]; | ||
| } | ||
| return nil; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical bug: dequeueDelayedInAppWithCampaignId: returns before removing the item.
The method returns inApp at line 320 while still inside the loop, before the removal logic at lines 323-326 can execute. This means the delayed in-app is never removed from the queue, causing it to be processed repeatedly.
🐛 Proposed fix
- (NSDictionary *)dequeueDelayedInAppWithCampaignId:(NSString *)campaignId {
if (!campaignId) return nil;
`@synchronized`(self) {
NSMutableArray *delayedInAppsQueue = [[NSMutableArray alloc] initWithArray:[self delayedInAppsQueue]];
- NSUInteger indexToRemove = NSNotFound;
for (NSUInteger i = 0; i < delayedInAppsQueue.count; i++) {
NSDictionary *inApp = delayedInAppsQueue[i];
id queuedCampaignIdObj = inApp[CLTAP_INAPP_ID];
NSString *queuedCampaignId;
if ([queuedCampaignIdObj isKindOfClass:[NSNumber class]]) {
queuedCampaignId = [(NSNumber *)queuedCampaignIdObj stringValue];
} else if ([queuedCampaignIdObj isKindOfClass:[NSString class]]) {
queuedCampaignId = (NSString *)queuedCampaignIdObj;
} else {
queuedCampaignId = [queuedCampaignIdObj description];
}
- if ([queuedCampaignId isEqualToString:campaignId]) {
- indexToRemove = i;
+ if ([queuedCampaignId isEqualToString:campaignId]) {
+ [delayedInAppsQueue removeObjectAtIndex:i];
+ [self storeDelayedInApps:delayedInAppsQueue];
return inApp;
}
}
- if (indexToRemove != NSNotFound) {
- [delayedInAppsQueue removeObjectAtIndex:indexToRemove];
- [self storeDelayedInApps:delayedInAppsQueue];
- }
return nil;
}
}🤖 Prompt for AI Agents
In `@CleverTapSDK/InApps/CTInAppStore.m` around lines 299 - 329, The function
dequeueDelayedInAppWithCampaignId: currently returns the matched inApp from
inside the for-loop before removing it from the delayedInAppsQueue; modify the
logic in dequeueDelayedInAppWithCampaignId: so that when a matching
queuedCampaignId is found you remove the item from the mutable
delayedInAppsQueue and call storeDelayedInApps: to persist the updated queue
(using the same delayedInAppsQueue NSMutableArray), then return the removed
inApp; ensure these changes are inside the `@synchronized`(self) block and
reference the existing symbols delayedInAppsQueue, storeDelayedInApps:, and
CLTAP_INAPP_ID so the item is actually removed before returning.
| // | ||
| // CTTimerResult.h | ||
| // CleverTapSDK | ||
| // | ||
| // Created by Sonal Kachare on 23/01/26. | ||
| // | ||
|
|
||
| // CTTimerResult.h | ||
| typedef NS_ENUM(NSInteger, CTTimerResultType) { | ||
| CTTimerResultTypeCompleted, | ||
| CTTimerResultTypeError, | ||
| CTTimerResultTypeDiscarded | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing #import <Foundation/Foundation.h> causes compilation failure.
The header is missing the Foundation import, which causes all the static analysis errors (NS_ENUM, NSObject, NSString, NSError, etc. are undefined). Compare with CTInActionResult.h which correctly imports Foundation.
Additionally, consider adding NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END for consistency with other headers in this module.
🐛 Proposed fix
//
// CTTimerResult.h
// CleverTapSDK
//
// Created by Sonal Kachare on 23/01/26.
//
-// CTTimerResult.h
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
typedef NS_ENUM(NSInteger, CTTimerResultType) {
CTTimerResultTypeCompleted,
CTTimerResultTypeError,
CTTimerResultTypeDiscarded
};And at the end of the file:
+ (instancetype)discardedWithId:(NSString *)resultId;
`@end`
+
+NS_ASSUME_NONNULL_END🧰 Tools
🪛 Clang (14.0.6)
[error] 9-9: function definition declared 'typedef'
(clang-diagnostic-error)
[error] 10-10: use of undeclared identifier 'CTTimerResultTypeCompleted'
(clang-diagnostic-error)
[error] 11-11: use of undeclared identifier 'CTTimerResultTypeError'; did you mean 'CTTimerResultType'?
(clang-diagnostic-error)
[error] 12-12: use of undeclared identifier 'CTTimerResultTypeDiscarded'
(clang-diagnostic-error)
🤖 Prompt for AI Agents
In `@CleverTapSDK/InApps/InAppsScheduler/CTTimerResult.h` around lines 1 - 14, Add
the missing Foundation import and nullability annotations to the CTTimerResult.h
header: include `#import` <Foundation/Foundation.h> at the top of the file and
wrap the public declarations (the CTTimerResultType enum) with
NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END to match other headers (e.g.,
CTInActionResult.h) so NS_ENUM and other Foundation symbols resolve correctly.
CleverTapSDK/InApps/InAppsScheduler/InAppSelectionStrategy.swift
Outdated
Show resolved
Hide resolved
| @objc public func cancelAllTimers() { | ||
| lock.lock() | ||
| let cancelledCount = activeJobs.count | ||
| let jobsToCancel = activeJobs.values.map { $0.workItem } | ||
| lock.unlock() | ||
|
|
||
| for workItem in jobsToCancel { | ||
| workItem.cancel() | ||
| } | ||
|
|
||
| print("\(tag) Cancelled \(cancelledCount) timers") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all callers of cancelAllTimers
rg -n "cancelAllTimers" --type swift -C 3Repository: CleverTap/clevertap-ios-sdk
Length of output: 2668
🏁 Script executed:
#!/bin/bash
# Get the full InAppTimerManager.swift file
wc -l CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swiftRepository: CleverTap/clevertap-ios-sdk
Length of output: 134
🏁 Script executed:
#!/bin/bash
# Read key sections of the file to understand the implementation
echo "=== Lines 1-60 (Class definition and structure) ==="
sed -n '1,60p' CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift
echo ""
echo "=== Lines 80-105 (scheduleTimer method) ==="
sed -n '80,105p' CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift
echo ""
echo "=== Lines 155-175 (cancelAllTimers and cleanup) ==="
sed -n '155,175p' CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift
echo ""
echo "=== Lines 210-230 (cleanup method) ==="
sed -n '210,230p' CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swiftRepository: CleverTap/clevertap-ios-sdk
Length of output: 4326
🏁 Script executed:
#!/bin/bash
# Search entire codebase for cancelAllTimers calls (excluding the definition and cleanup)
rg "cancelAllTimers" --type swift | grep -v "^CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift"Repository: CleverTap/clevertap-ios-sdk
Length of output: 53
Race condition: cancelAllTimers() releases lock before cancelling work items.
The lock is released at line 162 before the cancellation loop begins at line 164, allowing new timers to be scheduled concurrently via scheduleTimer() during the cancellation window. While scheduleTimer() checks isCancelled before reusing existing timers, this race condition could still cause newly-scheduled timers to be immediately cancelled.
Additionally, cancelAllTimers() doesn't clear activeJobs, leaving stale cancelled entries. Although this is mitigated by scheduleTimer() creating new work items for cancelled entries, and by cleanup() immediately calling activeJobs.removeAll() after cancellation, the public @objc visibility means external callers could invoke cancelAllTimers() directly, accumulating stale entries.
🤖 Prompt for AI Agents
In `@CleverTapSDK/InApps/InAppsScheduler/InAppTimerManager.swift` around lines 157
- 168, cancelAllTimers() currently unlocks before cancelling, which allows
scheduleTimer() to add new timers that might be incorrectly cancelled and leaves
stale entries; fix by acquiring lock, copying the current workItems from
activeJobs (e.g., map values' workItem), clearing activeJobs
(activeJobs.removeAll()) while still holding the lock, then release the lock and
iterate to cancel the copied workItems (workItem.cancel()), and finally log the
cancelledCount; update the method to reference cancelAllTimers(), activeJobs,
workItem, scheduleTimer(), and cleanup() accordingly.
CleverTapSDK/CleverTap.h
Outdated
|
|
||
| @discussion | ||
| Fetch in-action in-app content from backend after inactionDuration expires | ||
| Sends wzrk_fetch event with t=6 and target ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this statement needed?
CleverTapSDK/CleverTap.m
Outdated
| static int currentRequestTimestamp = 0; | ||
| static int initialAppEnteredForegroundTime = 0; | ||
| static BOOL isAutoIntegrated; | ||
| static BOOL freshAppLaunchSent = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it NO
| [self.instance fetchInactionInApps:inAppId]; | ||
| } | ||
|
|
||
| - (NSMutableDictionary *)createInActionFetchRequestWithTargetId:(NSNumber *)targetId { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is never called
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed - unused
|
@Sonal-Kachare |
CleverTapSDK/CleverTap.h
Outdated
|
|
||
| @param inAppId the campaign ID (ti) to fetch content for | ||
| */ | ||
| - (void)fetchInactionInApps:(NSString * _Nonnull)inAppId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is not a client side public api, move it to an internal file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved it to internal header file
|
@Sonal-Kachare Refactor NSLog and print to CleverTapDebug |
|
@Sonal-Kachare fix the warnings in |
@coderabbitai
Summary by CodeRabbit
Release Notes
New Features
Refactoring
✏️ Tip: You can customize this high-level summary in your review settings.