1# The Knife Mobile
2
3> [!WARNING]
4> The Knife Mobile is currently in development and is not distributed yet. If you want to try it out, you can build it from source.
5
6## Quickstart
7
8> [!NOTE]
9> Uses native modules so using Expo Go is not supported. You need to use the Expo Dev Client.
10
11This app has three variants:
12
13- `development`: Expo dev client, installable side-by-side as `The Knife Dev`
14- `preview`: persistent internal preview build, installable side-by-side as `The Knife Preview`
15- `production`: store/release build as `The Knife`
16
17Run commands from `apps/mobile`.
18
19T3 Connect is optional and disabled in a fresh clone. Public configuration belongs in the
20repository-root `.env` or `.env.local`, not an `apps/mobile/.env` file. See
21[`../../.env.example`](../../.env.example).
22
23## Development
24
25For simulator/emulator development, select and boot a device, then ensure its native client matches
26this checkout before starting Metro:
27
28```bash
29node ../../scripts/mobile-native-client.ts ensure ios <simulator-udid>
30# Or: node ../../scripts/mobile-native-client.ts ensure android <emulator-serial>
31vp run dev:client
32```
33
34The helper compares a local Expo fingerprint and the installed binary with its last successful
35build record. It builds and installs missing, stale, or unverified clients and reuses matching ones.
36Use `check` instead of `ensure` for a read-only decision: exit 0 means compatible, 2 means a build is
37needed, and 1 means an operational error. Run it on the simulator host; no EAS login is required.
38An externally installed client is unverified until the helper builds it once.
39
40Start Metro for an already verified dev client:
41
42```bash
43vp run dev:client
44```
45
46Metro keeps its transform cache between ordinary starts. If the cache itself is causing stale or
47invalid output, clear it for one development-client start:
48
49```bash
50vp run dev:client:reset
51```
52
53Run that reset once after installing or changing the Uniwind dependency patch. Cached transforms
54can otherwise reference its previous pnpm package path. Ordinary Metro starts still keep the cache.
55
56Component edits use Fast Refresh. See [mobile development lifecycle](../../docs/internals/mobile-development.md)
57before changing runtime ownership or refresh behavior.
58
59Build and run the local iOS dev client:
60
61```bash
62vp run ios:dev
63```
64
65After changing a native dependency patch, rerun CocoaPods before rebuilding an existing iOS
66project. pnpm gives each patch hash a new package path; Pods can otherwise keep compiling the
67previous directory.
68
69If your Xcode account only has a Personal Team, use a bundle identifier you control and opt into the
70reduced-capability local build. Personal Team builds omit the widget and share extensions, push
71entitlement, and native Sign in with Apple entitlement; builds without this opt-in are unchanged.
72
73```bash
74T3CODE_IOS_PERSONAL_TEAM=1 \
75T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID=com.example.t3code.dev \
76vp run ios:dev
77```
78
79Build and install a self-contained Release app that does not need Metro:
80
81```bash
82vp run ios:release
83```
84
85The Personal Team equivalent also needs a unique bundle identifier:
86
87```bash
88T3CODE_IOS_PERSONAL_TEAM=1 \
89T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID=com.example.t3code \
90vp run ios:release
91```
92
93Build and run the local iOS preview app:
94
95```bash
96vp run ios:preview
97```
98
99Force the review diff highlighter engine:
100
101```bash
102EXPO_PUBLIC_REVIEW_HIGHLIGHTER_ENGINE=javascript vp run ios:dev
103```
104
105`javascript` is the default and recommended setting for the review diff screen. Set `EXPO_PUBLIC_REVIEW_HIGHLIGHTER_ENGINE=native` only when you explicitly want to test the native Shiki engine.
106
107Inspect the resolved Expo config for a variant:
108
109```bash
110vp run config:dev
111vp run config:preview
112```
113
114Run static checks for mobile native code:
115
116```bash
117node ../../scripts/mobile-native-static-check.ts
118```
119
120The native lint task runs SwiftLint for Swift plus ktlint and detekt for Kotlin. Missing native tools are reported as warnings and skipped locally. CI installs the default toolset from `apps/mobile/Brewfile` before running the native checks.
121
122## EAS Builds
123
124Preview and production variants use Expo fingerprinting so OTA updates only reach binaries with matching native dependencies, config plugins, and patches. CI uses the `preview:dev` profile to reuse a compatible native build when possible.
125
126The development variant uses `appVersion` to avoid recalculating the native fingerprint for each Metro launch manifest. `MOBILE_VERSION_POLICY` can override either default. If you distribute a custom Release build with the development identity and publish OTA updates to it, set `MOBILE_VERSION_POLICY=fingerprint` for both its build and updates. Changing the runtime policy requires a native rebuild for OTA matching; an existing dev client can still load local Metro bundles.
127
128For preview or production EAS environments, set `T3CODE_CLERK_PUBLISHABLE_KEY`,
129`T3CODE_CLERK_JWT_TEMPLATE`, and `T3CODE_RELAY_URL`
130as EAS environment variables. Expo config maps the canonical values into the mobile build.
131
132Create a PR preview dev-client build manually:
133
134```bash
135vp run eas:ios:preview:dev
136```
137
138Create a cloud dev-client build:
139
140```bash
141vp run eas:ios:dev
142```
143
144Create a persistent preview build:
145
146```bash
147vp run eas:ios:preview
148```
149
150Android equivalents:
151
152```bash
153vp run eas:android:dev
154vp run eas:android:preview:dev
155vp run eas:android:preview
156```