expo-modules-autolinking 3.1.0-canary-20251008-6acbc1c → 3.1.0-canary-20251009-9919e08

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,15 +7,18 @@
7
7
  ### 🎉 New features
8
8
 
9
9
  - Added support for cli command extensions in the interactive devtools menu ([#39598](https://github.com/expo/expo/pull/39598) by [@chrfalch](https://github.com/chrfalch))
10
+ - [Android] Sync flavor dimensions and product flavors from app to expo module ([#40238](https://github.com/expo/expo/pull/40238) by [@kosmydel](https://github.com/kosmydel))
10
11
 
11
12
  ### 🐛 Bug fixes
12
13
 
14
+ - [iOS] Added build phase script for a workaround to autolinking-generated react-native-config output not being used in ReactCodegen script phase due to temp output directory. ([#40219](https://github.com/expo/expo/pull/40219) by [@chrfalch](https://github.com/chrfalch))
13
15
  - [Android] Fix passing exclude options. ([#40014](https://github.com/expo/expo/pull/40014) by [@jakex7](https://github.com/jakex7))
14
16
 
15
17
  ### 💡 Others
16
18
 
17
19
  - [Android] Move generate-package-list to Gradle task ([#39917](https://github.com/expo/expo/pull/39917) by [@jakex7](https://github.com/jakex7))
18
20
  - [Android] Use module name from `expo-module.config.json`. ([#39985](https://github.com/expo/expo/pull/39985) by [@jakex7](https://github.com/jakex7))
21
+ - Check `react-native` and `react-native-tvos` for duplicates in the verify command explicitly ([#40180](https://github.com/expo/expo/pull/40180) by [@kitten](https://github.com/kitten))
19
22
 
20
23
  ## 3.0.14 - 2025-10-01
21
24
 
@@ -1,6 +1,7 @@
1
1
  package expo.modules.plugin
2
2
 
3
3
  import com.android.build.api.variant.AndroidComponentsExtension
4
+ import com.android.build.gradle.BaseExtension
4
5
  import com.android.build.gradle.internal.tasks.factory.dependsOn
5
6
  import expo.modules.plugin.configuration.ExpoModule
6
7
  import expo.modules.plugin.text.Colors
@@ -27,6 +28,9 @@ open class ExpoAutolinkingPlugin : Plugin<Project> {
27
28
  project.logger.quiet("")
28
29
  project.logger.quiet("Using expo modules")
29
30
 
31
+ val appProject = findAppProject(project.rootProject)
32
+ appProject?.let { copyAppDimensionsAndFlavorsToProject(project, it) }
33
+
30
34
  val (prebuiltProjects, projects) = config.allProjects.partition { project ->
31
35
  project.usePublication
32
36
  }
@@ -88,4 +92,79 @@ open class ExpoAutolinkingPlugin : Plugin<Project> {
88
92
  it.modules = modules
89
93
  }
90
94
  }
95
+
96
+ private fun findAppProject(root: Project): Project? {
97
+ return root.allprojects.firstOrNull { it.plugins.hasPlugin("com.android.application") }
98
+ }
99
+
100
+ private fun copyAppDimensionsAndFlavorsToProject(
101
+ project: Project,
102
+ appProject: Project
103
+ ) {
104
+ val appAndroid = appProject.extensions.findByName("android") as? BaseExtension ?: run {
105
+ return
106
+ }
107
+ val consumerAndroid = project.extensions.findByName("android") as? BaseExtension ?: run {
108
+ return
109
+ }
110
+
111
+ val appDimensions = syncFlavorDimensions(project, consumerAndroid, appAndroid)
112
+ copyMissingProductFlavors(project, consumerAndroid, appAndroid, appDimensions)
113
+ }
114
+
115
+ private fun syncFlavorDimensions(
116
+ project: Project,
117
+ consumerAndroid: BaseExtension,
118
+ appAndroid: BaseExtension
119
+ ): List<String> {
120
+ val appDimensions = appAndroid
121
+ .flavorDimensionList
122
+ .takeIf { it.isNotEmpty() }
123
+ ?: return emptyList()
124
+
125
+ val consumerDimensions = (consumerAndroid.flavorDimensionList).toMutableList()
126
+ val dimensionsAdded = appDimensions.any { dimension ->
127
+ if (dimension !in consumerDimensions) {
128
+ consumerDimensions.add(dimension)
129
+ true
130
+ } else {
131
+ false
132
+ }
133
+ }
134
+
135
+ if (dimensionsAdded) {
136
+ consumerAndroid.flavorDimensions(*consumerDimensions.toTypedArray())
137
+ project.logger.quiet(" -> Copied/merged flavorDimensions: ${consumerDimensions.joinToString()}")
138
+ }
139
+
140
+ return appDimensions
141
+ }
142
+
143
+ private fun copyMissingProductFlavors(
144
+ project: Project,
145
+ consumerAndroid: BaseExtension,
146
+ appAndroid: BaseExtension,
147
+ appDimensions: List<String>
148
+ ) {
149
+ val appFlavors = appAndroid.productFlavors
150
+ val consumerFlavors = consumerAndroid.productFlavors
151
+ val existingFlavorNames = consumerFlavors.map { it.name }.toSet()
152
+
153
+ appFlavors.forEach { appFlavor ->
154
+ if (appFlavor.name !in existingFlavorNames) {
155
+ val dimension = appFlavor.dimension ?: appDimensions.singleOrNull()
156
+
157
+ consumerFlavors.create(appFlavor.name).apply {
158
+ this.dimension = dimension
159
+ appFlavor.applicationIdSuffix?.let { this.applicationIdSuffix = it }
160
+ appFlavor.versionNameSuffix?.let { this.versionNameSuffix = it }
161
+ if (appFlavor.manifestPlaceholders.isNotEmpty()) {
162
+ this.manifestPlaceholders.putAll(appFlavor.manifestPlaceholders)
163
+ }
164
+ }
165
+
166
+ project.logger.quiet(" -> Created flavor '${appFlavor.name}' (dimension='$dimension') in :${project.path}")
167
+ }
168
+ }
169
+ }
91
170
  }
@@ -2,4 +2,5 @@ package expo.modules.plugin.text
2
2
 
3
3
  object Emojis {
4
4
  const val INFORMATION = "\u2139\uFE0F"
5
+ const val GEAR = "\u2699"
5
6
  }
@@ -1,15 +1,21 @@
1
1
  package expo.modules.plugin
2
2
 
3
+ import expo.modules.plugin.gradle.addBuildCache
3
4
  import expo.modules.plugin.gradle.beforeRootProject
5
+ import expo.modules.plugin.gradle.loadLocalProperties
6
+ import expo.modules.plugin.utils.getPropertiesPrefixedBy
4
7
  import org.gradle.api.Plugin
5
8
  import org.gradle.api.initialization.Settings
6
9
  import java.io.File
10
+ import java.util.Properties
7
11
 
8
12
  open class ExpoAutolinkingSettingsPlugin : Plugin<Settings> {
9
13
  override fun apply(settings: Settings) {
10
14
  // Adds a property to the settings that indicates that the `expo-autolinking-plugin` is available.
11
15
  settings.gradle.extensions.extraProperties.set("expoAutolinkingSettingsPlugin", true)
12
16
 
17
+ settings.addBuildCache()
18
+
13
19
  // Creates an extension that allows users to link expo modules and add additional configuration.
14
20
  settings.extensions.create("expoAutolinking", ExpoAutolinkingSettingsExtension::class.java, settings)
15
21
 
@@ -3,8 +3,16 @@ package expo.modules.plugin.gradle
3
3
  import expo.modules.plugin.configuration.GradleAarProject
4
4
  import expo.modules.plugin.configuration.GradlePlugin
5
5
  import expo.modules.plugin.configuration.GradleProject
6
+ import expo.modules.plugin.text.Colors
7
+ import expo.modules.plugin.text.Emojis
8
+ import expo.modules.plugin.text.withColor
9
+ import expo.modules.plugin.utils.getPropertiesPrefixedBy
6
10
  import org.gradle.api.initialization.Settings
11
+ import org.gradle.api.logging.Logging
12
+ import org.gradle.caching.http.HttpBuildCache
7
13
  import java.io.File
14
+ import java.net.URI
15
+ import java.util.Properties
8
16
 
9
17
  internal fun Settings.linkProject(project: GradleProject) {
10
18
  include(":${project.name}")
@@ -23,3 +31,51 @@ internal fun Settings.linkAarProject(aarProject: GradleAarProject) {
23
31
  }
24
32
  project(":${aarProject.name}").projectDir = projectDir
25
33
  }
34
+
35
+ internal fun Settings.loadLocalProperties(): Properties {
36
+ return Properties().apply {
37
+ val localPropertiesFile = File(settings.rootDir, "local.properties")
38
+ if (localPropertiesFile.exists()) {
39
+ localPropertiesFile.reader().use(::load)
40
+ }
41
+ }
42
+ }
43
+
44
+ internal fun Settings.addBuildCache() {
45
+ val localProperties = settings
46
+ .loadLocalProperties()
47
+
48
+ val remoteCacheConfigPrefix = "expo.cache.remote."
49
+ val remoteCacheConfig = settings.getPropertiesPrefixedBy(remoteCacheConfigPrefix) +
50
+ localProperties.getPropertiesPrefixedBy(remoteCacheConfigPrefix)
51
+
52
+ val url = remoteCacheConfig["url"] ?: return
53
+ val username = remoteCacheConfig["username"]
54
+ val password = remoteCacheConfig["password"]
55
+ val readonly = remoteCacheConfig["read-only"]?.toBoolean() ?: false
56
+ val isUnsafe = url.startsWith("http://")
57
+
58
+ val logger = Logging.getLogger(Settings::class.java)
59
+
60
+ logger.quiet("${Emojis.GEAR} Configuring remote build cache: ${url.withColor(Colors.GREEN)} (username: ${username.withColor(Colors.GREEN)}, read-only: ${readonly.toString().withColor(Colors.GREEN)})")
61
+
62
+ settings.buildCache { configuration ->
63
+ configuration.remote(HttpBuildCache::class.java) { cache ->
64
+ cache.url = URI.create(url)
65
+
66
+ if (username != null && password != null) {
67
+ cache.credentials {
68
+ it.username = username
69
+ it.password = password
70
+ }
71
+ }
72
+
73
+ cache.isPush = !readonly
74
+
75
+ if (isUnsafe) {
76
+ cache.isAllowInsecureProtocol = true
77
+ cache.isAllowUntrustedServer = true
78
+ }
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,25 @@
1
+ package expo.modules.plugin.utils
2
+
3
+ import org.gradle.api.initialization.Settings
4
+ import java.util.Properties
5
+
6
+ internal fun Properties.getPropertiesPrefixedBy(prefix: String): Map<String, String> {
7
+ return entries
8
+ .mapNotNull { (key, value) ->
9
+ if (key !is String || value !is String) {
10
+ return@mapNotNull null
11
+ }
12
+
13
+ if (key.startsWith(prefix)) {
14
+ key.removePrefix(prefix) to value
15
+ } else {
16
+ null
17
+ }
18
+ }
19
+ .toMap()
20
+ }
21
+
22
+ internal fun Settings.getPropertiesPrefixedBy(prefix: String): Map<String, String> {
23
+ val prefixedProperty = providers.gradlePropertiesPrefixedBy(prefix).get()
24
+ return prefixedProperty.mapKeys { (key, _) -> key.removePrefix(prefix) }
25
+ }
@@ -10,6 +10,8 @@ const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const autolinkingOptions_1 = require("./autolinkingOptions");
12
12
  const dependencies_1 = require("../dependencies");
13
+ // NOTE(@kitten): These are excluded explicitly, but we want to include them for the verify command explicitly
14
+ const INCLUDE_PACKAGES = ['react-native', 'react-native-tvos'];
13
15
  function verifyCommand(cli) {
14
16
  return (0, autolinkingOptions_1.registerAutolinkingArguments)(cli.command('verify'))
15
17
  .option('-v, --verbose', 'Output all results instead of just warnings.', () => true, false)
@@ -20,7 +22,7 @@ function verifyCommand(cli) {
20
22
  const autolinkingOptionsLoader = (0, autolinkingOptions_1.createAutolinkingOptionsLoader)(commandArguments);
21
23
  const appRoot = await autolinkingOptionsLoader.getAppRoot();
22
24
  const linker = (0, dependencies_1.makeCachedDependenciesLinker)({ projectRoot: appRoot });
23
- const results = (0, dependencies_1.mergeResolutionResults)(await Promise.all(platforms.map((platform) => (0, dependencies_1.scanDependencyResolutionsForPlatform)(linker, platform))));
25
+ const results = (0, dependencies_1.mergeResolutionResults)(await Promise.all(platforms.map((platform) => (0, dependencies_1.scanDependencyResolutionsForPlatform)(linker, platform, INCLUDE_PACKAGES))));
24
26
  await verifySearchResults(results, {
25
27
  appRoot,
26
28
  verbose: !!commandArguments.verbose,
@@ -1 +1 @@
1
- {"version":3,"file":"verifyCommand.js","sourceRoot":"","sources":["../../src/commands/verifyCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport commander from 'commander';\nimport fs from 'fs';\nimport path from 'path';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport {\n type BaseDependencyResolution,\n type DependencyResolution,\n type ResolutionResult,\n DependencyResolutionSource,\n makeCachedDependenciesLinker,\n mergeResolutionResults,\n scanDependencyResolutionsForPlatform,\n} from '../dependencies';\n\ninterface VerifyArguments extends AutolinkingCommonArguments {\n verbose?: boolean | null;\n json?: boolean | null;\n}\n\nexport function verifyCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('verify'))\n .option('-v, --verbose', 'Output all results instead of just warnings.', () => true, false)\n .option('-j, --json', 'Output results in the plain JSON format.', () => true, false)\n .option(\n '-p, --platform [platform]',\n 'The platform to validate native modules for. Available options: \"android\", \"ios\", \"both\"',\n 'both'\n )\n .action(async (commandArguments: VerifyArguments) => {\n const platforms =\n commandArguments.platform === 'both' ? ['android', 'ios'] : [commandArguments.platform!];\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader(commandArguments);\n const appRoot = await autolinkingOptionsLoader.getAppRoot();\n const linker = makeCachedDependenciesLinker({ projectRoot: appRoot });\n const results = mergeResolutionResults(\n await Promise.all(\n platforms.map((platform) => scanDependencyResolutionsForPlatform(linker, platform))\n )\n );\n await verifySearchResults(results, {\n appRoot,\n verbose: !!commandArguments.verbose,\n json: !!commandArguments.json,\n });\n });\n}\n\ninterface VerifyOptions {\n appRoot: string;\n verbose?: boolean;\n json?: boolean;\n}\n\ninterface VerifyGroups {\n reactNativeProjectConfig: DependencyResolution[];\n searchPaths: DependencyResolution[];\n dependencies: DependencyResolution[];\n duplicates: DependencyResolution[];\n}\n\n/**\n * Verifies the search results by checking whether there are no duplicates.\n */\nexport async function verifySearchResults(\n results: ResolutionResult,\n options: VerifyOptions\n): Promise<void> {\n const { appRoot } = options;\n\n async function getHumanReadableDependency(dependency: BaseDependencyResolution): Promise<string> {\n let version = dependency.version || null;\n if (!version) {\n try {\n const pkgContents = await fs.promises.readFile(\n path.join(dependency.path, 'package.json'),\n 'utf8'\n );\n const pkg: unknown = JSON.parse(pkgContents);\n if (pkg && typeof pkg === 'object' && 'version' in pkg && typeof pkg.version === 'string') {\n version = pkg.version;\n }\n } catch (error) {\n version = null;\n }\n }\n const relative = path.relative(appRoot, dependency.originPath);\n return version\n ? `${dependency.name}@${version} (at: ${relative})`\n : `${dependency.name} at: ${relative}`;\n }\n\n const groups: VerifyGroups = {\n reactNativeProjectConfig: [],\n searchPaths: [],\n dependencies: [],\n duplicates: [],\n };\n\n for (const moduleName in results) {\n const revision = results[moduleName];\n if (!revision) {\n continue;\n } else if (revision.duplicates?.length) {\n groups.duplicates.push(revision);\n } else {\n switch (revision.source) {\n case DependencyResolutionSource.RN_CLI_LOCAL:\n groups.reactNativeProjectConfig.push(revision);\n break;\n case DependencyResolutionSource.SEARCH_PATH:\n groups.searchPaths.push(revision);\n break;\n case DependencyResolutionSource.RECURSIVE_RESOLUTION:\n groups.dependencies.push(revision);\n break;\n }\n }\n }\n\n if (options.json) {\n console.log(JSON.stringify(groups));\n return;\n }\n\n if (options.verbose) {\n const sortResolutions = (resolutions: DependencyResolution[]) =>\n [...resolutions].sort((a, b) => a.name.localeCompare(b.name));\n\n if (groups.reactNativeProjectConfig.length) {\n console.log(\n `🔎 Found ${groups.reactNativeProjectConfig.length} modules from React Native project config`\n );\n for (const revision of sortResolutions(groups.reactNativeProjectConfig)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n if (groups.searchPaths.length) {\n console.log(`🔎 Found ${groups.searchPaths.length} modules in search paths`);\n for (const revision of sortResolutions(groups.searchPaths)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n console.log(`🔎 Found ${groups.dependencies.length} modules in dependencies`);\n for (const revision of sortResolutions(groups.dependencies)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n if (groups.duplicates.length) {\n for (const revision of groups.duplicates) {\n console.warn(`⚠️ Found duplicate installations for ${chalk.green(revision.name)}`);\n const revisions = [revision, ...(revision.duplicates ?? [])];\n for (let idx = 0; idx < revisions.length; idx++) {\n const prefix = idx !== revisions.length - 1 ? '├─' : '└─';\n const duplicate = revisions[idx];\n console.log(` ${prefix} ${await getHumanReadableDependency(duplicate)}`);\n }\n }\n\n console.warn(\n '⚠️ Multiple versions of the same module may introduce some side effects or compatibility issues.\\n' +\n `Resolve your dependency issues and deduplicate your dependencies. Learn more: https://expo.fyi/resolving-dependency-issues`\n );\n } else {\n console.log('✅ Everything is fine!');\n }\n}\n"]}
1
+ {"version":3,"file":"verifyCommand.js","sourceRoot":"","sources":["../../src/commands/verifyCommand.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport commander from 'commander';\nimport fs from 'fs';\nimport path from 'path';\n\nimport {\n AutolinkingCommonArguments,\n createAutolinkingOptionsLoader,\n registerAutolinkingArguments,\n} from './autolinkingOptions';\nimport {\n type BaseDependencyResolution,\n type DependencyResolution,\n type ResolutionResult,\n DependencyResolutionSource,\n makeCachedDependenciesLinker,\n mergeResolutionResults,\n scanDependencyResolutionsForPlatform,\n} from '../dependencies';\n\n// NOTE(@kitten): These are excluded explicitly, but we want to include them for the verify command explicitly\nconst INCLUDE_PACKAGES = ['react-native', 'react-native-tvos'];\n\ninterface VerifyArguments extends AutolinkingCommonArguments {\n verbose?: boolean | null;\n json?: boolean | null;\n}\n\nexport function verifyCommand(cli: commander.CommanderStatic) {\n return registerAutolinkingArguments(cli.command('verify'))\n .option('-v, --verbose', 'Output all results instead of just warnings.', () => true, false)\n .option('-j, --json', 'Output results in the plain JSON format.', () => true, false)\n .option(\n '-p, --platform [platform]',\n 'The platform to validate native modules for. Available options: \"android\", \"ios\", \"both\"',\n 'both'\n )\n .action(async (commandArguments: VerifyArguments) => {\n const platforms =\n commandArguments.platform === 'both' ? ['android', 'ios'] : [commandArguments.platform!];\n const autolinkingOptionsLoader = createAutolinkingOptionsLoader(commandArguments);\n const appRoot = await autolinkingOptionsLoader.getAppRoot();\n const linker = makeCachedDependenciesLinker({ projectRoot: appRoot });\n const results = mergeResolutionResults(\n await Promise.all(\n platforms.map((platform) =>\n scanDependencyResolutionsForPlatform(linker, platform, INCLUDE_PACKAGES)\n )\n )\n );\n await verifySearchResults(results, {\n appRoot,\n verbose: !!commandArguments.verbose,\n json: !!commandArguments.json,\n });\n });\n}\n\ninterface VerifyOptions {\n appRoot: string;\n verbose?: boolean;\n json?: boolean;\n}\n\ninterface VerifyGroups {\n reactNativeProjectConfig: DependencyResolution[];\n searchPaths: DependencyResolution[];\n dependencies: DependencyResolution[];\n duplicates: DependencyResolution[];\n}\n\n/**\n * Verifies the search results by checking whether there are no duplicates.\n */\nexport async function verifySearchResults(\n results: ResolutionResult,\n options: VerifyOptions\n): Promise<void> {\n const { appRoot } = options;\n\n async function getHumanReadableDependency(dependency: BaseDependencyResolution): Promise<string> {\n let version = dependency.version || null;\n if (!version) {\n try {\n const pkgContents = await fs.promises.readFile(\n path.join(dependency.path, 'package.json'),\n 'utf8'\n );\n const pkg: unknown = JSON.parse(pkgContents);\n if (pkg && typeof pkg === 'object' && 'version' in pkg && typeof pkg.version === 'string') {\n version = pkg.version;\n }\n } catch (error) {\n version = null;\n }\n }\n const relative = path.relative(appRoot, dependency.originPath);\n return version\n ? `${dependency.name}@${version} (at: ${relative})`\n : `${dependency.name} at: ${relative}`;\n }\n\n const groups: VerifyGroups = {\n reactNativeProjectConfig: [],\n searchPaths: [],\n dependencies: [],\n duplicates: [],\n };\n\n for (const moduleName in results) {\n const revision = results[moduleName];\n if (!revision) {\n continue;\n } else if (revision.duplicates?.length) {\n groups.duplicates.push(revision);\n } else {\n switch (revision.source) {\n case DependencyResolutionSource.RN_CLI_LOCAL:\n groups.reactNativeProjectConfig.push(revision);\n break;\n case DependencyResolutionSource.SEARCH_PATH:\n groups.searchPaths.push(revision);\n break;\n case DependencyResolutionSource.RECURSIVE_RESOLUTION:\n groups.dependencies.push(revision);\n break;\n }\n }\n }\n\n if (options.json) {\n console.log(JSON.stringify(groups));\n return;\n }\n\n if (options.verbose) {\n const sortResolutions = (resolutions: DependencyResolution[]) =>\n [...resolutions].sort((a, b) => a.name.localeCompare(b.name));\n\n if (groups.reactNativeProjectConfig.length) {\n console.log(\n `🔎 Found ${groups.reactNativeProjectConfig.length} modules from React Native project config`\n );\n for (const revision of sortResolutions(groups.reactNativeProjectConfig)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n if (groups.searchPaths.length) {\n console.log(`🔎 Found ${groups.searchPaths.length} modules in search paths`);\n for (const revision of sortResolutions(groups.searchPaths)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n console.log(`🔎 Found ${groups.dependencies.length} modules in dependencies`);\n for (const revision of sortResolutions(groups.dependencies)) {\n console.log(` - ${await getHumanReadableDependency(revision)}`);\n }\n }\n\n if (groups.duplicates.length) {\n for (const revision of groups.duplicates) {\n console.warn(`⚠️ Found duplicate installations for ${chalk.green(revision.name)}`);\n const revisions = [revision, ...(revision.duplicates ?? [])];\n for (let idx = 0; idx < revisions.length; idx++) {\n const prefix = idx !== revisions.length - 1 ? '├─' : '└─';\n const duplicate = revisions[idx];\n console.log(` ${prefix} ${await getHumanReadableDependency(duplicate)}`);\n }\n }\n\n console.warn(\n '⚠️ Multiple versions of the same module may introduce some side effects or compatibility issues.\\n' +\n `Resolve your dependency issues and deduplicate your dependencies. Learn more: https://expo.fyi/resolving-dependency-issues`\n );\n } else {\n console.log('✅ Everything is fine!');\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-autolinking",
3
- "version": "3.1.0-canary-20251008-6acbc1c",
3
+ "version": "3.1.0-canary-20251009-9919e08",
4
4
  "description": "Scripts that autolink Expo modules.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -34,7 +34,7 @@
34
34
  "license": "MIT",
35
35
  "homepage": "https://github.com/expo/expo/tree/main/packages/expo-modules-autolinking#readme",
36
36
  "devDependencies": {
37
- "expo-module-scripts": "5.0.8-canary-20251008-6acbc1c",
37
+ "expo-module-scripts": "5.0.8-canary-20251009-9919e08",
38
38
  "memfs": "^3.2.0",
39
39
  "minimatch": "^9.0.0"
40
40
  },
@@ -22,10 +22,91 @@ module Pod
22
22
  class Installer
23
23
  private
24
24
 
25
+ _original_run_podfile_post_install_hooks = instance_method(:run_podfile_post_install_hooks)
25
26
  _original_run_podfile_pre_install_hooks = instance_method(:run_podfile_pre_install_hooks)
27
+ _script_phase_name = '[Expo Autolinking] Run Codegen with autolinking'
26
28
 
27
29
  public
28
30
 
31
+ define_method(:run_podfile_post_install_hooks) do
32
+ # Call original implementation first
33
+ _original_run_podfile_post_install_hooks.bind(self).()
34
+
35
+ # Next we'll perform an Expo workaround for Codegen in React Native where it uses the wrong output path for
36
+ # the generated files. This can be remove when the following PR is merged and released upstream:
37
+ # https://github.com/facebook/react-native/pull/54066
38
+ # TODO: chrfalch - remove when RN PR is released
39
+ # Find the ReactCodegen pod target in the pods project
40
+ react_codegen_native_target = self.pods_project.targets.find { |target| target.name == 'ReactCodegen' }
41
+
42
+ if react_codegen_native_target
43
+ # Check if the build phase already exists
44
+ already_exists = react_codegen_native_target.build_phases.any? do |phase|
45
+ phase.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && phase.name == _script_phase_name
46
+ end
47
+
48
+ if !already_exists
49
+ Pod::UI.puts "[Expo] ".blue + "Adding '#{_script_phase_name}' build phase to ReactCodegen"
50
+
51
+ # Create the new shell script build phase
52
+ phase = react_codegen_native_target.new_shell_script_build_phase(_script_phase_name)
53
+ phase.shell_path = '/bin/sh'
54
+ phase.shell_script = <<~SH
55
+ # Remove this step when the fix is merged and released.
56
+ # See: https://github.com/facebook/react-native/pull/54066
57
+
58
+ # This re-runs Codegen without the broken "scripts/react_native_pods_utils/script_phases.sh" script, causing Codegen to run without autolinking.
59
+ # Instead of using "script_phases.sh" which always runs inside DerivedData, we run it in the normal "/ios" folder
60
+ # See: https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods_utils/script_phases.sh
61
+ pushd "$PODS_ROOT/../" > /dev/null
62
+ RCT_SCRIPT_POD_INSTALLATION_ROOT="$PODS_ROOT/.."
63
+ popd >/dev/null
64
+
65
+ export RCT_SCRIPT_RN_DIR="$REACT_NATIVE_PATH" # This is set by Expo
66
+ export RCT_SCRIPT_APP_PATH="$RCT_SCRIPT_POD_INSTALLATION_ROOT/.."
67
+ export RCT_SCRIPT_OUTPUT_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT"
68
+ export RCT_SCRIPT_TYPE="withCodegenDiscovery"
69
+
70
+ # This is the broken script that runs inside DerivedData, meaning it can't find the autolinking result in `ios/build/generated/autolinking.json`.
71
+ # Resulting in Codegen running with it's own autolinking, not discovering transitive peer dependencies.
72
+ # export SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh"
73
+ export WITH_ENVIRONMENT="$RCT_SCRIPT_RN_DIR/scripts/xcode/with-environment.sh"
74
+
75
+ # Start of workaround code
76
+
77
+ # Load the $NODE_BINARY from the "with-environment.sh" script
78
+ source "$WITH_ENVIRONMENT"
79
+
80
+ # Run this script directly in the right folders:
81
+ # https://github.com/facebook/react-native/blob/3f7f9d8fb8beb41408d092870a7c7cac58029a4d/packages/react-native/scripts/react_native_pods_utils/script_phases.sh#L96-L101
82
+ pushd "$RCT_SCRIPT_RN_DIR" >/dev/null || exit 1
83
+ set -x
84
+ "$NODE_BINARY" "scripts/generate-codegen-artifacts.js" --path "$RCT_SCRIPT_APP_PATH" --outputPath "$RCT_SCRIPT_OUTPUT_DIR" --targetPlatform "ios"
85
+ set +x
86
+ popd >/dev/null || exit 1
87
+
88
+ # End of workaround code
89
+ SH
90
+
91
+ # Find the index of the "Compile Sources" phase (PBXSourcesBuildPhase)
92
+ compile_sources_index = react_codegen_native_target.build_phases.find_index do |p|
93
+ p.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase)
94
+ end
95
+
96
+ if compile_sources_index
97
+ # Remove the phase from its current position (it was added at the end)
98
+ react_codegen_native_target.build_phases.delete(phase)
99
+ # Insert it before the "Compile Sources" phase
100
+ react_codegen_native_target.build_phases.insert(compile_sources_index, phase)
101
+ else
102
+ Pod::UI.puts "[Expo] ".yellow + "Could not find 'Compile Sources' phase, build phase added at default position"
103
+ end
104
+ end
105
+ else
106
+ Pod::UI.puts "[Expo] ".yellow + "ReactCodegen target not found in pods project"
107
+ end
108
+ end
109
+
29
110
  define_method(:run_podfile_pre_install_hooks) do
30
111
  # Call original implementation first
31
112
  _original_run_podfile_pre_install_hooks.bind(self).()
@@ -18,6 +18,9 @@ import {
18
18
  scanDependencyResolutionsForPlatform,
19
19
  } from '../dependencies';
20
20
 
21
+ // NOTE(@kitten): These are excluded explicitly, but we want to include them for the verify command explicitly
22
+ const INCLUDE_PACKAGES = ['react-native', 'react-native-tvos'];
23
+
21
24
  interface VerifyArguments extends AutolinkingCommonArguments {
22
25
  verbose?: boolean | null;
23
26
  json?: boolean | null;
@@ -40,7 +43,9 @@ export function verifyCommand(cli: commander.CommanderStatic) {
40
43
  const linker = makeCachedDependenciesLinker({ projectRoot: appRoot });
41
44
  const results = mergeResolutionResults(
42
45
  await Promise.all(
43
- platforms.map((platform) => scanDependencyResolutionsForPlatform(linker, platform))
46
+ platforms.map((platform) =>
47
+ scanDependencyResolutionsForPlatform(linker, platform, INCLUDE_PACKAGES)
48
+ )
44
49
  )
45
50
  );
46
51
  await verifySearchResults(results, {