| 1 | --- |
| 2 | name: rastrillo-native |
| 3 | description: Build native companions for Rastrillo apps using shared Swift components, an Apple app scaffold and optional Go Mobile bindings. |
| 4 | --- |
| 5 | |
| 6 | # Rastrillo Native |
| 7 | |
| 8 | Optional sibling of Rastrillo web. Source and review: |
| 9 | `https://amadan.net/rastrillo/native`. Swift product/module: |
| 10 | `RastrilloNative`, iOS 17+ and macOS 14+. Pin the package to a reviewed |
| 11 | revision and read this file from that checkout. Core Rastrillo does not |
| 12 | import native tooling. |
| 13 | |
| 14 | Start from `examples/companion/project.yml` and `Sources/Companion.swift`. |
| 15 | Copy into the app; replace the local package path with the repository URL |
| 16 | and revision, set app-owned bundle IDs, run `xcodegen generate`. The example |
| 17 | checks `/api/version` only; it supplies no authenticated session. The app |
| 18 | owns linking, navigation, storage, signing and release policy. |
| 19 | |
| 20 | ## Prefer native UI |
| 21 | |
| 22 | Aim for a fully native interface wherever practical. Meeting the platform's |
| 23 | expectations can substantially improve daily use: navigation, selection, |
| 24 | menus, context menus/right-click, keyboard shortcuts, accessibility, links, |
| 25 | windows and system sharing should behave as people already expect. Treat |
| 26 | those behaviours as part of the feature, not final polish. Share logic and |
| 27 | contracts freely; let each platform own how the feature is presented. |
| 28 | |
| 29 | For a complex app, a native navigation layer around selected webview screens |
| 30 | can avoid duplicating a large working surface. Use that as a deliberate |
| 31 | boundary: keep app navigation, menus, contextual actions and link routing |
| 32 | native, and expose typed actions from the embedded screen. Route internal |
| 33 | links to native destinations and ordinary external links through the |
| 34 | platform's normal browser behaviour. Do not intercept text editing or |
| 35 | replace useful web behaviour with a less capable native imitation. |
| 36 | |
| 37 | If both clients would otherwise duplicate navigation and action definitions, |
| 38 | consider a shared app manifest compiled into separate web and native |
| 39 | presentations. Share destination IDs, available commands, capabilities and |
| 40 | link intent; each renderer chooses platform-appropriate controls. A command |
| 41 | may appear in a web toolbar, a Mac menu/context menu, or an iPhone action |
| 42 | menu. Avoid encoding DOM trees, pixel layout or one platform's navigation |
| 43 | model as the common schema. See [docs/app-architecture.md](docs/app-architecture.md). |
| 44 | This is architectural guidance, not an existing dual-target generator; |
| 45 | Rastrillo's current resource manifests generate web CRUD only. |
| 46 | |
| 47 | ## Shared components |
| 48 | |
| 49 | `@MainActor CoalescedRunner.run` serializes one refresh operation. A burst |
| 50 | during a pass queues one trailing pass; callers await its completion. |
| 51 | Trailing passes reuse the first caller's closure. Keep one runner per |
| 52 | operation/account, handle errors inside the closure, and never recursively |
| 53 | call it from the work it runs. Cancelling a waiter does not cancel shared |
| 54 | work. Existing consumers can keep their public API with |
| 55 | `public typealias CoalescedRunner = RastrilloNative.CoalescedRunner`. |
| 56 | |
| 57 | Native platform integrations belong in platform adapters. Share API and |
| 58 | crypto contracts with the web app; replay the same golden vectors before |
| 59 | claiming compatible bytes. Reuse Rastrillo crypto/keyring where compatible; |
| 60 | do not migrate existing envelopes just to use the package. Native secure |
| 61 | storage, browser key storage, Web Push and APNs/FCM have different lifecycle |
| 62 | contracts. Never treat aviso as native push transport. |
| 63 | |
| 64 | For an app with reusable Go logic, read [docs/go-mobile.md](docs/go-mobile.md). |
| 65 | Go Mobile is optional; the shipped Swift component does not require it. |
| 66 | Android bindings and UI are not supplied by this first package. |
| 67 | |
| 68 | Run `make ci`: Swift tests plus unsigned iOS simulator and macOS builds. |
| 69 | Consumer adoption also runs that app's core tests and builds; a package |
| 70 | test alone cannot detect a missing Xcode dependency. Keep release/device |
| 71 | checks distinct from compile checks. |
| 72 | |