Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions packages/cli/src/tools/config/resolveReactNativePath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,14 @@ export default function resolveReactNativePath(root: string) {
return resolveNodeModuleDir(root, 'react-native');
} catch (_ignored) {
throw new CLIError(`
Unable to find React Native files. Make sure "react-native" module is installed
Unable to find React Native files looking up from ${root}. Make sure "react-native" module is installed
in your project dependencies.

If you are using React Native from a non-standard location, consider setting:
{
"react-native": {
"reactNativePath": "./path/to/react-native"
}
reactNativePath: "./path/to/react-native"
}
in your \`package.json\`.
in your \`react-native.config.js\`.
`);
}
}
84 changes: 54 additions & 30 deletions packages/platform-android/native_modules.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import groovy.json.JsonSlurper
import org.gradle.initialization.DefaultSettings
import org.apache.tools.ant.taskdefs.condition.Os

def jsAppDir = buildscript.sourceFile.toString().split("node_modules/@react-native-community/cli-platform-android")[0]
def generatedFileName = "PackageList.java"
def generatedFilePackage = "com.facebook.react"
def generatedFileContentsTemplate = """
Expand Down Expand Up @@ -71,12 +72,14 @@ public class PackageList {
class ReactNativeModules {
private Logger logger
private String packageName
private String jsAppDir
private ArrayList<HashMap<String, String>> reactNativeModules

private static String LOG_PREFIX = ":ReactNative:"

ReactNativeModules(Logger logger) {
ReactNativeModules(Logger logger, String jsAppDir) {
this.logger = logger
this.jsAppDir = jsAppDir

def (nativeModules, packageName) = this.getReactNativeConfig()
this.reactNativeModules = nativeModules
Expand Down Expand Up @@ -142,45 +145,66 @@ class ReactNativeModules {
}

/**
* Runs a process to call the React Native CLI Config command and parses the output
*
* @return ArrayList < HashMap < String , String > >
* Runs a specified command using Runtime exec() in a specified directory.
* Throws when the command result is empty.
*/
ArrayList<HashMap<String, String>> getReactNativeConfig() {
if (this.reactNativeModules != null) return this.reactNativeModules
ArrayList<HashMap<String, String>> reactNativeModules = new ArrayList<HashMap<String, String>>()

def cmdProcess
def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx"
def command = "${npx} --quiet react-native config"
def reactNativeConfigOutput = ""

String getCommandOutput(String command, File directory = null) {
try {
cmdProcess = Runtime.getRuntime().exec(command)
def output = ""
def cmdProcess = Runtime.getRuntime().exec(command, null, directory)
def bufferedReader = new BufferedReader(new InputStreamReader(cmdProcess.getInputStream()))
def buff = ""
def readBuffer = new StringBuffer()
while ((buff = bufferedReader.readLine()) != null){
readBuffer.append(buff)
while ((buff = bufferedReader.readLine()) != null) {
readBuffer.append(buff)
}
output = readBuffer.toString()
if (!output) {
this.logger.error("${LOG_PREFIX}Unexpected empty result of running '${command}' command from '${directory}' directory.")
def bufferedErrorReader = new BufferedReader(new InputStreamReader(cmdProcess.getErrorStream()))
def errBuff = ""
def readErrorBuffer = new StringBuffer()
while ((errBuff = bufferedErrorReader.readLine()) != null) {
readErrorBuffer.append(errBuff)
}
throw new Exception(readErrorBuffer.toString())
}
reactNativeConfigOutput = readBuffer.toString()
return output
} catch (Exception exception) {
this.logger.warn("${LOG_PREFIX}${exception.message}")
this.logger.warn("${LOG_PREFIX}Automatic import of native modules failed.")
this.logger.error("${LOG_PREFIX}Running '${command}' command from '${directory}' directory failed.")
throw exception
}
}

def bufferedErrorReader = new BufferedReader(new InputStreamReader(cmdProcess.getErrorStream()))
def buff = ""
def readBuffer = new StringBuffer()
while ((buff = bufferedErrorReader.readLine()) != null){
readBuffer.append(buff)
}
this.logger.warn("${LOG_PREFIX}${readBuffer.toString()}")
/**
* Runs a process to call the React Native CLI Config command and parses the output
*/
ArrayList<HashMap<String, String>> getReactNativeConfig() {
if (this.reactNativeModules != null) return this.reactNativeModules

return reactNativeModules
ArrayList<HashMap<String, String>> reactNativeModules = new ArrayList<HashMap<String, String>>()
def npx = Os.isFamily(Os.FAMILY_WINDOWS) ? "npx.cmd" : "npx"
def command = "${npx} --quiet --no-install react-native config"
/**
* Running npx from the directory of the JS app which holds this script in its node_modules.
* We do so, because Gradle may be ran with a different directory as CWD, that's outside of JS project
* (e.g. when running with -p flag), in which case npx wouldn't resolve correct `react-native` binary.
*/
def dir = new File(this.jsAppDir)
def reactNativeConfigOutput = this.getCommandOutput(command, dir)
def json
try {
json = new JsonSlurper().parseText(reactNativeConfigOutput)
} catch (Exception exception) {
this.logger.error("${LOG_PREFIX}Failed to parse React Native CLI configuration: ${exception.toString()}")
throw new Exception("Failed to parse React Native CLI configuration. Expected running '${command}' command from '${dir}' directory to output valid JSON, but it didn't. This may be caused by npx resolving to a legacy global react-native binary. Please make sure to uninstall any global 'react-native' binaries: 'npm uninstall -g react-native react-native-cli' and try again")
}

def json = new JsonSlurper().parseText(reactNativeConfigOutput)
def dependencies = json["dependencies"]
def project = json["project"]["android"]

if (project == null) {
throw new Exception("React Native CLI failed to determine Android project configuration. This is likely due to misconfiguration. Config output:\n${json.toMapString()}")
}

dependencies.each { name, value ->
def platformsConfig = value["platforms"];
Expand Down Expand Up @@ -211,7 +235,7 @@ class ReactNativeModules {
* Exported Extensions
* ------------------------ */

def autoModules = new ReactNativeModules(logger)
def autoModules = new ReactNativeModules(logger, jsAppDir)

ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = null ->
if (root != null) {
Expand Down