1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import org.apache.tools.ant.taskdefs.condition.Os
|
9 |
|
10 | def config = project.hasProperty("react") ? project.react : [:];
|
11 |
|
12 | def detectEntryFile(config) {
|
13 | if (System.getenv('ENTRY_FILE')) {
|
14 | return System.getenv('ENTRY_FILE')
|
15 | } else if (config.entryFile) {
|
16 | return config.entryFile
|
17 | } else if ((new File("${projectDir}/../../index.android.js")).exists()) {
|
18 | return "index.android.js"
|
19 | }
|
20 |
|
21 | return "index.js";
|
22 | }
|
23 |
|
24 | def cliPath = config.cliPath ?: "node_modules/react-native/cli.js"
|
25 | def composeSourceMapsPath = config.composeSourceMapsPath ?: "node_modules/react-native/scripts/compose-source-maps.js"
|
26 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
|
27 | def entryFile = detectEntryFile(config)
|
28 | def bundleCommand = config.bundleCommand ?: "bundle"
|
29 | def reactRoot = file(config.root ?: "../../")
|
30 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
|
31 | def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : null ;
|
32 | def enableVmCleanup = config.enableVmCleanup == null ? true : config.enableVmCleanup
|
33 | def hermesCommand = config.hermesCommand ?: "../../node_modules/hermes-engine/%OS-BIN%/hermes"
|
34 |
|
35 | def reactNativeDevServerPort() {
|
36 | def value = project.getProperties().get("reactNativeDevServerPort")
|
37 | return value != null ? value : "8081"
|
38 | }
|
39 |
|
40 | def reactNativeInspectorProxyPort() {
|
41 | def value = project.getProperties().get("reactNativeInspectorProxyPort")
|
42 | return value != null ? value : reactNativeDevServerPort()
|
43 | }
|
44 |
|
45 | def getHermesOSBin() {
|
46 | if (Os.isFamily(Os.FAMILY_WINDOWS)) return "win64-bin";
|
47 | if (Os.isFamily(Os.FAMILY_MAC)) return "osx-bin";
|
48 | if (Os.isOs(null, "linux", "amd64", null)) return "linux64-bin";
|
49 | throw new Exception("OS not recognized. Please set project.ext.react.hermesCommand " +
|
50 | "to the path of a working Hermes compiler.");
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 | def getHermesCommand = {
|
56 |
|
57 | if (!hermesCommand.contains("%OS-BIN%")) {
|
58 | return hermesCommand
|
59 | }
|
60 |
|
61 |
|
62 | return hermesCommand
|
63 | .replaceAll("%OS-BIN%", getHermesOSBin())
|
64 | .replace('/' as char, File.separatorChar);
|
65 | }
|
66 |
|
67 |
|
68 |
|
69 | def enableHermesForVariant = config.enableHermesForVariant ?: {
|
70 | def variant -> config.enableHermes ?: false
|
71 | }
|
72 |
|
73 | android {
|
74 | buildTypes.all {
|
75 | resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort()
|
76 | resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort()
|
77 | }
|
78 | }
|
79 |
|
80 | afterEvaluate {
|
81 | def isAndroidLibrary = plugins.hasPlugin("com.android.library")
|
82 | def variants = isAndroidLibrary ? android.libraryVariants : android.applicationVariants
|
83 | variants.all { def variant ->
|
84 |
|
85 | def targetName = variant.name.capitalize()
|
86 | def targetPath = variant.dirName
|
87 |
|
88 |
|
89 | def jsBundleDir = file("$buildDir/generated/assets/react/${targetPath}")
|
90 | def resourcesDir = file("$buildDir/generated/res/react/${targetPath}")
|
91 |
|
92 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
|
93 | def jsSourceMapsDir = file("$buildDir/generated/sourcemaps/react/${targetPath}")
|
94 | def jsIntermediateSourceMapsDir = file("$buildDir/intermediates/sourcemaps/react/${targetPath}")
|
95 | def jsPackagerSourceMapFile = file("$jsIntermediateSourceMapsDir/${bundleAssetName}.packager.map")
|
96 | def jsCompilerSourceMapFile = file("$jsIntermediateSourceMapsDir/${bundleAssetName}.compiler.map")
|
97 | def jsOutputSourceMapFile = file("$jsSourceMapsDir/${bundleAssetName}.map")
|
98 |
|
99 |
|
100 | def nodeExecutableAndArgs = config.nodeExecutableAndArgs ?: ["node"]
|
101 | def extraPackagerArgs = config.extraPackagerArgs ?: []
|
102 | def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx"
|
103 |
|
104 | def execCommand = []
|
105 |
|
106 | if (config.cliPath || config.nodeExecutableAndArgs) {
|
107 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
108 | execCommand.addAll(["cmd", "/c", *nodeExecutableAndArgs, cliPath])
|
109 | } else {
|
110 | execCommand.addAll([*nodeExecutableAndArgs, cliPath])
|
111 | }
|
112 | } else {
|
113 | execCommand.addAll([npx, "react-native"])
|
114 | }
|
115 |
|
116 | def enableHermes = enableHermesForVariant(variant)
|
117 |
|
118 | def currentBundleTask = tasks.create(
|
119 | name: "bundle${targetName}JsAndAssets",
|
120 | type: Exec) {
|
121 | group = "react"
|
122 | description = "bundle JS and assets for ${targetName}."
|
123 |
|
124 |
|
125 | doFirst {
|
126 | jsBundleDir.deleteDir()
|
127 | jsBundleDir.mkdirs()
|
128 | resourcesDir.deleteDir()
|
129 | resourcesDir.mkdirs()
|
130 | jsIntermediateSourceMapsDir.deleteDir()
|
131 | jsIntermediateSourceMapsDir.mkdirs()
|
132 | jsSourceMapsDir.deleteDir()
|
133 | jsSourceMapsDir.mkdirs()
|
134 | }
|
135 |
|
136 |
|
137 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
|
138 | outputs.dir(jsBundleDir)
|
139 | outputs.dir(resourcesDir)
|
140 |
|
141 |
|
142 | workingDir(reactRoot)
|
143 |
|
144 |
|
145 | def devEnabled = !(config."devDisabledIn${targetName}"
|
146 | || targetName.toLowerCase().contains("release"))
|
147 |
|
148 | def extraArgs = extraPackagerArgs;
|
149 |
|
150 | if (bundleConfig) {
|
151 | extraArgs = extraArgs.clone()
|
152 | extraArgs.add("--config");
|
153 | extraArgs.add(bundleConfig);
|
154 | }
|
155 |
|
156 | commandLine(*execCommand, bundleCommand, "--platform", "android", "--dev", "${devEnabled}",
|
157 | "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir,
|
158 | "--sourcemap-output", enableHermes ? jsPackagerSourceMapFile : jsOutputSourceMapFile, *extraArgs)
|
159 |
|
160 |
|
161 | if (enableHermes) {
|
162 | doLast {
|
163 | def hermesFlags;
|
164 | def hbcTempFile = file("${jsBundleFile}.hbc")
|
165 | exec {
|
166 | if (targetName.toLowerCase().contains("release")) {
|
167 |
|
168 | hermesFlags = config.hermesFlagsRelease
|
169 | if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"]
|
170 | } else {
|
171 | hermesFlags = config.hermesFlagsDebug
|
172 | if (hermesFlags == null) hermesFlags = []
|
173 | }
|
174 |
|
175 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
176 | commandLine("cmd", "/c", getHermesCommand(), "-emit-binary", "-out", hbcTempFile, jsBundleFile, *hermesFlags)
|
177 | } else {
|
178 | commandLine(getHermesCommand(), "-emit-binary", "-out", hbcTempFile, jsBundleFile, *hermesFlags)
|
179 | }
|
180 | }
|
181 | ant.move(
|
182 | file: hbcTempFile,
|
183 | toFile: jsBundleFile
|
184 | );
|
185 | if (hermesFlags.contains("-output-source-map")) {
|
186 | ant.move(
|
187 |
|
188 | file: "${jsBundleFile}.hbc.map",
|
189 | tofile: jsCompilerSourceMapFile
|
190 | );
|
191 | exec {
|
192 |
|
193 |
|
194 |
|
195 | workingDir(reactRoot)
|
196 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
197 | commandLine("cmd", "/c", *nodeExecutableAndArgs, composeSourceMapsPath, jsPackagerSourceMapFile, jsCompilerSourceMapFile, "-o", jsOutputSourceMapFile)
|
198 | } else {
|
199 | commandLine(*nodeExecutableAndArgs, composeSourceMapsPath, jsPackagerSourceMapFile, jsCompilerSourceMapFile, "-o", jsOutputSourceMapFile)
|
200 | }
|
201 | }
|
202 | }
|
203 | }
|
204 | }
|
205 |
|
206 | enabled config."bundleIn${targetName}" != null
|
207 | ? config."bundleIn${targetName}"
|
208 | : config."bundleIn${variant.buildType.name.capitalize()}" != null
|
209 | ? config."bundleIn${variant.buildType.name.capitalize()}"
|
210 | : targetName.toLowerCase().contains("release")
|
211 | }
|
212 |
|
213 |
|
214 | variant.ext.bundleJsAndAssets = currentBundleTask
|
215 | currentBundleTask.ext.generatedResFolders = files(resourcesDir).builtBy(currentBundleTask)
|
216 | currentBundleTask.ext.generatedAssetsFolders = files(jsBundleDir).builtBy(currentBundleTask)
|
217 |
|
218 |
|
219 | if (variant.respondsTo("registerGeneratedResFolders")) {
|
220 | variant.registerGeneratedResFolders(currentBundleTask.generatedResFolders)
|
221 | } else {
|
222 | variant.registerResGeneratingTask(currentBundleTask)
|
223 | }
|
224 | variant.mergeResourcesProvider.get().dependsOn(currentBundleTask)
|
225 |
|
226 |
|
227 | def packageTask = variant.hasProperty("packageApplication")
|
228 | ? variant.packageApplicationProvider.get()
|
229 | : tasks.findByName("package${targetName}")
|
230 | if (variant.hasProperty("packageLibrary")) {
|
231 | packageTask = variant.packageLibrary
|
232 | }
|
233 |
|
234 |
|
235 | def buildPreBundleTask = tasks.findByName("build${targetName}PreBundle")
|
236 |
|
237 | def resourcesDirConfigValue = config."resourcesDir${targetName}"
|
238 | if (resourcesDirConfigValue) {
|
239 | def currentCopyResTask = tasks.create(
|
240 | name: "copy${targetName}BundledResources",
|
241 | type: Copy) {
|
242 | group = "react"
|
243 | description = "copy bundled resources into custom location for ${targetName}."
|
244 |
|
245 | from(resourcesDir)
|
246 | into(file(resourcesDirConfigValue))
|
247 |
|
248 | dependsOn(currentBundleTask)
|
249 |
|
250 | enabled(currentBundleTask.enabled)
|
251 | }
|
252 |
|
253 | packageTask.dependsOn(currentCopyResTask)
|
254 | if (buildPreBundleTask != null) {
|
255 | buildPreBundleTask.dependsOn(currentCopyResTask)
|
256 | }
|
257 | }
|
258 |
|
259 | def currentAssetsCopyTask = tasks.create(
|
260 | name: "copy${targetName}BundledJs",
|
261 | type: Copy) {
|
262 | group = "react"
|
263 | description = "copy bundled JS into ${targetName}."
|
264 |
|
265 | if (config."jsBundleDir${targetName}") {
|
266 | from(jsBundleDir)
|
267 | into(file(config."jsBundleDir${targetName}"))
|
268 | } else {
|
269 | into ("$buildDir/intermediates")
|
270 | into ("assets/${targetPath}") {
|
271 | from(jsBundleDir)
|
272 | }
|
273 |
|
274 |
|
275 | into ("merged_assets/${variant.name}/merge${targetName}Assets/out") {
|
276 | from(jsBundleDir)
|
277 | }
|
278 |
|
279 |
|
280 | into ("merged_assets/${variant.name}/out") {
|
281 | from(jsBundleDir)
|
282 | }
|
283 | }
|
284 |
|
285 |
|
286 | dependsOn(variant.mergeAssetsProvider.get())
|
287 |
|
288 | enabled(currentBundleTask.enabled)
|
289 | }
|
290 |
|
291 | packageTask.dependsOn(currentAssetsCopyTask)
|
292 | if (buildPreBundleTask != null) {
|
293 | buildPreBundleTask.dependsOn(currentAssetsCopyTask)
|
294 | }
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | def isRelease = targetName.toLowerCase().contains("release")
|
303 | def libDir = "$buildDir/intermediates/transforms/"
|
304 | def vmSelectionAction = {
|
305 | fileTree(libDir).matching {
|
306 | if (enableHermes) {
|
307 |
|
308 | include "**/libjsc*.so"
|
309 |
|
310 | if (isRelease) {
|
311 |
|
312 | include '**/libhermes-inspector.so'
|
313 | include '**/libhermes-executor-debug.so'
|
314 | } else {
|
315 |
|
316 |
|
317 | include '**/libhermes-executor-release.so'
|
318 | }
|
319 | } else {
|
320 |
|
321 | include "**/libhermes*.so"
|
322 | }
|
323 | }.visit { details ->
|
324 | def targetVariant = ".*/transforms/[^/]*/${targetPath}/.*"
|
325 | def path = details.file.getAbsolutePath().replace(File.separatorChar, '/' as char)
|
326 | if (path.matches(targetVariant) && details.file.isFile()) {
|
327 | details.file.delete()
|
328 | }
|
329 | }
|
330 | }
|
331 |
|
332 | if (enableVmCleanup) {
|
333 | def task = tasks.findByName("package${targetName}")
|
334 | task.doFirst(vmSelectionAction)
|
335 | }
|
336 | }
|
337 | }
|