1class KotlinExpoModulesCorePlugin implements Plugin<Project> {
2  void apply(Project project) {
3    project.buildscript {
4      project.ext.kotlinVersion = {
5        project.rootProject.ext.has("kotlinVersion")
6            ? project.rootProject.ext.get("kotlinVersion")
7            : "1.8.10"
8      }
9
10      project.ext.kspVersion = {
11        def kspVersionsMap = [
12          "1.6.10": "1.6.10-1.0.4",
13          "1.6.21": "1.6.21-1.0.6",
14          "1.7.22": "1.7.22-1.0.8",
15          "1.8.0": "1.8.0-1.0.9",
16          "1.8.10": "1.8.10-1.0.9"
17        ]
18
19        project.rootProject.ext.has("kspVersion")
20          ? project.rootProject.ext.get("kspVersion")
21          : kspVersionsMap.containsKey(project.ext.kotlinVersion())
22          ? kspVersionsMap.get(project.ext.kotlinVersion())
23          : "1.8.10-1.0.9"
24      }
25    }
26  }
27}
28
29ext.applyKotlinExpoModulesCorePlugin = {
30  apply plugin: KotlinExpoModulesCorePlugin
31}
32
33ext.boolish = { value ->
34  return value.toString().toBoolean()
35}
36
37// [BEGIN] Remove when we drop SDK 47
38abstract class ExtractReactNativeAARTask extends DefaultTask {
39  @Input
40  abstract Property<String> getBuildType()
41
42  @Input
43  abstract Property<String> getReactNativeDir()
44
45  @TaskAction
46  def taskAction() {
47    def suffix = buildType.get() == 'Debug' ? '-debug' : '-release'
48    def rnAARs = project.fileTree("${reactNativeDir.get()}/android").matching { include "**/react-native/**/*${suffix}.aar" }
49    if (rnAARs.isEmpty()) {
50      rnAARs = project.fileTree("${reactNativeDir.get()}/android").matching { include "**/react-native/**/*.aar" }
51    }
52    if (rnAARs.any()) {
53      // node_modules/react-native has a .aar, extract headers
54      if (rnAARs.size() > 1) {
55        logger.error("More than one React Native AAR file has been found:")
56        rnAARs.each {println(it) }
57        throw new GradleException("Multiple React Native AARs found:\n${rnAARs.join("\n")}" +
58            "\nRemove the old ones and try again")
59      }
60    }
61    def rnAAR = rnAARs.singleFile
62    def file = rnAAR.absoluteFile
63    def packageName = file.name.tokenize('-')[0]
64    project.copy {
65      from project.zipTree(file)
66      into "${project.buildDir}/${packageName}"
67      include "jni/**/*"
68    }
69  }
70}
71
72class LegacyReactNativeLibsExtractionPlugin implements Plugin<Project> {
73  void nativeBuildDependsOn(project, dependsOnTask, buildTypesIncludes) {
74    def buildTasks = project.tasks.findAll { task ->
75      def taskName = task.name
76      if (taskName.contains("Clean")) { return false }
77      if (taskName.contains("externalNative") || taskName.contains("CMake") || taskName.contains("generateJsonModel")) {
78        if (buildTypesIncludes == null) { return true }
79        for (buildType in buildTypesIncludes) {
80          if (taskName.contains(buildType)) { return true }
81        }
82      }
83      return false
84    }
85    buildTasks.forEach { task -> task.dependsOn(dependsOnTask) }
86  }
87
88  void apply(Project project) {
89    def REACT_NATIVE_BUILD_FROM_SOURCE = project.findProject(":ReactAndroid") != null
90    def REACT_NATIVE_DIR = REACT_NATIVE_BUILD_FROM_SOURCE
91      ? project.findProject(":ReactAndroid").getProjectDir().parent
92      : new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, project.rootDir).text.trim()).parent
93
94    def reactProperties = new Properties()
95    new File("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
96    def FOLLY_VERSION = reactProperties.getProperty("FOLLY_VERSION")
97    def DOUBLE_CONVERSION_VERSION = reactProperties.getProperty("DOUBLE_CONVERSION_VERSION")
98    def REACT_NATIVE_VERSION = System.getenv("REACT_NATIVE_OVERRIDE_VERSION") ?: reactProperties.getProperty("VERSION_NAME")
99    def REACT_NATIVE_TARGET_VERSION = REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
100
101    def isNewArchitectureEnabled = project.findProperty("newArchEnabled") == "true"
102    def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR")
103    def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("${project.buildDir}/downloads")
104    def thirdPartyNdkDir = new File("${project.buildDir}/third-party-ndk")
105    def reactNativeThirdParty = new File("$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/third-party")
106
107    def createNativeDepsDirectories = project.tasks.findByName('createNativeDepsDirectories') ?: project.tasks.register('createNativeDepsDirectories') {
108      downloadsDir.mkdirs()
109      thirdPartyNdkDir.mkdirs()
110    }
111
112    def extractReactNativeAARRelease = project.tasks.register('extractReactNativeAARRelease', ExtractReactNativeAARTask) {
113      reactNativeDir = REACT_NATIVE_DIR
114      buildType = 'Release'
115    }
116    def extractReactNativeAARDebug = project.tasks.register('extractReactNativeAARDebug', ExtractReactNativeAARTask) {
117      reactNativeDir = REACT_NATIVE_DIR
118      buildType = 'Debug'
119    }
120
121    def packageReactNdkDebugLibs = project.tasks.register("packageReactNdkDebugLibs", Copy) {
122      dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
123      from("$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/prebuilt/lib")
124      into("${project.buildDir}/react-ndk/exported")
125    }
126    def packageReactNdkReleaseLibs = project.tasks.register("packageReactNdkReleaseLibs", Copy) {
127      dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
128      from("$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/prebuilt/lib")
129      into("${project.buildDir}/react-ndk/exported")
130    }
131
132    // [BEGIN] Extra libs
133   def downloadDoubleConversion = project.tasks.create('downloadDoubleConversion', project.Download) {
134      dependsOn(createNativeDepsDirectories)
135      src("https://github.com/google/double-conversion/archive/v${DOUBLE_CONVERSION_VERSION}.tar.gz")
136      onlyIfNewer(true)
137      overwrite(false)
138      dest(new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz"))
139    }
140
141    def prepareDoubleConversion = project.tasks.register('prepareDoubleConversion', Copy) {
142      dependsOn(downloadDoubleConversion)
143      from(project.tarTree(downloadDoubleConversion.dest))
144      from("$reactNativeThirdParty/double-conversion/Android.mk")
145      include("double-conversion-${DOUBLE_CONVERSION_VERSION}/src/**/*", "Android.mk")
146      filesMatching("*/src/**/*", { fname -> fname.path = "double-conversion/${fname.name}" })
147      includeEmptyDirs = false
148      into("$thirdPartyNdkDir/double-conversion")
149    }
150
151    def downloadFolly = project.tasks.create('downloadFolly', project.Download) {
152      dependsOn(createNativeDepsDirectories)
153      src("https://github.com/facebook/folly/archive/v${FOLLY_VERSION}.tar.gz")
154      onlyIfNewer(true)
155      overwrite(false)
156      dest(new File(downloadsDir, "folly-${FOLLY_VERSION}.tar.gz"))
157    }
158
159    def prepareFolly = project.tasks.register('prepareFolly', Copy) {
160      dependsOn(downloadFolly)
161      from(project.tarTree(downloadFolly.dest))
162      from("$reactNativeThirdParty/folly/Android.mk")
163      include("folly-${FOLLY_VERSION}/folly/**/*", "Android.mk")
164      eachFile { fname -> fname.path = (fname.path - "folly-${FOLLY_VERSION}/") }
165      // Fixes problem with Folly failing to build on certain systems. See
166      // https://github.com/software-mansion/react-native-reanimated/issues/1024
167      def follyReplaceContent = '''
168      ssize_t r;
169      do {
170        r = open(name, flags, mode);
171      } while (r == -1 && errno == EINTR);
172        return r;
173      '''
174      filter { line -> line.replaceAll("return int\\(wrapNoInt\\(open, name, flags, mode\\)\\);", follyReplaceContent) }
175      includeEmptyDirs = false
176      into("$thirdPartyNdkDir/folly")
177    }
178    // [END] Extra libs
179
180    project.afterEvaluate {
181      if (REACT_NATIVE_BUILD_FROM_SOURCE) {
182        nativeBuildDependsOn(project, ":ReactAndroid:copyReleaseJniLibsProjectOnly", ["Release", "RelWithDebInfo"])
183        nativeBuildDependsOn(project, ":ReactAndroid:copyDebugJniLibsProjectOnly", ["Debug"])
184      } else {
185        nativeBuildDependsOn(project, extractReactNativeAARRelease, ["Release", "RelWithDebInfo"])
186        nativeBuildDependsOn(project, extractReactNativeAARDebug, ["Debug"])
187      }
188
189      def extraLibs = project.extensions.extraProperties.has('extraLegacyReactNativeLibs')
190        ? project.extensions.extraProperties.get('extraLegacyReactNativeLibs')
191        : []
192      extraLibs.each {
193        nativeBuildDependsOn(project, project.tasks.named(it), null)
194      }
195
196      if (isNewArchitectureEnabled) {
197        def preDebugBuild = project.tasks.named('preDebugBuild')
198        def preReleaseBuild = project.tasks.named('preReleaseBuild')
199        preDebugBuild.configure {
200          dependsOn(packageReactNdkDebugLibs)
201        }
202        preReleaseBuild.configure {
203          dependsOn(packageReactNdkReleaseLibs)
204        }
205
206        // Due to a bug inside AGP, we have to explicitly set a dependency
207        // between configureCMake* tasks and the preBuild tasks.
208        // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
209        project.tasks.named('configureCMakeDebug').configure {
210          dependsOn(preDebugBuild)
211        }
212        project.tasks.named('configureCMakeRelWithDebInfo').configure {
213          dependsOn(preReleaseBuild)
214        }
215        def reactNativeArchitectures = project.getProperties().get("reactNativeArchitectures")?.split(",") ?: ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
216
217        reactNativeArchitectures.each { architecture ->
218          project.tasks.named("configureCMakeDebug[${architecture}]")?.configure {
219            dependsOn("preDebugBuild")
220          }
221          project.tasks.named("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
222            dependsOn("preReleaseBuild")
223          }
224        }
225      }
226    }
227  }
228}
229
230ext.applyLegacyReactNativeLibsExtractionPlugin = {
231  apply plugin: LegacyReactNativeLibsExtractionPlugin
232}
233
234// [END] Remove when we drop SDK 47
235