Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/151-objectos-rebrand.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Metadata-protocol: none
Rebrand the app to ObjectOS. The app is named `ObjectOS`, its URL scheme
defaults to `objectos` (`objectos://open?route=…`, `objectos://console/…`),
the iOS bundle identifier and Android package are `ai.objectos.mobile`, and the
Expo slug is `objectos-mobile`. The server picker says "ObjectOS server" in
Expo slug is `objectos`. The server picker says "ObjectOS server" in
en / zh / ar.

Development builds made before this change are a different app (old bundle id,
Expand Down
16 changes: 16 additions & 0 deletions .changeset/eas-project-link.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"mobile": patch
---

Clause-②: no
Metadata-protocol: none

Link the app to the EAS project `@objectstack/objectos`, so CI can produce
installable builds. The Expo slug moves from `objectos-mobile` to `objectos`,
matching that project. Over-the-air updates are on, gated by the fingerprint
runtime version (`expo-updates`). A `development-device` profile builds a dev
client for a phone (`expo-dev-client`). `preview` builds use channel `preview`,
pre-fill no server and skip Sentry's source map upload. The EAS workflows run on
Node 22, which `eas-cli` requires.

Both modules are native: earlier development builds need rebuilding.
2 changes: 1 addition & 1 deletion .github/workflows/eas-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- uses: actions/setup-node@v4
if: ${{ env.EXPO_TOKEN != '' }}
with:
node-version: 20
node-version: 22
cache: pnpm
- uses: expo/expo-github-action@v8
if: ${{ env.EXPO_TOKEN != '' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/eas-submit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- uses: actions/setup-node@v4
if: ${{ env.EXPO_TOKEN != '' }}
with:
node-version: 20
node-version: 22
cache: pnpm
- uses: expo/expo-github-action@v8
if: ${{ env.EXPO_TOKEN != '' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/eas-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- uses: actions/setup-node@v4
if: ${{ env.EXPO_TOKEN != '' }}
with:
node-version: 20
node-version: 22
cache: pnpm
- uses: expo/expo-github-action@v8
if: ${{ env.EXPO_TOKEN != '' }}
Expand Down
2 changes: 1 addition & 1 deletion __tests__/lib/shell/incoming-link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ describe("redirectIncomingPath", () => {
it("passes internal paths and the dev-client launcher through", () => {
expect(redirectIncomingPath("/server-config")).toBe("/server-config");
const dev =
"exp+objectos-mobile://expo-development-client/?url=http%3A%2F%2F10.0.0.2%3A8081";
"exp+objectos://expo-development-client/?url=http%3A%2F%2F10.0.0.2%3A8081";
expect(redirectIncomingPath(dev)).toBe(dev);
});
});
13 changes: 12 additions & 1 deletion app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,21 @@ const PERMISSION_LOCALES: Record<
ar,
};

// The EAS project this app builds and publishes under: `@objectstack/objectos`.
// `owner`, `slug` and this ID must name the same project, and neither the slug
// nor the ID can change without moving to a new EAS project.
const EAS_PROJECT_ID = "40edd17e-752e-4062-a404-5eb8892ce47f";

export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: "ObjectOS",
slug: "objectos-mobile",
owner: "objectstack",
slug: "objectos",
version: "2.0.0",
// An over-the-air update only reaches a binary with the same native modules:
// the fingerprint changes whenever the native side does.
runtimeVersion: { policy: "fingerprint" },
updates: { url: `https://u.expo.dev/${EAS_PROJECT_ID}` },
orientation: "portrait",
icon: "./assets/icon.png",
scheme: process.env.EXPO_PUBLIC_APP_SCHEME ?? "objectos",
Expand Down Expand Up @@ -145,5 +155,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
// configured server — typically the SSO identity provider.
trustedHosts: process.env.EXPO_PUBLIC_TRUSTED_HOSTS ?? "",
sentryDsn: process.env.EXPO_PUBLIC_SENTRY_DSN ?? "",
eas: { projectId: EAS_PROJECT_ID },
},
});
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"expo": {
"name": "ObjectOS",
"slug": "objectos-mobile",
"slug": "objectos",
"version": "2.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
Expand Down
20 changes: 18 additions & 2 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
| `EXPO_PUBLIC_SENTRY_DSN` | crash reporting |
| `EXPO_PUBLIC_APP_SCHEME` | URL scheme for app links (default `objectos`) |

Profiles and their values live in `eas.json`.
Profiles and their values live in `eas.json`. `preview` skips Sentry's source map
upload (`SENTRY_DISABLE_AUTO_UPLOAD`); a `production` build uploads, so it needs a
`SENTRY_AUTH_TOKEN` in the project's EAS environment variables.

## Managed deployment (MDM)

Expand Down Expand Up @@ -108,12 +110,16 @@ a build without it reads no managed config.
## Builds

```bash
eas build --profile development --platform ios|android # dev client
eas build --profile development --platform ios|android # dev client, iOS simulator
eas build --profile development-device --platform ios|android # dev client, phone
eas build --profile preview --platform all # internal distribution
eas build --profile production --platform all # store builds
eas submit --platform ios|android --profile production
```

The app builds under the EAS project `@objectstack/objectos`. `owner`, `slug` and
`extra.eas.projectId` in `app.config.ts` name it together.

CI (`.github/workflows/`):

- `ci.yml` — Jest with coverage on every PR;
Expand All @@ -128,6 +134,16 @@ release. A new store build is needed only for native changes (new native
module, bridge method, permission, icon). Shell-only JavaScript fixes can ship
over the air with EAS Update.

`runtimeVersion` uses the fingerprint policy, so an update only reaches binaries
with the same native side. A binary reads the branch its channel points at:
`preview` builds use channel `preview`, while `eas-update.yml` publishes with
`--auto`, to a branch named after the git branch (`main`). Until the channel is
pointed there, an update from CI reaches no installed build:

```bash
eas channel:edit preview --branch main
```

## App review

App Store guideline 4.2 rejects apps that are only a website in a frame. The
Expand Down
62 changes: 56 additions & 6 deletions docs/DEVICE-TESTING.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
# Device Testing

The shell uses native modules (`react-native-webview`, notifications), so run a
**development build** rather than Expo Go.
The shell uses native modules (`react-native-webview`, notifications), so it does
not run in Expo Go. Install a build from EAS, project
[`@objectstack/objectos`](https://expo.dev/accounts/objectstack/projects/objectos/builds).

## Build and run
## Install on a phone

The `preview` profile is the build for testers. It needs no computer on the
phone's side.

**Android**

1. Open the latest `preview` Android build on the
[builds page](https://expo.dev/accounts/objectstack/projects/objectos/builds),
or scan its QR code.
2. Install the APK. Android asks once to allow installs from that browser.

**iOS** needs an Apple Developer team, and only registered devices can install.

1. Someone with the Expo account runs `eas device:create` and sends the phone the
link it prints. Open it on the iPhone and install the profile.
2. Build after registering, because a build only includes the devices registered
when it was made: `eas build --profile preview --platform ios`.
3. Open the build's link on the iPhone and install.

Then open the app and enter a server (see [Server address](#server-address)).
`preview` builds pre-fill no server.

## Development builds

For working on the shell itself, against `pnpm start`:

```bash
pnpm install
eas build --profile development --platform ios # or android
eas build --profile development-device --platform ios # or android; a phone
eas build --profile development --platform ios # or android; a simulator
# install the build, then:
pnpm start
```

`eas build --profile development --platform ios` produces a simulator build by
default (see `eas.json`); remove `ios.simulator` for a device build.
A development build for an iPhone needs the same device registration as above.

## Server address

Expand All @@ -37,6 +63,30 @@ anything public must be `https://`.
| Links | `xcrun simctl openurl booted "objectos://console/apps"` / `adb shell am start -d "objectos://console/apps"` opens that route |
| Push | see [PUSH-NOTIFICATIONS.md](./PUSH-NOTIFICATIONS.md) — needs the server device registry |

## Smoke checklist for landed cards

None of these has run on a device yet. Each comes from the manual check on its
card. "Dev" means it needs a development build for the tooling named.

| Card | Check |
|---|---|
| #151 Rebrand | `objectos://console/apps` opens the Console's apps page (`adb shell am start -d "objectos://console/apps"`, Dev on iOS: `xcrun simctl openurl booted`) |
| #154 Server probe | a private server shows the confirm page with the right details; a server with a bad certificate says the certificate is invalid; an https site that is not ObjectOS says so |
| #162 Ready signals | kill the app, tap a push notification: the target record opens with no second cover or full page reload |
| #163 Device registration | after a push token rotates, a signed-in Console receives `objectstack-native:pushTokenChanged`; `window.ObjectStackNative.installId` survives clearing WebView storage |
| #156 Connect | scan a real connect QR code; open an `objectos://connect` link from mail or notes; deny the camera permission |
| #159 Languages | set the phone to Japanese, Arabic and Traditional Chinese (`zh-TW`) in turn: native pages follow, `zh-TW` shows Simplified Chinese, Arabic reads right to left |
| #146 Scan | in a Console page that calls `scan()`, a scanned code fills the field; closing the scanner returns `null`; a denied camera permission fails with `failed` |
| #152 Saved connections | add two connections and switch between them; remove one and confirm it is signed out; upgrade from a version that saved one server |
| #157 MDM | on Android with Test DPC or an EMM, push `serverUrl` and `lockServer=true`: the app goes straight to the confirm page, the switcher has no add-server row, the managed connection cannot be swiped away, and a failed probe says to contact the IT administrator |
| #155 IdP sign-in | with an https test OIDC provider: its page loads under the bar with its exact host; finishing sign-in removes the bar and loads the Console; Android back does not return to the provider; Cancel returns to `/login` |
| Navigation policy | Android: in-server navigation, trusted hosts and sign-in excursions work; a top-level page outside the policy is stopped and returns to the server |
| #147 Pick, share, open | take a photo and pick a library image to upload; open a PDF and an image; open the share sheet; on Android a page's own `input type=file` still works |
| #145 App lock | turn the lock on with "immediately", background and return: the cover shows; biometrics remove it with no reload and form contents intact; the passcode works after a cancelled prompt; the app switcher shows blur on iOS and blank on Android; changing the setting asks for biometrics first, and cancelling leaves it unchanged |

Report results on the maintainer's device-testing card, and open a defect card
for each failure.

## Debugging the page

Development builds enable WebView debugging: Safari → Develop → (device) on
Expand Down
14 changes: 9 additions & 5 deletions eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@
"simulator": true
}
},
"development-device": {
"extends": "development",
"ios": {
"simulator": false
}
},
"preview": {
"distribution": "internal",
"channel": "preview",
"env": {
"EXPO_PUBLIC_DEFAULT_SERVER_URL": "https://staging.objectstack.com"
"SENTRY_DISABLE_AUTO_UPLOAD": "true"
}
},
"production": {
"autoIncrement": true,
"env": {
"EXPO_PUBLIC_DEFAULT_SERVER_URL": ""
}
"autoIncrement": true
}
},
"submit": {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"expo": "~55.0.26",
"expo-camera": "~55.0.23",
"expo-constants": "~55.0.16",
"expo-dev-client": "~55.0.41",
"expo-device": "~55.0.17",
"expo-file-system": "~55.0.22",
"expo-font": "~55.0.8",
Expand All @@ -41,6 +42,7 @@
"expo-sharing": "~55.0.25",
"expo-status-bar": "~55.0.6",
"expo-system-ui": "~55.0.18",
"expo-updates": "~55.0.33",
"expo-web-browser": "~55.0.16",
"i18next": "^25.8.4",
"lucide-react-native": "^0.563.0",
Expand Down
Loading
Loading