diff --git a/apps/mobile/changelog/0.5.3.md b/apps/mobile/changelog/0.5.3.md
new file mode 100644
index 000000000..c8e24f30d
--- /dev/null
+++ b/apps/mobile/changelog/0.5.3.md
@@ -0,0 +1,11 @@
+# What's New in v0.5.3
+
+## Shiny new things
+
+## Improvements
+
+## No longer broken
+
+## Thanks
+
+Special thanks to volunteer contributors @ for their valuable contributions
diff --git a/apps/mobile/ios/Folo/Info.plist b/apps/mobile/ios/Folo/Info.plist
index f2d0c36e9..9c849eaa5 100644
--- a/apps/mobile/ios/Folo/Info.plist
+++ b/apps/mobile/ios/Folo/Info.plist
@@ -33,7 +33,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 0.5.2
+ 0.5.3
CFBundleSignature
????
CFBundleURLTypes
@@ -54,7 +54,7 @@
CFBundleVersion
- 5
+ 6
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index d3a3aac83..d439ab9e3 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -1,6 +1,6 @@
{
"name": "@follow/mobile",
- "version": "0.5.2",
+ "version": "0.5.3",
"private": true,
"main": "src/main.tsx",
"scripts": {
diff --git a/apps/mobile/release.json b/apps/mobile/release.json
index 2e6f3e8e2..60ae1b255 100644
--- a/apps/mobile/release.json
+++ b/apps/mobile/release.json
@@ -1,5 +1,5 @@
{
- "version": "0.5.2",
+ "version": "0.5.3",
"mode": "ota",
"runtimeVersion": "0.5.0",
"channel": "production"
diff --git a/apps/ota/src/__tests__/manifest.test.ts b/apps/ota/src/__tests__/manifest.test.ts
index 2653162f3..e6307c958 100644
--- a/apps/ota/src/__tests__/manifest.test.ts
+++ b/apps/ota/src/__tests__/manifest.test.ts
@@ -85,6 +85,41 @@ describe("buildManifest", () => {
expect(first.id).toBe(second.id)
})
+
+ it("includes the embedded Expo config needed by expo-constants after an OTA launch", () => {
+ const manifest = buildManifest(createRelease(), {
+ origin: "https://ota.folo.is",
+ platform: "ios",
+ })
+
+ expect(manifest.extra).toMatchObject({
+ expoClient: {
+ name: "Folo",
+ slug: "follow",
+ owner: "follow",
+ scheme: ["follow", "folo"],
+ version: "0.4.2",
+ runtimeVersion: "0.4.1",
+ updates: {
+ url: "https://ota.folo.is/manifest",
+ requestHeaders: {
+ "expo-channel-name": "production",
+ },
+ },
+ ios: {
+ bundleIdentifier: "is.follow",
+ },
+ android: {
+ package: "is.follow",
+ },
+ extra: {
+ eas: {
+ projectId: "a6335b14-fb84-45aa-ba80-6f6ab8926920",
+ },
+ },
+ },
+ })
+ })
})
describe("/manifest", () => {
diff --git a/apps/ota/src/lib/manifest.ts b/apps/ota/src/lib/manifest.ts
index 866201017..1b47972d7 100644
--- a/apps/ota/src/lib/manifest.ts
+++ b/apps/ota/src/lib/manifest.ts
@@ -5,6 +5,43 @@ import type { OtaPlatform, OtaPlatformPayload, OtaProjectedPlatforms, OtaRelease
type PlatformPayload = OtaPlatformPayload
type PlatformAsset = PlatformPayload["launchAsset"] | PlatformPayload["assets"][number]
+type MobileExpoClientConfig = {
+ name: string
+ slug: string
+ owner: string
+ version: string
+ runtimeVersion: string
+ orientation: "portrait"
+ scheme: string[]
+ userInterfaceStyle: "automatic"
+ updates: {
+ url: string
+ requestHeaders: {
+ "expo-channel-name": string
+ }
+ codeSigningMetadata: {
+ keyid: string
+ alg: string
+ }
+ checkAutomatically: "NEVER"
+ }
+ ios: {
+ bundleIdentifier: string
+ supportsTablet: boolean
+ usesAppleSignIn: boolean
+ }
+ android: {
+ package: string
+ }
+ extra: {
+ eas: {
+ projectId: string
+ }
+ }
+}
+
+const MOBILE_UPDATE_URL = "https://ota.folo.is/manifest"
+const MOBILE_EAS_PROJECT_ID = "a6335b14-fb84-45aa-ba80-6f6ab8926920"
export interface ManifestAsset {
key: string
@@ -26,6 +63,7 @@ export interface OtaManifest {
}
extra: {
product: OtaRelease["product"]
+ expoClient?: MobileExpoClientConfig
}
}
@@ -62,9 +100,7 @@ export function buildManifest(
channel: release.channel,
releaseVersion: release.releaseVersion,
},
- extra: {
- product: release.product,
- },
+ extra: buildManifestExtra(release),
}
}
@@ -142,6 +178,56 @@ function toExpoAssetIdentity(path: string, contentType: string) {
}
}
+function buildManifestExtra(release: OtaRelease): OtaManifest["extra"] {
+ const extra: OtaManifest["extra"] = {
+ product: release.product,
+ }
+
+ if (release.product === "mobile") {
+ // Expo Updates hydrates Constants.expoConfig from extra.expoClient after an OTA launch.
+ extra.expoClient = buildMobileExpoClientConfig(release)
+ }
+
+ return extra
+}
+
+function buildMobileExpoClientConfig(release: Extract) {
+ return {
+ name: "Folo",
+ slug: "follow",
+ owner: "follow",
+ version: release.releaseVersion,
+ runtimeVersion: release.runtimeVersion,
+ orientation: "portrait",
+ scheme: ["follow", "folo"],
+ userInterfaceStyle: "automatic",
+ updates: {
+ url: MOBILE_UPDATE_URL,
+ requestHeaders: {
+ "expo-channel-name": release.channel,
+ },
+ codeSigningMetadata: {
+ keyid: "main",
+ alg: "rsa-v1_5-sha256",
+ },
+ checkAutomatically: "NEVER",
+ },
+ ios: {
+ bundleIdentifier: "is.follow",
+ supportsTablet: true,
+ usesAppleSignIn: true,
+ },
+ android: {
+ package: "is.follow",
+ },
+ extra: {
+ eas: {
+ projectId: MOBILE_EAS_PROJECT_ID,
+ },
+ },
+ } satisfies MobileExpoClientConfig
+}
+
function inferExtensionFromContentType(contentType: string) {
switch (contentType) {
case "application/javascript": {