feat(sample): Live Activities demo screens - #369
Conversation
Sample app builds 📱Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request. |
525604e to
190ff56
Compare
dd67534 to
6cc9583
Compare
Shahroz16
left a comment
There was a problem hiding this comment.
I confirmed the existing Cursor thread about the SPM sample is practical: the SPM app owns the shared Dart screen but has none of the native iOS wiring and no Android custom callback. I am not duplicating that thread. I found one additional custom-widget gap below. Android custom tap and dismissal behavior is covered by the root SDK comment on Android #734.
| } minimal: { | ||
| Image(systemName: "car.fill") | ||
| } | ||
| } |
There was a problem hiding this comment.
Could we apply .cioWidgetUrl(context.state.cioMetadata) to both the lock-screen view and the DynamicIsland, like the bundled templates do? The AppDelegate routing in this PR is never reached for a Rideshare tap without that URL, so every server-pushed custom activity loses its opened metric and customer deep-link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Return a terminal, non-ongoing notification on the end event so the custom rideshare notification can be dismissed instead of persisting. - Format bridged numeric ETA as an integer (was rendering "5.0 min"). - End the current notification before re-issuing startCustom on update so Android replaces it in place instead of stacking/orphaning a second one. - Show the section description above the action buttons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AppDelegate: handleWidgetUrl replaces reportDeepLinkOpen and returns the customer's redirect URL, which is what the app now routes. - MainActivity: the custom rideshare renderer implements the dedicated CustomerIOLiveNotificationsCallback (createLiveNotification moved off CustomerIOPushNotificationCallback in the native Android SDK). - Config: `templates` -> `types`. Verified: sample APK builds against the local native Android SDK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cond module Custom iOS activity types previously stood up their own LiveActivitiesModule alongside the plugin's. With Live Activities now an SDK-managed module reached through CustomerIO.liveActivities, a second registration is last-write-wins and would clobber the built-in templates — and the static initialize entry point it used is gone. The app now requests the activity through ActivityKit and adopts it, so update/end still report. `adopt` does not report `start`: that needs the type registered on the SDK module, which only a Swift metatype can do and so cannot be driven from Dart. Verified: Runner + LiveActivityWidget.appex build for the simulator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ending Segments left the card frozen mid-progress; it now ends showing all segments complete and "Delivered". Countdown ends without an endTime so it reads as finished instead of counting down. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TEMPORARY (REL-1). Adds a :git/:branch override so CocoaPods can find the Live Activities pods, which are not on trunk yet. Remove once they ship. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The LiveActivityWidget target is in the Xcode project and its bundle imports CioLiveActivities_Attributes/_Templates, but the Podfile declared no target for it, so it linked nothing and failed to resolve those modules. The block was written earlier and lost in a rebase; this restores it, retargeted at the branch the Runner target already uses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Live Activities are now opt-in on iOS, so the samples have to ask for them or they silently lose the feature: the cocoapods app adds the `liveactivities` subspec, and both apps set customerio_live_activities_enabled=true, which is what the SPM Package.swift reads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rideshare demo needed an app-owned native module and an `adopt` call on iOS, a MethodChannel of its own, and a Platform branch in between. It now uses the same start/update/end the built-in templates use, on both platforms. Deletes what that made redundant: the RideshareAttributes type, the SampleCustomLiveActivity handler, and their Xcode project entries. The widget renders CIOCustomAttributes instead — the SDK owns the type, the app owns the view, which is the whole point of the new custom template. Android's "update" was ending the notification and starting a new one, justified by a comment claiming the wrapper has no by-id update for custom types. It does now (updateLiveNotification(activityId, activityType, data)); the workaround and the comment are both gone. Also fixes the config call the samples never caught up with: `liveActivitiesConfig` was renamed `liveNotificationsConfig` in the SDK branch, so the sample app did not compile. Verified: flutter analyze clean (2 pre-existing infos), and the cocoapods sample builds for device with the LiveActivityWidget extension embedded, against native iOS commit 95255429 which carries CIOCustomAttributes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…se branch The per-PR branch these pods were pinned to was deleted when it merged, so CocoaPods can no longer resolve it.
CI builds this app without code signing, so nothing here is required for it to pass. The identifier is listed for the same reason the notification-service one is: running the sample on a device needs a development profile for every embedded extension.
…CocoaPods one The SPM sample shipped the demo screens and `liveNotificationsConfig` while the native half landed only in the CocoaPods app, so it could not render an activity on either platform and a tap reported nothing. It now has the widget extension, the `handleWidgetUrl` route, and the Android render callback. Two things were missing beyond the widget itself: the AppDelegate never imported `customer_io`, and `Runner/Info.plist` had no `NSSupportsLiveActivities` — without that key ActivityKit refuses to start an activity at all, so the widget would have been inert even once it compiled. Where the CocoaPods app declares the Live Activities pods in a widget Podfile target, this one takes them as a remote Swift package pinned to the same unreleased branch (REL-1: swap for a version requirement once they ship). Also fixes the rideshare headline in both samples: it hardcoded "is on the way" while the demo ends the activity with a terminal "Arrived" status.
`flutter build ios --release` failed with "Signing for LiveActivityWidget requires a development team". Runner and the notification service carry empty DEVELOPMENT_TEAM placeholders that fastlane fills in, and nothing fills one for a target added outside the CocoaPods integration. Matches the CocoaPods sample's widget, which disallows code signing for the same reason. The extension is therefore unsigned in these builds — enough for CI, which only verifies compilation, but not installable on a device.
8ac3874 to
6541874
Compare
Both samples' rideshare widgets rendered correctly but applied no `.cioWidgetUrl`, so the AppDelegate route added in this PR was never reached for a rideshare tap: every server-pushed custom activity lost its opened metric and deep link. Applied to the lock screen and the Dynamic Island, matching where the SDK's built-in templates put it.
The Android renderer hardcoded "is on the way" for any non-terminal event, so an update that changed the status left the title stale while the body already showed the new state — and it disagreed with the iOS widget, which now leads with `status`. The title follows `status` too, and the driver moves into the body so nothing is lost. The demo screen also called `setState` after awaiting a native call and only checked `mounted` afterwards, which guarded the snackbar but not the rebuild. Leaving the route mid-call could assert.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit be8b519. Configure here.
| // once the Flutter engine runs). The wrapper stores this statically and applies it onto the | ||
| // push module config during SDK init. | ||
| CustomerIOLiveActivities.setLiveNotificationCallback(RideshareLiveNotificationCallback()) | ||
| super.onCreate(savedInstanceState) |
There was a problem hiding this comment.
CocoaPods sample missing Dart demo
Medium Severity
This PR wires Live Activities natively in the CocoaPods sample (widget extension, AppDelegate URL handling, Android rideshare renderer) but adds the demo screen and liveNotificationsConfig only under flutter_sample_spm. The CocoaPods app never registers template or custom types from Dart, so the native callback and routing added here cannot be exercised the way the SPM sample can.
Reviewed by Cursor Bugbot for commit be8b519. Configure here.


Demo screens for the two built-in templates and an app-owned custom type, plus AppDelegate routing for the opened metric.
Stacked on #368.
Note
Low Risk
Changes are confined to sample/testbed apps and reference integration patterns; no production SDK or auth paths are modified beyond optional temporary iOS dependency branch pins.
Overview
Adds end-to-end Live Activities / live notifications wiring to the
flutter_sample_cocoapodsandflutter_sample_spmtestbeds so integrators can exercise built-in templates and a custom rideshare type.On Dart (SPM sample), a new Live Activities screen drives
CustomerIO.liveActivitiesstart/update/end for segments, countdown, and custom payloads; SDK init gainsLiveActivitiesConfigwith template types pluscustomTypefor rideshare, with dashboard navigation and routing hooked up.Android enables live activities via
customerio_live_activities_enabledand registersRideshareLiveNotificationCallbackinMainActivity.onCreate(before Flutter SDK init) to render the custom type and dismiss onend.iOS adds a LiveActivityWidget extension (built-in
CIOSegments/CIOCountdownTimerplus app-ownedRideshareLiveActivityonCIOCustomAttributes),NSSupportsLiveActivities, andAppDelegateopen urlhandling throughCustomerIOLiveActivities.handleWidgetUrlfor tap/openedattribution and deep links. CocoaPods opts intocustomer_io/liveactivitieswith temporaryfeat/live-activitiesgit overrides; SPM pulls the same branch for widget package products. Fastlane lists the widget bundle ID for on-device signing.Reviewed by Cursor Bugbot for commit be8b519. Bugbot is set up for automated code reviews on this repo. Configure here.