Lazy initialization of Fabric kits? - android

Is it possible to lazily initialize Fabric Kits? for example, right now I do:
Fabric.with(this, crashlytics, twitterCore, tweetUi); // 500ms
I would like to initialize only Crashlytics (no twitter stuff), like below, because it is 10x faster, and I don't need the Twitter stuff right away
Fabric.with(this, crashlytics); // 50ms
Later on, when the user visits an activity where I need TwitterCore & TweetUi, I'd like to add them to Fabric on the fly before using them.
Is this possible ?
Edit: I managed to do it with reflection, which is obviously not ideal, but it works for the time being. I'm still looking for a proper solution to this. Here's how I did it:
try {
final Fabric newFabric = (new Fabric.Builder(context)).kits(crashlytics, twitterCore, tweetUi).build();
final Method method = Fabric.class.getDeclaredMethod("setFabric", Fabric.class);
method.setAccessible(true);
method.invoke(null, newFabric);
} catch (Exception e) {
Timber.e(e, e.getMessage());
}

You can use builder pattern for the initialisation and can disable the crash reporting in debug mode:
CrashlyticsCore core =
new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build();
Fabric.with(this, new Crashlytics.Builder().core(core).build(), new Crashlytics());
Update 1: Add more Kit afterwards or Lazy initialization of Fabric kits?:
CrashlyticsCore core =
new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build();
//Store the below fabric as an instance member
Fabric fabric = Fabric.with(this, new Crashlytics.Builder().core(core).build(), new Crashlytics
());
//To add later:
fabric.getKits().add(YOUR_NEW_KIT);

Mike from Fabric here. Currently, we only respect the first initialization of Fabric. One option would to be initialize everything up front or if you're ok for missing some crashes, not initialize Twitter and Crashlytics until later in your app's code.

Related

Should we first call MobileAds.setRequestConfiguration or MobileAds.initialize?

There isn't much documentation on this. I was wondering, should we first call
RequestConfiguration conf= new RequestConfiguration.Builder()
.setMaxAdContentRating(
MAX_AD_CONTENT_RATING_T)
.build();
MobileAds.setRequestConfiguration(conf);
MobileAds.initialize(context, APP_ID);
Or
MobileAds.initialize(context, APP_ID);
RequestConfiguration conf= new RequestConfiguration.Builder()
.setMaxAdContentRating(
MAX_AD_CONTENT_RATING_T)
.build();
MobileAds.setRequestConfiguration(conf);
In https://developers.google.com/admob/android/quick-start
Although Google recommend calling MobileAds.initialize as early as possible
Before loading ads, have your app initialize the Mobile Ads SDK by
calling MobileAds.initialize() which initializes the SDK and calls
back a completion listener once initialization is complete (or after a
30-second timeout). This needs to be done only once, ideally at app
launch.
They also mention "request-specific flags" need to be set before MobileAds.initialize.
Warning: Ads may be preloaded by the Mobile Ads SDK or mediation
partner SDKs upon calling MobileAds.initialize(). If you need to
obtain consent from users in the European Economic Area (EEA), set any
request-specific flags (such as tagForChildDirectedTreatment or
tag_for_under_age_of_consent), or otherwise take action before loading
ads, ensure you do so before initializing the Mobile Ads SDK.
So, not super clear on which should be called first.
According to Google Developer support, the following is the right way to do
https://groups.google.com/forum/#!category-topic/google-admob-ads-sdk/android/17oVu0sABjs
RequestConfiguration conf= new RequestConfiguration.Builder()
.setMaxAdContentRating(
MAX_AD_CONTENT_RATING_T)
.build();
MobileAds.setRequestConfiguration(conf);
MobileAds.initialize(context, APP_ID);
It's done as such:
MobileAds.RequestConfiguration =
new RequestConfiguration
.Builder()
.SetTagForChildDirectedTreatment(RequestConfiguration.TagForChildDirectedTreatmentTrue)
.SetMaxAdContentRating(RequestConfiguration.MaxAdContentRatingG)
#if DEBUG
.SetTestDeviceIds(new[] { "..." })
#endif
.Build();
according to the official documentation
Before loading ads, have your app initialize the Mobile Ads SDK by calling MobileAds.initialize() which initializes the SDK and calls back a completion listener once initialization is complete (or after a 30-second timeout). This needs to be done only once, ideally at app launch.
So , you should initialize MobileAds first ,look at the example here form the official documentation :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
mAdView = findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
mAdView.loadAd(adRequest);
}

Disable/Enable Firebase Crashlytics during runtime

With Google sending out waves of warnings about the need to let users opt-in to crash reporting (source) I'm trying to build an opt-in dialog for Firebase Crashlytics.
To be able to do this I would need to know whether Crashlytics is currently enabled (to decide whether to show the dialog or not). It seems CrashlyticsCore.disabled is responsible for tracking this but I haven't found any way to access the value because it's package private and doesn't have an accessor. How can I know during runtime if Firebase Crashlytics is enabled?
The second thing I'd need to do is disable crash reporting by default and enable it when the user agrees to opt-in. How I suspected to be able to do this:
AndroidManifest:
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
Activity:
boolean userAgrees = true;
CrashlyticsCore core = new CrashlyticsCore.Builder().disabled(!userAgrees).build();
Fabric.with(this, new Crashlytics.Builder().core(core).build());
throw new RuntimeException("why doesn't this show up in Firebase Crashlytics?");
Why isn't my RuntimeException showing up in Firebase Crashlytics?
P.S. Crashlytics is working fine when removing these attempts to create an opt-in dialog.
It seems toggling Crashlytics will only take effect after your app restarts. Fabric is a singleton and all calls to its Fabric.with method will simply be ignored after it's been initialized. Source code below.
public static Fabric with(Context context, Kit... kits) {
if (singleton == null) {
Class var2 = Fabric.class;
synchronized(Fabric.class) {
if (singleton == null) {
setFabric((new Fabric.Builder(context)).kits(kits).build());
}
}
}
return singleton;
}
One way around it is to keep track of the value yourself using SharedPreferences or other persistent storage methods and update your UI accordingly.

Initialise Crashlytics error reporting by itself without Answers etc

I want to initialise CrashlyticsCore, which just has error reporting, not Crashlytics, which has automatic built in usage reporting.
I have found this answer:
How do i initialize the new version of crashlytics?
Which says to do this:
Fabric.with(this, new CrashlyticsCore.getInstance());
I am not sure whether the "new" keyword is meant to be there. However, with or without "new", it gives the following error:
java.lang.IllegalStateException: Must Initialize Fabric before using singleton()
Does anyone know how to just initialise CrashlyticsCore without Crashlytics?
You can try the answer in this thread
Fabric.with(this, new Crashlytics.Builder().core(new CrashlyticsCore.Builder().build()).build());
Or you can create a method that only enables sending Answer events based on a boolean flag:
public static void logCustom(boolean isEnabled, String eventText) {
if (isEnabled) {
Answers.getInstance().logCustom(new CustomEvent(eventText));
}
}

Android Realm issue with setDefaultConfiguration

I've got a problem with realm and his method setDefaultConfiguration.
Indeed, my app is multi user, and I need to switch between several realm configurations.
During the main activity loading, I configure the realm configuration like this:
String bddName = String.format("%s.realm",userID);
userFolder = new File(getApplicationContext().getFilesDir() + "/" + userID);
config = new RealmConfiguration.Builder(userFolder)
.name(bddName)
.schemaVersion(2)
.migration(new RealmMigration2())
.build();
Realm.setDefaultConfiguration(config);
But, If I try to configure it twice with the same config, Realm send me an error:
Configurations cannot be different if used to open the same file.
Is it possible to test whether the current configuration is different from the one I want to set?
I've tried :
if(!config.equals(Realm.getDefaultInstance().getConfiguration()))
But at the first launch of the Activity, Realm return an error, because no default instance is set.
I'm turning around because it's impossible to test the realm configuration before setting it.
Could you help me ?
Thank you a lot.
Edit :
this solution doesn't work too, i've got the same error, however, the RealmFileName are different:
try{
//first time, Realm is not configure, so It's catched.
//else, it set the default config only if the config is different
if(!config.getRealmFileName().equals(Realm.getDefaultInstance().getConfiguration().getRealmFileName())){
Realm.setDefaultConfiguration(config);
}
}
catch (Exception e){
Realm.setDefaultConfiguration(config);
}
The problem is that you are creating two instances of the RealmMigration2 class. If you don't override equals in your class:
RealmMigration migration1 = new RealmMigration2();
RealmMigration migration2 = new RealmMigration2();
migration1.equals(migration2) == false
Which will cause the comparison of RealmConfigurations to fail.
So you should either make your RealmMigration instance a singleton or override hashCode()/equals().

How to Disable Crashlytics/Fabric at Runtime when User Changes Preferences

I am using com.crashlytics.sdk.android:crashlytics:2.3.2#aar version of crashlytics and i disable crash reporting if user opt out.
I tried this solution but still it is not working, crash reports are still being sent to Fabric.
I am doing it as:
Preference errorReportingEnabled = findPreference(MatlistanPrefs.BUGREPORTS_SEND_AUTOMATICALLY);
errorReportingEnabled.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Boolean value = (Boolean) newValue;
Fabric.with(DataCollectionSettingsActivity.this, new Crashlytics.Builder().
core(new CrashlyticsCore.Builder().disabled(!value).build())
.build());
return true;
}
});
Is there any working solution for this problem?
Thanks.
Fabric on initialization creates a singleton instance and returns same instance whenever you call Fabric.with(...). So, your code inside onPreferenceChangehas no effect on Fabric class.
The only solution to this problem can be if library itself provide methods for enabling or disabling crashlytics. So, up-till now (crashlytics:2.5.2) there is no solution to enable/disable crashlytics at run-time. You have to do it at startup like this:
Fabric.with(this, new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder()
.disabled(true).build()).build());

Categories

Resources