-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[codex] Add Android mobile support #3579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7263f87
3940c8d
bc274f5
b4ab65e
1086910
e4fea10
84e3ca4
ab36472
8169f6d
69c50b2
d39ac7d
9fe4b2b
632784d
a872963
f7279df
e48a9c6
cf0f396
dfde2ad
b2057e2
2f15df1
76cf489
31c8df6
af6100b
74c935b
5fc495e
baff316
fe8fcce
9fe61a6
274b299
f1fe7aa
5fdf4d1
47c5849
dbdf432
13cca5f
cf65adc
7df8cf3
01199df
fcb5645
0911f5a
8c3e487
7a40525
43c55b4
5aae4b3
9b924e6
efdc6c6
3422d9b
57e6060
80cf687
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "expo": {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,20 @@ const repoEnv = loadRepoEnv(); | |
| Object.assign(process.env, repoEnv); | ||
|
|
||
| const APP_VARIANT = resolveAppVariant(repoEnv.APP_VARIANT); | ||
| const isIosPersonalTeamBuild = repoEnv.T3CODE_IOS_PERSONAL_TEAM === "1"; | ||
|
|
||
| const personalTeamBundleIdentifier = repoEnv.T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID?.trim(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π High
π Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| const IOS_BUNDLE_IDENTIFIER_PATTERN = /^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/; | ||
|
|
||
| if ( | ||
| isIosPersonalTeamBuild && | ||
| (!personalTeamBundleIdentifier || | ||
| !IOS_BUNDLE_IDENTIFIER_PATTERN.test(personalTeamBundleIdentifier)) | ||
| ) { | ||
| throw new Error( | ||
| "T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID must be a reverse-DNS identifier such as com.example.t3code when T3CODE_IOS_PERSONAL_TEAM=1.", | ||
| ); | ||
| } | ||
|
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| const VARIANT_CONFIG: Record< | ||
| AppVariant, | ||
|
|
@@ -69,6 +83,26 @@ const dmSansFonts = { | |
| bold: "@expo-google-fonts/dm-sans/700Bold/DMSans_700Bold.ttf", | ||
| } as const; | ||
|
|
||
| const widgetsPlugin: NonNullable<ExpoConfig["plugins"]>[number] = [ | ||
| "expo-widgets", | ||
| { | ||
| bundleIdentifier: `${variant.iosBundleIdentifier}.widgets`, | ||
| groupIdentifier: `group.${variant.iosBundleIdentifier}`, | ||
| enablePushNotifications: true, | ||
| // Agent activity can update many times an hour; without the | ||
| // frequent-updates entitlement iOS throttles the update budget sooner. | ||
| frequentUpdates: true, | ||
| widgets: [ | ||
| { | ||
| name: "AgentActivity", | ||
| displayName: "Agent Activity", | ||
| description: "Shows the current state of active T3 Code agents.", | ||
| supportedFamilies: ["systemSmall", "systemMedium", "accessoryRectangular"], | ||
| }, | ||
| ], | ||
| }, | ||
| ]; | ||
|
|
||
| // These aliases match the fonts' PostScript names on iOS. Register the same | ||
| // names on Android so React Native and the native composer use one set of | ||
| // family names without waiting for runtime font loading. | ||
|
|
@@ -125,12 +159,16 @@ const config: ExpoConfig = { | |
| backgroundImage: "./assets/android-icon-background.png", | ||
| monochromeImage: "./assets/android-icon-monochrome.png", | ||
| }, | ||
| predictiveBackGestureEnabled: false, | ||
| // Opts into OnBackInvokedCallback-based back dispatch (Android 13+). | ||
| // JS back handling survives it via react-native's Android 16 shim plus | ||
| // withAndroidPredictiveBackCompat on Android 13-15. | ||
| predictiveBackGestureEnabled: true, | ||
| }, | ||
| web: { | ||
| favicon: "./assets/favicon.png", | ||
| }, | ||
| plugins: [ | ||
| "expo-asset", | ||
| [ | ||
| "expo-font", | ||
| { | ||
|
|
@@ -157,8 +195,23 @@ const config: ExpoConfig = { | |
| ], | ||
| "expo-secure-store", | ||
| "expo-sqlite", | ||
| ["@clerk/expo", { theme: "./clerk-theme.json" }], | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| // appleSignIn must be gated here: withoutIosPersonalTeamCapabilities.cjs runs before | ||
| // plugins earlier in this array, so it cannot strip the entitlement Clerk would add. | ||
| ["@clerk/expo", { theme: "./clerk-theme.json", appleSignIn: !isIosPersonalTeamBuild }], | ||
| "expo-web-browser", | ||
| [ | ||
| "expo-quick-actions", | ||
| { | ||
| // Adaptive launcher-shortcut icon; referenced by resource name from | ||
| // the shortcut items set in src/features/shortcuts. | ||
| androidIcons: { | ||
| shortcut_icon: { | ||
| foregroundImage: "./assets/android-icon-foreground.png", | ||
| backgroundColor: "#E6F4FE", | ||
| }, | ||
| }, | ||
| }, | ||
| ], | ||
| [ | ||
| "expo-camera", | ||
| { | ||
|
|
@@ -198,31 +251,18 @@ const config: ExpoConfig = { | |
| // expo-widgets' β its dangerous mod wipes ios/ExpoWidgetsTarget/ (which | ||
| // would delete the asset catalog) and its xcodeproj mod creates the widget | ||
| // target (which must exist before the compile phase can be attached). | ||
| "./plugins/withWidgetLogoAsset.cjs", | ||
| [ | ||
| "expo-widgets", | ||
| { | ||
| bundleIdentifier: `${variant.iosBundleIdentifier}.widgets`, | ||
| groupIdentifier: `group.${variant.iosBundleIdentifier}`, | ||
| enablePushNotifications: true, | ||
| // Agent activity can update many times an hour; without the | ||
| // frequent-updates entitlement iOS throttles the update budget sooner. | ||
| frequentUpdates: true, | ||
| widgets: [ | ||
| { | ||
| name: "AgentActivity", | ||
| displayName: "Agent Activity", | ||
| description: "Shows the current state of active T3 Code agents.", | ||
| supportedFamilies: ["systemSmall", "systemMedium", "accessoryRectangular"], | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| ...(!isIosPersonalTeamBuild ? ["./plugins/withWidgetLogoAsset.cjs", widgetsPlugin] : []), | ||
| "./plugins/withIosSceneLifecycle.cjs", | ||
| "./plugins/withAndroidCleartextTraffic.cjs", | ||
| "./plugins/withAndroidGradleHeap.cjs", | ||
| "./plugins/withAndroidModernPopupMenu.cjs", | ||
| "./plugins/withAndroidModernAlertDialog.cjs", | ||
| "./plugins/withAndroidPredictiveBackCompat.cjs", | ||
| ...(isIosPersonalTeamBuild ? ["./plugins/withoutIosPersonalTeamCapabilities.cjs"] : []), | ||
| ], | ||
| extra: { | ||
| appVariant: APP_VARIANT, | ||
| iosPersonalTeamBuild: isIosPersonalTeamBuild, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Medium When Also found in 2 other location(s)
π Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| relay: { | ||
| url: repoEnv.T3CODE_RELAY_URL ?? null, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| apply plugin: 'com.android.library' | ||
| apply plugin: 'org.jetbrains.kotlin.android' | ||
|
|
||
| group = 'com.t3tools.composereditor' | ||
| version = '0.0.0' | ||
|
|
||
| android { | ||
| namespace 'expo.modules.t3composereditor' | ||
| compileSdk rootProject.ext.compileSdkVersion | ||
|
|
||
| defaultConfig { | ||
| minSdkVersion rootProject.ext.minSdkVersion | ||
| targetSdkVersion rootProject.ext.targetSdkVersion | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| implementation project(':expo-modules-core') | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package expo.modules.t3composereditor | ||
|
|
||
| import expo.modules.kotlin.modules.Module | ||
| import expo.modules.kotlin.modules.ModuleDefinition | ||
|
|
||
| class T3ComposerEditorModule : Module() { | ||
| override fun definition() = ModuleDefinition { | ||
| Name("T3ComposerEditor") | ||
|
|
||
| View(T3ComposerEditorView::class) { | ||
| Prop("controlledDocumentJson") { view: T3ComposerEditorView, documentJson: String -> | ||
| view.setControlledDocumentJson(documentJson) | ||
| } | ||
| Prop("themeJson") { view: T3ComposerEditorView, themeJson: String -> | ||
| view.setThemeJson(themeJson) | ||
| } | ||
| Prop("placeholder") { view: T3ComposerEditorView, placeholder: String -> | ||
| view.setPlaceholder(placeholder) | ||
| } | ||
| Prop("fontFamily") { view: T3ComposerEditorView, fontFamily: String -> | ||
| view.setFontFamily(fontFamily) | ||
| } | ||
| Prop("fontSize") { view: T3ComposerEditorView, fontSize: Double -> | ||
| view.setFontSize(fontSize.toFloat()) | ||
| } | ||
| Prop("lineHeight") { view: T3ComposerEditorView, lineHeight: Double -> | ||
| view.setLineHeight(lineHeight.toFloat()) | ||
| } | ||
| Prop("contentInsetVertical") { view: T3ComposerEditorView, contentInsetVertical: Double -> | ||
| view.setContentInsetVertical(contentInsetVertical.toInt()) | ||
| } | ||
|
|
||
| Prop("singleLineCentered") { view: T3ComposerEditorView, singleLineCentered: Boolean -> | ||
| view.setSingleLineCentered(singleLineCentered) | ||
| } | ||
| Prop("editable") { view: T3ComposerEditorView, editable: Boolean -> | ||
| view.setEditable(editable) | ||
| } | ||
| Prop("scrollEnabled") { view: T3ComposerEditorView, scrollEnabled: Boolean -> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Medium The Also found in 1 other location(s)
π Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| view.setScrollEnabled(scrollEnabled) | ||
| } | ||
| Prop("autoFocus") { view: T3ComposerEditorView, autoFocus: Boolean -> | ||
| view.setAutoFocus(autoFocus) | ||
| } | ||
| Prop("autoCorrect") { view: T3ComposerEditorView, autoCorrect: Boolean -> | ||
| view.setAutoCorrect(autoCorrect) | ||
| } | ||
| Prop("spellCheck") { view: T3ComposerEditorView, spellCheck: Boolean -> | ||
| view.setSpellCheck(spellCheck) | ||
| } | ||
|
|
||
| Events( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Medium The π Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| "onComposerChange", | ||
| "onComposerSelectionChange", | ||
| "onComposerFocus", | ||
| "onComposerBlur", | ||
| "onComposerPasteImages", | ||
| "onComposerContentSizeChange", | ||
| ) | ||
|
|
||
| AsyncFunction("focus") { view: T3ComposerEditorView -> | ||
| view.focusEditor() | ||
| } | ||
| AsyncFunction("blur") { view: T3ComposerEditorView -> | ||
| view.blurEditor() | ||
| } | ||
| AsyncFunction("setSelection") { view: T3ComposerEditorView, start: Int, end: Int -> | ||
| view.setSelection(start, end) | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ Medium
t3code/apps/mobile/app.config.ts
Line 139 in 63c8660
When
T3CODE_IOS_PERSONAL_TEAM=1, the config still pinsios.appleTeamIdtoARK85ZXQ4Z, so prebuild/Xcode signs with the T3 Tools team instead of the developer's personal team. The new personal-team path therefore fails at code signing rather than using the developer's own team. Consider clearing or overridingios.appleTeamIdwhenisIosPersonalTeamBuildis true.π Reply "fix it for me" or copy this AI Prompt for your agent: