feat(SDK-5835): Flutter sample app#52
Merged
CTLalit merged 8 commits intoMay 28, 2026
Merged
Conversation
- 4-tab bottom nav (Banners, Browser, Demos, More) mirroring Android/iOS apps - BannerShowcaseScreen: scrollable list of 10 banner cards with detail navigation - BannerDetailScreen: full-screen single banner display - ArrangementDemoScreen: interactive chip strip switching all 7 strategies - AnimationDemoScreen: 3 animation demos with info card, keyed for rebuild - HomeScreenDemo: loads home_screen.json with action/component listeners - OtherDemosScreen: tabbed view (Home, Gallery, E-commerce, Social, Dashboard) - BridgeIntegrationScreen: loads mock product/notification configs, shows API snippet - SlotDemoScreen: native display units interleaved with mock feed items - TestBrowserScreen: prev/next navigation across 181 test-config filenames - JsonViewerScreen: scrollable raw JSON with copy-to-clipboard - MoreMenuScreen: list navigation to all demo screens - Assets: 10 banner JSONs + 12 config JSONs copied from android-sample - flutter analyze: no issues Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Flutter) Android (flutter-sample/android/): - SampleApplication: init CleverTap, bind NativeDisplayBridge, register listener - MainActivity: EventChannel (native→Dart units_updated), MethodChannel (pushEvent) - AndroidManifest: CT account ID/token/region meta-data, INTERNET permission - build.gradle.kts: CT core SDK 8.0.0 + native-display-sdk dependencies iOS (flutter-sample/ios/): - AppDelegate: CleverTap.autoIntegrate(), NativeDisplayBridge bind + fetch - Podfile: CleverTap-iOS-SDK ~>7.0, CleverTapNativeDisplay :path Dart (flutter-sample/lib/): - CleverTapIntegrationScreen: subscribe NativeDisplayBridge.eventStream, parse units_updated events, render via NativeDisplayView, Send Event → pushEvent - app.dart: bottom nav Events/Slots/Browser/More matching Android structure - SlotDemoScreen: 15 feed items + 4 dashed-border slot placeholders - Lint fixes: prefer_const_constructors / prefer_const_literals flutter/ plugin: - android/build.gradle + AndroidManifest.xml: plugin Android library scaffold - NativeDisplayBridge: pushEvent (sample MethodChannel) + eventStream (EventChannel) - gallery_renderer.dart: LayoutBuilder fallback height for unbounded PageView Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…op composite build Problem: flutter-sample referenced clevertap-native-ui-kit (compiled Kotlin 2.1.0) via includeBuild, forcing Kotlin 2.1.0 + AGP 8.9.1 + Gradle 8.11.1 on the sample. Fix: remove includeBuild and the native-display-sdk dependency entirely. Subscribe to display unit callbacks via CleverTapAPI.setDisplayUnitListener(DisplayUnitListener) from clevertap-android-sdk:8.0.0 (Java interface — no Kotlin binary compat issue). Forward CleverTapDisplayUnit.getJsonObject().toString() directly to Flutter via EventChannel. Restores original Flutter scaffold versions: Kotlin 1.8.22, AGP 8.7.0, Gradle 8.10.2. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…play Two bugs prevented display units from rendering in CleverTapIntegrationScreen: 1. Wrong JSON format: CleverTapDisplayUnit.getJsonObject() returns raw CT JSON (type:advanced-builder, slot_id, wzrk_id, etc.) not NativeDisplayConfig JSON. Flutter's NativeDisplayConfig.fromJson() cannot parse this format. Fix: extract NativeDisplayConfig from the raw CT JSON using the same 3-strategy detection as NativeDisplayConfigParser: - native_display_config top-level key (dashboard format) - custom_kv.nd_config string value - root top-level key (direct NativeDisplayConfig JSON) 2. Timing race: display units can arrive from CT server before Flutter subscribes to the EventChannel, causing them to be silently dropped (eventSink is null). Fix: cache the last received unit JSONs in SampleApplication.cachedUnitJsons and replay them immediately in EventChannel.StreamHandler.onListen(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…utter sample platform targets ## Flutter SDK — renderer fixes - native_display_view: aspectRatio now takes precedence over width.percent — when AR is set on a node the renderer uses full available parent width and derives height = parentWidth / aspectRatio, matching Android (Compose modifier ordering) and iOS (guard check in resolveRootWidth). _effectiveWidth returns availableWidth when AR > 0; _applyRootSizing short-circuits immediately when AR is present. - native_display_view: fix _computeRootHeight for percent height roots — previously fell through to screenHeight, inflating percent-based fonts by up to 67 %. - native_display_renderer: remove debugLabel field and all _wrapWithSizing debugPrint calls. - box_container: remove _buildChild debugPrint. - vertical_container / horizontal_container: promote from v1 stubs to full arrangement implementations — all ArrangementStrategy values (spaced, space_between, space_evenly, space_around, start, center, end) now produce correct Column/Row with spacers or MainAxisAlignment. - button_element: propagate maxLines, overflow, and softWrap from resolved style. - style_applier: fix border resolution — require width > 0 before rendering; skip zero- width borders rather than rendering a phantom 1 dp default. ## Flutter sample app - clevertap_integration_screen: remove debug red border, outer LayoutBuilder, and [SAMPLE] log prints; clean up raw JSON logging from onUnitsLoaded. - test_browser_screen: add test-parity-80pct-ar.json to browser list. - Add 180+ test-config JSON assets for the in-app test browser. - Add multi-platform scaffolding (linux, macos, web, windows). - pubspec: add clevertap_plugin dependency; update flutter-sdk path reference. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…knowledge bases Codifies the cross-platform rule discovered while debugging the Flutter renderer: when aspectRatio is set on a node, it takes full available parent width and derives height = parentWidth / aspectRatio. Any width.percent (or height.percent) value is ignored. The rule is identical on all three platforms: - Android: Compose applies aspectRatio() modifier before fillMaxWidth(fraction); the AR modifier locks minW=parentWidth, making fillMaxWidth ineffective. - iOS: resolveRootWidth() guard returns parentWidth when aspectRatio > 0, regardless of percent. Documented in NativeDisplayRenderer.swift line 244. - Flutter: _effectiveWidth returns availableWidth when layout.aspectRatio > 0; _applyRootSizing short-circuits when AR is set. aspectRatio is skipped only when BOTH width AND height are simultaneously fixed (dp/sp/px). Percent dimensions are never treated as "fixed" for this check. Files updated: - CLAUDE.md — layout system section - .claude/reference/CLAUDE_CODE_REFERENCE_ACTUAL.md — layout model + priority table - .claude/reference/JSON_STRUCTURE_REFERENCE.md — How it works + Priority Rules sections - docs/JSON_STRUCTURE_REFERENCE.md — same (kept in sync) - docs/BACKEND_PAYLOAD_SPEC.md — per-platform mechanism table - .claude/agents/android-sdk/knowledge/rendering-pipeline.md — Stage 4 precedence rule - .claude/agents/android-sdk/knowledge/gotchas.md — new gotcha entry - .claude/agents/ios-sdk/knowledge/architecture.md — Swift code evidence - .claude/agents/flutter-sdk/knowledge/rendering-pipeline.md — root sizing implementation - .claude/agents/flutter-sdk/knowledge/architecture.md — NativeDisplayView description - .claude/agents/testing/knowledge/json-generation-rules.md — Section 6 Aspect Ratio Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add NativeDisplayUnit model (unitId, slotId, config, customExtras, resolvedStyles) - Add NativeDisplayConfigParser with tryParse/parseAll running off main thread via Isolate.run(); falls back to synchronous on Dart < 3.4 - Mirrors 3-strategy extraction from Android NativeDisplayConfigParser.kt: native_display_config key → custom_kv.nd_config string → root key - NativeDisplayView accepts optional pre-resolved resolvedStyles to skip redundant StyleResolver calls when using NativeDisplayConfigParser - Export both new types from the public barrel - Simplify clevertap_integration_screen.dart: remove _deepCast, _extractEntry, _UnitEntry; replace with NativeDisplayConfigParser.parseAll() (4 lines) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NativeDisplayView: StatelessWidget → StatefulWidget; StyleResolver.resolveAll() now runs once in initState/didUpdateWidget, not on every parent rebuild; added fixed-dimension shortcut that bypasses LayoutBuilder when root has only dp dimensions (no percent, no aspectRatio) - style_applier.dart: for solid backgrounds, bake opacity into Color.withValues() instead of wrapping the whole subtree in Opacity widget (avoids saveLayer) - image_element.dart: replace Image.network() with CachedNetworkImage for static images (GIFs keep Image.network for animation fidelity); wrap in RepaintBoundary - video_element.dart: wrap in RepaintBoundary to isolate frame repaints - gallery_renderer.dart: wrap each page item in RepaintBoundary Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6 tasks
Contributor
Author
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.
Summary
flutter-sample/— a standalone Flutter demo app with full feature parity to the Android and iOS sample appsclevertap_native_displayFlutter plugin viapath: ../flutterScreens implemented
BannerShowcaseScreenBannerDetailScreenBannerDetailScreenNativeDisplayViewwith back buttonArrangementDemoScreenAnimationDemoScreenkey: ValueKey(index)to force widget rebuildHomeScreenDemohome_screen.jsonwith action + component listenersOtherDemosScreenBridgeIntegrationScreenNativeDisplayBridgeAPI code snippetSlotDemoScreenTestBrowserScreenJsonViewerScreenNdDemoCardMoreMenuScreenAssets
assets/banners/— 10 banner JSONs copied fromandroid-sampleassets/configs/— 12 config JSONs (animations, arrangement, bridge, gallery, home, showcase)Test plan
flutter pub getresolves without errorflutter analyzereports no issuesJira: SDK-5835
🤖 Generated with Claude Code