Cross-Platform Reference
Perry widgets compile from a single TypeScript source to four platforms. The same Widget({...}) declaration produces native code for each target.
Status: this page has no TypeScript fences (only target-flag tables and shell build commands), so the doc-tests harness has nothing to run here. The
--targetflags listed below are all wired incrates/perry/src/commands/compile.rs, but the harness still can’t exercise them end-to-end — each requires--app-bundle-idand a platform SDK (Xcode, Android NDK).
Target Flags
| Platform | Target Flag | Output |
|---|---|---|
| iOS | --target ios-widget | SwiftUI .swift + Info.plist |
| iOS Simulator | --target ios-widget-simulator | Same, simulator SDK |
| Android | --target android-widget | Kotlin/Glance .kt + widget_info XML |
| watchOS | --target watchos-widget | SwiftUI .swift (accessory families) |
| watchOS Simulator | --target watchos-widget-simulator | Same, simulator SDK |
| Wear OS | --target wearos-tile | Kotlin Tiles .kt + manifest |
Feature Matrix
| Feature | iOS | Android | watchOS | Wear OS |
|---|---|---|---|---|
| Text | Yes | Yes | Yes | Yes |
| VStack/HStack/ZStack | Yes | Column/Row/Box | Yes | Column/Row/Box |
| Image (SF Symbols) | Yes | R.drawable | Yes | R.drawable |
| Spacer | Yes | Yes | Yes | Yes |
| Divider | Yes | Spacer+bg | Yes | Spacer |
| ForEach | Yes | forEach | Yes | forEach |
| Label | Yes | Row compound | Yes | Text fallback |
| Gauge | N/A | Text fallback | Yes | CircularProgressIndicator |
| Conditional | Yes | if | Yes | if |
| FamilySwitch | Yes | LocalSize | Yes | requestedSize |
| Config (AppIntent) | Yes | Config Activity | Yes (10+) | SharedPrefs |
| Native provider | Yes | JNI | Yes | JNI |
| sharedStorage | UserDefaults | SharedPrefs | UserDefaults | SharedPrefs |
| Deep linking (url) | widgetURL | clickable Intent | widgetURL | N/A |
Platform-Specific Notes
iOS
- Minimum deployment: iOS 17.0
- AppIntentConfiguration requires
import AppIntents - Widget extension memory limit: ~30MB
Android
- Requires Glance dependency:
androidx.glance:glance-appwidget:1.1.0 - Widget sizes mapped from iOS families: systemSmall=2x2, systemMedium=4x2, systemLarge=4x4
minimumScaleFactornot supported in Glance (skipped with warning)
watchOS
- Minimum deployment: watchOS 9.0
- Accessory families only (circular, rectangular, inline)
- Tighter memory (~15-20MB) and refresh budgets (hourly)
- AppIntent requires watchOS 10+; older versions get StaticConfiguration
Wear OS
- Same native compilation as Android phone (Wear OS = Android)
- Requires Horologist + Tiles Material 3 dependencies
- Tiles are full-screen cards in the carousel
Gaugemaps toCircularProgressIndicator
Build Instructions
iOS
perry widget.ts --target ios-widget --app-bundle-id com.example.app -o widget_out
xcrun --sdk iphoneos swiftc -target arm64-apple-ios17.0 \
widget_out/*.swift -framework WidgetKit -framework SwiftUI \
-o widget_out/WidgetExtension
Android
perry widget.ts --target android-widget --app-bundle-id com.example.app -o widget_out
# Copy .kt files to app/src/main/java/com/example/app/
# Copy xml/ to app/src/main/res/xml/
# Merge AndroidManifest_snippet.xml into AndroidManifest.xml
watchOS
perry widget.ts --target watchos-widget --app-bundle-id com.example.app -o widget_out
xcrun --sdk watchos swiftc -target arm64-apple-watchos9.0 \
widget_out/*.swift -framework WidgetKit -framework SwiftUI \
-o widget_out/WidgetExtension
Wear OS
perry widget.ts --target wearos-tile --app-bundle-id com.example.app -o widget_out
# Copy .kt files to Wear OS module
# Add Horologist + Tiles Material 3 dependencies to build.gradle
# Merge AndroidManifest_snippet.xml