Skip to content

Commit

Permalink
feat(crashlytics)!: upgrade to new Firebase Crashlytics SDK (#3580)
Browse files Browse the repository at this point in the history
Goodbye Fabric, hello Firebase Crashlytics.

BREAKING CHANGE: This is a breaking change to remove the use of the Fabric SDKs.

Co-authored-by: David Buchan-Swanson <[email protected]>
Co-authored-by: Mike Diarmid <[email protected]>
[publish]
  • Loading branch information
Aure77 authored Jun 30, 2020
1 parent c8f7c31 commit cad58e1
Show file tree
Hide file tree
Showing 18 changed files with 175 additions and 373 deletions.
40 changes: 26 additions & 14 deletions docs/crashlytics/android-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,23 @@ These steps are required, if you do not add these your app will most likely cras
"The Crashlytics build ID is missing. This occurs when Crashlytics tooling is absent from your app's build configuration.
Please review Crashlytics onboarding instructions and ensure you have a valid Crashlytics account."\_

## 1. Add the Fabric Maven repository
## 1. Add the Google repository (if it's not there already)

Add the following line to the `android/build.gradle` file:
Add the following line to the `android/build.gradle` file :

```groovy
// ..
buildscript {
// ..
repositories {
// ..
maven {
url 'https://maven.fabric.io/public'
}
google()
}
// ..
}
```

## 2. Add the Fabric Tools Plugin dependency
## 2. Add the Firebase Crashlytics Plugin dependency

Add the following dependency to the `android/build.gradle` file:

Expand All @@ -40,19 +38,20 @@ buildscript {
// ..
dependencies {
// ..
classpath 'io.fabric.tools:gradle:1.28.1'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0'
}
// ..
}
```

## 3. Apply the Fabric Tools Plugin to your app
## 3. Apply the Firebase Crashlytics Plugin to your app

Apply the `io.fabric` plugin by adding the following to the top of your `android/app/build.gradle` file:
Apply the `com.google.firebase.crashlytics` plugin by adding the following to the top of your `android/app/build.gradle` file:

```
apply plugin: 'com.android.application' // apply after this line
apply plugin: 'io.fabric'
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services' // apply after this line
apply plugin: 'com.google.firebase.crashlytics'
// ..
```

Expand All @@ -61,11 +60,24 @@ apply plugin: 'io.fabric'
Crashlytics NDK reporting allows you to capture Native Development Kit crashes, e.g. in React Native this will capture
crashes originating from the Yoga layout engine.

Add the `crashlytics` block line to the `android/app/build.gradle` file:
Add the `firebaseCrashlytics` block line to the `android/app/build.gradle` file:

```groovy
crashlytics {
enableNdk true
android {
// ...
buildTypes {
release {
/* Add the firebaseCrashlytics extension (by default,
* it's disabled to improve build speeds) and set
* nativeSymbolUploadEnabled to true. */
firebaseCrashlytics {
nativeSymbolUploadEnabled true
}
// ...
}
}
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/crashlytics/ios-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ add a 'New Run Script Phase':
In the new build phase, add a new script into the text box:

```
"${PODS_ROOT}/Fabric/run"
"${PODS_ROOT}/FirebaseCrashlytics/run"
```

![Script](https://prismic-io.s3.amazonaws.com/invertase%2Ff06cf5b3-884e-4cbc-8c3d-81072a254f1d_new+project+%281%29.png)
Expand Down
14 changes: 1 addition & 13 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,7 @@ project.ext {
// Overriding Library SDK Versions
firebase: [
// Override Firebase SDK Version
bom : "21.1.0",
// Override Crashlytics SDK Version
crashlytics : "2.10.0",
// Override Crashlytics SDK Version
crashlyticsNdk: "2.1.0"
bom : "21.1.0"
],
],
])
Expand All @@ -214,12 +208,6 @@ Open your projects `/ios/Podfile` and add any of the globals shown below to the
```ruby
# Override Firebase SDK Version
$FirebaseSDKVersion = '6.13.0'

# Override Fabric SDK Version
$FabricSDKVersion = '1.6.0'

# Override Crashlytics SDK Version
$CrashlyticsSDKVersion = '3.1.0'
```

Once changed, reinstall your projects pods via pod install and rebuild your project with `npx react-native run-ios`.
Expand Down
2 changes: 1 addition & 1 deletion packages/app/ios_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ if [[ ${_SEARCH_RESULT} ]]; then
if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == "true" ]]; then
echo "Disabled Crashlytics auto disabler." # do nothing
else
_PLIST_ENTRY_KEYS+=("firebase_crashlytics_collection_enabled")
_PLIST_ENTRY_KEYS+=("FirebaseCrashlyticsCollectionEnabled")
_PLIST_ENTRY_TYPES+=("bool")
_PLIST_ENTRY_VALUES+=("NO")
fi
Expand Down
20 changes: 2 additions & 18 deletions packages/crashlytics/RNFBCrashlytics.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ if coreVersionDetected != coreVersionRequired
Pod::UI.warn "NPM package '#{package['name']}' depends on '#{appPackage['name']}' v#{coreVersionRequired} but found v#{coreVersionDetected}, this might cause build issues or runtime crashes."
end

# Fabric SDK Override
fabric_sdk_version = '~> 1.10.2'

# Crashlytics SDK Override
crashlytics_sdk_version = '~> 3.14.0'

Pod::Spec.new do |s|
s.name = "RNFBCrashlytics"
s.version = package["version"]
Expand All @@ -44,19 +38,9 @@ Pod::Spec.new do |s|
firebase_sdk_version = $FirebaseSDKVersion
end

if defined?($CrashlyticsSDKVersion)
Pod::UI.puts "#{s.name}: Using user specified Crashlytics SDK version '#{$CrashlyticsSDKVersion}'"
crashlytics_sdk_version = $CrashlyticsSDKVersion
end

if defined?($FabricSDKVersion)
Pod::UI.puts "#{s.name}: Using user specified Fabric SDK version '#{$FabricSDKVersion}'"
fabric_sdk_version = $FabricSDKVersion
end

# Firebase dependencies
s.dependency 'Fabric', fabric_sdk_version
s.dependency 'Crashlytics', crashlytics_sdk_version
s.dependency 'Firebase/Core', firebase_sdk_version
s.dependency 'Firebase/Crashlytics', firebase_sdk_version

if defined?($RNFirebaseAsStaticFramework)
Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
Expand Down
10 changes: 4 additions & 6 deletions packages/crashlytics/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ project.ext {
],

firebase: [
crashlytics : "2.10.1",
crashlyticsNdk: "2.1.1" // not in BoM
bom: "25.3.0",
],
],
])
Expand All @@ -82,10 +81,9 @@ repositories {

dependencies {
api appProject
// don't use firebase bom here as crashlytics-ndk is not included in the bom, trying to partially use bom here fails
implementation "com.crashlytics.sdk.android:crashlytics:${ReactNative.ext.getVersion("firebase", "crashlytics")}"
// ndk not in Firebase BoM
implementation "com.crashlytics.sdk.android:crashlytics-ndk:${ReactNative.ext.getVersion("firebase", "crashlyticsNdk")}"
implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}")
implementation "com.google.firebase:firebase-crashlytics"
implementation "com.google.firebase:firebase-crashlytics-ndk"
}

ReactNative.shared.applyPackageVersion()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
*/

import android.util.Log;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.core.CrashlyticsCore;
import com.crashlytics.android.ndk.CrashlyticsNdk;
import io.fabric.sdk.android.Fabric;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import io.invertase.firebase.common.ReactNativeFirebaseInitProvider;
import io.invertase.firebase.common.ReactNativeFirebaseJSON;
import io.invertase.firebase.common.ReactNativeFirebaseMeta;
Expand Down Expand Up @@ -53,35 +50,12 @@ static boolean isCrashlyticsCollectionEnabled() {
public boolean onCreate() {
super.onCreate();

if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled() && getContext() != null) {
ReactNativeFirebaseJSON json = ReactNativeFirebaseJSON.getSharedInstance();
boolean useNdk = json.getBooleanValue(KEY_CRASHLYTICS_NDK_ENABLED, true);
boolean debug = json.getBooleanValue(KEY_CRASHLYTICS_DEBUG_ENABLED, false);

try {
Fabric.Builder builder = new Fabric.Builder(getContext());

Crashlytics crashlyticsCore = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(!debug && BuildConfig.DEBUG).build())
.build();

if (useNdk) {
builder.kits(crashlyticsCore, new CrashlyticsNdk());
} else {
builder.kits(crashlyticsCore);
}

builder.debuggable(debug);

Fabric.with(builder.build());

Log.i(TAG, "initialization successful");
} catch (IllegalStateException exception) {
Log.e(TAG, "initialization failed", exception);
return false;
}
} else {
Log.i(TAG, "auto collection disabled, skipping initialization");
try {
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled());
Log.i(TAG, "initialization successful");
} catch (Exception exception) {
Log.e(TAG, "initialization failed", exception);
return false;
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
* limitations under the License.
*
*/

import android.os.Handler;

import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.core.CrashTest;
import com.crashlytics.android.core.CrashlyticsCore;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.facebook.react.bridge.*;
import io.invertase.firebase.common.ReactNativeFirebaseModule;
import io.invertase.firebase.common.ReactNativeFirebasePreferences;
Expand All @@ -38,32 +38,36 @@ public class ReactNativeFirebaseCrashlyticsModule extends ReactNativeFirebaseMod
@ReactMethod
public void crash() {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.log("Crash Test");
// async task so as not to get caught by the React Native redbox handler in debug
(new CrashTest()).crashAsyncTask(50);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
throw new RuntimeException("Crash Test");
}
}, 50);
}
}

@ReactMethod
public void log(String message) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.log(message);
FirebaseCrashlytics.getInstance().log(message);
}
}

// For internal use only.
@ReactMethod
public void logPromise(String message, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.log(message);
FirebaseCrashlytics.getInstance().log(message);
}
promise.resolve(null);
}

@ReactMethod
public void setAttribute(String key, String value, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.setString(key, value);
FirebaseCrashlytics.getInstance().setCustomKey(key, value);
}
promise.resolve(null);
}
Expand All @@ -72,12 +76,12 @@ public void setAttribute(String key, String value, Promise promise) {
public void setAttributes(ReadableMap keyValuesMap, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
ReadableMapKeySetIterator iterator = keyValuesMap.keySetIterator();
CrashlyticsCore crashlyticsCore = Crashlytics.getInstance().core;
FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();

while (iterator.hasNextKey()) {
String key = iterator.nextKey();
String value = keyValuesMap.getString(key);
crashlyticsCore.setString(key, value);
crashlytics.setCustomKey(key, value);
}
}

Expand All @@ -88,23 +92,7 @@ public void setAttributes(ReadableMap keyValuesMap, Promise promise) {
@ReactMethod
public void setUserId(String userId, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.setUserIdentifier(userId);
}
promise.resolve(null);
}

@ReactMethod
public void setUserName(String userName, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.setUserName(userName);
}
promise.resolve(null);
}

@ReactMethod
public void setUserEmail(String userEmail, Promise promise) {
if (ReactNativeFirebaseCrashlyticsInitProvider.isCrashlyticsCollectionEnabled()) {
Crashlytics.getInstance().core.setUserEmail(userEmail);
FirebaseCrashlytics.getInstance().setUserId(userId);
}
promise.resolve(null);
}
Expand Down Expand Up @@ -155,7 +143,7 @@ private void recordJavaScriptError(ReadableMap jsErrorMap) {

customException.setStackTrace(stackTraceElements);

Crashlytics.getInstance().core.logException(customException);
FirebaseCrashlytics.getInstance().recordException(customException);
}

@Override
Expand Down
30 changes: 0 additions & 30 deletions packages/crashlytics/e2e/crashlytics.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,6 @@ describe('crashlytics()', () => {
});
});

describe('setUserName()', () => {
it('accepts string values', async () => {
await firebase.crashlytics().setUserName('invertase');
});

it('rejects none string values', async () => {
try {
await firebase.crashlytics().setUserName(666.1337);
return Promise.reject(new Error('Did not throw.'));
} catch (e) {
e.message.should.containEql('must be a string');
}
});
});

describe('setUserEmail()', () => {
it('accepts string values', async () => {
await firebase.crashlytics().setUserEmail('[email protected]');
});

it('rejects none string values', async () => {
try {
await firebase.crashlytics().setUserEmail(666.1337);
return Promise.reject(new Error('Did not throw.'));
} catch (e) {
e.message.should.containEql('must be a string');
}
});
});

describe('setAttribute()', () => {
it('accepts string values', async () => {
await firebase.crashlytics().setAttribute('invertase', '1337');
Expand Down
Loading

0 comments on commit cad58e1

Please sign in to comment.