SDK-5788: React Native SDK#37
Draft
akashvercetti wants to merge 39 commits into
Draft
Conversation
Lands the .github/workflows/docs.yml file on the default branch so the "Run workflow" button appears in the Actions UI. This is a small, infra-only PR cherry-picked ahead of the full docs PR (#27) so we can trigger workflow_dispatch against the feat branch and produce a first gh-pages deploy without waiting for the v1 release stack to merge. The workflow itself does nothing destructive on main pushes until the docs PR cascade lands (Dokka + DocC + Docusaurus all live on the docs branch). The only intended use of this workflow file on main right now is workflow_dispatch from the feat branch. Once the docs PR merges into main via the cascade, the workflow file content here will match the docs PR — no merge conflict. Jira: https://wizrocket.atlassian.net/browse/SDK-5784 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(SDK-5784): add docs CI workflow scaffolding (infra-only)
… gallery ancestors/parents
…vent host app crashes for malformed json
feat: Native Display SDK — initial release
… action.metadata (#55) * feat: remove elementID transport marker — attribution fields flow via action metadata wzrk_element_id (and wzrk_btn_text, wzrk_activity_type, wzrk_data) are now injected by the BE into each action's metadata field. ActionAttributionExtras already spreads action.metadata into the extras map, so these keys reach Core SDK via additionalProperties without a dedicated elementID parameter. - Remove wzrk_btn_id transport marker from ActionAttributionExtras (Android + iOS) - Update NativeDisplayBridge reflection probe to 2-arg Core SDK method signature - Simplify invokeClickedEvent — pass all sanitized extras directly - Remove sendThreeArgSelector (dead code) from iOS bridge - Update NativeDisplayRenderer call sites to match new from() signature - Update all tests to match new API and 2-arg selector Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * rename wzrk_btn_text→wzrk_c2a and wzrk_activity_type→wzrk_act * rename wzrk_btn_text→wzrk_c2a and wzrk_activity_type→wzrk_act * rename wzrk_btn_text→wzrk_c2a and wzrk_activity_type→wzrk_act * fix: replace string literals with enum values for type-correct compilation - IndicatorPosition.BOTTOM / IndicatorShape.CIRCLE in sample gallery configs - TextAlign.CENTER replaces "center" strings in sample and StylePropertiesTest * fix: add Dokka plugin to :sdk so dokkaHtml CI task resolves Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): skip docs site job when website/ content is absent The site job references website/package-lock.json for npm caching, but that content only lands when the docs/native-ui-kit-site branch is merged. PRs touching android/sdk/** triggered the job and failed immediately on the setup-node cache-path resolution step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): gate docs site job via a pre-check job output hashFiles() is not valid in job-level if conditions. Replace it with a check-website job that shells out to test for website/package.json and exports a has_website output; the site job gates on that output via needs.check-website.outputs.has_website. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(SDK-5846): add metadata to OpenUrl action and harden metadata parsing (Android + iOS) - Action.OpenUrl gains metadata: Map<String, String>? so attribution fields (wzrk_element_id, wzrk_c2a, wzrk_act, wzrk_data) reach Core SDK for URL button clicks — previously they were silently dropped - CustomAction now uses CustomActionSerializer (Android) / custom init(from:) (iOS) replacing the auto-synthesised Codable that crashed when a metadata value was a JSON object; values that are objects/arrays are serialised to compact JSON strings so the map stays Map<String,String> without throwing - ActionAttributionExtras spreads OpenUrl.metadata into attribution extras, matching the existing CustomAction.metadata spreading - OpenUrlSerializer URL resolution hardened to handle plain strings, platform objects, and legacy {text,replacements} Ultron format without crashing - 4 new unit tests: string metadata round-trip, wzrk_data as JSON object for CustomAction and OpenUrl, and null value dropping Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(SDK-5846): fix cache bridge architecture and element-click attribution (Android + iOS) Android: - Fix updateDisplayUnits proxy handler — was casting ArrayList<CleverTapDisplayUnit> to JSONArray (always null); now extracts JSON via getJsonObject() reflection - Change onServerUpdate signature from (JSONArray) to (List<String>) to match - Simplify coreSdkCacheProxy lambda now that list is pre-extracted - Revert wireListener to early-return when cache is attached; remove activeCache field (Core SDK holds the cache strongly — extra reference was dead weight) - Fix invokeClickedEvent gate: prefer element-clicked method whenever available, passing empty map when extras is absent (Core SDK still enriches from cached JSON) - Add diagnostic logging for element-clicked method resolution iOS: - Fix handleServerCacheUpdate: replace wrong [[String:Any]] cast with performSelector extraction (json/jsonObject) matching the delegate fallback path - Remove activeCache field from CleverTapAutoWire — Core SDK holds cache strongly via @Property(nonatomic,strong); bridge also holds it; extra reference was redundant - Move isCacheAttached flag to NativeDisplayBridge; set it in attachCache - Fix invokeClickedEvent gate: prefer element-clicked path whenever available - Replace perform(_:with:with:) with class_getMethodImplementation + unsafeBitCast for the 2-arg void ObjC call — perform misinterprets the empty return register Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…id (#54) * Fix BOX hit-testing and video controls tap handling for ios and android Video controls — tap not registering on AndroidView and tap unreliable on UIViewRepresentable Bindings — non-string JSON values cause parse failure VariableEvaluator — numeric booleans not evaluated correctly * fix(ios): handle Double in asBool and cancel stale video control timers - Add Double case to asBool(_:) so numeric JSON values like 1.0 are treated as truthy instead of falling through to nil - Replace untracked asyncAfter dispatches with cancellable DispatchWorkItem in VideoPlayerView and VideoFullscreenView to prevent stale timers hiding controls prematurely Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: CTLalit <144685420+CTLalit@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tation (#56) * SDK-5847: Fix Android sample ND views disappearing on device rotation (Android) On rotation the Activity recreates, destroying all Compose `remember`/ `mutableStateOf` state. Bridge callbacks (onNativeDisplaysLoaded) fire only once — so the received units were never re-delivered, leaving the canvas blank after rotation. Fix: move received units and log messages into ViewModels that survive configuration changes. - New CleverTapIntegrationViewModel: holds receivedUnits + logMessages as StateFlows; CleverTapIntegrationScreen collects via collectAsState() - New BridgeIntegrationViewModel: holds the NativeDisplayBridge instance (so the same bridge survives rotation) plus all UI state flows; bridge.clear() deferred to onCleared() instead of DisposableEffect - XmlFeedViewModel: added receivedUnits StateFlow + setUnits(); Fragment collects it in a second repeatOnLifecycle coroutine to restore canvas on view recreation without waiting for a new bridge callback - Added lifecycle-viewmodel-compose dependency (reuses lifecycle 2.8.7) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): improve ExoPlayer lifecycle and video rendering robustness - Switch PlayerView surface from SurfaceView to TextureView (via ct_player_view.xml) so parent alpha/graphicsLayer transforms are respected; fixes overlapping video bleed-through when tabs are hidden with graphicsLayer { alpha = 0f } - Replace 100ms polling loop with Player.Listener callbacks (onIsPlayingChanged, onVolumeChanged, onPlaybackStateChanged) to eliminate unnecessary recompositions - Add onPlayerError listener to catch async decoder failures (e.g. 4K H.264 NO_EXCEEDS_CAPABILITIES) and surface them as a visible error state instead of silently stalling - Remove inline AndroidView from composition when fullscreen is active using if (!isFullscreen) instead of view.player = null - Configure AudioAttributes (USAGE_MEDIA + AUDIO_CONTENT_TYPE_MOVIE) with handleAudioFocus=true so video correctly pauses on audio interruptions - Drop manual isMuted = !isMuted toggle from click handlers; onVolumeChanged fires synchronously so the manual toggle was immediately inverting the state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(android-sample): decouple navigation and improve MainActivity structure - Replace NavController params with callback lambdas in BannerDetailScreen, BannerShowcaseScreen, JSONViewerScreen, and DemoScreenContainer; screens no longer import NavController and are independently testable - Add Routes object centralising all route strings and builder functions; eliminates raw string literals scattered across NavHost declarations - Add MainTab enum and replace 5 repetitive NavigationBarItem blocks with a forEachIndexed loop over MainTab.entries - Switch selectedTab to rememberSaveable { mutableIntStateOf(0) } so the active tab survives screen rotation and process death - Replace TabContent visibility wrapper with a plain when(selectedTab) expression; TabContent function deleted as it no longer had a role after the conditional composition fix from the previous commit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * SDK-5847: Address CodeRabbit PR #56 review comments - VideoRenderer: add `import android.util.Log`, replace all qualified calls - VideoRenderer: `errorMessage` keyed on `videoUrl` (remember → remember(videoUrl)) - VideoRenderer: clear errorMessage on STATE_READY recovery - VideoRenderer: rebind `view.player = exoPlayer` in AndroidView.update for both inline and fullscreen PlayerView instances - BridgeIntegrationScreen: move bridge.addListener into DisposableEffect keyed on (bridge, listenerRegistered) so listener re-attaches after rotation - CleverTapIntegrationViewModel: atomic log append via _logMessages.update { } - MainActivity: Uri.encode route params; omit filename query param when null Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Update readme * removes unwanted docs * Update README.md
* SDK-5859: Support custom URL schemes in open_url action (Android + iOS) Replace the scheme allowlist (http/https/tel/mailto) with a blocklist of dangerous schemes (javascript/data/file) in both ActionHandler implementations. For non-http/https schemes the OS resolves the handler directly — enabling deep-links into other apps (e.g. myapp://, fb://) without going through Chrome Custom Tabs / SFSafariViewController. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * SDK-5859: Match Core SDK openUrl behavior exactly (Android + iOS) Replace the previous allowlist/blocklist scheme validation and custom routing with an implementation identical to Core SDK: Android: strip \n/\r, extract query params as Bundle extras, use Intent.ACTION_VIEW, prefer own app's handler (mirrors InAppActionHandler.openUrl / setPackageNameFromResolveInfoList). iOS: call UIApplication.shared.open(url, options: [:]) directly, matching CleverTap.m openURL:forModule: (openURL:options:completionHandler:). Only the customTabsEnabled flag introduces a branch — Custom Tabs on Android / SFSafariViewController on iOS. Everything else, including custom app schemes (myapp://, fb://, spotify://) and http/https, goes through the same OS-level dispatch as Core SDK. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty imageview removed when failure or no image Adds explicit clear background to make UI similar to android
…ndroid and iOS (#60) * feat(SDK-5860): add NDLogger with client-configurable log level for Android and iOS Replace raw android.util.Log / print() calls across both SDKs with a structured NDLogger that respects a configurable level. Clients can now silence or amplify SDK output independently of the Core SDK. Android: - New internal NDLogger object (OFF/INFO/DEBUG/VERBOSE, default INFO) - New public NDLogLevel enum exposed via NativeDisplayBridge.setLogLevel() - CleverTapAutoWire syncs Core SDK's getDebugLevel() as default on auto-wire when the client has not set an explicit level - Replaced ~60 Log.* calls across handler, renderer, bridge, placement, internal iOS: - New internal NDLogger enum with matching levels (default .info) - CTNDLogLevel typealias + NativeDisplayBridge.setLogLevel(_:) as public API - CleverTapAutoWire reads debugLevel via KVC on auto-wire as default - Replaced ~51 print() calls across Bridge, Handlers, Placement Client call always wins regardless of call order relative to auto-wire. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(SDK-5860): address CodeRabbit review — thread safety and cross-platform parity Android NDLogger: - Guard setLevel and syncFromCoreSdk under stateLock to eliminate the check-then-write race between @volatile fields iOS NDLogger: - Add NSLock protecting setLevel and syncFromCoreSdk writes - Add syncFromCoreSdk(_ level:) that updates _level without setting explicitlySet, matching Android's re-sync semantics iOS CleverTapAutoWire: - Switch syncLogLevelFromCoreSdk to call NDLogger.syncFromCoreSdk so auto-wire does not permanently lock out future Core SDK syncs - Change unknown-level fallback from .info to .debug (matches Android) - Clarify comment to reflect actual explicitlySet behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(SDK-5860): add NDLogger.swift to Xcode project — resolves 'cannot find NDLogger in scope' The .xcodeproj explicitly enumerates source files and does not auto-discover new subdirectories. Added Internal/ group and NDLogger.swift PBXFileReference + PBXBuildFile so Xcode targets compile the file alongside the rest of the SDK. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Adds oslog for iOS * update android logs with [NativeDisplay] tag and class name * Adds fix for italic style in ios --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Sonal Kachare <sonal@clevertap.com>
…ment taps (#61) * SDK-5862: fire "Notification Clicked" attribution for IMAGE taps (Android + iOS) IMAGE elements with click actions were executing the action (open URL, etc.) but silently skipping the "Notification Clicked" system event, so click-through attribution was never recorded in CleverTap analytics. Android: extend onSystemClick guard in NativeDisplayRenderer from isButton to isButton || isImage — one-line change, no impact on shouldApplyClickable. iOS: add onSystemClick hook to TappableModifier / applyTappable (default nil, zero impact on containers and non-image elements); RenderNode passes the system-event closure for IMAGE nodes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * SDK-5862: guard image attribution against missing onClick action onSystemClick was wired for all IMAGE nodes, so tapping an image that has a componentListener but no server onClick action would fire "Notification Clicked" with empty extras. Android: use a `when` expression so the image branch only produces a closure when node.actions[ON_CLICK] != null. iOS: add a `guard let onClick` in the closure — returns early when no onClick action is defined, preventing a spurious attribution event. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(SDK-5860): add NDLogger with client-configurable log level for Android and iOS Replace raw android.util.Log / print() calls across both SDKs with a structured NDLogger that respects a configurable level. Clients can now silence or amplify SDK output independently of the Core SDK. Android: - New internal NDLogger object (OFF/INFO/DEBUG/VERBOSE, default INFO) - New public NDLogLevel enum exposed via NativeDisplayBridge.setLogLevel() - CleverTapAutoWire syncs Core SDK's getDebugLevel() as default on auto-wire when the client has not set an explicit level - Replaced ~60 Log.* calls across handler, renderer, bridge, placement, internal iOS: - New internal NDLogger enum with matching levels (default .info) - CTNDLogLevel typealias + NativeDisplayBridge.setLogLevel(_:) as public API - CleverTapAutoWire reads debugLevel via KVC on auto-wire as default - Replaced ~51 print() calls across Bridge, Handlers, Placement Client call always wins regardless of call order relative to auto-wire. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(SDK-5860): address CodeRabbit review — thread safety and cross-platform parity Android NDLogger: - Guard setLevel and syncFromCoreSdk under stateLock to eliminate the check-then-write race between @volatile fields iOS NDLogger: - Add NSLock protecting setLevel and syncFromCoreSdk writes - Add syncFromCoreSdk(_ level:) that updates _level without setting explicitlySet, matching Android's re-sync semantics iOS CleverTapAutoWire: - Switch syncLogLevelFromCoreSdk to call NDLogger.syncFromCoreSdk so auto-wire does not permanently lock out future Core SDK syncs - Change unknown-level fallback from .info to .debug (matches Android) - Clarify comment to reflect actual explicitlySet behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(SDK-5860): add NDLogger.swift to Xcode project — resolves 'cannot find NDLogger in scope' The .xcodeproj explicitly enumerates source files and does not auto-discover new subdirectories. Added Internal/ group and NDLogger.swift PBXFileReference + PBXBuildFile so Xcode targets compile the file alongside the rest of the SDK. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Adds oslog for iOS * update android logs with [NativeDisplay] tag and class name * Adds fix for italic style in ios * Adds push support * Fixes a crash in syncLogLevelFromCoreSdk as performselector breaks for primitive type Update package.swift path * update debug mapping comment --------- Co-authored-by: CTLalit <144685420+CTLalit@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… small fixes (#63) * SDK-5862: fire "Notification Clicked" attribution for IMAGE taps (Android + iOS) IMAGE elements with click actions were executing the action (open URL, etc.) but silently skipping the "Notification Clicked" system event, so click-through attribution was never recorded in CleverTap analytics. Android: extend onSystemClick guard in NativeDisplayRenderer from isButton to isButton || isImage — one-line change, no impact on shouldApplyClickable. iOS: add onSystemClick hook to TappableModifier / applyTappable (default nil, zero impact on containers and non-image elements); RenderNode passes the system-event closure for IMAGE nodes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * SDK-5862: guard image attribution against missing onClick action onSystemClick was wired for all IMAGE nodes, so tapping an image that has a componentListener but no server onClick action would fire "Notification Clicked" with empty extras. Android: use a `when` expression so the image branch only produces a closure when node.actions[ON_CLICK] != null. iOS: add a `guard let onClick` in the closure — returns early when no onClick action is defined, preventing a spurious attribution event. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: rebrand sample apps to "CT Display Lab" with Firebase FCM setup - Rename app to "CT Display Lab" on Android (strings.xml) and iOS (CFBundleDisplayName) - Add launcher icons (mdpi–xxxhdpi) with adaptive icon support (back/fore layers + anydpi-v26 XML) - Update iOS AppIcon.appiconset with new 1024px icon - Add Firebase Messaging dependency (BOM 33.7.0) and google-services plugin to Android sample - Add POST_NOTIFICATIONS permission and FCM service to AndroidManifest - Add google-services.json to .gitignore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review comments - Fix iOS/Android parity: fire onSystemClick unconditionally before notifyComponentListener in TappableModifier.swift so "Notification Clicked" attribution always fires on click, matching Android behavior - Replace hardcoded CleverTap credentials with placeholders in AndroidManifest.xml and iOS Info.plist - Remove empty colors.xml (unused after adaptive icon switched to PNG background) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: bump sample app versions to 2.0 (build 15) for QA distribution Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#64) * feat: add ObjC sample app with full SDK integration - Restructure ObjC sample with 4-tab layout (Events, Slots, UIKit, More) - Add RootTabBarController, BridgeIntegrationViewController, CleverTapIntegrationViewController, UIKitDemoViewController, SlotDemoViewController - Remove unused screens (Browser, Arrangements, Animations, Home, TestCases) - Add NDSlotPlaceholderView in NDDisplayHelper for slot-driven placeholder management - Make NativeDisplayBridge, NativeDisplaySlotManager, NDLogLevel @objc-compatible - Fix SlotDemoView AsyncImage frame/clipping in Swift sample - Clean up NDDisplayHelper: remove unused arrangement-override, font-demo, and no-placeholder slot methods Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Update creds in sample app objc * Adds code review fixes * Fix coderabbit review comments * Adds license and updates podspec Fix: pod lib lint --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
…hey were leaking through and breaking evaluateBoolean.
…tribution survives, and accepted the legacy nested {text} URL shape.
… with every click event so the dashboard can slice by button on RN like it can on native.
…nd native renderers behave.
…the video can open a link.
…Notification Viewed/Clicked itself, so hosts don't double-report.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.