| 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 | |
| 11 | This 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 | |
| 17 | Run commands from `apps/mobile`. |
| 18 | |
| 19 | T3 Connect is optional and disabled in a fresh clone. Public configuration belongs in the |
| 20 | repository-root `.env` or `.env.local`, not an `apps/mobile/.env` file. See |
| 21 | [`../../.env.example`](../../.env.example). |
| 22 | |
| 23 | ## Development |
| 24 | |
| 25 | For simulator/emulator development, select and boot a device, then ensure its native client matches |
| 26 | this checkout before starting Metro: |
| 27 | |
| 28 | ```bash |
| 29 | node ../../scripts/mobile-native-client.ts ensure ios <simulator-udid> |
| 30 | # Or: node ../../scripts/mobile-native-client.ts ensure android <emulator-serial> |
| 31 | vp run dev:client |
| 32 | ``` |
| 33 | |
| 34 | The helper compares a local Expo fingerprint and the installed binary with its last successful |
| 35 | build record. It builds and installs missing, stale, or unverified clients and reuses matching ones. |
| 36 | Use `check` instead of `ensure` for a read-only decision: exit 0 means compatible, 2 means a build is |
| 37 | needed, and 1 means an operational error. Run it on the simulator host; no EAS login is required. |
| 38 | An externally installed client is unverified until the helper builds it once. |
| 39 | |
| 40 | Start Metro for an already verified dev client: |
| 41 | |
| 42 | ```bash |
| 43 | vp run dev:client |
| 44 | ``` |
| 45 | |
| 46 | Metro keeps its transform cache between ordinary starts. If the cache itself is causing stale or |
| 47 | invalid output, clear it for one development-client start: |
| 48 | |
| 49 | ```bash |
| 50 | vp run dev:client:reset |
| 51 | ``` |
| 52 | |
| 53 | Run that reset once after installing or changing the Uniwind dependency patch. Cached transforms |
| 54 | can otherwise reference its previous pnpm package path. Ordinary Metro starts still keep the cache. |
| 55 | |
| 56 | Component edits use Fast Refresh. See [mobile development lifecycle](../../docs/internals/mobile-development.md) |
| 57 | before changing runtime ownership or refresh behavior. |
| 58 | |
| 59 | Build and run the local iOS dev client: |
| 60 | |
| 61 | ```bash |
| 62 | vp run ios:dev |
| 63 | ``` |
| 64 | |
| 65 | After changing a native dependency patch, rerun CocoaPods before rebuilding an existing iOS |
| 66 | project. pnpm gives each patch hash a new package path; Pods can otherwise keep compiling the |
| 67 | previous directory. |
| 68 | |
| 69 | If your Xcode account only has a Personal Team, use a bundle identifier you control and opt into the |
| 70 | reduced-capability local build. Personal Team builds omit the widget and share extensions, push |
| 71 | entitlement, and native Sign in with Apple entitlement; builds without this opt-in are unchanged. |
| 72 | |
| 73 | ```bash |
| 74 | T3CODE_IOS_PERSONAL_TEAM=1 \ |
| 75 | T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID=com.example.t3code.dev \ |
| 76 | vp run ios:dev |
| 77 | ``` |
| 78 | |
| 79 | Build and install a self-contained Release app that does not need Metro: |
| 80 | |
| 81 | ```bash |
| 82 | vp run ios:release |
| 83 | ``` |
| 84 | |
| 85 | The Personal Team equivalent also needs a unique bundle identifier: |
| 86 | |
| 87 | ```bash |
| 88 | T3CODE_IOS_PERSONAL_TEAM=1 \ |
| 89 | T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID=com.example.t3code \ |
| 90 | vp run ios:release |
| 91 | ``` |
| 92 | |
| 93 | Build and run the local iOS preview app: |
| 94 | |
| 95 | ```bash |
| 96 | vp run ios:preview |
| 97 | ``` |
| 98 | |
| 99 | Force the review diff highlighter engine: |
| 100 | |
| 101 | ```bash |
| 102 | EXPO_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 | |
| 107 | Inspect the resolved Expo config for a variant: |
| 108 | |
| 109 | ```bash |
| 110 | vp run config:dev |
| 111 | vp run config:preview |
| 112 | ``` |
| 113 | |
| 114 | Run static checks for mobile native code: |
| 115 | |
| 116 | ```bash |
| 117 | node ../../scripts/mobile-native-static-check.ts |
| 118 | ``` |
| 119 | |
| 120 | The 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 | |
| 124 | Preview 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 | |
| 126 | The 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 | |
| 128 | For preview or production EAS environments, set `T3CODE_CLERK_PUBLISHABLE_KEY`, |
| 129 | `T3CODE_CLERK_JWT_TEMPLATE`, and `T3CODE_RELAY_URL` |
| 130 | as EAS environment variables. Expo config maps the canonical values into the mobile build. |
| 131 | |
| 132 | Create a PR preview dev-client build manually: |
| 133 | |
| 134 | ```bash |
| 135 | vp run eas:ios:preview:dev |
| 136 | ``` |
| 137 | |
| 138 | Create a cloud dev-client build: |
| 139 | |
| 140 | ```bash |
| 141 | vp run eas:ios:dev |
| 142 | ``` |
| 143 | |
| 144 | Create a persistent preview build: |
| 145 | |
| 146 | ```bash |
| 147 | vp run eas:ios:preview |
| 148 | ``` |
| 149 | |
| 150 | Android equivalents: |
| 151 | |
| 152 | ```bash |
| 153 | vp run eas:android:dev |
| 154 | vp run eas:android:preview:dev |
| 155 | vp run eas:android:preview |
| 156 | ``` |