expo-modules-autolinking 1.1.2 → 1.3.0

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
@@ -10,6 +10,18 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 1.3.0 — 2023-05-08
14
+
15
+ ### 🎉 New features
16
+
17
+ - Generating `ExpoModulesProvider.swift` in the build phase script instead of only `pod install`. ([#21108](https://github.com/expo/expo/pull/21108) by [@tsapeta](https://github.com/tsapeta))
18
+
19
+ ## 1.2.0 - 2023-04-13
20
+
21
+ ### 🎉 New features
22
+
23
+ - Added Gradle plugin autolinking support for Android. ([#21377](https://github.com/expo/expo/pull/21377) by [@kudo](https://github.com/kudo))
24
+
13
25
  ## 1.1.2 — 2023-02-14
14
26
 
15
27
  ### 💡 Others
package/README.md CHANGED
@@ -16,7 +16,7 @@ Scripts that autolink Expo modules.
16
16
 
17
17
  # Installation in managed Expo projects
18
18
 
19
- For [managed](https://docs.expo.dev/versions/latest/introduction/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
19
+ For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
20
20
 
21
21
  # Installation in bare React Native projects
22
22
 
@@ -1,4 +1,4 @@
1
- import { RawExpoModuleConfig, SupportedPlatform } from './types';
1
+ import { AndroidGradlePluginDescriptor, RawExpoModuleConfig, SupportedPlatform } from './types';
2
2
  /**
3
3
  * A class that wraps the raw config (`expo-module.json` or `unimodule.json`).
4
4
  */
@@ -41,6 +41,10 @@ export declare class ExpoModuleConfig {
41
41
  * Returns build.gradle file paths defined by the module author.
42
42
  */
43
43
  androidGradlePaths(): string[];
44
+ /**
45
+ * Returns gradle plugins descriptors defined by the module author.
46
+ */
47
+ androidGradlePlugins(): AndroidGradlePluginDescriptor[];
44
48
  /**
45
49
  * Returns serializable raw config.
46
50
  */
@@ -72,6 +72,12 @@ class ExpoModuleConfig {
72
72
  androidGradlePaths() {
73
73
  return arrayize(this.rawConfig.android?.gradlePath ?? []);
74
74
  }
75
+ /**
76
+ * Returns gradle plugins descriptors defined by the module author.
77
+ */
78
+ androidGradlePlugins() {
79
+ return arrayize(this.rawConfig.android?.gradlePlugins ?? []);
80
+ }
75
81
  /**
76
82
  * Returns serializable raw config.
77
83
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoModuleConfig.js","sourceRoot":"","sources":["../src/ExpoModuleConfig.ts"],"names":[],"mappings":";;;AAEA,SAAS,QAAQ,CAAI,KAA0B;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACxB,OAAO,KAAK,CAAC;KACd;IACD,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAa,gBAAgB;IAC3B,YAAqB,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAEvD;;OAEG;IACH,gBAAgB,CAAC,QAA2B;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,UAAU;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;QAErC,4DAA4D;QAC5D,OAAO,SAAS,EAAE,OAAO,IAAI,SAAS,EAAE,iBAAiB,IAAI,EAAE,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,yBAAyB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,sBAAsB,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,wBAAwB;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,qBAAqB,IAAI,EAAE,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,IAAI,KAAK,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAE7C,4DAA4D;QAC5D,OAAO,aAAa,EAAE,OAAO,IAAI,aAAa,EAAE,iBAAiB,IAAI,EAAE,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AA9ED,4CA8EC;AAED;;GAEG;AACH,SAAgB,iCAAiC,CAAC,IAAY;IAC5D,kDAAkD;IAClD,4DAA4D;IAC5D,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAwB,CAAC,CAAC;AACpE,CAAC;AAJD,8EAIC","sourcesContent":["import { RawExpoModuleConfig, SupportedPlatform } from './types';\n\nfunction arrayize<T>(value: T[] | T | undefined): T[] {\n if (Array.isArray(value)) {\n return value;\n }\n return value != null ? [value] : [];\n}\n\n/**\n * A class that wraps the raw config (`expo-module.json` or `unimodule.json`).\n */\nexport class ExpoModuleConfig {\n constructor(readonly rawConfig: RawExpoModuleConfig) {}\n\n /**\n * Whether the module supports given platform.\n */\n supportsPlatform(platform: SupportedPlatform): boolean {\n return this.rawConfig.platforms?.includes(platform) ?? false;\n }\n\n /**\n * Returns a list of names of Swift native modules classes to put to the generated modules provider file.\n */\n iosModules() {\n const iosConfig = this.rawConfig.ios;\n\n // `modulesClassNames` is a legacy name for the same config.\n return iosConfig?.modules ?? iosConfig?.modulesClassNames ?? [];\n }\n\n /**\n * Returns a list of names of Swift classes that receives AppDelegate life-cycle events.\n */\n iosAppDelegateSubscribers(): string[] {\n return this.rawConfig.ios?.appDelegateSubscribers ?? [];\n }\n\n /**\n * Returns a list of names of Swift classes that implement `ExpoReactDelegateHandler`.\n */\n iosReactDelegateHandlers(): string[] {\n return this.rawConfig.ios?.reactDelegateHandlers ?? [];\n }\n\n /**\n * Returns podspec paths defined by the module author.\n */\n iosPodspecPaths(): string[] {\n return arrayize(this.rawConfig.ios?.podspecPath);\n }\n\n /**\n * Returns the product module names, if defined by the module author.\n */\n iosSwiftModuleNames(): string[] {\n return arrayize(this.rawConfig.ios?.swiftModuleName);\n }\n\n /**\n * Returns whether this module will be added only to the debug configuration\n */\n iosDebugOnly(): boolean {\n return this.rawConfig.ios?.debugOnly ?? false;\n }\n\n /**\n * Returns a list of names of Kotlin native modules classes to put to the generated package provider file.\n */\n androidModules() {\n const androidConfig = this.rawConfig.android;\n\n // `modulesClassNames` is a legacy name for the same config.\n return androidConfig?.modules ?? androidConfig?.modulesClassNames ?? [];\n }\n\n /**\n * Returns build.gradle file paths defined by the module author.\n */\n androidGradlePaths(): string[] {\n return arrayize(this.rawConfig.android?.gradlePath ?? []);\n }\n\n /**\n * Returns serializable raw config.\n */\n toJSON(): RawExpoModuleConfig {\n return this.rawConfig;\n }\n}\n\n/**\n * Reads the config at given path and returns the config wrapped by `ExpoModuleConfig` class.\n */\nexport function requireAndResolveExpoModuleConfig(path: string): ExpoModuleConfig {\n // TODO: Validate the raw config against a schema.\n // TODO: Support for `*.js` files, not only static `*.json`.\n return new ExpoModuleConfig(require(path) as RawExpoModuleConfig);\n}\n"]}
1
+ {"version":3,"file":"ExpoModuleConfig.js","sourceRoot":"","sources":["../src/ExpoModuleConfig.ts"],"names":[],"mappings":";;;AAEA,SAAS,QAAQ,CAAI,KAA0B;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACxB,OAAO,KAAK,CAAC;KACd;IACD,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAa,gBAAgB;IAC3B,YAAqB,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAEvD;;OAEG;IACH,gBAAgB,CAAC,QAA2B;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,UAAU;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;QAErC,4DAA4D;QAC5D,OAAO,SAAS,EAAE,OAAO,IAAI,SAAS,EAAE,iBAAiB,IAAI,EAAE,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,yBAAyB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,sBAAsB,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,wBAAwB;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,qBAAqB,IAAI,EAAE,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,IAAI,KAAK,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAE7C,4DAA4D;QAC5D,OAAO,aAAa,EAAE,OAAO,IAAI,aAAa,EAAE,iBAAiB,IAAI,EAAE,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,oBAAoB;QAClB,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AArFD,4CAqFC;AAED;;GAEG;AACH,SAAgB,iCAAiC,CAAC,IAAY;IAC5D,kDAAkD;IAClD,4DAA4D;IAC5D,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAwB,CAAC,CAAC;AACpE,CAAC;AAJD,8EAIC","sourcesContent":["import { AndroidGradlePluginDescriptor, RawExpoModuleConfig, SupportedPlatform } from './types';\n\nfunction arrayize<T>(value: T[] | T | undefined): T[] {\n if (Array.isArray(value)) {\n return value;\n }\n return value != null ? [value] : [];\n}\n\n/**\n * A class that wraps the raw config (`expo-module.json` or `unimodule.json`).\n */\nexport class ExpoModuleConfig {\n constructor(readonly rawConfig: RawExpoModuleConfig) {}\n\n /**\n * Whether the module supports given platform.\n */\n supportsPlatform(platform: SupportedPlatform): boolean {\n return this.rawConfig.platforms?.includes(platform) ?? false;\n }\n\n /**\n * Returns a list of names of Swift native modules classes to put to the generated modules provider file.\n */\n iosModules() {\n const iosConfig = this.rawConfig.ios;\n\n // `modulesClassNames` is a legacy name for the same config.\n return iosConfig?.modules ?? iosConfig?.modulesClassNames ?? [];\n }\n\n /**\n * Returns a list of names of Swift classes that receives AppDelegate life-cycle events.\n */\n iosAppDelegateSubscribers(): string[] {\n return this.rawConfig.ios?.appDelegateSubscribers ?? [];\n }\n\n /**\n * Returns a list of names of Swift classes that implement `ExpoReactDelegateHandler`.\n */\n iosReactDelegateHandlers(): string[] {\n return this.rawConfig.ios?.reactDelegateHandlers ?? [];\n }\n\n /**\n * Returns podspec paths defined by the module author.\n */\n iosPodspecPaths(): string[] {\n return arrayize(this.rawConfig.ios?.podspecPath);\n }\n\n /**\n * Returns the product module names, if defined by the module author.\n */\n iosSwiftModuleNames(): string[] {\n return arrayize(this.rawConfig.ios?.swiftModuleName);\n }\n\n /**\n * Returns whether this module will be added only to the debug configuration\n */\n iosDebugOnly(): boolean {\n return this.rawConfig.ios?.debugOnly ?? false;\n }\n\n /**\n * Returns a list of names of Kotlin native modules classes to put to the generated package provider file.\n */\n androidModules() {\n const androidConfig = this.rawConfig.android;\n\n // `modulesClassNames` is a legacy name for the same config.\n return androidConfig?.modules ?? androidConfig?.modulesClassNames ?? [];\n }\n\n /**\n * Returns build.gradle file paths defined by the module author.\n */\n androidGradlePaths(): string[] {\n return arrayize(this.rawConfig.android?.gradlePath ?? []);\n }\n\n /**\n * Returns gradle plugins descriptors defined by the module author.\n */\n androidGradlePlugins(): AndroidGradlePluginDescriptor[] {\n return arrayize(this.rawConfig.android?.gradlePlugins ?? []);\n }\n\n /**\n * Returns serializable raw config.\n */\n toJSON(): RawExpoModuleConfig {\n return this.rawConfig;\n }\n}\n\n/**\n * Reads the config at given path and returns the config wrapped by `ExpoModuleConfig` class.\n */\nexport function requireAndResolveExpoModuleConfig(path: string): ExpoModuleConfig {\n // TODO: Validate the raw config against a schema.\n // TODO: Support for `*.js` files, not only static `*.json`.\n return new ExpoModuleConfig(require(path) as RawExpoModuleConfig);\n}\n"]}
@@ -44,9 +44,15 @@ async function resolveModuleAsync(packageName, revision) {
44
44
  sourceDir: path_1.default.dirname(gradleFilePath),
45
45
  };
46
46
  });
47
+ const plugins = (revision.config?.androidGradlePlugins() ?? []).map(({ id, group, sourceDir }) => ({
48
+ id,
49
+ group,
50
+ sourceDir: path_1.default.join(revision.path, sourceDir),
51
+ }));
47
52
  return {
48
53
  packageName,
49
54
  projects,
55
+ ...(plugins.length > 0 ? { plugins } : {}),
50
56
  modules: revision.config?.androidModules() ?? [],
51
57
  };
52
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/platforms/android.ts"],"names":[],"mappings":"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","sourcesContent":["import glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nimport { ModuleDescriptorAndroid, PackageRevision } from '../types';\n\n/**\n * Generates Java file that contains all autolinked packages.\n */\nexport async function generatePackageListAsync(\n modules: ModuleDescriptorAndroid[],\n targetPath: string,\n namespace: string\n): Promise<void> {\n const generatedFileContent = await generatePackageListFileContentAsync(modules, namespace);\n await fs.outputFile(targetPath, generatedFileContent);\n}\n\nasync function findGradleFilesAsync(revision: PackageRevision): Promise<string[]> {\n const configGradlePaths = revision.config?.androidGradlePaths();\n if (configGradlePaths && configGradlePaths.length) {\n return configGradlePaths;\n }\n\n const buildGradleFiles = await glob('*/build.gradle', {\n cwd: revision.path,\n ignore: ['**/node_modules/**'],\n });\n\n return buildGradleFiles;\n}\n\nexport async function resolveModuleAsync(\n packageName: string,\n revision: PackageRevision\n): Promise<ModuleDescriptorAndroid | null> {\n // TODO: Relative source dir should be configurable through the module config.\n\n // Don't link itself... :D\n if (packageName === '@unimodules/react-native-adapter') {\n return null;\n }\n\n const buildGradleFiles = await findGradleFilesAsync(revision);\n // Just in case where the module doesn't have its own `build.gradle`.\n if (!buildGradleFiles.length) {\n return null;\n }\n\n const projects = buildGradleFiles.map((buildGradleFile) => {\n const gradleFilePath = path.join(revision.path, buildGradleFile);\n return {\n name: convertPackageNameToProjectName(\n packageName,\n path.relative(revision.path, gradleFilePath)\n ),\n sourceDir: path.dirname(gradleFilePath),\n };\n });\n\n return {\n packageName,\n projects,\n modules: revision.config?.androidModules() ?? [],\n };\n}\n\n/**\n * Generates the string to put into the generated package list.\n */\nasync function generatePackageListFileContentAsync(\n modules: ModuleDescriptorAndroid[],\n namespace: string\n): Promise<string> {\n // TODO: Instead of ignoring `expo` here, make the package class paths configurable from `expo-module.config.json`.\n const packagesClasses = await findAndroidPackagesAsync(\n modules.filter((module) => module.packageName !== 'expo')\n );\n\n const modulesClasses = await findAndroidModules(modules);\n\n return `package ${namespace};\n\nimport java.util.Arrays;\nimport java.util.List;\nimport expo.modules.core.interfaces.Package;\nimport expo.modules.kotlin.modules.Module;\nimport expo.modules.kotlin.ModulesProvider;\n\npublic class ExpoModulesPackageList implements ModulesProvider {\n private static class LazyHolder {\n static final List<Package> packagesList = Arrays.<Package>asList(\n${packagesClasses.map((packageClass) => ` new ${packageClass}()`).join(',\\n')}\n );\n\n static final List<Class<? extends Module>> modulesList = Arrays.<Class<? extends Module>>asList(\n ${modulesClasses.map((moduleClass) => ` ${moduleClass}.class`).join(',\\n')}\n );\n }\n\n public static List<Package> getPackageList() {\n return LazyHolder.packagesList;\n }\n\n @Override\n public List<Class<? extends Module>> getModulesList() {\n return LazyHolder.modulesList;\n }\n}\n`;\n}\n\nfunction findAndroidModules(modules: ModuleDescriptorAndroid[]): string[] {\n const modulesToProvide = modules.filter((module) => module.modules.length > 0);\n const classNames = ([] as string[]).concat(...modulesToProvide.map((module) => module.modules));\n return classNames;\n}\n\nasync function findAndroidPackagesAsync(modules: ModuleDescriptorAndroid[]): Promise<string[]> {\n const classes: string[] = [];\n\n const flattenedSourceDirList: string[] = [];\n for (const module of modules) {\n for (const project of module.projects) {\n flattenedSourceDirList.push(project.sourceDir);\n }\n }\n\n await Promise.all(\n flattenedSourceDirList.map(async (sourceDir) => {\n const files = await glob('**/*Package.{java,kt}', {\n cwd: sourceDir,\n });\n\n for (const file of files) {\n const fileContent = await fs.readFile(path.join(sourceDir, file), 'utf8');\n\n const packageRegex = (() => {\n if (process.env.EXPO_SHOULD_USE_LEGACY_PACKAGE_INTERFACE) {\n return /\\bimport\\s+org\\.unimodules\\.core\\.(interfaces\\.Package|BasePackage)\\b/;\n } else {\n return /\\bimport\\s+expo\\.modules\\.core\\.(interfaces\\.Package|BasePackage)\\b/;\n }\n })();\n\n // Very naive check to skip non-expo packages\n if (!packageRegex.test(fileContent)) {\n continue;\n }\n\n const classPathMatches = fileContent.match(/^package ([\\w.]+)\\b/m);\n\n if (classPathMatches) {\n const basename = path.basename(file, path.extname(file));\n classes.push(`${classPathMatches[1]}.${basename}`);\n }\n }\n })\n );\n return classes.sort();\n}\n\n/**\n * Converts the package name and gradle file path to Android's project name.\n * `$` to indicate subprojects\n * `/` path will transform as `-`\n *\n * Example: `@expo/example` + `android/build.gradle` → `expo-example`\n *\n * Example: multiple projects\n * - `expo-test` + `android/build.gradle` → `react-native-third-party`\n * - `expo-test` + `subproject/build.gradle` → `react-native-third-party$subproject`\n */\nexport function convertPackageNameToProjectName(\n packageName: string,\n buildGradleFile: string\n): string {\n const name = packageName.replace(/^@/g, '').replace(/\\W+/g, '-');\n const baseDir = path.dirname(buildGradleFile).replace(/\\//g, '-');\n return baseDir === 'android' ? name : `${name}$${baseDir}`;\n}\n"]}
1
+ {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/platforms/android.ts"],"names":[],"mappings":"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","sourcesContent":["import glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nimport { ModuleDescriptorAndroid, PackageRevision } from '../types';\n\n/**\n * Generates Java file that contains all autolinked packages.\n */\nexport async function generatePackageListAsync(\n modules: ModuleDescriptorAndroid[],\n targetPath: string,\n namespace: string\n): Promise<void> {\n const generatedFileContent = await generatePackageListFileContentAsync(modules, namespace);\n await fs.outputFile(targetPath, generatedFileContent);\n}\n\nasync function findGradleFilesAsync(revision: PackageRevision): Promise<string[]> {\n const configGradlePaths = revision.config?.androidGradlePaths();\n if (configGradlePaths && configGradlePaths.length) {\n return configGradlePaths;\n }\n\n const buildGradleFiles = await glob('*/build.gradle', {\n cwd: revision.path,\n ignore: ['**/node_modules/**'],\n });\n\n return buildGradleFiles;\n}\n\nexport async function resolveModuleAsync(\n packageName: string,\n revision: PackageRevision\n): Promise<ModuleDescriptorAndroid | null> {\n // TODO: Relative source dir should be configurable through the module config.\n\n // Don't link itself... :D\n if (packageName === '@unimodules/react-native-adapter') {\n return null;\n }\n\n const buildGradleFiles = await findGradleFilesAsync(revision);\n // Just in case where the module doesn't have its own `build.gradle`.\n if (!buildGradleFiles.length) {\n return null;\n }\n\n const projects = buildGradleFiles.map((buildGradleFile) => {\n const gradleFilePath = path.join(revision.path, buildGradleFile);\n return {\n name: convertPackageNameToProjectName(\n packageName,\n path.relative(revision.path, gradleFilePath)\n ),\n sourceDir: path.dirname(gradleFilePath),\n };\n });\n\n const plugins = (revision.config?.androidGradlePlugins() ?? []).map(\n ({ id, group, sourceDir }) => ({\n id,\n group,\n sourceDir: path.join(revision.path, sourceDir),\n })\n );\n\n return {\n packageName,\n projects,\n ...(plugins.length > 0 ? { plugins } : {}),\n modules: revision.config?.androidModules() ?? [],\n };\n}\n\n/**\n * Generates the string to put into the generated package list.\n */\nasync function generatePackageListFileContentAsync(\n modules: ModuleDescriptorAndroid[],\n namespace: string\n): Promise<string> {\n // TODO: Instead of ignoring `expo` here, make the package class paths configurable from `expo-module.config.json`.\n const packagesClasses = await findAndroidPackagesAsync(\n modules.filter((module) => module.packageName !== 'expo')\n );\n\n const modulesClasses = await findAndroidModules(modules);\n\n return `package ${namespace};\n\nimport java.util.Arrays;\nimport java.util.List;\nimport expo.modules.core.interfaces.Package;\nimport expo.modules.kotlin.modules.Module;\nimport expo.modules.kotlin.ModulesProvider;\n\npublic class ExpoModulesPackageList implements ModulesProvider {\n private static class LazyHolder {\n static final List<Package> packagesList = Arrays.<Package>asList(\n${packagesClasses.map((packageClass) => ` new ${packageClass}()`).join(',\\n')}\n );\n\n static final List<Class<? extends Module>> modulesList = Arrays.<Class<? extends Module>>asList(\n ${modulesClasses.map((moduleClass) => ` ${moduleClass}.class`).join(',\\n')}\n );\n }\n\n public static List<Package> getPackageList() {\n return LazyHolder.packagesList;\n }\n\n @Override\n public List<Class<? extends Module>> getModulesList() {\n return LazyHolder.modulesList;\n }\n}\n`;\n}\n\nfunction findAndroidModules(modules: ModuleDescriptorAndroid[]): string[] {\n const modulesToProvide = modules.filter((module) => module.modules.length > 0);\n const classNames = ([] as string[]).concat(...modulesToProvide.map((module) => module.modules));\n return classNames;\n}\n\nasync function findAndroidPackagesAsync(modules: ModuleDescriptorAndroid[]): Promise<string[]> {\n const classes: string[] = [];\n\n const flattenedSourceDirList: string[] = [];\n for (const module of modules) {\n for (const project of module.projects) {\n flattenedSourceDirList.push(project.sourceDir);\n }\n }\n\n await Promise.all(\n flattenedSourceDirList.map(async (sourceDir) => {\n const files = await glob('**/*Package.{java,kt}', {\n cwd: sourceDir,\n });\n\n for (const file of files) {\n const fileContent = await fs.readFile(path.join(sourceDir, file), 'utf8');\n\n const packageRegex = (() => {\n if (process.env.EXPO_SHOULD_USE_LEGACY_PACKAGE_INTERFACE) {\n return /\\bimport\\s+org\\.unimodules\\.core\\.(interfaces\\.Package|BasePackage)\\b/;\n } else {\n return /\\bimport\\s+expo\\.modules\\.core\\.(interfaces\\.Package|BasePackage)\\b/;\n }\n })();\n\n // Very naive check to skip non-expo packages\n if (!packageRegex.test(fileContent)) {\n continue;\n }\n\n const classPathMatches = fileContent.match(/^package ([\\w.]+)\\b/m);\n\n if (classPathMatches) {\n const basename = path.basename(file, path.extname(file));\n classes.push(`${classPathMatches[1]}.${basename}`);\n }\n }\n })\n );\n return classes.sort();\n}\n\n/**\n * Converts the package name and gradle file path to Android's project name.\n * `$` to indicate subprojects\n * `/` path will transform as `-`\n *\n * Example: `@expo/example` + `android/build.gradle` → `expo-example`\n *\n * Example: multiple projects\n * - `expo-test` + `android/build.gradle` → `react-native-third-party`\n * - `expo-test` + `subproject/build.gradle` → `react-native-third-party$subproject`\n */\nexport function convertPackageNameToProjectName(\n packageName: string,\n buildGradleFile: string\n): string {\n const name = packageName.replace(/^@/g, '').replace(/\\W+/g, '-');\n const baseDir = path.dirname(buildGradleFile).replace(/\\//g, '-');\n return baseDir === 'android' ? name : `${name}$${baseDir}`;\n}\n"]}
package/build/types.d.ts CHANGED
@@ -34,9 +34,14 @@ export interface ModuleAndroidProjectInfo {
34
34
  name: string;
35
35
  sourceDir: string;
36
36
  }
37
+ export interface ModuleAndroidPluginInfo {
38
+ id: string;
39
+ sourceDir: string;
40
+ }
37
41
  export interface ModuleDescriptorAndroid {
38
42
  packageName: string;
39
43
  projects: ModuleAndroidProjectInfo[];
44
+ plugins?: ModuleAndroidPluginInfo[];
40
45
  modules: string[];
41
46
  }
42
47
  export interface ModuleIosPodspecInfo {
@@ -54,6 +59,20 @@ export interface ModuleDescriptorIos {
54
59
  debugOnly: boolean;
55
60
  }
56
61
  export type ModuleDescriptor = ModuleDescriptorAndroid | ModuleDescriptorIos;
62
+ export interface AndroidGradlePluginDescriptor {
63
+ /**
64
+ * Gradle plugin ID
65
+ */
66
+ id: string;
67
+ /**
68
+ * Artifact group
69
+ */
70
+ group: string;
71
+ /**
72
+ * Relative path to the gradle plugin directory
73
+ */
74
+ sourceDir: string;
75
+ }
57
76
  /**
58
77
  * Represents a raw config from `expo-module.json`.
59
78
  */
@@ -117,5 +136,9 @@ export interface RawExpoModuleConfig {
117
136
  * To have multiple build.gradle projects, string array type is also supported.
118
137
  */
119
138
  gradlePath?: string | string[];
139
+ /**
140
+ * Gradle plugins.
141
+ */
142
+ gradlePlugins?: AndroidGradlePluginDescriptor[];
120
143
  };
121
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ExpoModuleConfig } from './ExpoModuleConfig';\n\nexport type SupportedPlatform = 'ios' | 'android' | 'web';\n\nexport interface SearchOptions {\n // Available in the CLI\n searchPaths: string[];\n ignorePaths?: string[] | null;\n exclude?: string[] | null;\n platform: SupportedPlatform;\n silent?: boolean;\n nativeModulesDir?: string | null;\n\n // Scratched from project's config\n flags?: Record<string, any>;\n}\n\nexport interface ResolveOptions extends SearchOptions {\n json?: boolean;\n}\n\nexport interface GenerateOptions extends ResolveOptions {\n target: string;\n namespace?: string;\n empty?: boolean;\n}\n\nexport interface PatchReactImportsOptions {\n podsRoot: string;\n dryRun: boolean;\n}\n\nexport type PackageRevision = {\n path: string;\n version: string;\n config?: ExpoModuleConfig;\n duplicates?: PackageRevision[];\n};\n\nexport type SearchResults = {\n [moduleName: string]: PackageRevision;\n};\n\nexport interface ModuleAndroidProjectInfo {\n name: string;\n sourceDir: string;\n}\n\nexport interface ModuleDescriptorAndroid {\n packageName: string;\n projects: ModuleAndroidProjectInfo[];\n modules: string[];\n}\n\nexport interface ModuleIosPodspecInfo {\n podName: string;\n podspecDir: string;\n}\nexport interface ModuleDescriptorIos {\n packageName: string;\n pods: ModuleIosPodspecInfo[];\n flags: Record<string, any> | undefined;\n swiftModuleNames: string[];\n modules: string[];\n appDelegateSubscribers: string[];\n reactDelegateHandlers: string[];\n debugOnly: boolean;\n}\n\nexport type ModuleDescriptor = ModuleDescriptorAndroid | ModuleDescriptorIos;\n\n/**\n * Represents a raw config from `expo-module.json`.\n */\nexport interface RawExpoModuleConfig {\n /**\n * An array of supported platforms.\n */\n platforms?: SupportedPlatform[];\n\n /**\n * iOS-specific config.\n */\n ios?: {\n /**\n * Names of Swift native modules classes to put to the generated modules provider file.\n */\n modules?: string[];\n\n /**\n * Names of Swift native modules classes to put to the generated modules provider file.\n * @deprecated Deprecated in favor of `modules`. Might be removed in the future releases.\n */\n modulesClassNames?: string[];\n\n /**\n * Names of Swift classes that hooks into `ExpoAppDelegate` to receive AppDelegate life-cycle events.\n */\n appDelegateSubscribers?: string[];\n\n /**\n * Names of Swift classes that implement `ExpoReactDelegateHandler` to hook React instance creation.\n */\n reactDelegateHandlers?: string[];\n\n /**\n * Podspec relative path.\n * To have multiple podspecs, string array type is also supported.\n */\n podspecPath?: string | string[];\n\n /**\n * Swift product module name. If empty, the pod name is used for Swift imports.\n * To have multiple modules, string array is also supported.\n */\n swiftModuleName?: string | string[];\n\n /**\n * Whether this module will be added only to the debug configuration.\n * Defaults to false.\n */\n debugOnly?: boolean;\n };\n\n /**\n * Android-specific config.\n */\n android?: {\n /**\n * Full names (package + class name) of Kotlin native modules classes to put to the generated package provider file.\n */\n modules?: string[];\n\n /**\n * Full names (package + class name) of Kotlin native modules classes to put to the generated package provider file.\n * @deprecated Deprecated in favor of `modules`. Might be removed in the future releases.\n */\n modulesClassNames?: string[];\n\n /**\n * build.gradle relative path.\n * To have multiple build.gradle projects, string array type is also supported.\n */\n gradlePath?: string | string[];\n };\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ExpoModuleConfig } from './ExpoModuleConfig';\n\nexport type SupportedPlatform = 'ios' | 'android' | 'web';\n\nexport interface SearchOptions {\n // Available in the CLI\n searchPaths: string[];\n ignorePaths?: string[] | null;\n exclude?: string[] | null;\n platform: SupportedPlatform;\n silent?: boolean;\n nativeModulesDir?: string | null;\n\n // Scratched from project's config\n flags?: Record<string, any>;\n}\n\nexport interface ResolveOptions extends SearchOptions {\n json?: boolean;\n}\n\nexport interface GenerateOptions extends ResolveOptions {\n target: string;\n namespace?: string;\n empty?: boolean;\n}\n\nexport interface PatchReactImportsOptions {\n podsRoot: string;\n dryRun: boolean;\n}\n\nexport type PackageRevision = {\n path: string;\n version: string;\n config?: ExpoModuleConfig;\n duplicates?: PackageRevision[];\n};\n\nexport type SearchResults = {\n [moduleName: string]: PackageRevision;\n};\n\nexport interface ModuleAndroidProjectInfo {\n name: string;\n sourceDir: string;\n}\n\nexport interface ModuleAndroidPluginInfo {\n id: string;\n sourceDir: string;\n}\n\nexport interface ModuleDescriptorAndroid {\n packageName: string;\n projects: ModuleAndroidProjectInfo[];\n plugins?: ModuleAndroidPluginInfo[];\n modules: string[];\n}\n\nexport interface ModuleIosPodspecInfo {\n podName: string;\n podspecDir: string;\n}\nexport interface ModuleDescriptorIos {\n packageName: string;\n pods: ModuleIosPodspecInfo[];\n flags: Record<string, any> | undefined;\n swiftModuleNames: string[];\n modules: string[];\n appDelegateSubscribers: string[];\n reactDelegateHandlers: string[];\n debugOnly: boolean;\n}\n\nexport type ModuleDescriptor = ModuleDescriptorAndroid | ModuleDescriptorIos;\n\nexport interface AndroidGradlePluginDescriptor {\n /**\n * Gradle plugin ID\n */\n id: string;\n\n /**\n * Artifact group\n */\n group: string;\n\n /**\n * Relative path to the gradle plugin directory\n */\n sourceDir: string;\n}\n\n/**\n * Represents a raw config from `expo-module.json`.\n */\nexport interface RawExpoModuleConfig {\n /**\n * An array of supported platforms.\n */\n platforms?: SupportedPlatform[];\n\n /**\n * iOS-specific config.\n */\n ios?: {\n /**\n * Names of Swift native modules classes to put to the generated modules provider file.\n */\n modules?: string[];\n\n /**\n * Names of Swift native modules classes to put to the generated modules provider file.\n * @deprecated Deprecated in favor of `modules`. Might be removed in the future releases.\n */\n modulesClassNames?: string[];\n\n /**\n * Names of Swift classes that hooks into `ExpoAppDelegate` to receive AppDelegate life-cycle events.\n */\n appDelegateSubscribers?: string[];\n\n /**\n * Names of Swift classes that implement `ExpoReactDelegateHandler` to hook React instance creation.\n */\n reactDelegateHandlers?: string[];\n\n /**\n * Podspec relative path.\n * To have multiple podspecs, string array type is also supported.\n */\n podspecPath?: string | string[];\n\n /**\n * Swift product module name. If empty, the pod name is used for Swift imports.\n * To have multiple modules, string array is also supported.\n */\n swiftModuleName?: string | string[];\n\n /**\n * Whether this module will be added only to the debug configuration.\n * Defaults to false.\n */\n debugOnly?: boolean;\n };\n\n /**\n * Android-specific config.\n */\n android?: {\n /**\n * Full names (package + class name) of Kotlin native modules classes to put to the generated package provider file.\n */\n modules?: string[];\n\n /**\n * Full names (package + class name) of Kotlin native modules classes to put to the generated package provider file.\n * @deprecated Deprecated in favor of `modules`. Might be removed in the future releases.\n */\n modulesClassNames?: string[];\n\n /**\n * build.gradle relative path.\n * To have multiple build.gradle projects, string array type is also supported.\n */\n gradlePath?: string | string[];\n\n /**\n * Gradle plugins.\n */\n gradlePlugins?: AndroidGradlePluginDescriptor[];\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-autolinking",
3
- "version": "1.1.2",
3
+ "version": "1.3.0",
4
4
  "description": "Scripts that autolink Expo modules.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -48,5 +48,5 @@
48
48
  "find-up": "^5.0.0",
49
49
  "fs-extra": "^9.1.0"
50
50
  },
51
- "gitHead": "c8107d57eabaedff5d53bc8036d062db12a473c8"
51
+ "gitHead": "4ba50c428c8369bb6b3a51a860d4898ad4ccbe78"
52
52
  }
@@ -16,6 +16,24 @@ class ExpoModuleGradleProject {
16
16
  }
17
17
  }
18
18
 
19
+ // Object representing a gradle plugin
20
+ class ExpoModuleGradlePlugin {
21
+ // ID of the gradle plugin
22
+ String id
23
+
24
+ // Artifact group
25
+ String group
26
+
27
+ // Path to the plugin folder
28
+ String sourceDir
29
+
30
+ ExpoModuleGradlePlugin(Object data) {
31
+ this.id = data.id
32
+ this.group = data.group
33
+ this.sourceDir = data.sourceDir
34
+ }
35
+ }
36
+
19
37
  // Object representing a module.
20
38
  class ExpoModule {
21
39
  // Name of the JavaScript package
@@ -27,10 +45,14 @@ class ExpoModule {
27
45
  // Gradle projects
28
46
  ExpoModuleGradleProject[] projects
29
47
 
48
+ // Gradle plugins
49
+ ExpoModuleGradlePlugin[] plugins
50
+
30
51
  ExpoModule(Object data) {
31
52
  this.name = data.packageName
32
53
  this.version = data.packageVersion
33
54
  this.projects = data.projects.collect { new ExpoModuleGradleProject(it) }
55
+ this.plugins = data.plugins.collect { new ExpoModuleGradlePlugin(it) }
34
56
  }
35
57
  }
36
58
 
@@ -138,12 +160,16 @@ class ExpoAutolinkingManager {
138
160
 
139
161
  class Colors {
140
162
  static final String GREEN = "\u001B[32m"
163
+ static final String YELLOW = "\u001B[33m"
141
164
  static final String RESET = "\u001B[0m"
142
165
  }
166
+ class Emojis {
167
+ static final String INFORMATION = "\u2139\uFE0F"
168
+ }
143
169
 
144
- // We can't cast a manager that is created in `settings.gradle` to the `ExpoAutolinkingManager`
145
- // because if someone is using `buildSrc`, the `ExpoAutolinkingManager` class
146
- // will be loaded by two different class loader - `settings.gradle` will use a diffrent loader.
170
+ // We can't cast a manager that is created in `settings.gradle` to the `ExpoAutolinkingManager`
171
+ // because if someone is using `buildSrc`, the `ExpoAutolinkingManager` class
172
+ // will be loaded by two different class loader - `settings.gradle` will use a diffrent loader.
147
173
  // In the JVM, classes are equal only if were loaded by the same loader.
148
174
  // There is nothing that we can do in that case, but to make our code safer, we check if the class name is the same.
149
175
  def validateExpoAutolinkingManager(manager) {
@@ -166,6 +192,33 @@ if (rootProject instanceof ProjectDescriptor) {
166
192
  include(":${moduleProject.name}")
167
193
  project(":${moduleProject.name}").projectDir = new File(moduleProject.sourceDir)
168
194
  }
195
+ for (modulePlugin in module.plugins) {
196
+ includeBuild(new File(modulePlugin.sourceDir))
197
+ }
198
+ }
199
+
200
+ // Add plugin classpath to the root project
201
+ gradle.beforeProject { project ->
202
+ if (project === project.rootProject) {
203
+ for (module in modules) {
204
+ for (modulePlugin in module.plugins) {
205
+ project.buildscript.dependencies.add('classpath', "${modulePlugin.group}:${modulePlugin.id}")
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ // Apply plugins for all app projects
212
+ gradle.afterProject { project ->
213
+ if (!project.plugins.hasPlugin('com.android.application')) {
214
+ return
215
+ }
216
+ for (module in modules) {
217
+ for (modulePlugin in module.plugins) {
218
+ println " ${Emojis.INFORMATION} ${Colors.YELLOW}Applying gradle plugin${Colors.RESET} '${Colors.GREEN}${modulePlugin.id}${Colors.RESET}' (${module.name}@${module.version})"
219
+ project.plugins.apply(modulePlugin.id)
220
+ }
221
+ }
169
222
  }
170
223
 
171
224
  // Save the manager in the shared context, so that we can later use it in `build.gradle`.
@@ -251,7 +304,7 @@ if (rootProject instanceof ProjectDescriptor) {
251
304
  ExpoAutolinkingManager.generatePackageList(project, options)
252
305
  }
253
306
 
254
- ext.ensureDependeciesWereEvaluated = { Project project ->
307
+ ext.ensureDependeciesWereEvaluated = { Project project ->
255
308
  if (!gradle.ext.has('expoAutolinkingManager')) {
256
309
  return
257
310
  }
@@ -269,7 +322,7 @@ if (rootProject instanceof ProjectDescriptor) {
269
322
  if (moduleProject.name == project.name) {
270
323
  continue
271
324
  }
272
-
325
+
273
326
  project.evaluationDependsOn(":${moduleProject.name}")
274
327
  }
275
328
  }
@@ -103,6 +103,11 @@ module Expo
103
103
  @options.fetch(:providerName, Constants::MODULES_PROVIDER_FILE_NAME)
104
104
  end
105
105
 
106
+ # Absolute path to `Pods/Target Support Files/<pods target name>/<modules provider file>` within the project path
107
+ public def modules_provider_path(target)
108
+ File.join(target.support_files_dir, modules_provider_name)
109
+ end
110
+
106
111
  # For now there is no need to generate the modules provider for testing.
107
112
  public def should_generate_modules_provider?
108
113
  return !@options.fetch(:testsOnly, false)
@@ -126,20 +131,11 @@ module Expo
126
131
  end
127
132
  end
128
133
 
129
- private def node_command_args(command_name)
134
+ public def base_command_args
130
135
  search_paths = @options.fetch(:searchPaths, @options.fetch(:modules_paths, nil))
131
136
  ignore_paths = @options.fetch(:ignorePaths, nil)
132
137
  exclude = @options.fetch(:exclude, [])
133
-
134
- args = [
135
- 'node',
136
- '--no-warnings',
137
- '--eval',
138
- 'require(\'expo-modules-autolinking\')(process.argv.slice(1))',
139
- command_name,
140
- '--platform',
141
- 'ios'
142
- ]
138
+ args = []
143
139
 
144
140
  if !search_paths.nil? && !search_paths.empty?
145
141
  args.concat(search_paths)
@@ -156,11 +152,24 @@ module Expo
156
152
  args
157
153
  end
158
154
 
155
+ private def node_command_args(command_name)
156
+ eval_command_args = [
157
+ 'node',
158
+ '--no-warnings',
159
+ '--eval',
160
+ 'require(\'expo-modules-autolinking\')(process.argv.slice(1))',
161
+ command_name,
162
+ '--platform',
163
+ 'ios'
164
+ ]
165
+ return eval_command_args.concat(base_command_args())
166
+ end
167
+
159
168
  private def resolve_command_args
160
169
  node_command_args('resolve').concat(['--json'])
161
170
  end
162
171
 
163
- private def generate_package_list_command_args(target_path)
172
+ public def generate_package_list_command_args(target_path)
164
173
  node_command_args('generate-package-list').concat([
165
174
  '--target',
166
175
  target_path
@@ -3,5 +3,7 @@ module Expo
3
3
  module Constants
4
4
  GENERATED_GROUP_NAME = 'ExpoModulesProviders'
5
5
  MODULES_PROVIDER_FILE_NAME = 'ExpoModulesProvider.swift'
6
+ CONFIGURE_PROJECT_BUILD_SCRIPT_NAME = '[Expo] Configure project'
7
+ CONFIGURE_PROJECT_SCRIPT_FILE_NAME = 'expo-configure-project.sh'
6
8
  end
7
9
  end
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+ require 'colored2'
1
3
 
2
4
  module Expo
3
5
  module ProjectIntegrator
@@ -32,15 +34,15 @@ module Expo
32
34
  # The user target name (without `Pods-` prefix which is a part of `target.name`)
33
35
  target_name = target.target_definition.name
34
36
 
35
- UI.message '- Generating the provider for ' << target_name.green << ' target' do
36
- # PBXNativeTarget of the user target
37
- native_target = project.native_targets.find { |native_target| native_target.name == target_name }
37
+ # PBXNativeTarget of the user target
38
+ native_target = project.native_targets.find { |native_target| native_target.name == target_name }
38
39
 
39
- # Shorthand ref for the autolinking manager.
40
- autolinking_manager = target.target_definition.autolinking_manager
40
+ # Shorthand ref for the autolinking manager.
41
+ autolinking_manager = target.target_definition.autolinking_manager
41
42
 
42
- # Absolute path to `Pods/Target Support Files/<pods target name>/<modules provider file>` within the project path
43
- modules_provider_path = File.join(target.support_files_dir, autolinking_manager.modules_provider_name)
43
+ UI.message '- Generating the provider for ' << target_name.green << ' target' do
44
+ # Get the absolute path to the modules provider
45
+ modules_provider_path = autolinking_manager.modules_provider_path(target)
44
46
 
45
47
  # Run `expo-modules-autolinking` command to generate the file
46
48
  autolinking_manager.generate_package_list(target_name, modules_provider_path)
@@ -62,6 +64,8 @@ module Expo
62
64
  end
63
65
  end
64
66
  end
67
+
68
+ integrate_build_script(autolinking_manager, project, target, native_target)
65
69
  end
66
70
 
67
71
  # Remove the generated group if it has nothing left inside
@@ -128,5 +132,135 @@ module Expo
128
132
  end
129
133
  end
130
134
 
131
- end # module ExpoAutolinkingExtension
135
+ # Makes sure that the build script configuring the project is installed,
136
+ # is up-to-date and is placed before the "Compile Sources" phase.
137
+ def self.integrate_build_script(autolinking_manager, project, target, native_target)
138
+ build_phases = native_target.build_phases
139
+ modules_provider_path = autolinking_manager.modules_provider_path(target)
140
+
141
+ # Look for our own build script phase
142
+ xcode_build_script = native_target.shell_script_build_phases.find { |script|
143
+ script.name == Constants::CONFIGURE_PROJECT_BUILD_SCRIPT_NAME
144
+ }
145
+
146
+ if xcode_build_script.nil?
147
+ # Inform the user that we added a build script.
148
+ puts "[Expo] ".blue << "Installing the build script for target " << native_target.name.green
149
+
150
+ # Create a new build script in the target, it's added as the last phase
151
+ xcode_build_script = native_target.new_shell_script_build_phase(Constants::CONFIGURE_PROJECT_BUILD_SCRIPT_NAME)
152
+ end
153
+
154
+ # Make sure it is before the "Compile Sources" build phase
155
+ xcode_build_script_index = build_phases.find_index(xcode_build_script)
156
+ compile_sources_index = build_phases.find_index { |phase|
157
+ phase.is_a?(Xcodeproj::Project::PBXSourcesBuildPhase)
158
+ }
159
+
160
+ if xcode_build_script_index.nil?
161
+ # This is almost impossible to get here as the script was just created with `new_shell_script_build_phase`
162
+ # that puts the script at the end of the phases, but let's log it just in case.
163
+ puts "[Expo] ".blue << "Unable to find the configuring build script in the Xcode project".red
164
+ end
165
+
166
+ if compile_sources_index.nil?
167
+ # In this case the project will probably not compile but that's not our fault
168
+ # and it doesn't block us from updating our build script.
169
+ puts "[Expo] ".blue << "Unable to find the compilation build phase in the Xcode project".red
170
+ end
171
+
172
+ # Insert our script before the "Compile Sources" phase when necessary
173
+ unless compile_sources_index.nil? || xcode_build_script_index < compile_sources_index
174
+ build_phases.insert(
175
+ compile_sources_index,
176
+ build_phases.delete_at(xcode_build_script_index)
177
+ )
178
+ end
179
+
180
+ # Get path to the script that will be added to the target support files
181
+ support_script_path = File.join(target.support_files_dir, Constants::CONFIGURE_PROJECT_SCRIPT_FILE_NAME)
182
+ support_script_relative_path = Pathname.new(support_script_path).relative_path_from(project.project_dir)
183
+
184
+ # Write to the shell script so it's always in-sync with the autolinking configuration
185
+ IO.write(
186
+ support_script_path,
187
+ generate_support_script(autolinking_manager, modules_provider_path)
188
+ )
189
+
190
+ # Make the support script executable
191
+ FileUtils.chmod('+x', support_script_path)
192
+
193
+ # Force the build phase script to run on each build (including incremental builds)
194
+ xcode_build_script.always_out_of_date = '1'
195
+
196
+ # Make sure the build script in Xcode is up to date, but probably it's not going to change
197
+ # as it just runs the script generated in the target support files
198
+ xcode_build_script.shell_script = generate_xcode_build_script(support_script_relative_path)
199
+ end
200
+
201
+ # Generates the shell script of the build script phase.
202
+ # Try not to modify this since it involves changes in the pbxproj so
203
+ # it's better to modify the support script instead, if possible.
204
+ def self.generate_xcode_build_script(script_relative_path)
205
+ escaped_path = script_relative_path.to_s.gsub(/[^a-zA-Z0-9,\._\+@%\/\-]/) { |char| "\\#{char}" }
206
+
207
+ <<~XCODE_BUILD_SCRIPT
208
+ # This script configures Expo modules and generates the modules provider file.
209
+ bash -l -c "./#{escaped_path}"
210
+ XCODE_BUILD_SCRIPT
211
+ end
212
+
213
+ # Generates the support script that is executed by the build script phase.
214
+ def self.generate_support_script(autolinking_manager, modules_provider_path)
215
+ args = autolinking_manager.base_command_args.map { |arg| "\"#{arg}\"" }.join(' ')
216
+
217
+ <<~SUPPORT_SCRIPT
218
+ #!/usr/bin/env bash
219
+ # @generated by expo-modules-autolinking
220
+
221
+ set -eo pipefail
222
+
223
+ function with_node() {
224
+ # Start with a default
225
+ export NODE_BINARY=$(command -v node)
226
+
227
+ # Override the default with the global environment
228
+ ENV_PATH="$PODS_ROOT/../.xcode.env"
229
+ if [[ -f "$ENV_PATH" ]]; then
230
+ source "$ENV_PATH"
231
+ fi
232
+
233
+ # Override the global with the local environment
234
+ LOCAL_ENV_PATH="${ENV_PATH}.local"
235
+ if [[ -f "$LOCAL_ENV_PATH" ]]; then
236
+ source "$LOCAL_ENV_PATH"
237
+ fi
238
+
239
+ if [[ -n "$NODE_BINARY" && -x "$NODE_BINARY" ]]; then
240
+ echo "Node found at: ${NODE_BINARY}"
241
+ else
242
+ cat >&2 << NODE_NOT_FOUND
243
+ error: Could not find "node" executable while running an Xcode build script.
244
+ You need to specify the path to your Node.js executable by defining an environment variable named NODE_BINARY in your project's .xcode.env or .xcode.env.local file.
245
+ You can set this up quickly by running:
246
+
247
+ echo "export NODE_BINARY=\\$(command -v node)" >> .xcode.env
248
+
249
+ in the ios folder of your project.
250
+ NODE_NOT_FOUND
251
+
252
+ exit 1
253
+ fi
254
+
255
+ # Execute argument, if present
256
+ if [[ "$#" -gt 0 ]]; then
257
+ "$NODE_BINARY" "$@"
258
+ fi
259
+ }
260
+
261
+ with_node --no-warnings --eval "require(\'expo-modules-autolinking\')(process.argv.slice(1))" generate-package-list #{args} --target "#{modules_provider_path}"
262
+ SUPPORT_SCRIPT
263
+ end
264
+
265
+ end # module ProjectIntegrator
132
266
  end # module Expo
@@ -1,4 +1,4 @@
1
- import { RawExpoModuleConfig, SupportedPlatform } from './types';
1
+ import { AndroidGradlePluginDescriptor, RawExpoModuleConfig, SupportedPlatform } from './types';
2
2
 
3
3
  function arrayize<T>(value: T[] | T | undefined): T[] {
4
4
  if (Array.isArray(value)) {
@@ -82,6 +82,13 @@ export class ExpoModuleConfig {
82
82
  return arrayize(this.rawConfig.android?.gradlePath ?? []);
83
83
  }
84
84
 
85
+ /**
86
+ * Returns gradle plugins descriptors defined by the module author.
87
+ */
88
+ androidGradlePlugins(): AndroidGradlePluginDescriptor[] {
89
+ return arrayize(this.rawConfig.android?.gradlePlugins ?? []);
90
+ }
91
+
85
92
  /**
86
93
  * Returns serializable raw config.
87
94
  */
@@ -58,9 +58,18 @@ export async function resolveModuleAsync(
58
58
  };
59
59
  });
60
60
 
61
+ const plugins = (revision.config?.androidGradlePlugins() ?? []).map(
62
+ ({ id, group, sourceDir }) => ({
63
+ id,
64
+ group,
65
+ sourceDir: path.join(revision.path, sourceDir),
66
+ })
67
+ );
68
+
61
69
  return {
62
70
  packageName,
63
71
  projects,
72
+ ...(plugins.length > 0 ? { plugins } : {}),
64
73
  modules: revision.config?.androidModules() ?? [],
65
74
  };
66
75
  }
package/src/types.ts CHANGED
@@ -46,9 +46,15 @@ export interface ModuleAndroidProjectInfo {
46
46
  sourceDir: string;
47
47
  }
48
48
 
49
+ export interface ModuleAndroidPluginInfo {
50
+ id: string;
51
+ sourceDir: string;
52
+ }
53
+
49
54
  export interface ModuleDescriptorAndroid {
50
55
  packageName: string;
51
56
  projects: ModuleAndroidProjectInfo[];
57
+ plugins?: ModuleAndroidPluginInfo[];
52
58
  modules: string[];
53
59
  }
54
60
 
@@ -69,6 +75,23 @@ export interface ModuleDescriptorIos {
69
75
 
70
76
  export type ModuleDescriptor = ModuleDescriptorAndroid | ModuleDescriptorIos;
71
77
 
78
+ export interface AndroidGradlePluginDescriptor {
79
+ /**
80
+ * Gradle plugin ID
81
+ */
82
+ id: string;
83
+
84
+ /**
85
+ * Artifact group
86
+ */
87
+ group: string;
88
+
89
+ /**
90
+ * Relative path to the gradle plugin directory
91
+ */
92
+ sourceDir: string;
93
+ }
94
+
72
95
  /**
73
96
  * Represents a raw config from `expo-module.json`.
74
97
  */
@@ -142,5 +165,10 @@ export interface RawExpoModuleConfig {
142
165
  * To have multiple build.gradle projects, string array type is also supported.
143
166
  */
144
167
  gradlePath?: string | string[];
168
+
169
+ /**
170
+ * Gradle plugins.
171
+ */
172
+ gradlePlugins?: AndroidGradlePluginDescriptor[];
145
173
  };
146
174
  }