Adding Firebase Crashlytics to an Android app

I have not been able to get Firebase Crashlytics fully integrated into my Android app.

On 2503 I added the google-services.json file to the Properties folder in my new test project and added a gradle reference for com.google.firebase:firebase-analytics:17.0.3. The json file is picked up by EBuild. The google services task executes and the intermediate google-services/values/google-services-values.json file is generated with the correct info. But the functionality is missing from the built app.

I did the same process in Android Studio and compared the apks of the two projects, and it seems that EBuild is not merging the final manifest correctly. The manifest in my Android Studio created app is 126 lines long, compared to 36 lines for my EBuild created app, and it is due to a lot of missing google services stuff. For example,

    <receiver
        android:name="com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver"
        android:permission="android.permission.INSTALL_PACKAGES"
        android:enabled="true"
        android:exported="true">

        <intent-filter>

            <action
                android:name="com.android.vending.INSTALL_REFERRER" />
        </intent-filter>
    </receiver>

    <service
        android:name="com.google.android.gms.measurement.AppMeasurementService"
        android:enabled="true"
        android:exported="false" />

    <service
        android:name="com.google.android.gms.measurement.AppMeasurementJobService"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:enabled="true"
        android:exported="false" />

    <service
        android:name="com.google.firebase.components.ComponentDiscoveryService"
        android:exported="false"
        android:directBootAware="true">

        <meta-data
            android:name="com.google.firebase.components:com.google.firebase.analytics.connector.internal.AnalyticsConnectorRegistrar"
            android:value="com.google.firebase.components.ComponentRegistrar" />

        <meta-data
            android:name="com.google.firebase.components:com.google.firebase.iid.Registrar"
            android:value="com.google.firebase.components.ComponentRegistrar" />
    </service>

    <receiver
        android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
        android:permission="com.google.android.c2dm.permission.SEND"
        android:exported="true">

        <intent-filter>

            <action
                android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </receiver>

    <provider
        android:name="com.google.firebase.provider.FirebaseInitProvider"
        android:exported="false"
        android:authorities="com.mattrobertson.fireycrashtest.firebaseinitprovider"
        android:initOrder="100" />

There are a lot of google services generated properties files that are packaged correctly into the final apk, but it seems there should be some stuff merged into the manifest as well that is missing.

When we spec’ed this task together, e made it create a new folder of resources that get merged into the resources of the app. I dont’ recall us discussion that there’s an XML that needs to be merged with the manifest, so no surprise that’s not happening.

is this the generated google-services-values.xml, and soul that me merged with the manifest instead of being deployed as resource?

do you have quick tetscase project you can send me to run and fix this?

thanx,
marc

No, the google-services-values.xml is only used when generating the R.java file, so it is correct as is.

Right, I didn’t know that anything needed to be merged into the manifest. My fault there. But I don’t think it is the google-services.json stuff that needs to be merged but rather something from the gradle reference com.google.firebase:firebase-analytics:17.0.3 .

Strangely, a few weeks ago I analyzed my EBuild-generated apk and it was identical to the ADS generated apk.

com.mattrobertson.WateryCrashTest.zip (2.8 MB)

Hmm. I’ll have a look.

That package is rather sparse, thought. its AndroidManifest.xml contains nothing, and aside from that it has just the jar and an R.txt.

So no idea where all that other stuff should come form. Maybe you’re supposed to add it to the main manifest, manually?

Hmm possibly from firebase-core, though I didn’t add that manually in ADS, and I tried that in EBuild without any luck.

No it definitely is automatically added as part of the build. I followed the exact steps in ADS and the values ended up in the manifest.

I repeated this step by step in ADS with a new project.

  1. Initial build => nothing in manifest
  2. Added google-services.json and Google Services gradle plugin => nothing in manifest
  3. Added 'com.google.firebase:firebase-analytics:17.3.0' gradle reference => everything in manifest

So it’s definitely this package that triggers the manifest merge. I’ll keep looking to see where the actual data is coming from.

@mh found it.

The pom file in com.google.firebase:firebase-analytics:17.3.0 has this dependency:

<dependency>
  <groupId>com.google.android.gms</groupId>
  <artifactId>play-services-measurement</artifactId>
  <version>17.3.0</version>
  <scope>compile</scope>
  <type>aar</type>
</dependency>

The manifest for this package (com.google.android.gms:play-services-measurement:17.3.0) contains these values, which are all added to the final manifest in ADS but not in EBuild.

<uses-sdk android:minSdkVersion="14" />

<!-- Required permission for App measurement to run. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" />

<application>
    <receiver
        android:name="com.google.android.gms.measurement.AppMeasurementReceiver"
        android:enabled="true"
        android:exported="false" >
    </receiver>
    <receiver
        android:name="com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver"
        android:enabled="true"
        android:exported="true"
        android:permission="android.permission.INSTALL_PACKAGES" >
        <intent-filter>
            <action android:name="com.android.vending.INSTALL_REFERRER" />
        </intent-filter>
    </receiver>

    <service
        android:name="com.google.android.gms.measurement.AppMeasurementService"
        android:enabled="true"
        android:exported="false" />
    <service
        android:name="com.google.android.gms.measurement.AppMeasurementJobService"
        android:enabled="true"
        android:exported="false"
        android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
1 Like

Excellent. So if I’ll just merge all manifest xm ls files I find, it should work. will hook that up later today.

1 Like

There seems to be some competition with multiple packages adding items of the same name:

                     Added new Android permission 'android.permission.INTERNET' from reference 'play-services-measurement-17.3.0'.
                     Added new Android permission 'android.permission.ACCESS_NETWORK_STATE' from reference 'play-services-measurement-17.3.0'.
                     Added new Android permission 'android.permission.WAKE_LOCK' from reference 'play-services-measurement-17.3.0'.
                     Added new Android permission 'com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE' from reference 'play-services-measurement-17.3.0'.
                     Added new Android receiver 'com.google.android.gms.measurement.AppMeasurementReceiver' from reference 'play-services-measurement-17.3.0'.
                     Added new Android receiver 'com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver' from reference 'play-services-measurement-17.3.0'.
                     Added new Android service 'com.google.android.gms.measurement.AppMeasurementService' from reference 'play-services-measurement-17.3.0'.
                     Added new Android service 'com.google.android.gms.measurement.AppMeasurementJobService' from reference 'play-services-measurement-17.3.0'.
                     Added new Android meta-data 'com.google.android.gms.version' from reference 'play-services-basement-17.2.1'.
E:                   Cannot add new Android receiver 'com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver' from reference 'play-services-measurement-impl-17.3.0', because it already exists.
                     Added new Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'play-services-measurement-api-17.3.0'.
                     Added new Android provider 'com.google.firebase.provider.FirebaseInitProvider' from reference 'firebase-common-19.3.0'.
E:                   Cannot add new Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-common-19.3.0', because it already exists.
                     Added new Android permission 'com.google.android.c2dm.permission.RECEIVE' from reference 'firebase-iid-20.1.5'.
E:                   Cannot add new Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-iid-20.1.5', because it already exists.
                     Added new Android receiver 'com.google.firebase.iid.FirebaseInstanceIdReceiver' from reference 'firebase-iid-20.1.5'.
                     Added new Android activity 'com.google.android.gms.common.api.GoogleApiActivity' from reference 'play-services-base-17.2.1'.
E:                   Cannot add new Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-installations-16.2.1', because it already exists.
E:                   Cannot add new Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-installations-16.2.1', because it already exists.

not sure what’s the best approach here — add the first, and ignore the subsequent ones? add both? (I’m assuming names need to be unique, no?)

Implemented using the former (ignore subsequent dupes), for 20200422-193249-elements-develop and later. I’ll upload a new builds for you once I have on in ~1h our so; testing and feedback appreciated.

1 Like

Up.

1 Like

I’m not seeing any change in the final manifest. I tried a clean build, and tried removing and re-adding the gradle reference. Also tried adding the sub-references as full project references, but still nothing.

Here’s my “verbosity:Diagnostic” build log if it helps.
build_log.txt (239.9 KB)

Hmm, not in

.../RemObjects Software/EBuild/Obj/com.mattrobertson.WateryCrashTest-348420ADFB47D7518D7A89EA7ED986258A2A241C/Debug/Cooper-Android/AndroidManifest.xml

either? here’s what mine looks like:

AndroidManifest.xml (3.0 KB)

Ah damn. what happened I sent you an too-early build because we had an (unrelated) regression yesterday that caused the build meant for you to fail, and I didn’t notice :(.

My apologies. Will get you a new one today.

1 Like

Up, 2504B

1 Like

Success! and one more minor(?) feature request.

The build actually failed initially on a really subtle error. EBuild failed to pick up the error, but I noticed an odd message from aapt when I ran ebuild from the command line complaining about a $ character in the manifest.

After some investigation I found that that some android libraries (including all of the firebase libraries) use a placeholder ${applicationId} which gradle replaces with the package name at build time. Gradle allows configuring arbitrary variables that can be injected into the manifest but it looks like only ${applicationId} is assumed by default. So replacing the string literal ‘${applicationId}’ with the app’s package name, e.g., ‘com.company.appname’, would solve this issue.

I say “initially” because I did find that I can manually add the manifest item to my app manifest and the build works, since the element is ignored on subsequent discoveries. The problematic item was:

<provider
    android:name="com.google.firebase.provider.FirebaseInitProvider"
    android:authorities="${applicationId}.firebaseinitprovider"
    android:exported="false"
    android:initOrder="100"
    />

I got around this by adding this to my app manifest:

<provider
    android:name="com.google.firebase.provider.FirebaseInitProvider"
    android:authorities="com.mattrobertson.crashtest.firebaseinitprovider"
    android:exported="false"
    android:initOrder="100"
    />

But it’s very unintuitive to know to do so, since the build fails without any error indication.

1 Like

Done.

Added “invalid” to the range of trigger words, so this now gives a proper error:

E:                   aapt: Tag <provider> attribute authorities has invalid character '$'. [/Users/mh/Library/Application Support/RemObjects Software/EBuild/Obj/com.mattrobertson.WateryCrashTest-348420ADFB47D7518D7A89EA7ED986258A2A241C/Debug/Cooper-Android/AndroidManifest.xml (54)]
1 Like

I’ve been running into an issue adding Firebase and finally traced the cause back to this. When I run my project that includes Firebase, the following runtime error shows up in Logcat:

Failed to retrieve Firebase Instance ID

I used Android Studio’s APK Analyzer tool to compare the final merged manifests of my EBuild app and an equivalent app built in Android Studio (the ADS app is working as expected). The manifests are almost identical, with a couple key exceptions on ComponentDiscoveryService.

EBuild Manifest:

<service
    android:name="com.google.firebase.components.ComponentDiscoveryService"
    android:exported="false">

        <meta-data
            android:name="com.google.firebase.components:com.google.firebase.analytics.connector.internal.AnalyticsConnectorRegistrar"
            android:value="com.google.firebase.components.ComponentRegistrar" />
</service>

ADS Manifest:

<service
	android:name="com.google.firebase.components.ComponentDiscoveryService"
	android:exported="false"
	android:directBootAware="true">

	<meta-data
		android:name="com.google.firebase.components:com.google.firebase.analytics.connector.internal.AnalyticsConnectorRegistrar"
		android:value="com.google.firebase.components.ComponentRegistrar" />

	<meta-data
		android:name="com.google.firebase.components:com.google.firebase.iid.Registrar"
		android:value="com.google.firebase.components.ComponentRegistrar" />
</service>

The ADS manifest adds the directBootAware attribute. This comes from the firebase-common package. My EBuild log shows this message:

W: Skipped adding Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-common-19.3.0', because it already exists.

I can’t locate the GitHub directory where the firebase.iid.Registrar meta-data is coming from, but I’m sure this is what’s causing the “Failed to retrieve ID” error. My EBuild log also shows:

W: Skipped adding Android service 'com.google.firebase.components.ComponentDiscoveryService' from reference 'firebase-iid-20.1.5', because it already exists.

It looks like duplicates need to be merged, not skipped.