11

When installing "Crashlytics" in my Android App, it automatically installs "Answers". I only want to install "Crashlytics" and want to have "Answers" disabled. Does anyone know how to do that?

enter image description here

build.gradle

dependencies {
compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
    transitive = true;
}

Thanks!

Jim Clermonts
  • 1,694
  • 8
  • 39
  • 94

2 Answers2

8

Mike from Fabric and Crashlytics here.

As you saw, Crashlytics by default includes Answers. If you don't want Answers enabled on your app, then you want to invoke CrashlyticsCore() when building your app instead of Crashlytics.

For example, have these as your imports:

import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.core.CrashlyticsCore;
import io.fabric.sdk.android.Fabric;

Then when you initialize Fabric, use:

Fabric.with(this, new CrashlyticsCore());

and that will initialize only the crash reporting side of things.

Mike Bonnell
  • 16,181
  • 3
  • 61
  • 77
  • 4
    This doesn't seem to work, perhaps because Crashlytics.Builder.build() creates an Answers object internally, even if one wasn't passed to the builder. Crashlytics SDK 2.6.4. – Xargs Oct 03 '16 at 21:53
  • 11
    Answers is still enabled when using the snippet above. I essentially used the same code above and sessions were still shown in the Fabrio.io web interface. Then I looked at the code for Crashlytics.Builder.build() and it is obvious that the snippet would leave Answers still enabled. – Xargs Oct 04 '16 at 19:30
  • Yes, I tried that solution and was wondering about the web interface showing non-crash data anyways. Then I checked logcat, and it says `D/Answers: Analytics collection enabled`. You're right @Xargs, this answer does not work in the current sdk (Crashlytics 2.8.0). – Micha Dec 13 '17 at 16:11
  • You just should not build Crashlytics at all. And use CrashlyticsCore.getInstance() to access all crash reporting methods. – Aleksei Potapkin Oct 25 '18 at 15:31
1

I think it is not possible at the moment, because Crashlytics is making an Answers instance:

public Crashlytics build() {
            if(this.coreBuilder != null) {
                if(this.core != null) {
                    throw new IllegalStateException("Must not use Deprecated methods delay(), disabled(), listener(), pinningInfoProvider() with core()");
                }

                this.core = this.coreBuilder.build();
            }

            if(this.answers == null) {
                this.answers = new Answers();
            }

            if(this.beta == null) {
                this.beta = new Beta();
            }

            if(this.core == null) {
                this.core = new CrashlyticsCore();
            }

            return new Crashlytics(this.answers, this.beta, this.core);
        }

Crashlytics(Answers answers, Beta beta, CrashlyticsCore core) is not public, so we cannot instanciate this. Also the answers field is final, so you cannot override it. I think there is now way to let the user decide if they want to use answers.

Hey Fabric/Google, you should make a programmatically way to opt out for a session, to give the programmer the option to let the user decide if they want to be counted in some way.

EDIT

My solution is to to use a wraper for all needed funtioncs and init, feel free to use it:

public class AnalyticsWrapper {

    static AnalyticsWrapper instance;

    public static void initialize(Context context, boolean optOut) {
        if (instance != null) throw new IllegalStateException("AnalyticsWrapper must only be initialized once");
        instance = new AnalyticsWrapper(context.getApplicationContext(), optOut);
    }

    public static AnalyticsWrapper getInstance() {
        if (instance == null) throw new IllegalStateException("AnalyticsWrapper must be initialized before");
        return instance;
    }

    final boolean optOut;

    private AnalyticsWrapper(Context context, boolean optOut) {
        this.optOut = optOut;
        initFabric(context);
    }

    public boolean isOptOut() {
        return optOut;
    }

    private void initFabric(Context context) {
        if (!optOut) {

            if (!BuildConfig.DEBUG) {
                Timber.plant(new CrashlyticsLogExceptionTree());
                Timber.plant(new CrashlyticsLogTree(Log.INFO));
            }

            Crashlytics crashlyticsKit = new Crashlytics.Builder().core(
                    new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG)
                                                 .build())
                                                                  .build();

            Fabric fabric = new Fabric.Builder(context).kits(crashlyticsKit)
                                                             .debuggable(BuildConfig.DEBUG)
                                                             .build();


            Fabric.with(fabric);
        }
    }

    public void crashlyticsSetString(String key, String value) {
        if (!optOut) {
            Crashlytics.setString(key, value);
        }
    }

    public void logException(Throwable throwable) {
        if (!optOut) {
            Crashlytics.logException(throwable);
        }
    }

    public void logEvent(CustomEvent event) {
        if (!optOut) {
            Answers.getInstance()
                   .logCustom(event);
        }
    }
}
Mate
  • 418
  • 3
  • 13
  • Hmm, I tested my previous solution and it worked correctly. What precisely didn't work in your testing? If you want the end user to decide if they want they to opt-in to Answers or not, I'd recommend wrapping the Fabric init in an if block checking a boolean flag based on a user setting within your app. – Mike Bonnell Jan 27 '17 at 14:18
  • Excactly what Im doing. Edited my answer, this is a clean approach to handle optOut scenario. Sadly fabric just not has a "optOut" or dryRun function. – Mate Jan 27 '17 at 14:46
  • Yep, that's correct we don't have an optOut function currently, but I'll let the team know you'd like to see it added as an option. We've heard from other folks that the wrapping logic has been the most helpful for them as then they can implement it exactly as they want, but good to know you'd like an option in the SDK. – Mike Bonnell Jan 27 '17 at 15:34
  • Unfortunately, this does not solve the problem that one might want to allow crash reporting, but not analytics tracking when the user opted out. – Micha Dec 13 '17 at 16:12
  • @MikeBonnell the only way I currently see is to extend Answers and Beta and to override all methods with NOOP. I can put these empty classes into the Crashlytics Builder – DSchmidt Jun 09 '18 at 18:45