authorgravatar for 71498452+StiensWout@users.noreply.github.comWout Stiens <71498452+StiensWout@users.noreply.github.com> 2026-09-02 20:44:31+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-02 18:44:31+00:00
logaab4049646ffa8b9bcff92562992e6c3a8554bf0
tree03bf765b3785af152ea533f09917dead960928d6
parentb5a09e13fa464a8681e0bf9df404dd3c0afe8ac8
signature Signed by PGP key B5690EEEBB952194

fix(ci): keep Expo Sharing patch applied (#9248)


5 files changed, 131 insertions(+), 131 deletions(-)

apps/mobile/package.json+1-1
......@@ -97,7 +97,7 @@
9797 "expo-paste-input": "^0.1.15",
9898 "expo-quick-actions": "^6.0.2",
9999 "expo-secure-store": "~57.0.2",
100 "expo-sharing": "57.0.16",
100 "expo-sharing": "57.0.17",
101101 "expo-splash-screen": "~57.0.8",
102102 "expo-sqlite": "~57.0.2",
103103 "expo-symbols": "~57.0.2",
patches/expo-sharing@57.0.16.patch deleted-123
......@@ -1,123 +0,0 @@
1diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
2index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644
3--- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt
4+++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
5@@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable {
6 internal data class SharePayload(
7 @Field var value: String = "",
8 @Field var shareType: ShareType = ShareType.Text,
9- @Field var mimeType: String = "text/plain"
10+ @Field var mimeType: String = "text/plain",
11+ @Field var originalName: String? = null
12 ) : Record
13
14 @OptimizedRecord
15diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
16index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644
17--- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
18+++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
19@@ -3,6 +3,7 @@ package expo.modules.sharing
20 import android.content.Context
21 import android.content.Intent
22 import android.net.Uri
23+import android.provider.OpenableColumns
24
25 internal class SimpleShareIntentDataParser {
26 companion object {
27@@ -17,21 +18,26 @@ internal class SimpleShareIntentDataParser {
28 }
29
30 private fun handleSendAction(context: Context, intent: Intent, type: String): List<SharePayload> {
31- return if (type == "text/plain") {
32- val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return emptyList()
33- val isUrl = android.util.Patterns.WEB_URL.matcher(text).matches()
34-
35- listOf(
36+ val stream = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
37+ val text = intent.getStringExtra(Intent.EXTRA_TEXT)
38+ if (stream == null) {
39+ if (!type.startsWith("text/") || text == null) return emptyList()
40+ return listOf(
41 SharePayload().apply {
42 value = text
43- shareType = if (isUrl) ShareType.Url else ShareType.Text
44- mimeType = "text/plain"
45+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
46+ mimeType = type
47 }
48 )
49- } else {
50- val uri = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
51- listOfNotNull(uri?.let { createUriPayload(context, it, type) })
52 }
53+ val filePayload = createUriPayload(context, stream, type)
54+ if (text.isNullOrBlank()) return listOf(filePayload)
55+ val textPayload = SharePayload().apply {
56+ value = text
57+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
58+ mimeType = "text/plain"
59+ }
60+ return listOf(textPayload, filePayload)
61 }
62
63 private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List<SharePayload> {
64@@ -41,10 +47,25 @@ internal class SimpleShareIntentDataParser {
65
66 private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload {
67 val specificType = context.contentResolver.getType(uri) ?: defaultType
68+ // A blank DISPLAY_NAME must stay null: consumers treat originalName as
69+ // the attachment name, and an empty name fails contract validation.
70+ val displayName = runCatching {
71+ context.contentResolver.query(
72+ uri,
73+ arrayOf(OpenableColumns.DISPLAY_NAME),
74+ null,
75+ null,
76+ null
77+ )?.use { cursor ->
78+ val column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
79+ if (column >= 0 && cursor.moveToFirst()) cursor.getString(column) else null
80+ }
81+ }.getOrNull()?.takeIf { it.isNotBlank() }
82 return SharePayload().apply {
83 value = uri.toString()
84- shareType = ShareType.fromMimeType(specificType)
85+ shareType = if (specificType.startsWith("text/")) ShareType.File else ShareType.fromMimeType(specificType)
86 mimeType = specificType
87+ originalName = displayName
88 }
89 }
90 }
91diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts
92index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01c8728fcc 100644
93--- a/build/Sharing.types.d.ts
94+++ b/build/Sharing.types.d.ts
95@@ -77,6 +77,11 @@ export type SharePayload = {
96 * @default 'text/plain'
97 */
98 mimeType?: string;
99+ /**
100+ * The display name of a shared file, when the source app provided one.
101+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
102+ */
103+ originalName?: string | null;
104 };
105 export type BaseResolvedSharePayload = SharePayload & {
106 /**
107diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts
108index d9a5ad38f5fe2856b365eb91b71abd640314a5cc..21ea45f04b88cce272e2e02de24c5e4eb8157e82 100644
109--- a/src/Sharing.types.ts
110+++ b/src/Sharing.types.ts
111@@ -85,6 +85,12 @@ export type SharePayload = {
112 * @default 'text/plain'
113 */
114 mimeType?: string;
115+
116+ /**
117+ * The display name of a shared file, when the source app provided one.
118+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
119+ */
120+ originalName?: string | null;
121 };
122
123 export type BaseResolvedSharePayload = SharePayload & {
patches/expo-sharing@57.0.17.patch created+123
......@@ -0,0 +1,123 @@
1diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
2index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644
3--- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt
4+++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
5@@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable {
6 internal data class SharePayload(
7 @Field var value: String = "",
8 @Field var shareType: ShareType = ShareType.Text,
9- @Field var mimeType: String = "text/plain"
10+ @Field var mimeType: String = "text/plain",
11+ @Field var originalName: String? = null
12 ) : Record
13
14 @OptimizedRecord
15diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
16index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644
17--- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
18+++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
19@@ -3,6 +3,7 @@ package expo.modules.sharing
20 import android.content.Context
21 import android.content.Intent
22 import android.net.Uri
23+import android.provider.OpenableColumns
24
25 internal class SimpleShareIntentDataParser {
26 companion object {
27@@ -17,21 +18,26 @@ internal class SimpleShareIntentDataParser {
28 }
29
30 private fun handleSendAction(context: Context, intent: Intent, type: String): List<SharePayload> {
31- return if (type == "text/plain") {
32- val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return emptyList()
33- val isUrl = android.util.Patterns.WEB_URL.matcher(text).matches()
34-
35- listOf(
36+ val stream = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
37+ val text = intent.getStringExtra(Intent.EXTRA_TEXT)
38+ if (stream == null) {
39+ if (!type.startsWith("text/") || text == null) return emptyList()
40+ return listOf(
41 SharePayload().apply {
42 value = text
43- shareType = if (isUrl) ShareType.Url else ShareType.Text
44- mimeType = "text/plain"
45+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
46+ mimeType = type
47 }
48 )
49- } else {
50- val uri = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
51- listOfNotNull(uri?.let { createUriPayload(context, it, type) })
52 }
53+ val filePayload = createUriPayload(context, stream, type)
54+ if (text.isNullOrBlank()) return listOf(filePayload)
55+ val textPayload = SharePayload().apply {
56+ value = text
57+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
58+ mimeType = "text/plain"
59+ }
60+ return listOf(textPayload, filePayload)
61 }
62
63 private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List<SharePayload> {
64@@ -41,10 +47,25 @@ internal class SimpleShareIntentDataParser {
65
66 private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload {
67 val specificType = context.contentResolver.getType(uri) ?: defaultType
68+ // A blank DISPLAY_NAME must stay null: consumers treat originalName as
69+ // the attachment name, and an empty name fails contract validation.
70+ val displayName = runCatching {
71+ context.contentResolver.query(
72+ uri,
73+ arrayOf(OpenableColumns.DISPLAY_NAME),
74+ null,
75+ null,
76+ null
77+ )?.use { cursor ->
78+ val column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
79+ if (column >= 0 && cursor.moveToFirst()) cursor.getString(column) else null
80+ }
81+ }.getOrNull()?.takeIf { it.isNotBlank() }
82 return SharePayload().apply {
83 value = uri.toString()
84- shareType = ShareType.fromMimeType(specificType)
85+ shareType = if (specificType.startsWith("text/")) ShareType.File else ShareType.fromMimeType(specificType)
86 mimeType = specificType
87+ originalName = displayName
88 }
89 }
90 }
91diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts
92index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01c8728fcc 100644
93--- a/build/Sharing.types.d.ts
94+++ b/build/Sharing.types.d.ts
95@@ -77,6 +77,11 @@ export type SharePayload = {
96 * @default 'text/plain'
97 */
98 mimeType?: string;
99+ /**
100+ * The display name of a shared file, when the source app provided one.
101+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
102+ */
103+ originalName?: string | null;
104 };
105 export type BaseResolvedSharePayload = SharePayload & {
106 /**
107diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts
108index d9a5ad38f5fe2856b365eb91b71abd640314a5cc..21ea45f04b88cce272e2e02de24c5e4eb8157e82 100644
109--- a/src/Sharing.types.ts
110+++ b/src/Sharing.types.ts
111@@ -85,6 +85,12 @@ export type SharePayload = {
112 * @default 'text/plain'
113 */
114 mimeType?: string;
115+
116+ /**
117+ * The display name of a shared file, when the source app provided one.
118+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
119+ */
120+ originalName?: string | null;
121 };
122
123 export type BaseResolvedSharePayload = SharePayload & {
pnpm-lock.yaml+6-6
......@@ -93,7 +93,7 @@ patchedDependencies:
9393 '@react-navigation/native-stack@7.17.6': e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552
9494 effect@4.0.0-beta.103: af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6
9595 expo-audio@57.0.4: fa9a3e0442ed395d4071bb406e08c3a471c9a84700bdfa0b9ad7ff144c96041a
96 expo-sharing@57.0.16: 8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45
96 expo-sharing@57.0.17: 8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45
9797 react-native-gesture-handler@2.32.0: 808eb26f9e57cf4945efd3985af4d9c764da6f91f4c9764433cc868602bbf4d3
9898 react-native-keyboard-controller@1.21.13: 6e4339347bc5bb3c9ea67d85ff5c814058b211c5750f247aba59d07869a2e787
9999 react-native-nitro-modules@0.35.9: 825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675
......@@ -368,8 +368,8 @@ importers:
368368 specifier: ~57.0.2
369369 version: 57.0.2(expo@57.0.18)
370370 expo-sharing:
371 specifier: 57.0.16
372 version: 57.0.16(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3)
371 specifier: 57.0.17
372 version: 57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3)
373373 expo-splash-screen:
374374 specifier: ~57.0.8
375375 version: 57.0.8(expo@57.0.18)(typescript@6.0.3)
......@@ -6676,8 +6676,8 @@ packages:
66766676 resolution: {integrity: sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==}
66776677 engines: {node: '>=20.16.0'}
66786678
6679 expo-sharing@57.0.16:
6680 resolution: {integrity: sha512-Z4ZFYLP8+EqIdUAiERYRI4/r7rtZDCRQ8Lj6jDG0xPF19B8nsFhYMgh7uyic+WulFEr+Xn7FeWgSDAuufkOyzw==}
6679 expo-sharing@57.0.17:
6680 resolution: {integrity: sha512-p2B4SMeNsOv6hm1NkrxRlncjwu9mmLfi0drLaEyX13Rxn4DdDFPhuaezpOK7XLogTsmWGpfR46uq6oHMvSxbfA==}
66816681 peerDependencies:
66826682 expo: '*'
66836683 react: '*'
......@@ -16613,7 +16613,7 @@ snapshots:
1661316613
1661416614 expo-server@57.0.3: {}
1661516615
16616 expo-sharing@57.0.16(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3):
16616 expo-sharing@57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3):
1661716617 dependencies:
1661816618 '@expo/config-plugins': 57.0.9(typescript@6.0.3)
1661916619 '@expo/config-types': 57.0.2
pnpm-workspace.yaml+1-1
......@@ -155,7 +155,7 @@ patchedDependencies:
155155 "@react-navigation/native-stack@7.17.6": patches/@react-navigation%2Fnative-stack@7.17.6.patch
156156 effect@4.0.0-beta.103: patches/effect@4.0.0-beta.103.patch
157157 expo-audio@57.0.4: patches/expo-audio@57.0.4.patch
158 expo-sharing@57.0.16: patches/expo-sharing@57.0.16.patch
158 expo-sharing@57.0.17: patches/expo-sharing@57.0.17.patch
159159 react-native-gesture-handler@2.32.0: patches/react-native-gesture-handler@2.32.0.patch
160160 react-native-keyboard-controller@1.21.13: patches/react-native-keyboard-controller@1.21.13.patch
161161 react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch