1+ import org.apache.tools.ant.filters.ReplaceTokens
2+ import java.nio.file.Paths
3+
14buildscript {
25 if (project == rootProject) {
36 repositories {
@@ -18,6 +21,30 @@ def safeExtGet(prop, fallback) {
1821 rootProject. ext. has(prop) ? rootProject. ext. get(prop) : fallback
1922}
2023
24+ static def findNodeModules (baseDir ) {
25+ def basePath = baseDir. toPath(). normalize()
26+ // Node's module resolution algorithm searches up to the root directory,
27+ // after which the base path will be null
28+ while (basePath) {
29+ def nodeModulesPath = Paths . get(basePath. toString(), " node_modules" )
30+ def reactNativePath = Paths . get(nodeModulesPath. toString(), " react-native" )
31+ if (nodeModulesPath. toFile(). exists() && reactNativePath. toFile(). exists()) {
32+ return nodeModulesPath. toString()
33+ }
34+ basePath = basePath. getParent()
35+ }
36+ throw new GradleException (" sample: Failed to find node_modules/ path!" )
37+ }
38+
39+ def nodeModules = findNodeModules(projectDir);
40+ logger. warn(" sampe: node_modules/ found at: ${ nodeModules} " );
41+
42+ def reactNative = new File (" $nodeModules /react-native" )
43+
44+ def reactProperties = new Properties ()
45+ file(" $nodeModules /react-native/ReactAndroid/gradle.properties" ). withInputStream { reactProperties. load(it) }
46+ def REACT_NATIVE_VERSION = reactProperties. getProperty(" VERSION_NAME" ). split(" \\ ." )[1 ]. toInteger()
47+
2148android {
2249 compileSdkVersion safeExtGet(' TeachingJsi_compileSdkVersion' , 29 )
2350 defaultConfig {
@@ -28,8 +55,11 @@ android {
2855
2956 externalNativeBuild {
3057 cmake {
31- cppFlags " -O2 -frtti -fexceptions -Wall -fstack-protector-all "
58+ cppFlags " -O2" , " -fexceptions " , " -frtti " , " -std=c++1y " , " -DONANDROID "
3259 abiFilters ' x86' , ' x86_64' , ' armeabi-v7a' , ' arm64-v8a'
60+ arguments ' -DANDROID_STL=c++_shared' ,
61+ " -DREACT_NATIVE_VERSION=${ REACT_NATIVE_VERSION} " ,
62+ " -DNODE_MODULES_DIR=${ nodeModules} "
3363 }
3464 }
3565
@@ -41,6 +71,12 @@ android {
4171 }
4272 }
4373
74+ packagingOptions {
75+ // Exclude all Libraries that are already present in the user's app (through React Native or by him installing REA)
76+ excludes = [" **/libc++_shared.so" , " **/libfbjni.so" , " **/libjsi.so" , " **/libreactnativejni.so" , " **/libfolly_json.so" , " **/libjscexecutor.so" , " **/libhermes.so" ]
77+ exclude " META-INF/**"
78+ }
79+
4480 buildTypes {
4581 release {
4682 minifyEnabled false
@@ -53,6 +89,10 @@ android {
5389 sourceCompatibility JavaVersion . VERSION_1_8
5490 targetCompatibility JavaVersion . VERSION_1_8
5591 }
92+ configurations {
93+ extractHeaders
94+ extractJNI
95+ }
5696}
5797
5898repositories {
@@ -64,9 +104,131 @@ repositories {
64104 google()
65105 mavenCentral()
66106 jcenter()
107+
108+ def found = false
109+ def defaultDir = null
110+ def androidSourcesName = ' React Native sources'
111+
112+ if (rootProject. ext. has(' reactNativeAndroidRoot' )) {
113+ defaultDir = rootProject. ext. get(' reactNativeAndroidRoot' )
114+ } else {
115+ defaultDir = file(" $nodeModules /react-native/android" )
116+ }
117+
118+ if (defaultDir. exists()) {
119+ maven {
120+ url defaultDir. toString()
121+ name androidSourcesName
122+ }
123+
124+ logger. info(" :${ project.name} :reactNativeAndroidRoot ${ defaultDir.canonicalPath} " )
125+ found = true
126+ } else {
127+ def parentDir = rootProject. projectDir
128+
129+ 1. upto(5 , {
130+ if (found) return true
131+ parentDir = parentDir. parentFile
132+
133+ def androidSourcesDir = new File (
134+ parentDir,
135+ ' node_modules/react-native'
136+ )
137+
138+ def androidPrebuiltBinaryDir = new File (
139+ parentDir,
140+ ' node_modules/react-native/android'
141+ )
142+
143+ if (androidPrebuiltBinaryDir. exists()) {
144+ maven {
145+ url androidPrebuiltBinaryDir. toString()
146+ name androidSourcesName
147+ }
148+
149+ logger. info(" :${ project.name} :reactNativeAndroidRoot ${ androidPrebuiltBinaryDir.canonicalPath} " )
150+ found = true
151+ } else if (androidSourcesDir. exists()) {
152+ maven {
153+ url androidSourcesDir. toString()
154+ name androidSourcesName
155+ }
156+
157+ logger. info(" :${ project.name} :reactNativeAndroidRoot ${ androidSourcesDir.canonicalPath} " )
158+ found = true
159+ }
160+ })
161+ }
162+
163+ if (! found) {
164+ throw new GradleException (
165+ " ${ project.name} : unable to locate React Native android sources. " +
166+ " Ensure you have you installed React Native as a dependency in your project and try again."
167+ )
168+ }
67169}
68170
69171dependencies {
70172 // noinspection GradleDynamicVersion
71173 implementation " com.facebook.react:react-native:+" // From node_modules
174+
175+ // noinspection GradleDynamicVersion
176+ extractHeaders(" com.facebook.fbjni:fbjni:+:headers" )
177+ // noinspection GradleDynamicVersion
178+ extractJNI(" com.facebook.fbjni:fbjni:+" )
179+
180+ def rnAAR = fileTree(" ${ nodeModules} /react-native/android" ). matching({ it. include " **/**/*.aar" }). singleFile
181+ def jscAAR = fileTree(" ${ nodeModules} /jsc-android/dist/org/webkit/android-jsc" ). matching({ it. include " **/**/*.aar" }). singleFile
182+
183+
184+ extractJNI(files(rnAAR, jscAAR))
185+ }
186+
187+ def downloadsDir = new File (" $buildDir /downloads" )
188+
189+ task createNativeDepsDirectories {
190+ doLast {
191+ downloadsDir. mkdirs()
192+ }
193+ }
194+
195+
196+ task extractAARHeaders {
197+ doLast {
198+ configurations. extractHeaders. files. each {
199+ def file = it. absoluteFile
200+ copy {
201+ from zipTree(file)
202+ into " $buildDir /$file . name "
203+ include " **/*.h"
204+ }
205+ }
206+ }
207+ }
208+
209+ extractAARHeaders. mustRunAfter createNativeDepsDirectories
210+
211+ task extractJNIFiles {
212+ doLast {
213+ configurations. extractJNI. files. each {
214+ def file = it. absoluteFile
215+
216+ copy {
217+ from zipTree(file)
218+ into " $buildDir /$file . name "
219+ include " jni/**/*"
220+ }
221+ }
222+ }
223+ }
224+
225+ extractJNIFiles. mustRunAfter extractAARHeaders
226+
227+ // pre-native build pipeline
228+
229+ tasks. whenTaskAdded { task ->
230+ if (! task. name. contains(' Clean' ) && (task. name. contains(' externalNative' ) || task. name. contains(' CMake' ))) {
231+ task. dependsOn(extractAARHeaders)
232+ task. dependsOn(extractJNIFiles)
233+ }
72234}
0 commit comments