I was trying to install expo-av into a non-expo react-native project. After installing react-native-unimodules and adjusting the android/app/build.gradle file, I am not able to build the android app anymore.
This is the main error I get:
The terminal looks like this: Java or Kotlin file MainApplication.java does not include package declaration.
ENVFILE=.env react-native run-android
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 2152 file(s) to forward-jetify. Using 16 workers...
info JS server already running.
info Installing the app...
Configuration on demand is an incubating feature.
> Configure project :app
Reading env from: .env
FAILURE: Build failed with an exception.
* Where:
Script '/Users/*REDACTED*/HF-Projects/*REDACTED*/node_modules/react-native-unimodules/gradle.groovy' line: 75
* What went wrong:
A problem occurred evaluating project ':app'.
> Java or Kotlin file /Users/*REDACTED*/HF-Projects/*REDACTED*/android/app/src/main/java/com/*REDACTED*/MainApplication.java does not include package declaration
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 14s
I searched for package on that file and found 26 occurrences.
There is this packages variable on this ReactNativeHost instance.
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
#Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// Add unimodules
List<ReactPackage> unimodules = Arrays.<ReactPackage>asList(
new ModuleRegistryAdapter(mModuleRegistryProvider)
);
packages.addAll(unimodules);
return packages;
}
#Override
protected String getJSMainModuleName() {
return "index";
}
#Override
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage(); // <- add
}
};
Does anybody know about this error?
The short answer is:
This is a simple validation that looks for the main package of that java class.
On top of the file, there should be a package com.yourcompany.example.
It happened that my MainApplication.java class had TWO BLANK SPACES right after packages.
So the regex didn't find it.
The regex used in this validation may be found on the file node_modules/react-native-unimodules/gradle.groovy line 67.
Regex used: /^package ([0-9a-zA-Z._]*);?$/
def readPackageFromJavaOrKotlinFile(String filePath) {
def file = new File(filePath)
def fileReader = new BufferedReader(new FileReader(file))
def fileContent = ""
while ((fileContent = fileReader.readLine()) != null) {
def match = fileContent =~ /^package ([0-9a-zA-Z._]*);?$/
if (match.size() == 1 && match[0].size() == 2) {
fileReader.close()
return match[0][1]
}
}
fileReader.close()
throw new GradleException("Java or Kotlin file $file does not include package declaration")
}
Related
I am trying to write a plugin that adds my repo to settings.gradle if available or in build.gradle in other cases, like this:
public static void addLibraryRepositories(GradleBuildModel file, GradleSettingsModel settings, String url) {
// Check if settings.gradle contains the repositories
RepositoriesModel repositoryModel = null;
if (settings != null) {
repositoryModel = settings.dependencyResolutionManagement().repositories();
}
// if not use the build.gradle file
if (repositoryModel == null || repositoryModel.repositories().size() <= 0) {
repositoryModel = file.repositories();
}
// add my maven repo
if (!repositoryModel.containsMavenRepositoryByUrl(url)) {
repositoryModel.addMavenRepositoryByUrl(url, "My Repo");
file.applyChanges();
}
}
But I am getting this error when running gradle task 'buildPlugin':
error: cannot find symbol repositoryModel = settings.dependencyResolutionManagement().repositories();
^
symbol: method dependencyResolutionManagement()
location: variable settings of type GradleSettingsModel
Using IntelliJ 2022.1.3, there is no error on IDE, I can navigate to the definition of the interface and the GradleSettingsModelImpl implementation, in project view I can see it is included in android-gradle-dsl.jar.
I have these deps in plugin.xml
<depends>com.intellij.modules.all</depends>
<depends>com.intellij.modules.java</depends>
<depends>org.jetbrains.android</depends>
<depends>org.intellij.groovy</depends>
I can call other methods of the same class without this error.
Any help is appreciated.
PS Already tried invalidating cache.
I am trying to build an Android app instrumenting tool called Ella from https://github.com/saswatanand/ella
When I was trying to build it using ant, it shows this error:
Buildfile: /Users/sioyoo/tools/ella/build.xml
create-keystore:
init:
build:
init:
[mkdir] Created dir: /Users/sioyoo/tools/ella/instrument/build
compile:
[javac] Compiling 67 source files to /Users/sioyoo/tools/ella/instrument/build
[javac] Note: /Users/sioyoo/tools/ella/instrument/src/com/apposcopy/ella/Instrument.java uses or overrides a deprecated API.
[javac] Note: Recompile with -Xlint:deprecation for details.
[javac] Note: Some input files use unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
jar:
[zip] Building zip: /Users/sioyoo/tools/ella/bin/ella.instrument.jar
init:
[mkdir] Created dir: /Users/sioyoo/tools/ella/runtime/build
[javac] /Users/sioyoo/tools/ella/runtime/build.xml:15: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 1 source file to /Users/sioyoo/tools/ella/runtime
BUILD FAILED
/Users/sioyoo/tools/ella/build.xml:49: The following error occurred while executing this line:
/Users/sioyoo/tools/ella/runtime/build.xml:21: java.lang.RuntimeException: The executable 'android' is not in the path
at GuessDefaultSettingsTask.findAndroidSDKPath(GuessDefaultSettingsTask.java:46)
at GuessDefaultSettingsTask.execute(GuessDefaultSettingsTask.java:11)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:299)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:99)
at org.apache.tools.ant.Task.perform(Task.java:350)
at org.apache.tools.ant.Target.execute(Target.java:449)
at org.apache.tools.ant.Target.performTasks(Target.java:470)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1401)
at org.apache.tools.ant.helper.SingleCheckExecutor.executeTargets(SingleCheckExecutor.java:36)
at org.apache.tools.ant.Project.executeTargets(Project.java:1264)
at org.apache.tools.ant.taskdefs.Ant.execute(Ant.java:437)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:299)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:99)
at org.apache.tools.ant.Task.perform(Task.java:350)
at org.apache.tools.ant.Target.execute(Target.java:449)
at org.apache.tools.ant.Target.performTasks(Target.java:470)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1401)
at org.apache.tools.ant.Project.executeTarget(Project.java:1374)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1264)
at org.apache.tools.ant.Main.runBuild(Main.java:818)
at org.apache.tools.ant.Main.startAnt(Main.java:223)
at org.apache.tools.ant.launch.Launcher.run(Launcher.java:284)
at org.apache.tools.ant.launch.Launcher.main(Launcher.java:101)
Total time: 1 second
However, in the settings file, my android build tools is setted to location:
/Users/sioyoo/Library/Android/sdk/build-tools/32.0.0
where is actually where I kept my android build tools.
Can anyone help me with this? I am using MacOS to build this tool.
I solved the Problem by editing the
<path_to_ella>/ella/runtime/GuessDefaultSettingsTask.java file as follows:
import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;
import java.util.*;
import java.io.*;
public class GuessDefaultSettingsTask extends Task
{
public void execute() throws BuildException
{
String sdkPath = findAndroidSDKPath();
String btPath = getProject().getProperty("ella.android.buildtools.dir");
if(btPath == null){
btPath = findAndroidBuildToolsPath(sdkPath);
System.out.println("path to build-tools directory: "+btPath);
}
File dxPath = new File(btPath, "dx");
if(!dxPath.isFile())
throw new Error("The configuration variable android.buildtools.dir is probably not set correctly. Current value is "+btPath);
getProject().setProperty("ella.android.buildtools.dir", btPath);
String androidJarPath = getProject().getProperty("ella.android.jar");
if(androidJarPath == null){
androidJarPath = findAndroidJarPath(sdkPath);
if(androidJarPath == null)
throw new Error("Could not automatically infer path to android.jar. Set ella.android.jar variable in the .settings file.");
getProject().setProperty("ella.android.jar", androidJarPath);
}
}
String findAndroidSDKPath()
{
File sdk = new File("/Users/nicoostendorf1/Library/Android/sdk");
return sdk.getPath();
/*
String[] sCmdExts = {""}; //TODO: support windows?
StringTokenizer st = new StringTokenizer(System.getenv("PATH"), File.pathSeparator);
String path, sFile;
while (st.hasMoreTokens()) {
path = st.nextToken();
for (String sExt : sCmdExts) {
sFile = path + File.separator + "android" + sExt;
File file = new File(sFile);
if (file.isFile()) {
return file.getAbsoluteFile().getParentFile().getParent();
}
}
}
throw new RuntimeException("The executable 'android' is not in the path");*/
}
String findAndroidBuildToolsPath(String sdkPath)
{
/*File buildToolsDir = new File(sdkPath, "build-tools");
//find the latest version
String latestVersion = null;
for(String v : buildToolsDir.list()){
if(latestVersion == null || v.compareTo(latestVersion) > 0){
latestVersion = v;
}
}
assert latestVersion != null : "Build tools not found";
//return buildToolsDir.getPath()+File.separator+latestVersion;*/
File buildToolsDir = new File("/Users/nicoostendorf1/Library/Android/sdk/build-tools/25.0.0");
return buildToolsDir.getPath();
}
String findAndroidJarPath(String sdkPath)
{
File jarfile = new File("/Users/nicoostendorf1/Library/Android/sdk/platforms/android-25/android.jar");
return jarfile.getPath();
/*File platformsDir = new File(sdkPath, "platforms");
String latestVersion = null;
for(File v : platformsDir.listFiles()){
if(!v.getName().startsWith("android-"))
continue;
File androidJar = new File(v, "android.jar");
if(androidJar.isFile())
return androidJar.getPath();
}
return null;*/
}
}
You have to edit the File paths like you need it!
I'm trying to get an argument from the command line using a Gradle task:
class myApk extends DefaultTask {
#Option(option="apkName", description="apkName for your file")
String apkName
#TaskAction
void uploadApk() {
def arg = "curl -F \"demo${apkName}.apk=" +
"#${project.projectDir}\\app\\build\\outputs\\apk\\debug\\app-debug.apk\" " +
"https://URL"
project.exec {
commandLine("cmd", "/c", arg)
}
}
}
task uploadApk(type: myApk) { }
But after typing gradle uploadApk --apkName=foo in the terminal I get this kind of exception:
Problem configuring task :app:uploadApk from command line.
> Unknown command-line option '--apkName'.
P.S. I've read this topic(How to pass arguments from command line to gradle), but it doesn't seem helpful for this problem;(
Thanks to the comment above, I used -P to work it out
I'm integrating New Relic in my project (with Android Studio & Gradle) which has 2 variants. Each variant has its own generated token, which I store in each variant's string.xml file.
In the New Relic documentation, it states the following:
In your project’s root directory (projectname/app), add a newrelic.properties file with the following line:
com.newrelic.application_token=generated_token
The problem is, if I do this, how can make the correct token appear for the correct variant? If this file must appear in the project root, I can't create one per variant, and so I'm forced to use the same token for both variants, which doesn't work for my requirements.
Any insight would be appreciated.
Okay, so after contacting the support team at New Relic, there is apparently no direct solution for this as of today, although they said they've opened a feature request, and so this problem might be solved soon.
From what I managed to understand, the reason this file is needed is so that the New Relic system can display an un-obfuscated error log when an exception occurs on a production version which has been obfuscated with ProGuard.
The New Relic system, with the help of this file, will upload the ProGuard mapping.txt file to the New Relic servers and associate it with your app according to the specified token. With this, New Relic can un-obfuscate stack traces and display a descriptive stack trace with actual class & method names, rather a, b, c, etc.
As a workaround, I was told that I can forego this file all together, if I upload the mapping file manually.
The mapping file can be found at:
build/outputs/proguard/release/mapping.txt
In order to manually upload the file, perform the following via command line:
curl -v -F proguard=#"<path_to_mapping.txt>" -H "X-APP-LICENSE-KEY:<APPLICATION_TOKEN>" https://mobile-symbol-upload.newrelic.com/symbol
This must be done for each variant which is being obfuscated with ProGuard (classically, release builds).
Source
Hope this helps someone else.
I solved creating some Gradle tasks. Please, take a look at https://discuss.newrelic.com/t/how-to-set-up-newrelic-properties-file-for-project-with-multiple-build-variants/46176/5
I following a code that worked pretty well for me.
Add the New Relic application token on a string resource file. i.e.: api.xml.
Create a new Gradle file. i.e: newrelic-util.gradle.
Add the following content on the newly created Gradle file:
apply plugin: 'com.android.application'
android.applicationVariants.all { variant ->
//<editor-fold desc="Setup New Relic property file">
def variantName = variant.name.capitalize()
def newRelicTasksGroup = "newrelic"
def projectDirPath = project.getProjectDir().absolutePath
def newRelicPropertyFileName = "newrelic.properties"
def newRelicPropertyFilePath = "${projectDirPath}/${newRelicPropertyFileName}"
// Cleanup task for New Relic property file creation process.
def deleteNewRelicPropertyFile = "deleteNewRelicPropertyFile"
def taskDeleteNewRelicPropertyFile = project.tasks.findByName(deleteNewRelicPropertyFile)
if (!taskDeleteNewRelicPropertyFile) {
taskDeleteNewRelicPropertyFile = tasks.create(name: deleteNewRelicPropertyFile) {
group = newRelicTasksGroup
description = "Delete the newrelic.properties file on project dir."
doLast {
new File("${newRelicPropertyFilePath}").with {
if (exists()) {
logger.lifecycle("Deleting file ${absolutePath}.")
delete()
} else {
logger.lifecycle("Nothing to do. File ${absolutePath} not found.")
}
}
}
}
}
/*
* Fix for warning message reported by task "newRelicMapUploadVariantName"
* Message:
* [newrelic] newrelic.properties was not found! Mapping file for variant [variantName] not uploaded.
* New Relic discussion:
* https://discuss.newrelic.com/t/how-to-set-up-newrelic-properties-file-for-project-with-multiple-build-variants/46176
*/
def requiredTaskName = "assemble${variantName}"
def taskAssembleByVariant = project.tasks.findByName(requiredTaskName)
def createNewRelicPropertyFileVariantName = "createNewRelicPropertyFile${variantName}"
// 0. Searching task candidate to be dependent.
if (taskAssembleByVariant) {
logger.debug("Candidate task to be dependent found: ${taskAssembleByVariant.name}")
// 1. Task creation
def taskCreateNewRelicPropertyFile = tasks.create(name: createNewRelicPropertyFileVariantName) {
group = newRelicTasksGroup
description = "Generate the newrelic.properties file on project dir.\nA key/value propety " +
"will be written in file to be consumed by newRelicMapUploadVariantName task."
logger.debug("Creating task: ${name}")
doLast {
def newRelicPropertyKey = "com.newrelic.application_token"
def newRelicStringResourceKey = "new_relic_key"
def targetResourceFileName = "api.xml"
def variantXmlResourceFilePath = "${projectDirPath}/src/${variant.name}/res/values/${targetResourceFileName}"
def mainXmlResourceFilePath = "${projectDirPath}/src/main/res/values/${targetResourceFileName}"
def xmlResourceFilesPaths = [variantXmlResourceFilePath, mainXmlResourceFilePath]
xmlResourceFilesPaths.any { xmlResourceFilePath ->
// 1.1. Searching xml resource file.
def xmlResourceFile = new File(xmlResourceFilePath)
if (xmlResourceFile.exists()) {
logger.lifecycle("Reading property from xml resource file: ${xmlResourceFilePath}.")
// 1.2. Searching for string name new_relic_key api.xml resource file.
def nodeResources = new XmlParser().parse(xmlResourceFile)
def nodeString = nodeResources.find {
Node nodeString -> nodeString.'#name'.toString() == newRelicStringResourceKey
}
// 1.3. Checking if string name new_relic_key was found.
if (nodeString != null) {
def newRelicApplicationToken = "${nodeString.value()[0]}"
logger.lifecycle("name:${nodeString.'#name'.toString()};" +
"value:${newRelicApplicationToken}")
// 1.4 Checking the content of newRelicApplicationToken
if (newRelicApplicationToken == 'null' || newRelicApplicationToken.allWhitespace) {
logger.warn("Invalid value for key ${newRelicStringResourceKey}. " +
"Please, consider configuring a value for key ${newRelicStringResourceKey}" +
" on ${xmlResourceFile.name} resource file for buildVariant: ${variantName}. " +
"The ${newRelicPropertyFileName} will be not created.")
return true // break the loop
}
// 1.5. File creation.
File fileProperties = new File(newRelicPropertyFilePath)
fileProperties.createNewFile()
logger.lifecycle("File ${fileProperties.absolutePath} created.")
// 1.6. Writing content on properties file.
def fileComments = "File generated dynamically by gradle task ${createNewRelicPropertyFileVariantName}.\n" +
"Don't change it manually.\n" +
"Don't track it on VCS."
new Properties().with {
load(fileProperties.newDataInputStream())
setProperty(newRelicPropertyKey, newRelicApplicationToken.toString())
store(fileProperties.newWriter(), fileComments)
}
logger.lifecycle("Properties saved on file ${fileProperties.absolutePath}.")
return true // break the loop
} else {
logger.warn("The key ${newRelicStringResourceKey} was not found on ${xmlResourceFile.absolutePath}.\n" +
"Please, consider configuring a key/value on ${xmlResourceFile.name} resource file for buildVariant: ${variantName}.")
return // continue to next xmlResourceFilePath
}
} else {
logger.error("Resource file not found: ${xmlResourceFile.absolutePath}")
return // continue next xmlResourceFilePath
}
}
}
}
// 2. Task dependency setup
// To check the task dependencies, use:
// logger.lifecycle("Task ${name} now depends on tasks:")
// dependsOn.forEach { dep -> logger.lifecycle("\tTask: ${dep}") }
tasks['clean'].dependsOn taskDeleteNewRelicPropertyFile
taskCreateNewRelicPropertyFile.dependsOn taskDeleteNewRelicPropertyFile
taskAssembleByVariant.dependsOn taskCreateNewRelicPropertyFile
} else {
logger.error("Required task ${requiredTaskName} was not found. " +
"The task ${createNewRelicPropertyFileVariantName} will be not created.")
}
//</editor-fold>
}
On app/build.gradle file, apply the Gradle file.
apply from: './newrelic-util.gradle'
That’s it. I created a file named newrelic-util.gradle on project app dir. If you execute the task assembleAnyVariantName, the task createNewRelicPropertyFileAnyVarianteName will be performed first. Tip: don’t track the generated file newrelic.properties file. Ignore it on your VCS.
Additionally, the task deleteNewRelicPropertyFile will be performed right before the tasks ‘clean’ and ‘createNewRelicPropertyFileAnyVarianteName’ in order to avoid a file with a wrong New Relic application token.
I have the following setup in my build.gradle file:
// Task designed to bump version numbers. This should be the first task run
// after a new release branch is created.
task bumpVersion(description: 'Bumps the version number of the current Android release. Should be used as a standalone task, and should only be the first task called after creating a release branch.', group: 'Management') << {
Properties props = new Properties();
File propsFile = new File('gradle.properties');
props.load(propsFile.newDataInputStream());
def currentVersionCode = props.getProperty("CORE_VERSION_CODE") as int;
def currentVersionName = props.getProperty("CORE_VERSION_NAME") as String;
def intPortionsOfVersionName = currentVersionName.tokenize('.').toArray();
def leastSignificantPortion = intPortionsOfVersionName[intPortionsOfVersionName.length - 1] as int;
def newVersionCode = currentVersionCode + 1;
def newVersionName = "";
if (!project.hasProperty('newVersion')) {
leastSignificantPortion = leastSignificantPortion + 1;
intPortionsOfVersionName[intPortionsOfVersionName.length - 1] = leastSignificantPortion;
newVersionName = intPortionsOfVersionName.collect{ it }.join(".");
} else {
newVersionName = project.getProperty('newVersion');
}
props.setProperty("CORE_VERSION_NAME", newVersionName as String);
props.setProperty("CORE_VERSION_CODE", newVersionCode as String);
props.store(propsFile.newWriter(), null);
}
Under the line newVersionName = project.getProperty('newVersion') I try to acquire the property called "newVersion", if it exists, and bump the least significant digit if it's not available.
This works fine, but what I want to do is add a way to specify this option in the documentation (i.e. gradle help --task bumpVersion). For instance, if I run gradle help --task help, it gives me:
:help
Detailed task information for help
Path
:help
Type
Help (org.gradle.configuration.Help)
Options
--task The task, detailed help is requested for.
Description
Displays a help message
Notice how '--task' is under the Options section. I'm wondering how to do this with my own code.
This can be done using the #Option annotation.
#Option(option = "version", description = "Version number to use")
public void setVersion(String version) { ... }
Note: This is an internal API so it may change.
Edit: May have forgotten to mention you will have to implement your task as a custom task class to leverage this capability.