Uploading Symbol files for Android NDK crash reports automatically - firebase

I am using Crashlytic sdk for collecting Android NDK crash reports. Please find the configuration file below.
It works well if I run the following command:
./gradlew crashlyticsUploadSymbolsXXXRelease
Also, If I add assembleXXXRelease.finalizedBy(crashlyticsUploadSymbolsXXXRelease) to afterEvaluate block, the symbol files also are uploaded after each build.
Here are my questions:
I want this uploading process to be automatic. The issue I am facing is the finalizedBy way will added around 10 more minutes to the build time, which is I have to avoid. I prefer to create a new task and invoke it somewhere else after each build, so the APK build time will stay the same as now. I tried to do so, but it seems not working. See the code below. If you have any clue or I missed something, please let me know.
Is that possible to override the NDK output path based on different flavor? I tried to get the flavor XXX from task name like assbleXXXRelease, and assign it to the output path like XXX/obj, but failed. It seems the flavor has been fixed to the default flavor.
Is that possible that I can pick up the cSYM symbols files and upload to Crashlytics without Crashlytic sdk?
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
// Question 2 will be happening here:
crashlytics {
enableNdk true
androidNdkOut "obj" // override the path based on the flavor name to flavorName/obj?
androidNdkLibsOut "libs" // override the path based on the flavor name to flavorName/libs?
}
dependencies {
// ...
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
// Add the Crashlytics NDK dependency
implementation 'com.crashlytics.sdk.android:crashlytics-ndk:2.1.1'
}
// Question 1 will be happening here:
// If I call this task from command line, it won't work. Nothing will happen.
task upload {
doLast {
crashlyticsUploadSymbolsXXXRelease
}
}
afterEvaluate {project ->
android.applicationVariants.all { variant ->
assembleXXXRelease.finalizedBy(crashlyticsUploadSymbolsXXXRelease) // it works here
}
}

I want this uploading process to be automatic. The issue I am facing is the finalizedBy way will added around 10 more minutes to the build time, which is I have to avoid. I prefer to create a new task and invoke it somewhere else after each build, so the APK build time will stay the same as now. I tried to do so, but it seems not working.
I solved this by modifying the task as follows:
task upload {
doLast {
// do something whatever
}
}
upload.finalizedBy(crashlyticsUploadSymbolsXXXRelease)
Is that possible to override the NDK output path based on different flavor? I tried to get the flavor XXX from task name like assbleXXXRelease, and assign it to the output path like XXX/obj, but failed. It seems the flavor has been fixed to the default flavor.
I have made this work to get the current flavor name by calling
gradle.startParameter.taskName[0]
Is that possible that I can pick up the cSYM symbols files and upload to Crashlytics without Crashlytic sdk?
I have not yet found a solution for this.

I want this uploading process to be automatic. The issue I am facing is the finalizedBy way will added around 10 more minutes to the build time, which is I have to avoid. I prefer to create a new task and invoke it somewhere else after each build, so the APK build time will stay the same as now.
I created a Gradle project that allows exactly that: uploading Firebase Crashlytics NDK symbols independent from the build process of your app.
You can check it out here:
https://github.com/triplef/android-upload-ndk-symbols

Related

Firebase app distribution via gradle updating the same APK instead of creating new one

I recently integrated firebase app distribution in my app and used the Firebase console. I used to generate APK and upload manualy via console and distribute the app. I was so naive. Then I came to know that this entire process can be automated via Fastlane or Gradle app distribution. support. I was successful in integrating the app distribution via gradle thanks to this.
But I soon observed that when I was using the console a new entry was created for every new APK no matter the version name or version code ie. new APK entry was created even if I did not change the APK version code or name. However, when I am doing it through Gradle it is updating the same APK again and again until I change the version code and name.
Already gone through the documentation but there is no mention of this. Do i need to change the version code and name for every upload if i want a new entry for it in the app distribution console?
build.gradle(app)
buildTypes {
debug{
firebaseAppDistribution {
appId = "MY_APP_ID"
releaseNotesFile = "app/releasenotes.txt"
groups = "test"
}
}
to upload i run
./gradlew assembleDebug appDistributionUploadDebug
I faced the same problem while trying to push feature-branch builds, i wanted to not have any different version code
I did some try and error to fix the problem so my solution is kind of out of the box.
Solution 1
First I tried to see what was the issue, and I have added a groovy method that generates a timestamp
static def getDate() {
return new Date().format('yyyyMMddHHmm')
}
then i have changed the buildType.debug.versionNameSuffix to have a name for each build based on the timestamp, so we got this
versionNameSuffix "-DEBUG-" + getDate()
Solution 2
As our Github Action CI doesn't need to name the name of the debug apk file, why don't just change that file name?
So the gradle change becomes
defaultConfig {
archivesBaseName = "${applicationId}-v${versionName}(${versionCode})" + getDate()
}
And we get this output
I hope this will help you

Unity Firebase Crashlytics not sending any crash reports, getting "failed to retrieve settings" error on logcat

Unity editor version: 2019.3.15f1
Firebase Unity SDK version: firebase_unity_sdk_6.15.2
Additional SDKs im using: Unity IAP, Gamesparks, Ironsource, Facebook, Appsflyer, GameAnalytics
Platform im using the Unity editor on: Windows
Platform im targeting: Android
Scripting Runtime: IL2CPP
Problem
I am getting data on firebase analytics, but I cannot get crashlytics to report anything. Im stuck on this...
Steps to reproduce:
Add the firebase analytics and crashlytics sdks.
Add the google-services.json GoogleService-Info.plist files somewhere in assets folder
Add this code to initialise the firebase
// Use this for initialization
void Start ()
{
// Initialize Firebase
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available)
{
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
// Crashlytics will use the DefaultInstance, as well;
// this ensures that Crashlytics is initialized.
Firebase.FirebaseApp app = Firebase.FirebaseApp.DefaultInstance;
// Set a flag here for indicating that your project is ready to use Firebase.
VisualDebugger.SetText("crashlytics initialised");
}
else
{
UnityEngine.Debug.LogError(System.String.Format(
"Could not resolve all Firebase dependencies: {0}",dependencyStatus));
VisualDebugger.SetText("crashlytics NOT initialised: " + dependencyStatus);
// Firebase Unity SDK is not safe to use here.
}
});
Invoke("IsCrashEnabled", 5f);
}
void IsCrashEnabled()
{
VisualDebugger.AddLine("IsCrashlyticsCollectionEnabled: "+Firebase.Crashlytics.Crashlytics.IsCrashlyticsCollectionEnabled);
}
In order to get the app to run with the facebook sdk installed Ive added these two lines to proguard-user.txt
-keep public class com.facebook.**{public *; }
-keep public class com.facebook.internal.**{ public *; }
and commented out the following lines from mainTemplate.gradle
//implementation 'com.android.support:appcompat-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency
//implementation 'com.android.support:customtabs:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency
//implementation 'com.android.support:support-v4:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency
When I run the app, firebase is initialised successfully. Also Firebase.Crashlytics.Crashlytics.IsCrashlyticsCollectionEnabled returns true.
I crash the app in a number of different ways, then open it again without reinstalling. But no crash reports are sent.
When I watch logcat when starting the app I see this error from firebase each time the app is opened
2020-09-28 16:18:59.332 25773-25847/? E/FirebaseCrashlytics: Failed to retrieve settings from https://firebase-settings.crashlytics.com/spi/v2/platforms/android/gmp/REDACTEDblahblahblah/settings
Update Oct 19, 2020:
Today a developer updated the issue I linked in this answer saying the Firebase team fixed a backend bug last Friday (Oct 16) that was affecting some new Unity Android apps registering w/ Firebase - likely the bug behind your issue. I had already solved the issue in my own project using the below solution, but if you haven't yet updated your project, I recommend running it again and seeing if Crashlytics is working for you now..
I've been dealing with the same issue this week in Unity 2019.4.11f1 - i see the same error message about not being able to retrieve settings, but with my specific project and appIds in the URL.
I found a solution in this Github issue, which suggests the problem is caused by the version of an android library that is a dependency for the Unity Firebase Crashlytics package. My rough understanding is that the firebase-crashlytics-unity library is a wrapper around android library firebase:firebase-crashlytics, and the unity package allows the underlying native Android code to be used from Unity. Version com.google.firebase:firebase-crashlytics:17.10.0 has issues with getting the settings for some Firebase projects on Android. Myself and several others following this issue found forcing Unity to use this specific dependency at version 17.1.1 resolved the issue.
Someone else with the same issue in the thread contacted Firebase support and was told:
The error you are seeing "Failed to retrieve settings" is related to
the SDK version being used. If you go to "Assets > Firebase > Editor>
CrashlyticsDependencies" you can manually update the SDK to point to
the latest Crashlytics SDK version 17.2.2. Please give it a try and if
you continue having issues, let me know.
It turned out this advice wasn't quite right - some of us following the thread then experienced a different issue when using the Android Crashlytics SDK version 17.2.2 with Unity crashlytics version 6.16.0. So I'd specifically recommend trying out the below suggestion or other solutions in the thread to set your Android crashlytics library to v17.1.1.
Changes I made in my project to address this:
First, I updated my unity firebase packages in the package manager to use version 6.16.0. In my project 4 packages were installed - core, analytics, crashlytics, and messaging.
Then I searched for the the Crashlytics package's dependency file - Crashlytics-Dependencies.xml (found by searching project - was in /Library/PackageCache/com.google.firebase.crashlytics#6.16.0/Firebase/Editor/ for me). This file initally had "com.google.firebase:firebase-crashlytics:17.0.0" listed, which I updated to be: "com.google.firebase:firebase-crashlytics:17.1.1".
As an extra precaution, I also added created a MyProject-Dependencies.xml file, as was suggested by a user in the thread - this file also specifies version "com.google.firebase:firebase-crashlytics:17.1.1".
Next, I modified the Unity build process to use a custom mainTemplate.gradle file to specify dependencies,
rather than using the External Dependency Resolver to manage and
embed unity packages (option in Build Settings > PlayerSettings >
Android).
I also updated the settings on the External Dependency Manager Android Ressolver:
Disabled AutoResolve and Disabled Resolve on Build (we dont want EDM updating dependencies without our knowledge when building)
I also turned disabled AndroidPackageInstallationEnabled - this has made the resolution process much faster and removed a bunch of .aar files from the android dependencies list, and hasn't caused any problems in my project.
I then ran External Dependency Resolver > Android > Force Resolve, which after the settings changes above, should now embed a list of the dependencies for the Android build into the mainTemplate.gradle file - Check this file (its in Assets/Plugins/Android) and you should now see com.google.firebase:firebase-crashlytics:17.1.1 in that list.
Also, I recommend reading this article about managing Unity Firebase dependencies from one of the Firebase developer advocates, Patrick Martin. It helped me wrap my head around how Android dependency management in Unity works, as well as how the Android gradle build process works.

How to check build info from a user plugin before downloading an artifact?

We want to prevent downloading artifacts without build info with a user plugin in our on-prem Artifactory installation. We are struggling to find a connection between the Request and the corresponding BuildInfo.
import org.artifactory.request.Request
import org.artifactory.repo.RepoPath
download {
beforeDownloadRequest { Request request, RepoPath repoPath ->
if (isRelease(repoPath.repoKey)) {
log.warn "Is a release artifact"
// How to verify build info here??
}
}
}
def isRelease(String repoKey) {
return repoKey in ["libs-release-local"]
}
Using the Artifactory Query Language you can find builds based on an artifact, and if the result is empty, then there is no such a build: https://www.jfrog.com/confluence/display/JFROG/Artifactory+Query+Language
For example:
builds.find({"module.artifact.item.name": "artifactory.war"})
Also artifacts linked to a build will have a property "build.number" and "build.name", so that's one way to approach it
The proper solution would be to use JFrog Xray. You can then set scans for your builds, so that all artifacts part of a build will get scanned (plus you get security and license compliance checks there too), and then block the download of unscanned artifacts
Lastly, when you create a build you can also promote it, for instance from "staging" to "release" and on that operation copy or move the artifacts to a repository that is build-release only.
The properties "build.name" and "build.number" are likely the best way for what you are trying to do.

How to setup different firebase environments in Flutter

I am trying to figure out how to set up different firebase environments in a flutter project.
I understand how to do this in firebase, I created two projects, one for production, one for the test. Then, in an iOS or Android project, I could use various methods to switch between these two environments using separate google-services.json or GoogleServices-Info.plist files.
In Flutter I found this description of how to separate environments, but it only explains how to differentiate between environments in the flutter code.
How can I get this environment to change what iOS and Android build at compile time? It would even be sufficient simply to allow a file copy hook at build time.
You can switch accounts using FirebaseApp.configure. You can offer your own solution or secret dev panel to switch between them.
The solutions will build flavours and plist implementations will lock you into builds when you deploy for TestFlight + they are messy.
Here's an example: (You could use Assets as well.)
// Load a named file.
let filePath = Bundle.main.path(forResource: "MyGoogleService", ofType: "plist")
guard let fileopts = FirebaseOptions(contentsOfFile: filePath!)
else { assert(false, "Couldn't load config file") }
FirebaseApp.configure(options: fileopts)
I wrote an article about how to do this for Firebase configuration as well as runtime configuration in dart code using flavors and platform channels.
https://medium.com/#matt.goodson.business/separating-build-environment-configurations-in-flutter-with-firebase-doing-it-the-right-way-c72c3ad3621f
Flutter flavors work pretty seamlessly with Android flavors. For iOS you need to create Xcode schemes for each flavor and link them to build configurations.
For dart configuration, you can use platform channels to get the flavor used during the build at runtime. This lets you configure the app without having multiple main.dart files or passing a target argument.
Salvatore Giordano has written a blog post with a detailed description of how to achieve this:
https://medium.com/#salvatoregiordanoo/flavoring-flutter-392aaa875f36
Flutter accepts a parameter --flavor=<flavor> which allows you to select different build flavors. In Android this works as expected, selecting different build flavors. IOS is a little tricker because a scheme is needed for every flavor, and the build configurations in the form of Release-<flavor> are also needed.
Once these parts are in place, they can be used, to select the firebase configuration as you would in any iOS or Android project.
The challenge is getting Dart code to also be aware of the flavor, and the blog post provides no good solution for this. It suggests the standard method of using different entry points can be used, but the correct entry point must be matched to the correct flavor manually by the person invoking the app.
Specifically to Firebase env config you can use this article and this article from CodeMagic which explains how you can set up plist files with build env variables.
If you need to have a different set of values inside your Dart code, like an option you can use this package. It allows to generate Dart class config file from console command params.
Update 12/05/2020
Since Flutter 1.17 you can actually use compile-time variables with --dart-define argument in flutter run and flutter build commands
Here is an article that describes how to specify and use them.
With the release of Flutter for Web to the stable channel, I put together instructions for targeting multiple firebase projects (e.g. dev, staging, prod) from multiple build platforms (i.e. iOS, Android, and Web).

Enterprise Library not logging in setup project

I need your opinion on this: Is it possible to use enterprise library logging dll in the setup project?
Here's what I did:
I created a setup project which will call a windows form to install the database. When I installed the project, it did call the windows form. However, when I click on the "Install" button, it seems that there's a problem and I don't know where it is. Then another popup message is displayed which said that it cannot locate the logging configuration.
But the config file for the windows form is there which includes the configuration for the logging dll. I don't have any idea where to look into.
Please help me with this?
Below is the error message:
UPDATE
I observed that when I run the exe file as is, the enterprise library logging config works. But with the setup project, it does not look for it. Any help on this?
Below is the code for this:
[RunInstaller(true)]
public partial class IPWInstaller : Installer
{
public IPWInstaller()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string targetPath = Context.Parameters["TargetDir"];
InstallDatabase db = new InstallDatabase(targetPath);
DialogResult dbResult = db.ShowDialog();
if (dbResult != DialogResult.OK)
{
throw new InstallException("Database is not installed.");
}
ConfigureFiles config = new ConfigureFiles(targetPath);
DialogResult configResult = config.ShowDialog();
if (configResult != DialogResult.OK)
{
throw new InstallException("Config files are not saved correctly.");
}
}
}
LATEST UPDATE:
I tried to set the value of a certain configuration to my messagebox. This is the result of it when I run the install project.
Is there a way to call my app.config in the setup project
There are at least a couple of things that can go wrong.
The app is not running as it would if you ran it as an interactive user. It is being called from an msiexec.exe process that knows nothing about your intended environment, such as working directory. None of the automatic things that happen because you run from an explorer shell will happen. Any paths you use need to be full and explicit. I think you may need to explicitly load your settings file.
Something else that can happen in a per machine install is that custom actions run with the system account so any code which assumes you have access to databases, user profile items like folders can fail.
Another problem is that Windows Forms often don't work well when called from a VS custom action. It's not something that works very well because that environment is not the STA threading model that is required for window messages etc.
In general it's better to run these config programs after the install the first time the app starts because then you are in a normal environment, debugging and testing is straightforward, and if the db gets lost the user could run the program again to recreate it instead of uninstalling and reinstalling the setup.

Resources