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