expo-modules-autolinking 3.1.0-canary-20251003-7b9d7ff → 3.1.0-canary-20251008-f2d1b4a
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 +3 -0
- package/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt +79 -0
- package/android/expo-gradle-plugin/expo-autolinking-plugin-shared/src/main/kotlin/expo/modules/plugin/text/Emojis.kt +1 -0
- package/android/expo-gradle-plugin/expo-autolinking-settings-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingSettingsPlugin.kt +6 -0
- package/android/expo-gradle-plugin/expo-autolinking-settings-plugin/src/main/kotlin/expo/modules/plugin/gradle/SettingsExtension.kt +56 -0
- package/android/expo-gradle-plugin/expo-autolinking-settings-plugin/src/main/kotlin/expo/modules/plugin/utils/PropertiesExtension.kt +25 -0
- package/build/commands/verifyCommand.js +3 -1
- package/build/commands/verifyCommand.js.map +1 -1
- package/package.json +2 -2
- package/scripts/ios/cocoapods/installer.rb +81 -0
- package/src/commands/verifyCommand.ts +6 -1
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
|
}
|
|
@@ -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-
|
|
3
|
+
"version": "3.1.0-canary-20251008-f2d1b4a",
|
|
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-
|
|
37
|
+
"expo-module-scripts": "5.0.8-canary-20251008-f2d1b4a",
|
|
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) =>
|
|
46
|
+
platforms.map((platform) =>
|
|
47
|
+
scanDependencyResolutionsForPlatform(linker, platform, INCLUDE_PACKAGES)
|
|
48
|
+
)
|
|
44
49
|
)
|
|
45
50
|
);
|
|
46
51
|
await verifySearchResults(results, {
|