Skip to content

SDK-5611: tvOS App Inbox Support#528

Open
reshab-code wants to merge 11 commits intofeature/tvos-supportfrom
task/SDK-5611/tvOS-App-Inbox-support
Open

SDK-5611: tvOS App Inbox Support#528
reshab-code wants to merge 11 commits intofeature/tvos-supportfrom
task/SDK-5611/tvOS-App-Inbox-support

Conversation

@reshab-code
Copy link
Copy Markdown

@reshab-code reshab-code commented Mar 26, 2026

Summary

  • Added App Inbox support for tvOS for all message types
  • Implemented necessary UI components and created tvOS specific xibs.

Changes

  • Updated Inbox-related cells for all 4 types
  • Added tvOS-specific logic for focus
  • Minor project configuration updates in podspec for including the tvOS files.

Testing

  • Tested on tvOS simulator
  • Verified existing functionality is unaffected

Summary by CodeRabbit

  • New Features
    • Inbox messaging system now available on Apple TV with tvOS-optimized layouts and navigation.
    • Added video playback support for inbox messages on tvOS.
    • Enhanced carousel message display for Apple TV with improved controls and focus handling.
    • Extended demo app with tvOS support, featuring card-based navigation and deep linking capabilities.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

Walkthrough

This PR adds comprehensive Apple TV (tvOS) support to the CleverTap iOS SDK by enabling Inbox functionality, adding tvOS-specific UI components and layouts, implementing focus navigation and remote control handling, and creating a tvOS-compatible sample app with card-based navigation.

Changes

Cohort / File(s) Summary
Podspec Configuration
CleverTap-iOS-SDK.podspec
Updated iOS/tvOS podspec to include expanded resource bundles (XIB patterns, privacy files, images, HTML), added SDWebImage dependency for tvOS, extended source file includes for tvOS Inbox support, and updated public header files to expose CleverTap+Inbox.h on tvOS.
Core Data & Inbox Controllers
CleverTapSDK.xcodeproj/project.pbxproj, CTConstants.h, CleverTap.h
Added new Core Data model implementation files, Inbox controller and message model files, and updated project references; removed CLEVERTAP_NO_INBOX_SUPPORT from tvOS build to enable Inbox; added inbox video player notification constant.
Inbox Cell & Base Components (tvOS-specific logic)
CTCarouselImageMessageCell.m, CTCarouselMessageCell.m, CTInboxBaseMessageCell.m, CTInboxIconMessageCell.m, CTInboxSimpleMessageCell.m
Added tvOS-specific layout, focus management, and remote control navigation handlers; disabled touch gestures on tvOS in favor of focus/remote interactions; introduced video player notification posting and focus animation.
Inbox Controller & Utilities
CleverTapInboxViewController.m, CTInboxUtils.m
Added tvOS NIB name resolution (using ~tv suffix), updated table view layout/styling for tvOS, added video player presenter, and adjusted segmented control styling/sizing for Apple TV.
Supporting Views
CTInboxMessageActionView.m, CTSwipeView.m, UIView+CTToast.m
Updated button control event handling and scroll configuration to use tvOS-specific alternatives; disabled pasteboard/toast features on tvOS.
tvOS Interface Builder Resources
CTCarouselImageMessageCell~tv.xib, CTCarouselImageView~tv.xib, CTCarouselMessageCell~tv.xib, CTInboxIconMessageCell~tv.xib, CTInboxSimpleMessageCell~tv.xib, CleverTapInboxViewController~tv.xib
Added six new tvOS-specific XIB layouts for Inbox cells and views with proper constraints, outlets, and component hierarchy optimized for Apple TV display and focus-based navigation.
SwiftStarter tvOS Sample App
SwiftStarter/SwiftTvOS/...
Added tvOS support to sample app including new Card-based collection view UI (CardModel.swift, CardViewCell.swift), deep-link URL handler, updated CleverTap credentials, and refactored ViewController to demonstrate Inbox and other SDK features via collection-based navigation.

Sequence Diagram

sequenceDiagram
    participant User as tvOS User
    participant Cell as CTInboxBaseMessageCell
    participant VC as CleverTapInboxViewController
    participant Player as AVPlayerViewController
    
    User->>Cell: Focus on video message
    Cell->>Cell: didUpdateFocusInContext (animate scale)
    
    User->>Cell: Press Select button
    Cell->>Cell: bodyFocusButtonTapped
    Cell->>VC: Post CLTAP_INBOX_VIDEO_PLAYER_REQUESTED_NOTIFICATION
    
    VC->>VC: handleVideoPlayerRequested (notification received)
    VC->>Player: Create AVPlayerViewController with mediaUrl
    Player->>Player: Seek to currentTime (if provided)
    Player->>Player: Begin playback
    VC->>User: Present Player modally
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

eaa

Suggested reviewers

  • Sonal-Kachare
  • nishant-clevertap
  • akashvercetti
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'SDK-5611: tvOS App Inbox Support' clearly and specifically summarizes the main change: adding App Inbox support for Apple TV OS.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task/SDK-5611/tvOS-App-Inbox-support

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@francispereira
Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@akashvercetti
Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@akashvercetti akashvercetti changed the title SDK-5611: tvOS App Inbox Support SDK-5611: tvOS App Inbox Support @coderabbitai Mar 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CleverTapSDK.xcodeproj/project.pbxproj`:
- Around line 1024-1026: Remove the duplicate PBXFileReference for
CTCarouselMessageCell~tv.xib and its duplicate inclusion in the resources group:
locate the second entry named "CTCarouselMessageCell~tv.xib" (the
PBXFileReference block with id 58D237B32F6ACEC100063FB9) and delete that file
reference, then remove the duplicate reference from the resources group where
that same id is added (the duplicate resource entry around the resources list).
Keep the single original PBXFileReference (58D237B02F6AC54100063FB9) and ensure
only that id is present in the resources group to avoid duplicate project
entries.

In `@CleverTapSDK/Inbox/cells/CTCarouselImageMessageCell.m`:
- Around line 102-110: The shouldUpdateFocusInContext: implementation currently
blocks all left/right focus exits; update it so lateral presses only get
consumed when the carousel can move to a previous/next item and otherwise fall
back to the system focus engine. In shouldUpdateFocusInContext: use
context.nextFocusedView first (keep returning YES if it's a descendant), then
for UIFocusHeadingLeft/Right check whether there is an actual previous/next card
to focus/scroll to (the same condition used elsewhere to decide scrolling); if
such an item exists consume the event (return NO or handle scroll), but if there
is no previous/next item return YES so tvOS can move focus out of the carousel.
Ensure you reference and reuse the carousel’s existing checks for "has previous"
/ "has next" rather than unconditionally returning NO for left/right.

In `@CleverTapSDK/Inbox/cells/CTInboxBaseMessageCell.m`:
- Around line 77-82: The cell's primary-action target (bodyFocusButton -> action
bodyFocusButtonTapped) only special-cases video, so audio messages never start
when the remote's select/primary action is used; modify the primary-action
handling in CTInboxBaseMessageCell (bodyFocusButtonTapped / the primary action
path that currently defers to handleOnMessageTapGesture:) to detect audio
message types and start audio playback the same way video is handled (mirror the
video-start logic used elsewhere), or call the same audio-start routine that
handleOnMessageTapGesture: uses for taps; ensure bodyFocusButton's action covers
both video and audio message types so remote select will play audio from the
cell body.
- Around line 77-82: The bodyFocusButton created in CTInboxBaseMessageCell is
the tvOS focus target but never given accessibility metadata; update the cell
configuration (e.g., in the method that applies a message to the cell) to set
bodyFocusButton.isAccessibilityElement = YES and populate
bodyFocusButton.accessibilityLabel (and accessibilityValue if appropriate) from
the message's title/body summary, or alternatively expose the cell as a grouped
accessible container and move the accessibilityLabel to that container; ensure
changes reference CTInboxBaseMessageCell and the created bodyFocusButton (and
keep existing bodyFocusButtonTapped behavior intact).

In `@CleverTapSDK/Inbox/controllers/CleverTapInboxViewController.m`:
- Around line 548-568: The method handleVideoPlayerRequested: may pass a nil
NSURL to AVPlayer when mediaUrl is malformed; before calling [AVPlayer
playerWithURL:], create an NSURL from mediaUrl and guard it (e.g., NSURL *url =
[NSURL URLWithString:mediaUrl]; if (!url) return;), then use that url with
[AVPlayer playerWithURL:] and proceed with player setup and presentation; update
all references to use the validated NSURL to avoid undefined behavior.

In `@CleverTapSDK/Inbox/resources/CleverTapInboxViewController`~tv.xib:
- Around line 14-21: The tableView element currently uses autoresizingMask
attributes flexibleMaxX="YES" flexibleMaxY="YES" which only makes margins
flexible; update the <autoresizingMask> on the tableView in
CleverTapInboxViewController~tv.xib to use widthSizable="YES"
heightSizable="YES" (replace flexibleMaxX/flexibleMaxY) so the tableView
stretches full-screen; keep the existing tableView element and its outlets
(dataSource/delegate) unchanged.

In `@SwiftStarter/SwiftTvOS/ViewController.swift`:
- Around line 140-142: The recordEvent method is sending a misspelled event
name; in the recordEvent() function update the call to
CleverTap.sharedInstance()?.recordEvent("tesr") to use the correct event name
"test" (locate the recordEvent method and the
CleverTap.sharedInstance()?.recordEvent call and replace the string).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: df602f24-56b8-4c9f-8c8a-13953e86ebd2

📥 Commits

Reviewing files that changed from the base of the PR and between ef6f3e6 and 5091e3d.

📒 Files selected for processing (26)
  • CleverTap-iOS-SDK.podspec
  • CleverTapSDK.xcodeproj/project.pbxproj
  • CleverTapSDK/CTConstants.h
  • CleverTapSDK/CleverTap.h
  • CleverTapSDK/Inbox/cells/CTCarouselImageMessageCell.m
  • CleverTapSDK/Inbox/cells/CTCarouselMessageCell.m
  • CleverTapSDK/Inbox/cells/CTInboxBaseMessageCell.m
  • CleverTapSDK/Inbox/cells/CTInboxIconMessageCell.m
  • CleverTapSDK/Inbox/cells/CTInboxSimpleMessageCell.m
  • CleverTapSDK/Inbox/controllers/CleverTapInboxViewController.m
  • CleverTapSDK/Inbox/models/CTInboxUtils.m
  • CleverTapSDK/Inbox/resources/CTCarouselImageMessageCell~tv.xib
  • CleverTapSDK/Inbox/resources/CTCarouselImageView~tv.xib
  • CleverTapSDK/Inbox/resources/CTCarouselMessageCell~tv.xib
  • CleverTapSDK/Inbox/resources/CTInboxIconMessageCell~tv.xib
  • CleverTapSDK/Inbox/resources/CTInboxSimpleMessageCell~tv.xib
  • CleverTapSDK/Inbox/resources/CleverTapInboxViewController~tv.xib
  • CleverTapSDK/Inbox/views/CTInboxMessageActionView.m
  • CleverTapSDK/Inbox/views/CTSwipeView.m
  • CleverTapSDK/Inbox/views/UIView+CTToast.m
  • SwiftStarter/SwiftStarter.xcodeproj/project.pbxproj
  • SwiftStarter/SwiftTvOS/AppDelegate.swift
  • SwiftStarter/SwiftTvOS/CardModel.swift
  • SwiftStarter/SwiftTvOS/CardViewCell.swift
  • SwiftStarter/SwiftTvOS/Info.plist
  • SwiftStarter/SwiftTvOS/ViewController.swift
💤 Files with no reviewable changes (1)
  • CleverTapSDK/CleverTap.h

Comment on lines +1024 to +1026
58D237B02F6AC54100063FB9 /* CTCarouselMessageCell~tv.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCarouselMessageCell~tv.xib"; sourceTree = "<group>"; };
58D237B32F6ACEC100063FB9 /* CTCarouselMessageCell~tv.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCarouselMessageCell~tv.xib"; sourceTree = "<group>"; };
58D237B62F6AD23B00063FB9 /* CTCarouselImageView~tv.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCarouselImageView~tv.xib"; sourceTree = "<group>"; };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove duplicate tvOS CTCarouselMessageCell~tv.xib file reference.

Line 1025 introduces a second PBXFileReference for the same CTCarouselMessageCell~tv.xib path, and Line 1535 adds that duplicate into the resources group. This creates duplicate project entries and avoidable merge churn.

🛠️ Proposed cleanup
-		58D237B32F6ACEC100063FB9 /* CTCarouselMessageCell~tv.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCarouselMessageCell~tv.xib"; sourceTree = "<group>"; };
...
-				58D237B32F6ACEC100063FB9 /* CTCarouselMessageCell~tv.xib */,

Also applies to: 1535-1536

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK.xcodeproj/project.pbxproj` around lines 1024 - 1026, Remove the
duplicate PBXFileReference for CTCarouselMessageCell~tv.xib and its duplicate
inclusion in the resources group: locate the second entry named
"CTCarouselMessageCell~tv.xib" (the PBXFileReference block with id
58D237B32F6ACEC100063FB9) and delete that file reference, then remove the
duplicate reference from the resources group where that same id is added (the
duplicate resource entry around the resources list). Keep the single original
PBXFileReference (58D237B02F6AC54100063FB9) and ensure only that id is present
in the resources group to avoid duplicate project entries.

Comment on lines +102 to +110
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context {
if ([context.nextFocusedView isDescendantOfView:self]) {
return YES;
}
UIFocusHeading heading = context.focusHeading;
if (heading == UIFocusHeadingLeft || heading == UIFocusHeadingRight) {
return NO;
}
return YES;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the CTCarouselImageMessageCell.m file
find . -name "CTCarouselImageMessageCell.m" -type f

Repository: CleverTap/clevertap-ios-sdk

Length of output: 126


🏁 Script executed:

# Read the file to see the actual code at the specified lines
wc -l ./CleverTapSDK/Inbox/cells/CTCarouselImageMessageCell.m

Repository: CleverTap/clevertap-ios-sdk

Length of output: 130


🏁 Script executed:

# Read the specific lines mentioned in the review
sed -n '95,136p' ./CleverTapSDK/Inbox/cells/CTCarouselImageMessageCell.m | cat -n

Repository: CleverTap/clevertap-ios-sdk

Length of output: 1962


Let boundary arrows fall back to the focus engine.

Lines 107-108 block every left/right focus exit unconditionally, and lines 121 and 129 return even when there's no previous/next item to scroll to. On the first or last card, lateral presses are consumed locally instead of being handed to tvOS, preventing navigation out of the carousel. After applying the suggested fix, verify first/last-item navigation behavior in the tvOS simulator.

🎯 Suggested adjustment
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context {
    if ([context.nextFocusedView isDescendantOfView:self]) {
        return YES;
    }
    UIFocusHeading heading = context.focusHeading;
-    if (heading == UIFocusHeadingLeft || heading == UIFocusHeadingRight) {
-        return NO;
+    if (heading == UIFocusHeadingLeft) {
+        return self.swipeView.currentItemIndex <= 0;
+    }
+    if (heading == UIFocusHeadingRight) {
+        return self.swipeView.currentItemIndex >= (NSInteger)self.itemViews.count - 1;
     }
     return YES;
 }

 - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
     for (UIPress *press in presses) {
         if (press.type == UIPressTypeLeftArrow) {
             NSInteger prev = self.swipeView.currentItemIndex - 1;
             if (prev >= 0) {
                 [self.swipeView scrollToItemAtIndex:prev duration:0.3];
                 self.pageControl.currentPage = (int)prev;
+                return;
             }
-            return;
         }
         if (press.type == UIPressTypeRightArrow) {
             NSInteger next = self.swipeView.currentItemIndex + 1;
             if (next < (NSInteger)self.itemViews.count) {
                 [self.swipeView scrollToItemAtIndex:next duration:0.3];
                 self.pageControl.currentPage = (int)next;
+                return;
             }
-            return;
         }
     }
     [super pressesBegan:presses withEvent:event];
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK/Inbox/cells/CTCarouselImageMessageCell.m` around lines 102 -
110, The shouldUpdateFocusInContext: implementation currently blocks all
left/right focus exits; update it so lateral presses only get consumed when the
carousel can move to a previous/next item and otherwise fall back to the system
focus engine. In shouldUpdateFocusInContext: use context.nextFocusedView first
(keep returning YES if it's a descendant), then for UIFocusHeadingLeft/Right
check whether there is an actual previous/next card to focus/scroll to (the same
condition used elsewhere to decide scrolling); if such an item exists consume
the event (return NO or handle scroll), but if there is no previous/next item
return YES so tvOS can move focus out of the carousel. Ensure you reference and
reuse the carousel’s existing checks for "has previous" / "has next" rather than
unconditionally returning NO for left/right.

Comment on lines +77 to +82
self.bodyFocusButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.bodyFocusButton.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.bodyFocusButton];
[self.bodyFocusButton addTarget:self
action:@selector(bodyFocusButtonTapped)
forControlEvents:UIControlEventPrimaryActionTriggered];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle audio in the tvOS primary-action path.

Lines 77-82 make bodyFocusButton the main focus target for the cell, but Lines 113-126 only special-case video. Audio messages fall through to handleOnMessageTapGesture: instead of starting playback, so the remote’s select action cannot play audio from the cell body.

🎵 One possible fix
- (void)bodyFocusButtonTapped {
    CleverTapInboxMessageContent *content = self.message.content.firstObject;
+    if (content.mediaIsAudio && content.mediaUrl.length > 0) {
+        [self togglePlay];
+        return;
+    }
     if (content.mediaIsVideo && content.mediaUrl.length > 0) {
         CMTime currentTime = self.avPlayer ? self.avPlayer.currentTime : kCMTimeZero;
         [self pause];
         [[NSNotificationCenter defaultCenter]
             postNotificationName:CLTAP_INBOX_VIDEO_PLAYER_REQUESTED_NOTIFICATION

Also applies to: 111-126

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK/Inbox/cells/CTInboxBaseMessageCell.m` around lines 77 - 82, The
cell's primary-action target (bodyFocusButton -> action bodyFocusButtonTapped)
only special-cases video, so audio messages never start when the remote's
select/primary action is used; modify the primary-action handling in
CTInboxBaseMessageCell (bodyFocusButtonTapped / the primary action path that
currently defers to handleOnMessageTapGesture:) to detect audio message types
and start audio playback the same way video is handled (mirror the video-start
logic used elsewhere), or call the same audio-start routine that
handleOnMessageTapGesture: uses for taps; ensure bodyFocusButton's action covers
both video and audio message types so remote select will play audio from the
cell body.

⚠️ Potential issue | 🟠 Major

Label the tvOS overlay button for VoiceOver.

Because Lines 93-95 make the cell itself non-focusable, this code-created bodyFocusButton becomes the primary tvOS focus target. It never gets an accessibility label/value from the message, so VoiceOver users will land on an unlabeled button for every inbox card. Populate its accessibility metadata when the message is configured, or expose a grouped accessible container instead.

That XIB-based pattern does not cover this code-created overlay. Based on learnings: In CleverTap iOS SDK, accessibility element configuration for UI components like cellIcon in CTInboxIconMessageCell is handled in XIB files through Interface Builder rather than programmatically in code, so setting isAccessibilityElement = YES in code is not needed.

Also applies to: 93-95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK/Inbox/cells/CTInboxBaseMessageCell.m` around lines 77 - 82, The
bodyFocusButton created in CTInboxBaseMessageCell is the tvOS focus target but
never given accessibility metadata; update the cell configuration (e.g., in the
method that applies a message to the cell) to set
bodyFocusButton.isAccessibilityElement = YES and populate
bodyFocusButton.accessibilityLabel (and accessibilityValue if appropriate) from
the message's title/body summary, or alternatively expose the cell as a grouped
accessible container and move the accessibilityLabel to that container; ensure
changes reference CTInboxBaseMessageCell and the created bodyFocusButton (and
keep existing bodyFocusButtonTapped behavior intact).

Comment on lines +548 to +568
#if TARGET_OS_TV
- (void)handleVideoPlayerRequested:(NSNotification *)notification {
NSString *mediaUrl = notification.userInfo[@"mediaUrl"];
NSValue *currentTimeValue = notification.userInfo[@"currentTime"];
NSString *title = notification.userInfo[@"title"];
if (!mediaUrl) return;
AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:mediaUrl]];
AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init];
playerVC.player = player;
playerVC.showsPlaybackControls = YES;
if (title.length > 0) {
playerVC.title = title;
}
[self presentViewController:playerVC animated:YES completion:^{
if (currentTimeValue) {
CMTime seekTime = [currentTimeValue CMTimeValue];
[player seekToTime:seekTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
[player play];
}];
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add nil check for NSURL creation.

If mediaUrl is non-nil but malformed, [NSURL URLWithString:mediaUrl] returns nil, and passing nil to AVPlayer playerWithURL: may cause undefined behavior.

🛡️ Proposed fix
 - (void)handleVideoPlayerRequested:(NSNotification *)notification {
     NSString *mediaUrl = notification.userInfo[@"mediaUrl"];
     NSValue *currentTimeValue = notification.userInfo[@"currentTime"];
     NSString *title = notification.userInfo[@"title"];
     if (!mediaUrl) return;
-    AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:mediaUrl]];
+    NSURL *url = [NSURL URLWithString:mediaUrl];
+    if (!url) return;
+    AVPlayer *player = [AVPlayer playerWithURL:url];
     AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK/Inbox/controllers/CleverTapInboxViewController.m` around lines
548 - 568, The method handleVideoPlayerRequested: may pass a nil NSURL to
AVPlayer when mediaUrl is malformed; before calling [AVPlayer playerWithURL:],
create an NSURL from mediaUrl and guard it (e.g., NSURL *url = [NSURL
URLWithString:mediaUrl]; if (!url) return;), then use that url with [AVPlayer
playerWithURL:] and proceed with player setup and presentation; update all
references to use the validated NSURL to avoid undefined behavior.

Comment on lines +14 to +21
<tableView clipsSubviews="YES" contentMode="scaleToFill" style="grouped" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="1" sectionFooterHeight="6" id="Pal-ed-Io6">
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<connections>
<outlet property="dataSource" destination="-1" id="mwF-we-s5N"/>
<outlet property="delegate" destination="-1" id="LpY-uj-7qh"/>
</connections>
</tableView>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how other tvOS XIBs in this project configure autoresizing masks for root views

echo "=== Checking autoresizing masks in tvOS XIBs ==="
fd -e xib -p '~tv\.xib$' --exec grep -l "autoresizingMask" {} \; | while read -r file; do
    echo "--- $file ---"
    grep -A1 "autoresizingMask" "$file"
done

echo ""
echo "=== Checking if iOS version has different autoresizing ==="
fd -e xib -p 'CleverTapInboxViewController' --exec cat {} \;

Repository: CleverTap/clevertap-ios-sdk

Length of output: 5628


Use widthSizable and heightSizable for full-screen table view.

The current autoresizing mask (flexibleMaxX, flexibleMaxY) keeps the view's dimensions constant and only makes margins flexible. For a full-screen table view that should stretch with its container, use widthSizable="YES" heightSizable="YES" instead. This pattern is already used in CTCarouselImageView~tv.xib for tvOS views in this codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CleverTapSDK/Inbox/resources/CleverTapInboxViewController`~tv.xib around
lines 14 - 21, The tableView element currently uses autoresizingMask attributes
flexibleMaxX="YES" flexibleMaxY="YES" which only makes margins flexible; update
the <autoresizingMask> on the tableView in CleverTapInboxViewController~tv.xib
to use widthSizable="YES" heightSizable="YES" (replace
flexibleMaxX/flexibleMaxY) so the tableView stretches full-screen; keep the
existing tableView element and its outlets (dataSource/delegate) unchanged.

@akashvercetti akashvercetti changed the title SDK-5611: tvOS App Inbox Support @coderabbitai SDK-5611: tvOS App Inbox Support Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants