Skip to content

Build on watchOS and tvOS without paywalls - #594

Merged
yusuftor merged 6 commits into
developfrom
feat/watchos-tvos-headless
Nov 5, 2026
Merged

yusuftor merged 6 commits into
developfrom
feat/watchos-tvos-headless

Conversation

@yusuftor

@yusuftor yusuftor commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Changes in this pull request

A customer ships on several Apple platforms and wants observer mode everywhere, but SuperwallKit only built on iOS and macOS. Package.swift declared watchOS without it ever building, and tvOS wasn't declared at all.

Neither platform has WebKit, so everything that needs a paywall on screen is now behind #if canImport(WebKit): the paywall view controller and presentation, debugger, Test Mode, Customer Center, permissions and the SDK's alerts. Everything else works as on iOS: configure, identify, user attributes, events, purchases, restores, observer mode, subscription status, entitlements, customer info and web checkout redemption.

Behaviour on watchOS and tvOS

  • register runs the audience filters, then ends the way iOS does without internet. A holdout, no match or missing placement is skipped and runs the feature. If a paywall matches, it's fetched: non-gated features run, gated ones get error 106, and a failed fetch sends its error. No present or dismiss callbacks fire, since nothing is shown, so register passes its feature block down on these platforms. This step (finishWithoutPaywallUI) builds on every platform so the iOS suite covers it.
  • getPresentationResult returns the paywall the user would see.
  • Implicit triggers and paywall preloading do nothing.
  • Test Mode never turns on, since its pickers can't be shown.
  • MMP install matching is off, as on native macOS.
  • tvOS: Local notifications aren't scheduled, since tvOS can't show their text.
  • watchOS: WatchKit-backed device info, lifecycle notifications and PlatformApplication. The connection type is reported as Unknown.

Other changes

  • Shared @available checks now name the matching watchOS and tvOS versions.
  • CI builds both platforms in build-platforms.yml.
  • CocoaPods stays iOS and macOS only.
  • Adds to the 4.19.1 release already staged on develop, with a changelog entry, a docs page (WatchAndTV.md), a README platform row and CLAUDE.md notes.

Testing

  • watchOS, tvOS, visionOS and Mac Catalyst build locally.
  • iOS: all 1596 tests pass.
  • macOS: 46 tests ran. SystemWindowHidingTests.paywallTakenDownAgainBeforeItsDelayedAppearanceIsNotLeftPresented failed once in the full run, then passed 3 out of 3 times on its own. This PR doesn't touch that code.
  • Not run on a watch or TV. There's no tvOS simulator here, and the test target depends on paywall code, so it can't build for watchOS.

Uses Superscript 1.0.18

With Superscript 1.0.17, a watch app using SuperwallKit fails to link on a real device: Superscript's watchOS device build only has arm64_32, but Xcode builds watch apps for arm64 too. CI only builds the package, so it doesn't catch that. 1.0.17 also had no tvOS build.

superwall/superscript#64 and superwall/superscript-ios-next#3 added both, and this PR uses the published 1.0.18, so audience filters run on every platform. The podspec stays on the Superscript pod 1.0.17, because CocoaPods Trunk is read-only this week and didn't accept 1.0.18. CocoaPods only installs on iOS and macOS, so it doesn't need the new slices.

Checklist

  • All unit tests pass.
  • All UI tests pass.
  • Demo project builds and runs on iOS.
  • Demo project builds and runs on Mac Catalyst.
  • Demo project builds and runs on visionOS.
  • I added/updated tests or detailed why my change isn't tested.
  • I added an entry to the CHANGELOG.md for any breaking changes, enhancements, or bug fixes.
  • I have run swiftlint in the main directory and fixed any issues.
  • I have updated the SDK documentation as well as the online docs.
  • I have reviewed the contributing guide

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The reviewed changes appear safe to merge.

Summary

Adds watchOS and tvOS support through Swift Package Manager without paywall screens.

  • SuperwallKit builds for watchOS and tvOS.
  • Placements finish without showing a paywall on watchOS and tvOS.
  • Purchases, restores, and entitlement updates remain available without paywall screens.
  • Screen-based features are left out of builds without WebKit.
  • The platform guide and release details cover watchOS and tvOS.

No new actionable issues were found in the changes since the previous review. Tests and Apple-platform builds were not run during this review.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["register on watchOS or tvOS"] --> B["Evaluate audience"]
  B -->|Skipped| C["Call onSkip, then feature"]
  B -->|Paywall matches| D["Fetch paywall"]
  D -->|Fetch fails| E["Call onError"]
  D -->|Gated| E
  D -->|Non-gated| F["Run feature on MainActor"]
Loading

Reviews (2) · Last reviewed commit: "Don't send a dismissal on watchOS and tv..." · Reviewed by Greptile

The package declared watchOS but never built there, and tvOS wasn't
declared at all. Both lack WebKit, so everything that needs a paywall
on screen is now behind `#if canImport(WebKit)`: the paywall view
controller and presentation, debugger, Test Mode, Customer Center,
permissions and the SDK's alerts. Purchases, observer mode, restores,
entitlements, customer info, user attributes, events and web checkout
redemption work as on iOS.

- `register` runs the audience filters, then skips (holdout, no match,
  placement not found) or sends a code 108 error when a paywall would
  show. Implicit triggers and paywall preloading do nothing.
- `getPresentationResult` returns the paywall the user would see.
- Test mode never turns on, since its pickers can't be shown.
- Superscript has no tvOS slice, so `Package.swift` drops it on tvOS
  and audience filters with an expression never match there.
- watchOS gets WatchKit-backed device info, lifecycle notifications and
  `PlatformApplication`. MMP install matching is off on both.
- Shared `@available` checks name matching watchOS/tvOS versions.
- CI builds watchOS and tvOS. CocoaPods stays iOS/macOS only.

Bumps to 4.20.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

This comment has been minimized.

The guard only stopped the paywall downloads, so the preload entry points
still evaluated audiences, read occurrences from Core Data and could leave
a queued task sleeping for five seconds. Guard the entry points instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

This comment has been minimized.

register used to send its own error whenever a paywall would show, so
non-gated features never ran there. It now ends the way iOS does without
internet: it fetches the paywall, and declines it with
webViewFailedToLoad. Non-gated features run, gated ones get the existing
web view error, and a failed fetch sends its error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

This comment has been minimized.

Reusing the web view failure path called onDismiss for a paywall that was
never presented. register now passes its feature block down: a non-gated
paywall runs it with no present or dismiss callbacks, and a gated one sends
error 106.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

This comment has been minimized.

develop already stages 4.19.1, so the watchOS and tvOS entry joins that
section instead of starting 4.20.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

This comment has been minimized.

Audience filters now run on tvOS, so the Superscript condition and the
canImport gates go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

maple-review-bot Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 10/10 · safe to merge. Changes align dependency pins and restore existing evaluator behavior; native device linking was not independently run.
no findings · tests not needed · risk low

The update pins Superscript 1.0.18 in SwiftPM and Xcode and restores the shared audience evaluator on tvOS. No new defects were found in the changes since the previous review.

3f16589 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@yusuftor
yusuftor merged commit 950b85e into develop Nov 5, 2026
8 checks passed
@yusuftor
yusuftor deleted the feat/watchos-tvos-headless branch November 5, 2026 10:06
@yusuftor yusuftor mentioned this pull request Nov 6, 2026
2 of 10 tasks
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.

1 participant