Uploading ProGuard Mapping Files to Firebase - android

Am trying out the recently released feature that allows uploading of ProGuard mapping file to Firebase (https://firebase.google.com/docs/crash/android) using gradle task. The following is the task I'm running.
./gradlew -PFirebaseServiceAccountFilePath=xxxxx.json :app:firebaseUploadReleaseProguardMapping
However, it doesn't seem to be recognizing service account file. Has anyone had any luck getting this working? I've also tried defining FirebaseServiceAccountFilePath in gradle.properties.
* What went wrong:
Execution failed for task ':app:firebaseUploadReleaseProguardMapping'.
> Service account file path has not been defined! Service accounts are used to authorize your mapping file uploads. Learn more at
https://firebase.google.com/docs/crash/android.

Set relative path to json in gradle.properties (in project root)
FirebaseServiceAccountFilePath = /firebase-crashreporting.json
and update this property in your build.gradle
apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.firebase-crash'
android {
...
}
setProperty("FirebaseServiceAccountFilePath", rootProject.rootDir.absolutePath + FirebaseServiceAccountFilePath)
dependencies {
...
}

The error message is misleading. You will see that if the file path that you give for the service account wasn't found. Try passing the full, unambiguous path of the service account file (try not to depend on relative paths).
I'll make sure that the next version of the plugin has a more meaningful error message for the case where the file isn't found. Sorry about the trouble.

In my case I was using Jenkins to upload the proguard mappings for me. I had to change the file permissions for the json private key file from 400 to 444.

Related

How to generate OpenAPI sources from gradle when building Android app

What I'm trying to achieve
I'm trying to generate my REST API client for Android using OpenAPI Generator from the build.gradle script. That way, I wouldn't have to run the generator command line every time the specs change. Ideally, this would be generated when I build/assemble my app, and the sources would end up in the java (generated) folder, where generated sources are then accessible from the code (this is what happens with the BuildConfig.java file for example).
What I've tried so far
Following this link from their official GitHub, here's the build.gradle file I ended up with:
apply plugin: 'com.android.application'
apply plugin: 'org.openapi.generator'
...
openApiValidate {
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
recommend = true
}
openApiGenerate {
generatorName = "java"
inputSpec = "$rootDir/app/src/main/openapi/my-api.yaml"
outputDir = "$buildDir/generated/openapi"
groupId = "$project.group"
id = "$project.name-openapi"
version = "$project.version"
apiPackage = "com.example.mypackage.api"
invokerPackage = "com.example.mypackage.invoker"
modelPackage = "com.example.mypackage.model"
configOptions = [
java8 : "true",
dateLibrary : "java8",
library : "retrofit2"
]
}
...
First, I've never managed to get the API generated with the build/assemble task, even when I tried adding:
compileJava.dependsOn tasks.openApiGenerate
or
assemble.dependsOn tasks.openApiGenerate
The only way I could generate the sources was by manually triggering the openApiGenerate task:
Then, when I do generate my sources this way, they end up in the build folder but aren't accessible from my code, and aren't visible in the java (generated) folder:
I then have to manually copy/paste the generated source files to my project sources in order to use the API.
Even though I'm able to work around these issues by adding manual procedures, it would be way more maintainable if the whole process was simply automatic. I was able to achieve a similar result with another tool, Protobuf. Indeed, my gradle task gets triggered every time I build the app, and the sources end up in the java (generated) folder, so I don't have to do any additional work. The task is much simpler though, so I assume the main work that I'm not able to replicate with OpenAPI Generator is handled by the Protobuf plugin itself.
You have to specify path to the generated sources as a custom source set for your Gradle module, which is app in this case, as described here โ€“ https://developer.android.com/studio/build/build-variants#configure-sourcesets. That way Gradle will treat your sources as accessible from your code.
Something like this:
android {
...
sourceSets {
main {
java.srcDirs = ['build/generated/openapi/src/main/java']
}
}
...
}
I solved the issue you described like this, I'm using gradle.kts however.
See my build.gradle.kts
plugins {
// Your other plugins
id("org.openapi.generator") version "5.3.0"
}
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("$rootDir/app/src/main/openapi/my-api.yaml")
outputDir.set("$buildDir/generated/api")
// Your other specification
}
application {
// Your other code
sourceSets {
main {
java {
// TODO: Set this path according to what was generated for you
srcDir("$buildDir/generated/api/src/main/kotlin")
}
}
}
}
tasks.compileKotlin {
dependsOn(tasks.openApiGenerate)
}
You need to build the application at least once for the IDE to detect the library (at least this is the case for me in Intellij)
Your build should automatically generate the open api classes , to refer the generated classes in your java project you should add the generated class path to your source directory like it was mentioned in the other answers
https://developer.android.com/studio/build/build-variants#configure-sourcesets
As far as the task dependency goes , in android tasks are generated after configuration thus for gradle to recognize the task , wrap it inside afterEvaluate block like
afterEvaluate {
tasks.compileDebugJavaWithJavac.dependsOn(tasks.openApiGenerate)
}
I had this issue, and this answer https://stackoverflow.com/a/55646891/14111809 led me to a more informative error:
error: incompatible types: Object cannot be converted to Annotation
#java.lang.Object()
Taking a look at the generated files that were causing this error, noticed:
import com.squareup.moshi.Json;
After including a Moshi in the app build.gradle, the build succeeded and the generated code was accessible.
implementation("com.squareup.moshi:moshi-kotlin:1.13.0")

Failed to Generate Signed Apk - An organization slug is required (provide with --org)

After setting up the Sentry.io error tracking I get this error when I try to Generate Signed Apk:
Java Compiler
error: An organization slug is required (provide with --org)
Click on this image and open it to see more details:
I cannot understand anything from this one:
Process 'command
'/var/folders/j4/_fzm1rks3tsc2h3j4l2qbq4w0000gn/T/.sentry-cli1369818638611304938.exe'
' finished with non-zero exit value 1
This is the file address that was raised in error:
How can I solve this problem and Generate Signed Apk?
The docs are not a bit clear, though its mentioned but easy to miss it. There are two different sentry.properties required here.
Please note the sentry.properties in your project root that configures sentry-cli is different than the one you include in your application resources to configure the Sentry SDK at runtime (as seen in the configuration documentation).
You need to have another sentry.properties file in the project root with
defaults.project=your-project
defaults.org=your-org
auth.token=YOUR_AUTH_TOKEN
and the runtime sentry.properties with DSN values, etc can be placed in app/src/main/resources directory(create resource directory if required)
Config Docs
You need to upload the Proguard mapping file to the sentry server.
create a file in the root project folder and set name sentry.properties.
defaults.url=https://sentry.io
defaults.org=TEST
defaults.project=TEST_DEV
auth.token=TOKEN
replace TEST, TEST_DEV, and TOKEN.
you can get TOKEN from https://sentry.io/api
if you are use custom sentry server, replace https://sentry.io to your server adddress.
and change file build.gradle
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'io.sentry:sentry-android-gradle-plugin:1.7.27'
}
}
and
apply plugin: 'com.android.application'
apply plugin: 'io.sentry.android.gradle'
...
sentry {
autoProguardConfig true
autoUpload true
}
android {
...
}
dependencies {
...
implementation 'io.sentry:sentry-android:1.7.27'
implementation 'org.slf4j:slf4j-nop:1.7.25'
...
}
When you enable Proguard minification, symbols are uploaded to Sentry.
This upload is done via the sentry-cli, which is throwing the error. The error says the CLI doesn't know which project within Sentry to associate your symbols with.
You need to make sure to go through the gradle integration in the docs.
Specifically:
defaults.project=airflow
defaults.org=sentry
auth.token=YOUR_AUTH_TOKEN
Alternatively you can use sentry-cli directly to upload symbols, although the gradle integration is advised.
For ReactNative/iOS, if you have such errors check that you put sentry.properties file in iOS folder
I also stranded here whilst trying to figure what was going wrong with my sentry source map uploads (not on android, but for web with a similar error). To debug my events that weren't matched, I was using the sentry-cli like so;
So I was searching how I could add the organization slug to my source map uploads. But this error wasn't about the event, but for using the explain CLI functionality itself!!! Which confused me.
I had to pass additional parameters to the CLI script to get the actual problem with the event;
Maybe this will help someone else who also skipped over the docs ๐Ÿ˜…
instead of making
minifyEnabled false
Just add these rules to proguard rules file and keep minifyEnabled true
#sentry
-keepattributes LineNumberTable,SourceFile
-dontwarn org.slf4j.**
-dontwarn javax.**
-keep class io.sentry.event.Event { *; }
That solved my issue without disabling minification
IT IS NOT A REAL ANSWER But it can solve our problem in the short term by setting false value to minifyEnabled.
app/build.gradle:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
but it added 1.3MB to the size my of Apk file.
Please let me know if anyone has a different better solution.

How gradle task deal with extension objects

About Bintray-release plugin
I am using bintray-release to upload my library to maven.Its doc says how to use it:
Use the publish closure to set the info of your package:
publish {
userOrg = 'novoda'
groupId = 'com.novoda'
artifactId = 'bintray-release'
publishVersion = '0.3.4'
desc = 'Oh hi, this is a nice description for a project, right?'
website = 'https://github.com/novoda/bintray-release'
}
Finally, use the task bintrayUpload to publish
$ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false
In my case
Then I define my publish closure:
publish {
groupId = 'com.uniquestudio'
artifactId = 'parsingplayer'
publishVersion = '2.0.6'
website = 'https://github.com/TedaLIEz/ParsingPlayer'
Properties properties = new Properties()
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream() ;
properties.load( inputStream )
bintrayUser = properties.getProperty('bintrayUser')
bintrayKey = properties.getProperty('bintrayKey')
}
As you can see,out of safety I put bintrayUser and bintrayKey into local.properties.
My Question
First
I know I can put bintrayUser and bintrayKey in loacal.properties and gradle.properties.Is there any other way to store private data while I don't think is't suitable to store private data within current project ?
Second
Everything is ok but when I push my project to CI.I get error:
/home/travis/build/TedaLIEz/ParsingPlayer/local.properties (No such file or directory)
So I want to know How gradle task deal with extension objects,in my case,publish object.Is there any way to fix it?
First, I have to tell you that it is not recommended to ask two questions at once via StackOverflow, mainly because it may be hard to choose a correct answer, if two answers help you with the different questions you asked.
Anyhow, I'll try to answer both of your questions:
First
To use an additional properties file (local.properties in your case) is not a Gradle approach. It is in fact pure Java. You should only read properties on your own in very rare cases and never in a build script. If you really need an additional properties file, develop a Gradle plugin, which handles the file access.
Gradle automatically reads the gradle.properties file, but not only in the project directory, but also in the user-specific gradle home directory (e.g. C:\Users\*<User>*\.gradle). This is helpful to define private data, which won't find its way into version control, even if you forget to ignore the files manually. The defined data will be accessible to any project.
Second
Well, I assume the file local.properties does not exist, because you did neither put it under version control nor let your CI add it automatically. Where should the login data come from?
The solution is simple. Just add the required data to the CI user gradle home directories (e.g. /home/travis/.gradle) gradle.properties file. This way, you can also simply add access right management, by entering the login data of a CI user. Local builds will be published by your local user account (if allowed), CI builds by the CI system.
Appendix
Your question includes the Gradle specific term 'extension', but, to be honest, it got nothing to do with your question. It is correct, that most configuration in Gradle is done via so-called extension objects, that are added to the Project object, but it is an internal term, you do not need to understand it to fix this problem.
Edit: Comment answer
Now I can understand your confusion. Gradle distinguishes between the configuration phase and the execution phase. Nearly everything in your build script is executed during the configuration phase, only task actions (what a task does, e.g. copying, deleting ...), doFirst and doLast closures (so basically tasks) are executed during execution phase. If you define the list of tasks to be executed (via command line), it only affects the execution phase, but your configuration code will be executed at every single build, even if only one independent task is executed afterwards.
To solve this problem, follow the solution in the First block and add your private data to the user-specific Gradle directory gradle.properties file. It will be added to the project object and therefor, it will be accessible from the build file. But, since the file (or the data) does not exist on your CI, accessing it directly will raise an error when building on the CI. You can use the findProperty(propertyName) method as a fail-safe way to access the property value. If the property does not exist, it returns null (in the configuration phase), so no error occurs, as long as you don not execute the bintrayUpload task (which is not your goal on the CI).

Using Google's App Invites beta with an android app that has multiple build flavors (production, qa, debug, etc.)

I'm trying to use Google's App Invites API with my Android app and according to their guide, I need to put a config file that is generated from the developer console in the app/ directory of the project. My app has multiple build flavors, one for production, qa, and debug. I don't know how this works (since it is a pluging) with multiple build flavors and am hoping that someone can shed some light on this issue.
I investigated a bit regarding the google-services plugin and json and found the sources to this plugin.
First things first:
The gradle-plugin google-services that is referenced by classpath and with apply is a build-time plugin only! So it only influences the build-process of your app, but not the runtime-process!
This plugin is only meant as a quickstart-helper to integrating Google-services quickly in your app. Obviously, the process is somewhat convoluted and not documented, so Google should have made it clear what this process does.
In fact, I found the source code for the plugin version com.google.gms:google-services:1.4.0-beta3 and didnt find any specific reference in it regarding appinvites nor did I find any Google API for App Invites! (But maybe it just uses a generic API project with its project id, I didnt try this)
What it does:
The google-services gradle-plugin looks for the mentioned google-services.json file in your app-module. Then it looks for configured settings like project-id's and tracking-id's and such, generated by the Google API developer console into the google-services.json file.
From the settings it found, Android resource values are generated into the following path:
$project.buildDir/generated/res/google-services/$variant.dirName/values/values.xml
For example for a debug-build of your app:
app/generated/res/google-services/debug/values/values.xml
E.g. if you followed the GCM tutorial, the JSON file would include the API project's id as the following android-resource:
<string name="gcm_defaultSenderId">project-id</string>
So this plugin and JSON file are not essential to running or publishing your app, it is just a quickstart helper to generate some basic android-resource files for easier integration of specific Google API features.
Notice in the source code referenced below that the google-services plugin always generates those android-resources for every app-variant that is defined in your app/build.gradle.
If you don't want that, you should use those generated resources in the app-variants you want, and delete the others. Don't forget to remove the google-services plugin apply from app/build.gradle, or else it will be regenerated for all app-variants.
What it does not:
This plugin and JSON-file do NOT directly influence the inner workings of said Google-features for your app!
If you already have followed older tutorials on developer.android.com on how to integrate e.g. GCM or Google Analytics, then you don't even need to integrate either the gradle-plugin google-services or the google-services.json file!
Notice about where I found the sources:
After you integrated the google-services gradle-plugin and when sync your project, Gradle automatically downloads the google-services dependency to a path similar to this (on Windows, you might need to look into your home/.gradle for Linux):
C:\Users\user\.gradle\caches\modules-2\files-2.1\com.google.gms\google-services\1.4.0-beta3\f1580f62e3be313eba041ce19b64fd3f44cf8951\google-services-1.4.0-beta3-sources.jar
If you extract this jar-file, you will find two files:
GoogleServicesPlugin.groovy
GoogleServicesTask.java
which contain the plain source code of the gradle-plugin.
GoogleServicesPlugin.groovy
contains the handling of the app-variants and basic definitions of paths etc.
GoogleServicesTask.java
contains the actual task-definition, look for the following method to see what it really does:
#TaskAction
public void action() throws IOException {
checkVersionConflict();
// google-services.json
if (!quickstartFile.isFile()) {
getLogger().warn("File " + quickstartFile.getName() + " is missing from module root folder." +
" The Google Services Plugin cannot function without it.");
// Skip the rest of the actions because it would not make sense if `quickstartFile` is missing.
return;
}
// delete content of outputdir.
deleteFolder(intermediateDir);
if (!intermediateDir.mkdirs()) {
throw new GradleException("Failed to create folder: " + intermediateDir);
}
JsonElement root = new JsonParser().parse(Files.newReader(quickstartFile, Charsets.UTF_8));
if (!root.isJsonObject()) {
throw new GradleException("Malformed root json");
}
JsonObject rootObject = root.getAsJsonObject();
Map<String, String> resValues = new TreeMap<String, String>();
handleProjectNumber(rootObject, resValues);
JsonObject clientObject = getClientForPackageName(rootObject);
if (clientObject != null) {
handleAnalytics(clientObject, resValues);
handleAdsService(clientObject, resValues);
handleGoogleAppId(clientObject, resValues);
} else {
getLogger().warn("No matching client found for package name '" + packageName + "'");
}
// write the values file.
File values = new File(intermediateDir, "values");
if (!values.exists() && !values.mkdirs()) {
throw new GradleException("Failed to create folder: " + values);
}
Files.write(getValuesContent(resValues), new File(values, "values.xml"), Charsets.UTF_8);
}
So if the Google-docs donโ€™t say which resources are needed for specific Google-features, I would suggest to generate the JSON-file for each relevant buildtype/flavor, see what resources get generated by the plugin and then put those resources manually into their respective src/buildtypeORflavor/res directories.
Delete the references to google-services plugin and the JSON-file after that, and you are done.
According to the Google services gradle plugin documentation, the plugin supports different google-services.json per buildType, but not per flavor
[...] as of version 2.0.0-alpha3 of the plugin support was added for
build types, which would make the following directory structure valid:
app/src/
main/google-services.json
dogfood/google-services.json
mytype1/google-services.json
However, it's not working for me. I'm using 2.0.0-alpha9 and Gradle still complains that it can't find a google-services.json file in root folder
Error:Execution failed for task
':app:processProdReleaseGoogleServices'.
File google-services.json is missing from module root folder. The Google Services Plugin cannot function without it.
I've filed a bug: https://code.google.com/p/android/issues/detail?id=200116

Where do I specify the appIdproperty that gradle is asking for?

I am working on an app that uses appengine as its backend. I would like to download the backend server side code for my app using gradle's command line.
I type gradlew appengineDownloadApp at the command prompt and this is what I get
FAILURE: Build failed with an exception.
What went wrong:
A problem was found with the configuration of task ':app_server:appengineDownloadApp'.
No value has been specified for property 'appId'.
Where do I enter the appId? I am assuming this is the project id from my appengine account but I am unsure where to stick this value for gradle to read it.
I have been looking for the answer and finally ended up on https://github.com/GoogleCloudPlatform/gradle-appengine-plugin#convention-properties page:
The task appengineDownloadApp requires you to at least define the application ID and directory to write the files to. Define the tasks properties in the closure app:
- id: The application ID.
- version: The current application version (defaults to current default version).
- outputDirectory: The directory where you wish to save the files (defaults to build/downloaded-app).
So the property "appId" in error message is a bit misleading... As described in plugin README, you only need to add to build.gradle:
appengine {
app {
id = 'your-app-id'
}
}

Categories

Resources