Merge remote-tracking branch 'origin/master'

# Conflicts:
#	android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrash.java
#	android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrashPackage.java
#	lib/index.d.ts
This commit is contained in:
Salakar 2018-08-04 22:47:04 +01:00
commit 52c63b5e18
56 changed files with 2912 additions and 1080 deletions

View File

@ -1,30 +1,30 @@
package io.invertase.firebase;
import android.util.Log;
import android.app.Activity;
import android.content.IntentSender;
import android.util.Log;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
// react
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
// play services
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// react
// play services
@SuppressWarnings("WeakerAccess")
public class RNFirebaseModule extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebase";
@ -103,7 +103,9 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule {
if (status != ConnectionResult.SUCCESS && gapi.isUserResolvableError(status)) {
Activity activity = getCurrentActivity();
if (activity != null) {
gapi.getErrorDialog(activity, status, status).show();
gapi
.getErrorDialog(activity, status, status)
.show();
}
}
}
@ -113,7 +115,9 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void resolutionForPlayServices() {
int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getReactApplicationContext());
int status = GoogleApiAvailability
.getInstance()
.isGooglePlayServicesAvailable(getReactApplicationContext());
ConnectionResult connectionResult = new ConnectionResult(status);
if (!connectionResult.isSuccess() && connectionResult.hasResolution()) {

View File

@ -8,9 +8,9 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("unused")
public class RNFirebasePackage implements ReactPackage {

View File

@ -1,9 +1,7 @@
package io.invertase.firebase;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
@ -48,7 +46,9 @@ public class Utils {
if (value == null) {
map.putNull(key);
} else {
String type = value.getClass().getName();
String type = value
.getClass()
.getName();
switch (type) {
case "java.lang.Boolean":
map.putBoolean(key, (Boolean) value);
@ -159,7 +159,9 @@ public class Utils {
}
public static int getResId(Context ctx, String resName) {
int resourceId = ctx.getResources().getIdentifier(resName, "string", ctx.getPackageName());
int resourceId = ctx
.getResources()
.getIdentifier(resName, "string", ctx.getPackageName());
if (resourceId == 0) {
Log.e(TAG, "resource " + resName + " could not be found");
}

View File

@ -18,6 +18,13 @@ import java.util.Map;
public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseAdMob";
private HashMap<String, RNFirebaseAdmobInterstitial> interstitials = new HashMap<>();
private HashMap<String, RNFirebaseAdMobRewardedVideo> rewardedVideos = new HashMap<>();
public RNFirebaseAdMob(ReactApplicationContext reactContext) {
super(reactContext);
Log.d(TAG, "New instance");
}
ReactApplicationContext getContext() {
return getReactApplicationContext();
@ -27,14 +34,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
return getCurrentActivity();
}
private HashMap<String, RNFirebaseAdmobInterstitial> interstitials = new HashMap<>();
private HashMap<String, RNFirebaseAdMobRewardedVideo> rewardedVideos = new HashMap<>();
public RNFirebaseAdMob(ReactApplicationContext reactContext) {
super(reactContext);
Log.d(TAG, "New instance");
}
@Override
public String getName() {
return TAG;
@ -53,7 +52,9 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
@ReactMethod
public void interstitialLoadAd(String adUnit, ReadableMap request) {
RNFirebaseAdmobInterstitial interstitial = getOrCreateInterstitial(adUnit);
interstitial.loadAd(RNFirebaseAdMobUtils.buildRequest(request).build());
interstitial.loadAd(RNFirebaseAdMobUtils
.buildRequest(request)
.build());
}
@ReactMethod
@ -65,7 +66,9 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
@ReactMethod
public void rewardedVideoLoadAd(String adUnit, ReadableMap request) {
RNFirebaseAdMobRewardedVideo rewardedVideo = getOrCreateRewardedVideo(adUnit);
rewardedVideo.loadAd(RNFirebaseAdMobUtils.buildRequest(request).build());
rewardedVideo.loadAd(RNFirebaseAdMobUtils
.buildRequest(request)
.build());
}
@ReactMethod
@ -75,7 +78,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
}
/**
*
* @param adUnit
* @return
*/
@ -89,7 +91,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
}
/**
*
* @param adUnit
* @return
*/

View File

@ -23,38 +23,15 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager<ReactViewGroup> {
public static final String REACT_CLASS = "RNFirebaseAdMobBanner";
public static final String BANNER_EVENT = "onBannerEvent";
public enum Events {
EVENT_AD_SIZE_CHANGE("onSizeChange"),
EVENT_AD_LOADED("onAdLoaded"),
EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"),
EVENT_AD_OPENED("onAdOpened"),
EVENT_AD_CLOSED("onAdClosed"),
EVENT_AD_LEFT_APPLICATION("onAdLeftApplication");
private final String event;
Events(final String name) {
event = name;
}
@Override
public String toString() {
return event;
}
}
private ThemedReactContext context;
private ReactViewGroup viewGroup;
private RCTEventEmitter emitter;
private Boolean requested = false;
// Internal prop values
private AdRequest.Builder request;
private AdSize size;
private String unitId;
@Override
public String getName() {
return REACT_CLASS;
@ -197,15 +174,22 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager<ReactViewGroup> {
int left = adView.getLeft();
int top = adView.getTop();
int width = adView.getAdSize().getWidthInPixels(context);
int height = adView.getAdSize().getHeightInPixels(context);
int width = adView
.getAdSize()
.getWidthInPixels(context);
int height = adView
.getAdSize()
.getHeightInPixels(context);
adView.measure(width, height);
adView.layout(left, top, left + width, top + height);
WritableMap payload = Arguments.createMap();
payload.putBoolean(RNFirebaseAdMobNativeExpress.Events.EVENT_AD_VIDEO_CONTENT.toString(), false);
payload.putBoolean(
RNFirebaseAdMobNativeExpress.Events.EVENT_AD_VIDEO_CONTENT.toString(),
false
);
payload.putInt("width", width);
payload.putInt("height", height);
@ -251,4 +235,24 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager<ReactViewGroup> {
emitter.receiveEvent(viewGroup.getId(), BANNER_EVENT, event);
}
public enum Events {
EVENT_AD_SIZE_CHANGE("onSizeChange"),
EVENT_AD_LOADED("onAdLoaded"),
EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"),
EVENT_AD_OPENED("onAdOpened"),
EVENT_AD_CLOSED("onAdClosed"),
EVENT_AD_LEFT_APPLICATION("onAdLeftApplication");
private final String event;
Events(final String name) {
event = name;
}
@Override
public String toString() {
return event;
}
}
}

View File

@ -25,38 +25,10 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
public static final String REACT_CLASS = "RNFirebaseAdMobNativeExpress";
public static final String BANNER_EVENT = "onBannerEvent";
public enum Events {
EVENT_AD_SIZE_CHANGE("onSizeChange"),
EVENT_AD_LOADED("onAdLoaded"),
EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"),
EVENT_AD_OPENED("onAdOpened"),
EVENT_AD_CLOSED("onAdClosed"),
EVENT_AD_LEFT_APPLICATION("onAdLeftApplication"),
EVENT_AD_VIDEO_END("onVideoEnd"),
EVENT_AD_VIDEO_MUTE("onVideoMute"),
EVENT_AD_VIDEO_PAUSE("onVideoPause"),
EVENT_AD_VIDEO_PLAY("onVideoPlay"),
EVENT_AD_VIDEO_START("onVideoStart"),
EVENT_AD_VIDEO_CONTENT("hasVideoContent");
private final String event;
Events(final String name) {
event = name;
}
@Override
public String toString() {
return event;
}
}
private ThemedReactContext context;
private ReactViewGroup viewGroup;
private RCTEventEmitter emitter;
private Boolean requested = false;
// Internal prop values
private AdRequest.Builder request;
private VideoOptions.Builder videoOptions;
@ -70,6 +42,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Create & return view instance
*
* @param themedReactContext
* @return
*/
@ -105,6 +78,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Declare custom events
*
* @return
*/
@Override
@ -116,6 +90,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Handle unitId prop
*
* @param view
* @param value
*/
@ -127,6 +102,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Handle request prop
*
* @param view
* @param map
*/
@ -138,6 +114,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Handle video prop
*
* @param view
* @param map
*/
@ -149,6 +126,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Handle size prop
*
* @param view
* @param value
*/
@ -210,8 +188,12 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
int left = adView.getLeft();
int top = adView.getTop();
int width = adView.getAdSize().getWidthInPixels(context);
int height = adView.getAdSize().getHeightInPixels(context);
int width = adView
.getAdSize()
.getWidthInPixels(context);
int height = adView
.getAdSize()
.getHeightInPixels(context);
adView.measure(width, height);
adView.layout(left, top, left + width, top + height);
@ -230,17 +212,21 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
public void onVideoEnd() {
sendEvent(Events.EVENT_AD_VIDEO_END.toString(), null);
}
public void onVideoMute(boolean isMuted) {
WritableMap videoMutePayload = Arguments.createMap();
videoMutePayload.putBoolean("isMuted", isMuted);
sendEvent(Events.EVENT_AD_VIDEO_MUTE.toString(), videoMutePayload);
}
public void onVideoPause() {
sendEvent(Events.EVENT_AD_VIDEO_PAUSE.toString(), null);
}
public void onVideoPlay() {
sendEvent(Events.EVENT_AD_VIDEO_PLAY.toString(), null);
}
public void onVideoStart() {
sendEvent(Events.EVENT_AD_VIDEO_START.toString(), null);
}
@ -273,6 +259,7 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
/**
* Sends an event back to the JS component to handle
*
* @param type
* @param payload
*/
@ -287,4 +274,30 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGro
int id = viewGroup.getId();
emitter.receiveEvent(viewGroup.getId(), BANNER_EVENT, event);
}
public enum Events {
EVENT_AD_SIZE_CHANGE("onSizeChange"),
EVENT_AD_LOADED("onAdLoaded"),
EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"),
EVENT_AD_OPENED("onAdOpened"),
EVENT_AD_CLOSED("onAdClosed"),
EVENT_AD_LEFT_APPLICATION("onAdLeftApplication"),
EVENT_AD_VIDEO_END("onVideoEnd"),
EVENT_AD_VIDEO_MUTE("onVideoMute"),
EVENT_AD_VIDEO_PAUSE("onVideoPause"),
EVENT_AD_VIDEO_PLAY("onVideoPlay"),
EVENT_AD_VIDEO_START("onVideoStart"),
EVENT_AD_VIDEO_CONTENT("hasVideoContent");
private final String event;
Events(final String name) {
event = name;
}
@Override
public String toString() {
return event;
}
}
}

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.admob;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;
@ -9,7 +8,6 @@ import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("unused")

View File

@ -18,6 +18,7 @@ class RNFirebaseAdMobUtils {
/**
* Convert common AdMob errors into a standard format
*
* @param errorCode
* @return
*/
@ -27,11 +28,17 @@ class RNFirebaseAdMobUtils {
switch (errorCode) {
case AdRequest.ERROR_CODE_INTERNAL_ERROR:
map.putString("code", "admob/error-code-internal-error");
map.putString("message", "Something happened internally; for instance, an invalid response was received from the ad server.");
map.putString(
"message",
"Something happened internally; for instance, an invalid response was received from the ad server."
);
break;
case AdRequest.ERROR_CODE_INVALID_REQUEST:
map.putString("code", "admob/error-code-invalid-request");
map.putString("message", "The ad request was invalid; for instance, the ad unit ID was incorrect.");
map.putString(
"message",
"The ad request was invalid; for instance, the ad unit ID was incorrect."
);
break;
case AdRequest.ERROR_CODE_NETWORK_ERROR:
map.putString("code", "admob/error-code-network-error");
@ -39,7 +46,10 @@ class RNFirebaseAdMobUtils {
break;
case AdRequest.ERROR_CODE_NO_FILL:
map.putString("code", "admob/error-code-no-fill");
map.putString("message", "The ad request was successful, but no ad was returned due to lack of ad inventory.");
map.putString(
"message",
"The ad request was successful, but no ad was returned due to lack of ad inventory."
);
break;
}
@ -114,6 +124,7 @@ class RNFirebaseAdMobUtils {
/**
* Map the size prop to the AdSize
*
* @param value
* @return
*/

View File

@ -3,10 +3,8 @@ package io.invertase.firebase.admob;
import android.app.Activity;
import android.support.annotation.Nullable;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
@ -60,6 +58,7 @@ class RNFirebaseAdmobInterstitial {
/**
* Load an Ad with a AdRequest instance
*
* @param adRequest
*/
void loadAd(final AdRequest adRequest) {
@ -93,6 +92,7 @@ class RNFirebaseAdmobInterstitial {
/**
* Send a native event over the bridge with a type and optional payload
*
* @param type
* @param payload
*/

View File

@ -1,15 +1,15 @@
package io.invertase.firebase.analytics;
import android.util.Log;
import android.app.Activity;
import android.support.annotation.Nullable;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
@ -31,7 +31,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
@ReactMethod
public void logEvent(final String name, @Nullable final ReadableMap params) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).logEvent(name, Arguments.toBundle(params));
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.logEvent(name, Arguments.toBundle(params));
}
/**
@ -39,7 +41,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void setAnalyticsCollectionEnabled(final Boolean enabled) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setAnalyticsCollectionEnabled(enabled);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setAnalyticsCollectionEnabled(enabled);
}
/**
@ -55,7 +59,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setCurrentScreen(activity, screenName, screenClassOverride);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setCurrentScreen(activity, screenName, screenClassOverride);
}
});
}
@ -66,7 +72,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void setMinimumSessionDuration(final double milliseconds) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setMinimumSessionDuration((long) milliseconds);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setMinimumSessionDuration((long) milliseconds);
}
/**
@ -74,7 +82,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void setSessionTimeoutDuration(final double milliseconds) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setSessionTimeoutDuration((long) milliseconds);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setSessionTimeoutDuration((long) milliseconds);
}
/**
@ -82,7 +92,9 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void setUserId(final String id) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setUserId(id);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setUserId(id);
}
/**
@ -91,6 +103,8 @@ public class RNFirebaseAnalytics extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void setUserProperty(final String name, final String value) {
FirebaseAnalytics.getInstance(getReactApplicationContext()).setUserProperty(name, value);
FirebaseAnalytics
.getInstance(getReactApplicationContext())
.setUserProperty(name, value);
}
}

View File

@ -3,7 +3,6 @@ package io.invertase.firebase.analytics;
import android.support.annotation.RequiresPermission;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.auth;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -3,26 +3,25 @@ package io.invertase.firebase.config;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.gms.tasks.Task;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableArray;
import com.google.android.gms.tasks.OnCompleteListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.google.firebase.FirebaseApp;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.List;
import io.invertase.firebase.Utils;
@ -49,11 +48,14 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
return TAG;
}
@ReactMethod public void enableDeveloperMode() {
@ReactMethod
public void enableDeveloperMode() {
FirebaseRemoteConfigSettings.Builder settings = new FirebaseRemoteConfigSettings.Builder();
settings.setDeveloperModeEnabled(true);
FirebaseRemoteConfig.getInstance().setConfigSettings(settings.build());
FirebaseRemoteConfig
.getInstance()
.setConfigSettings(settings.build());
}
@ReactMethod
@ -68,13 +70,19 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
@ReactMethod
public void activateFetched(final Promise promise) {
Boolean status = FirebaseRemoteConfig.getInstance().activateFetched();
Boolean status = FirebaseRemoteConfig
.getInstance()
.activateFetched();
promise.resolve(status);
}
@ReactMethod
public void getValue(String key, final Promise promise) {
FirebaseRemoteConfigValue value = FirebaseRemoteConfig.getInstance().getValue(key);
FirebaseRemoteConfigValue value = FirebaseRemoteConfig
.getInstance()
.getValue(key);
promise.resolve(convertRemoteConfigValue(value));
}
@ -84,7 +92,10 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
List<Object> keysList = Utils.recursivelyDeconstructReadableArray(keys);
for (Object key : keysList) {
FirebaseRemoteConfigValue value = FirebaseRemoteConfig.getInstance().getValue((String) key);
FirebaseRemoteConfigValue value = FirebaseRemoteConfig
.getInstance()
.getValue((String) key);
array.pushMap(convertRemoteConfigValue(value));
}
@ -93,7 +104,10 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
@ReactMethod
public void getKeysByPrefix(String prefix, final Promise promise) {
Set<String> keys = FirebaseRemoteConfig.getInstance().getKeysByPrefix(prefix);
Set<String> keys = FirebaseRemoteConfig
.getInstance()
.getKeysByPrefix(prefix);
WritableArray array = Arguments.createArray();
for (String key : keys) {
@ -106,16 +120,26 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
@ReactMethod
public void setDefaults(ReadableMap map) {
Map<String, Object> convertedMap = Utils.recursivelyDeconstructReadableMap(map);
FirebaseRemoteConfig.getInstance().setDefaults(convertedMap);
FirebaseRemoteConfig
.getInstance()
.setDefaults(convertedMap);
}
@ReactMethod
public void setDefaultsFromResource(int resourceId) {
FirebaseRemoteConfig.getInstance().setDefaults(resourceId);
FirebaseRemoteConfig
.getInstance()
.setDefaults(resourceId);
}
private void fetchInternal(final Promise promise, Boolean withExpiration, long expirationDuration) {
FirebaseRemoteConfig.getInstance().fetch(withExpiration ? expirationDuration : 43200) // 12 hours default
private void fetchInternal(
final Promise promise,
Boolean withExpiration,
long expirationDuration
) {
FirebaseRemoteConfig
.getInstance()
.fetch(withExpiration ? expirationDuration : 43200) // 12 hours default
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
@ -123,9 +147,17 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule {
promise.resolve(null);
} else {
if (task.getException() instanceof FirebaseRemoteConfigFetchThrottledException) {
promise.reject("config/throttled", "fetch() operation cannot be completed successfully, due to throttling.", task.getException());
promise.reject(
"config/throttled",
"fetch() operation cannot be completed successfully, due to throttling.",
task.getException()
);
} else {
promise.reject("config/failure", "fetch() operation cannot be completed successfully.", task.getException());
promise.reject(
"config/failure",
"fetch() operation cannot be completed successfully.",
task.getException()
);
}
}
}

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.config;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -4,26 +4,25 @@ import android.os.AsyncTask;
import android.util.Log;
import android.util.SparseArray;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.google.firebase.FirebaseApp;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Logger;
import com.google.firebase.database.MutableData;
import com.google.firebase.database.OnDisconnect;
import com.google.firebase.database.ServerValue;
import com.google.firebase.database.Transaction;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.DatabaseReference;
import java.util.HashMap;
import java.util.List;
@ -32,12 +31,11 @@ import java.util.Map;
import io.invertase.firebase.ErrorUtils;
import io.invertase.firebase.Utils;
public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseDatabase";
private static boolean enableLogging = false;
private HashMap<String, RNFirebaseDatabaseReference> references = new HashMap<>();
private static HashMap<String, Boolean> loggingLevelSet = new HashMap<>();
private HashMap<String, RNFirebaseDatabaseReference> references = new HashMap<>();
private SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();
RNFirebaseDatabase(ReactApplicationContext reactContext) {
@ -49,6 +47,210 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* REACT NATIVE METHODS
*/
/**
* Resolve null or reject with a js like error if databaseError exists
*
* @param promise
* @param databaseError
*/
static void handlePromise(Promise promise, DatabaseError databaseError) {
if (databaseError != null) {
WritableMap jsError = getJSError(databaseError);
promise.reject(
jsError.getString("code"),
jsError.getString("message"),
databaseError.toException()
);
} else {
promise.resolve(null);
}
}
/**
* Get a database instance for a specific firebase app instance
*
* @param appName
* @param dbURL
* @return
*/
public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) {
FirebaseDatabase firebaseDatabase;
if (dbURL != null && dbURL.length() > 0) {
if (appName != null && appName.length() > 0) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp, dbURL);
} else {
firebaseDatabase = FirebaseDatabase.getInstance(dbURL);
}
} else {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp);
}
Boolean logLevel = loggingLevelSet.get(firebaseDatabase
.getApp()
.getName());
if (enableLogging && (logLevel == null || !logLevel)) {
try {
loggingLevelSet.put(firebaseDatabase
.getApp()
.getName(), enableLogging);
firebaseDatabase.setLogLevel(Logger.Level.DEBUG);
} catch (DatabaseException dex) {
// do nothing - to catch 'calls to setLogLevel must be made for use of database' errors
// only occurs in dev after reloading or if user has actually incorrectly called it.
Log.w(
TAG,
"WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + firebaseDatabase
.getApp()
.getName()
);
}
} else if (!enableLogging && (logLevel != null && logLevel)) {
try {
loggingLevelSet.put(firebaseDatabase
.getApp()
.getName(), enableLogging);
firebaseDatabase.setLogLevel(Logger.Level.WARN);
} catch (DatabaseException dex) {
// do nothing - to catch 'calls to setLogLevel must be made for use of database' errors
// only occurs in dev after reloading or if user has actually incorrectly called it.
Log.w(
TAG,
"WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + firebaseDatabase
.getApp()
.getName()
);
}
}
return firebaseDatabase;
}
/**
* Convert as firebase DatabaseError instance into a writable map
* with the correct web-like error codes.
*
* @param nativeError
* @return
*/
static WritableMap getJSError(DatabaseError nativeError) {
WritableMap errorMap = Arguments.createMap();
errorMap.putInt("nativeErrorCode", nativeError.getCode());
errorMap.putString("nativeErrorMessage", nativeError.getMessage());
String code;
String message;
String service = "Database";
switch (nativeError.getCode()) {
case DatabaseError.DATA_STALE:
code = ErrorUtils.getCodeWithService(service, "data-stale");
message = ErrorUtils.getMessageWithService(
"The transaction needs to be run again with current data.",
service,
code
);
break;
case DatabaseError.OPERATION_FAILED:
code = ErrorUtils.getCodeWithService(service, "failure");
message = ErrorUtils.getMessageWithService(
"The server indicated that this operation failed.",
service,
code
);
break;
case DatabaseError.PERMISSION_DENIED:
code = ErrorUtils.getCodeWithService(service, "permission-denied");
message = ErrorUtils.getMessageWithService(
"Client doesn't have permission to access the desired data.",
service,
code
);
break;
case DatabaseError.DISCONNECTED:
code = ErrorUtils.getCodeWithService(service, "disconnected");
message = ErrorUtils.getMessageWithService(
"The operation had to be aborted due to a network disconnect.",
service,
code
);
break;
case DatabaseError.EXPIRED_TOKEN:
code = ErrorUtils.getCodeWithService(service, "expired-token");
message = ErrorUtils.getMessageWithService(
"The supplied auth token has expired.",
service,
code
);
break;
case DatabaseError.INVALID_TOKEN:
code = ErrorUtils.getCodeWithService(service, "invalid-token");
message = ErrorUtils.getMessageWithService(
"The supplied auth token was invalid.",
service,
code
);
break;
case DatabaseError.MAX_RETRIES:
code = ErrorUtils.getCodeWithService(service, "max-retries");
message = ErrorUtils.getMessageWithService(
"The transaction had too many retries.",
service,
code
);
break;
case DatabaseError.OVERRIDDEN_BY_SET:
code = ErrorUtils.getCodeWithService(service, "overridden-by-set");
message = ErrorUtils.getMessageWithService(
"The transaction was overridden by a subsequent set.",
service,
code
);
break;
case DatabaseError.UNAVAILABLE:
code = ErrorUtils.getCodeWithService(service, "unavailable");
message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code);
break;
case DatabaseError.USER_CODE_EXCEPTION:
code = ErrorUtils.getCodeWithService(service, "user-code-exception");
message = ErrorUtils.getMessageWithService(
"User code called from the Firebase Database runloop threw an exception.",
service,
code
);
break;
case DatabaseError.NETWORK_ERROR:
code = ErrorUtils.getCodeWithService(service, "network-error");
message = ErrorUtils.getMessageWithService(
"The operation could not be performed due to a network error.",
service,
code
);
break;
case DatabaseError.WRITE_CANCELED:
code = ErrorUtils.getCodeWithService(service, "write-cancelled");
message = ErrorUtils.getMessageWithService(
"The write was canceled by the user.",
service,
code
);
break;
default:
code = ErrorUtils.getCodeWithService(service, "unknown");
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
}
errorMap.putString("code", code);
errorMap.putString("message", message);
return errorMap;
}
/**
* @param appName
*/
@ -74,6 +276,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
getDatabaseForApp(appName, dbURL).setPersistenceEnabled(state);
}
/*
* TRANSACTIONS
*/
/**
* @param appName
* @param size
@ -83,7 +290,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
getDatabaseForApp(appName, dbURL).setPersistenceCacheSizeBytes((long) size);
}
/**
* @param enabled
*/
@ -95,42 +301,62 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
loggingLevelSet.put(app.getName(), enabled);
try {
if (enableLogging) {
FirebaseDatabase.getInstance(app).setLogLevel(Logger.Level.DEBUG);
FirebaseDatabase
.getInstance(app)
.setLogLevel(Logger.Level.DEBUG);
} else {
FirebaseDatabase.getInstance(app).setLogLevel(Logger.Level.WARN);
FirebaseDatabase
.getInstance(app)
.setLogLevel(Logger.Level.WARN);
}
} catch (DatabaseException dex) {
// do nothing - to catch 'calls to setLogLevel must be made for use of database' errors
// only occurs in dev after reloading or if user has actually incorrectly called it.
Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + app.getName());
Log.w(
TAG,
"WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + app.getName()
);
}
}
}
/*
* ON DISCONNECT
*/
/**
* @param appName
* @param path
* @param state
*/
@ReactMethod
public void keepSynced(String appName, String dbURL, String key, String path, ReadableArray modifiers, Boolean state) {
getInternalReferenceForApp(appName, dbURL, key, path, modifiers).getQuery().keepSynced(state);
public void keepSynced(
String appName,
String dbURL,
String key,
String path,
ReadableArray modifiers,
Boolean state
) {
getInternalReferenceForApp(appName, dbURL, key, path, modifiers)
.getQuery()
.keepSynced(state);
}
/*
* TRANSACTIONS
*/
/**
* @param transactionId
* @param updates
*/
@ReactMethod
public void transactionTryCommit(String appName, String dbURL, int transactionId, ReadableMap updates) {
public void transactionTryCommit(
String appName,
String dbURL,
int transactionId,
ReadableMap updates
) {
RNFirebaseTransactionHandler handler = transactionHandlers.get(transactionId);
if (handler != null) {
@ -147,7 +373,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param applyLocally
*/
@ReactMethod
public void transactionStart(final String appName, final String dbURL, final String path, final int transactionId, final Boolean applyLocally) {
public void transactionStart(
final String appName,
final String dbURL,
final String path,
final int transactionId,
final Boolean applyLocally
) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
@ -156,7 +388,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
reference.runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler(transactionId, appName, dbURL);
final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler(
transactionId,
appName,
dbURL
);
transactionHandlers.put(transactionId, transactionHandler);
final WritableMap updatesMap = transactionHandler.createUpdateMap(mutableData);
@ -165,7 +401,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
Utils.sendEvent(getReactApplicationContext(), "database_transaction_event", updatesMap);
Utils.sendEvent(
getReactApplicationContext(),
"database_transaction_event",
updatesMap
);
}
});
@ -198,11 +438,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
});
}
/*
* ON DISCONNECT
*/
/**
* Set a value on a ref when the client disconnects from the firebase server.
*
@ -212,7 +447,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void onDisconnectSet(String appName, String dbURL, String path, ReadableMap props, final Promise promise) {
public void onDisconnectSet(
String appName,
String dbURL,
String path,
ReadableMap props,
final Promise promise
) {
String type = props.getString("type");
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
@ -257,7 +498,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void onDisconnectUpdate(String appName, String dbURL, String path, ReadableMap props, final Promise promise) {
public void onDisconnectUpdate(
String appName,
String dbURL,
String path,
ReadableMap props,
final Promise promise
) {
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
OnDisconnect ondDisconnect = ref.onDisconnect();
@ -318,9 +565,17 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void set(String appName, String dbURL, String path, ReadableMap props, final Promise promise) {
public void set(
String appName,
String dbURL,
String path,
ReadableMap props,
final Promise promise
) {
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
Object value = Utils.recursivelyDeconstructReadableMap(props).get("value");
Object value = Utils
.recursivelyDeconstructReadableMap(props)
.get("value");
DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() {
@Override
@ -339,9 +594,17 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void setPriority(String appName, String dbURL, String path, ReadableMap priority, final Promise promise) {
public void setPriority(
String appName,
String dbURL,
String path,
ReadableMap priority,
final Promise promise
) {
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value");
Object priorityValue = Utils
.recursivelyDeconstructReadableMap(priority)
.get("value");
DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() {
@Override
@ -361,10 +624,21 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void setWithPriority(String appName, String dbURL, String path, ReadableMap data, ReadableMap priority, final Promise promise) {
public void setWithPriority(
String appName,
String dbURL,
String path,
ReadableMap data,
ReadableMap priority,
final Promise promise
) {
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
Object dataValue = Utils.recursivelyDeconstructReadableMap(data).get("value");
Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value");
Object dataValue = Utils
.recursivelyDeconstructReadableMap(data)
.get("value");
Object priorityValue = Utils
.recursivelyDeconstructReadableMap(priority)
.get("value");
DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() {
@Override
@ -383,7 +657,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void update(String appName, String dbURL, String path, ReadableMap props, final Promise promise) {
public void update(
String appName,
String dbURL,
String path,
ReadableMap props,
final Promise promise
) {
DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path);
Map<String, Object> updates = Utils.recursivelyDeconstructReadableMap(props);
@ -416,6 +696,9 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
ref.removeValue(listener);
}
/*
* INTERNALS/UTILS
*/
/**
* Subscribe once to a firebase reference.
@ -428,7 +711,15 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void once(String appName, String dbURL, String key, String path, ReadableArray modifiers, String eventType, Promise promise) {
public void once(
String appName,
String dbURL,
String key,
String path,
ReadableArray modifiers,
String eventType,
Promise promise
) {
getInternalReferenceForApp(appName, dbURL, key, path, modifiers).once(eventType, promise);
}
@ -466,80 +757,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
}
}
/*
* INTERNALS/UTILS
*/
/**
* Resolve null or reject with a js like error if databaseError exists
*
* @param promise
* @param databaseError
*/
static void handlePromise(Promise promise, DatabaseError databaseError) {
if (databaseError != null) {
WritableMap jsError = getJSError(databaseError);
promise.reject(
jsError.getString("code"),
jsError.getString("message"),
databaseError.toException()
);
} else {
promise.resolve(null);
}
}
/**
* Get a database instance for a specific firebase app instance
*
* @param appName
* @param dbURL
* @return
*/
public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) {
FirebaseDatabase firebaseDatabase;
if(dbURL != null && dbURL.length() > 0) {
if (appName != null && appName.length() > 0) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp, dbURL);
} else {
firebaseDatabase = FirebaseDatabase.getInstance(dbURL);
}
} else {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp);
}
Boolean logLevel = loggingLevelSet.get(firebaseDatabase.getApp().getName());
if (enableLogging && (logLevel == null || !logLevel)) {
try {
loggingLevelSet.put(firebaseDatabase.getApp().getName(), enableLogging);
firebaseDatabase.setLogLevel(Logger.Level.DEBUG);
} catch (DatabaseException dex) {
// do nothing - to catch 'calls to setLogLevel must be made for use of database' errors
// only occurs in dev after reloading or if user has actually incorrectly called it.
Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + firebaseDatabase.getApp().getName());
}
} else if (!enableLogging && (logLevel != null && logLevel)) {
try {
loggingLevelSet.put(firebaseDatabase.getApp().getName(), enableLogging);
firebaseDatabase.setLogLevel(Logger.Level.WARN);
} catch (DatabaseException dex) {
// do nothing - to catch 'calls to setLogLevel must be made for use of database' errors
// only occurs in dev after reloading or if user has actually incorrectly called it.
Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" +
"If you are sure you've done this then this message can be ignored during development as \n" +
"RN reloads can cause false positives. APP: " + firebaseDatabase.getApp().getName());
}
}
return firebaseDatabase;
}
/**
* Get a database reference for a specific app and path
*
@ -560,7 +777,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param modifiers
* @return
*/
private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String dbURL, String key, String path, ReadableArray modifiers) {
private RNFirebaseDatabaseReference getInternalReferenceForApp(
String appName,
String dbURL,
String key,
String path,
ReadableArray modifiers
) {
return new RNFirebaseDatabaseReference(
getReactApplicationContext(),
appName,
@ -578,7 +801,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
* @param props
* @return
*/
private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(String appName, String dbURL, ReadableMap props) {
private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(
String appName,
String dbURL,
ReadableMap props
) {
String key = props.getString("key");
String path = props.getString("path");
ReadableArray modifiers = props.getArray("modifiers");
@ -593,81 +820,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
return existingRef;
}
/**
* Convert as firebase DatabaseError instance into a writable map
* with the correct web-like error codes.
*
* @param nativeError
* @return
*/
static WritableMap getJSError(DatabaseError nativeError) {
WritableMap errorMap = Arguments.createMap();
errorMap.putInt("nativeErrorCode", nativeError.getCode());
errorMap.putString("nativeErrorMessage", nativeError.getMessage());
String code;
String message;
String service = "Database";
switch (nativeError.getCode()) {
case DatabaseError.DATA_STALE:
code = ErrorUtils.getCodeWithService(service, "data-stale");
message = ErrorUtils.getMessageWithService("The transaction needs to be run again with current data.", service, code);
break;
case DatabaseError.OPERATION_FAILED:
code = ErrorUtils.getCodeWithService(service, "failure");
message = ErrorUtils.getMessageWithService("The server indicated that this operation failed.", service, code);
break;
case DatabaseError.PERMISSION_DENIED:
code = ErrorUtils.getCodeWithService(service, "permission-denied");
message = ErrorUtils.getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
break;
case DatabaseError.DISCONNECTED:
code = ErrorUtils.getCodeWithService(service, "disconnected");
message = ErrorUtils.getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
break;
case DatabaseError.EXPIRED_TOKEN:
code = ErrorUtils.getCodeWithService(service, "expired-token");
message = ErrorUtils.getMessageWithService("The supplied auth token has expired.", service, code);
break;
case DatabaseError.INVALID_TOKEN:
code = ErrorUtils.getCodeWithService(service, "invalid-token");
message = ErrorUtils.getMessageWithService("The supplied auth token was invalid.", service, code);
break;
case DatabaseError.MAX_RETRIES:
code = ErrorUtils.getCodeWithService(service, "max-retries");
message = ErrorUtils.getMessageWithService("The transaction had too many retries.", service, code);
break;
case DatabaseError.OVERRIDDEN_BY_SET:
code = ErrorUtils.getCodeWithService(service, "overridden-by-set");
message = ErrorUtils.getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
break;
case DatabaseError.UNAVAILABLE:
code = ErrorUtils.getCodeWithService(service, "unavailable");
message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code);
break;
case DatabaseError.USER_CODE_EXCEPTION:
code = ErrorUtils.getCodeWithService(service, "user-code-exception");
message = ErrorUtils.getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
break;
case DatabaseError.NETWORK_ERROR:
code = ErrorUtils.getCodeWithService(service, "network-error");
message = ErrorUtils.getMessageWithService("The operation could not be performed due to a network error.", service, code);
break;
case DatabaseError.WRITE_CANCELED:
code = ErrorUtils.getCodeWithService(service, "write-cancelled");
message = ErrorUtils.getMessageWithService("The write was canceled by the user.", service, code);
break;
default:
code = ErrorUtils.getCodeWithService(service, "unknown");
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
}
errorMap.putString("code", code);
errorMap.putString("message", message);
return errorMap;
}
/**
* React Method - returns this module name
*

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.database;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -1,82 +1,41 @@
package io.invertase.firebase.database;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.lang.ref.WeakReference;
import android.util.Log;
import android.os.AsyncTask;
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.google.firebase.database.Query;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.invertase.firebase.Utils;
class RNFirebaseDatabaseReference {
private static final String TAG = "RNFirebaseDBReference";
private String key;
private Query query;
private String appName;
private String dbURL;
private ReactContext reactContext;
private static final String TAG = "RNFirebaseDBReference";
private HashMap<String, ChildEventListener> childEventListeners = new HashMap<>();
private HashMap<String, ValueEventListener> valueEventListeners = new HashMap<>();
/**
* AsyncTask to convert DataSnapshot instances to WritableMap instances.
*
* Introduced due to https://github.com/invertase/react-native-firebase/issues/1284
*/
private static class DataSnapshotToMapAsyncTask extends AsyncTask<Object, Void, WritableMap> {
private WeakReference<ReactContext> reactContextWeakReference;
private WeakReference<RNFirebaseDatabaseReference> referenceWeakReference;
DataSnapshotToMapAsyncTask(ReactContext context, RNFirebaseDatabaseReference reference) {
referenceWeakReference = new WeakReference<>(reference);
reactContextWeakReference = new WeakReference<>(context);
}
@Override
protected final WritableMap doInBackground(Object... params) {
DataSnapshot dataSnapshot = (DataSnapshot) params[0];
@Nullable String previousChildName = (String) params[1];
try {
return RNFirebaseDatabaseUtils.snapshotToMap(dataSnapshot, previousChildName);
} catch (RuntimeException e) {
if (isAvailable()) {
reactContextWeakReference.get().handleException(e);
}
throw e;
}
}
@Override
protected void onPostExecute(WritableMap writableMap) {
// do nothing as overridden on usage
}
Boolean isAvailable() {
return reactContextWeakReference.get() != null && referenceWeakReference.get() != null;
}
}
/**
* RNFirebase wrapper around FirebaseDatabaseReference,
* handles Query generation and event listeners.
@ -87,7 +46,14 @@ class RNFirebaseDatabaseReference {
* @param refPath
* @param modifiersArray
*/
RNFirebaseDatabaseReference(ReactContext context, String app, String url, String refKey, String refPath, ReadableArray modifiersArray) {
RNFirebaseDatabaseReference(
ReactContext context,
String app,
String url,
String refKey,
String refPath,
ReadableArray modifiersArray
) {
key = refKey;
query = null;
appName = app;
@ -96,7 +62,6 @@ class RNFirebaseDatabaseReference {
buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray);
}
/**
* Used outside of class for keepSynced etc.
*
@ -113,7 +78,8 @@ class RNFirebaseDatabaseReference {
* @return
*/
private Boolean hasEventListener(String eventRegistrationKey) {
return valueEventListeners.containsKey(eventRegistrationKey) || childEventListeners.containsKey(eventRegistrationKey);
return valueEventListeners.containsKey(eventRegistrationKey) || childEventListeners.containsKey(
eventRegistrationKey);
}
/**
@ -155,7 +121,6 @@ class RNFirebaseDatabaseReference {
}
/**
* Add a ChildEventListener to the query and internally keep a reference to it.
*
@ -174,8 +139,10 @@ class RNFirebaseDatabaseReference {
* @param promise
*/
private void addOnceValueEventListener(final Promise promise) {
@SuppressLint("StaticFieldLeak")
final DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(reactContext, this) {
@SuppressLint("StaticFieldLeak") final DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(
reactContext,
this
) {
@Override
protected void onPostExecute(WritableMap writableMap) {
if (this.isAvailable()) promise.resolve(writableMap);
@ -252,7 +219,6 @@ class RNFirebaseDatabaseReference {
query.addChildEventListener(childEventListener);
}
/**
* Handles a React Native JS '.on(..)' request and initializes listeners.
*
@ -280,7 +246,6 @@ class RNFirebaseDatabaseReference {
}
}
/**
* Add a native .on('child_X',.. ) event listener.
*
@ -365,7 +330,12 @@ class RNFirebaseDatabaseReference {
* @param dataSnapshot
* @param previousChildName
*/
private void handleDatabaseEvent(final String eventType, final ReadableMap registration, DataSnapshot dataSnapshot, @Nullable String previousChildName) {
private void handleDatabaseEvent(
final String eventType,
final ReadableMap registration,
DataSnapshot dataSnapshot,
@Nullable String previousChildName
) {
@SuppressLint("StaticFieldLeak")
DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(reactContext, this) {
@Override
@ -424,11 +394,6 @@ class RNFirebaseDatabaseReference {
}
}
/* =================
* QUERY MODIFIERS
* =================
*/
/**
* @param name
* @param type
@ -451,6 +416,11 @@ class RNFirebaseDatabaseReference {
}
}
/* =================
* QUERY MODIFIERS
* =================
*/
/**
* @param name
* @param type
@ -481,12 +451,6 @@ class RNFirebaseDatabaseReference {
}
}
/* ===============
* QUERY FILTERS
* ===============
*/
/**
* @param key
* @param valueType
@ -517,6 +481,12 @@ class RNFirebaseDatabaseReference {
}
}
/* ===============
* QUERY FILTERS
* ===============
*/
/**
* @param key
* @param valueType
@ -576,4 +546,46 @@ class RNFirebaseDatabaseReference {
}
}
}
/**
* AsyncTask to convert DataSnapshot instances to WritableMap instances.
* <p>
* Introduced due to https://github.com/invertase/react-native-firebase/issues/1284
*/
private static class DataSnapshotToMapAsyncTask extends AsyncTask<Object, Void, WritableMap> {
private WeakReference<ReactContext> reactContextWeakReference;
private WeakReference<RNFirebaseDatabaseReference> referenceWeakReference;
DataSnapshotToMapAsyncTask(ReactContext context, RNFirebaseDatabaseReference reference) {
referenceWeakReference = new WeakReference<>(reference);
reactContextWeakReference = new WeakReference<>(context);
}
@Override
protected final WritableMap doInBackground(Object... params) {
DataSnapshot dataSnapshot = (DataSnapshot) params[0];
@Nullable String previousChildName = (String) params[1];
try {
return RNFirebaseDatabaseUtils.snapshotToMap(dataSnapshot, previousChildName);
} catch (RuntimeException e) {
if (isAvailable()) {
reactContextWeakReference
.get()
.handleException(e);
}
throw e;
}
}
@Override
protected void onPostExecute(WritableMap writableMap) {
// do nothing as overridden on usage
}
Boolean isAvailable() {
return reactContextWeakReference.get() != null && referenceWeakReference.get() != null;
}
}
}

View File

@ -20,7 +20,10 @@ public class RNFirebaseDatabaseUtils {
* @param previousChildName
* @return
*/
public static WritableMap snapshotToMap(DataSnapshot dataSnapshot, @Nullable String previousChildName) {
public static WritableMap snapshotToMap(
DataSnapshot dataSnapshot,
@Nullable String previousChildName
) {
WritableMap result = Arguments.createMap();
WritableMap snapshot = snapshotToMap(dataSnapshot);
@ -71,7 +74,10 @@ public class RNFirebaseDatabaseUtils {
}
} else {
if (snapshot.getValue() != null) {
String type = snapshot.getValue().getClass().getName();
String type = snapshot
.getValue()
.getClass()
.getName();
switch (type) {
case "java.lang.Boolean":
case "java.lang.Long":
@ -101,7 +107,10 @@ public class RNFirebaseDatabaseUtils {
}
} else {
if (mutableData.getValue() != null) {
String type = mutableData.getValue().getClass().getName();
String type = mutableData
.getValue()
.getClass()
.getName();
switch (type) {
case "java.lang.Boolean":
case "java.lang.Long":
@ -190,7 +199,9 @@ public class RNFirebaseDatabaseUtils {
expectedKey = key;
}
Any castedChild = castValue(child);
switch (castedChild.getClass().getName()) {
switch (castedChild
.getClass()
.getName()) {
case "java.lang.Boolean":
array.pushBoolean((Boolean) castedChild);
break;
@ -211,7 +222,12 @@ public class RNFirebaseDatabaseUtils {
array.pushArray((WritableArray) castedChild);
break;
default:
Log.w(TAG, "Invalid type: " + castedChild.getClass().getName());
Log.w(
TAG,
"Invalid type: " + castedChild
.getClass()
.getName()
);
break;
}
expectedKey++;
@ -236,7 +252,9 @@ public class RNFirebaseDatabaseUtils {
expectedKey = key;
}
Any castedChild = castValue(child);
switch (castedChild.getClass().getName()) {
switch (castedChild
.getClass()
.getName()) {
case "java.lang.Boolean":
array.pushBoolean((Boolean) castedChild);
break;
@ -257,7 +275,12 @@ public class RNFirebaseDatabaseUtils {
array.pushArray((WritableArray) castedChild);
break;
default:
Log.w(TAG, "Invalid type: " + castedChild.getClass().getName());
Log.w(
TAG,
"Invalid type: " + castedChild
.getClass()
.getName()
);
break;
}
expectedKey++;
@ -275,7 +298,9 @@ public class RNFirebaseDatabaseUtils {
for (DataSnapshot child : snapshot.getChildren()) {
Any castedChild = castValue(child);
switch (castedChild.getClass().getName()) {
switch (castedChild
.getClass()
.getName()) {
case "java.lang.Boolean":
map.putBoolean(child.getKey(), (Boolean) castedChild);
break;
@ -295,7 +320,12 @@ public class RNFirebaseDatabaseUtils {
map.putArray(child.getKey(), (WritableArray) castedChild);
break;
default:
Log.w(TAG, "Invalid type: " + castedChild.getClass().getName());
Log.w(
TAG,
"Invalid type: " + castedChild
.getClass()
.getName()
);
break;
}
}
@ -312,7 +342,9 @@ public class RNFirebaseDatabaseUtils {
for (MutableData child : mutableData.getChildren()) {
Any castedChild = castValue(child);
switch (castedChild.getClass().getName()) {
switch (castedChild
.getClass()
.getName()) {
case "java.lang.Boolean":
map.putBoolean(child.getKey(), (Boolean) castedChild);
break;
@ -332,7 +364,12 @@ public class RNFirebaseDatabaseUtils {
map.putArray(child.getKey(), (WritableArray) castedChild);
break;
default:
Log.w(TAG, "Invalid type: " + castedChild.getClass().getName());
Log.w(
TAG,
"Invalid type: " + castedChild
.getClass()
.getName()
);
break;
}
}

View File

@ -19,18 +19,17 @@ import javax.annotation.Nullable;
import io.invertase.firebase.Utils;
public class RNFirebaseTransactionHandler {
private int transactionId;
private String appName;
private String dbURL;
private final ReentrantLock lock;
private final Condition condition;
private Map<String, Object> data;
private boolean signalled;
public Object value;
boolean interrupted;
boolean abort = false;
boolean timeout = false;
private int transactionId;
private String appName;
private String dbURL;
private Map<String, Object> data;
private boolean signalled;
RNFirebaseTransactionHandler(int id, String app, String url) {
appName = app;
@ -127,7 +126,11 @@ public class RNFirebaseTransactionHandler {
}
WritableMap createResultMap(@Nullable DatabaseError error, boolean committed, DataSnapshot snapshot) {
WritableMap createResultMap(
@Nullable DatabaseError error,
boolean committed,
DataSnapshot snapshot
) {
WritableMap resultMap = Arguments.createMap();
resultMap.putInt("id", transactionId);
@ -144,7 +147,10 @@ public class RNFirebaseTransactionHandler {
if (error == null && timeout) {
WritableMap timeoutError = Arguments.createMap();
timeoutError.putString("code", "DATABASE/INTERNAL-TIMEOUT");
timeoutError.putString("message", "A timeout occurred whilst waiting for RN JS thread to send transaction updates.");
timeoutError.putString(
"message",
"A timeout occurred whilst waiting for RN JS thread to send transaction updates."
);
resultMap.putMap("error", timeoutError);
}
} else {

View File

@ -2,11 +2,10 @@ package io.invertase.firebase.fabric.crashlytics;
import android.util.Log;
import com.facebook.react.bridge.ReactMethod;
import com.crashlytics.android.Crashlytics;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.crashlytics.android.Crashlytics;
import com.facebook.react.bridge.ReactMethod;
public class RNFirebaseCrashlytics extends ReactContextBaseJavaModule {
@ -25,7 +24,9 @@ public class RNFirebaseCrashlytics extends ReactContextBaseJavaModule {
@ReactMethod
public void crash() {
Crashlytics.getInstance().crash();
Crashlytics
.getInstance()
.crash();
}
@ReactMethod

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.fabric.crashlytics;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -28,7 +28,9 @@ class DocumentSnapshotSerializeAsyncTask extends AsyncTask<Object, Void, Writabl
return FirestoreSerialize.snapshotToWritableMap(querySnapshot);
} catch (RuntimeException e) {
if (isAvailable()) {
reactContextWeakReference.get().handleException(e);
reactContextWeakReference
.get()
.handleException(e);
} else {
throw e;
}

View File

@ -48,15 +48,30 @@ public class FirestoreSerialize {
static WritableMap snapshotToWritableMap(DocumentSnapshot documentSnapshot) {
WritableMap documentMap = Arguments.createMap();
documentMap.putString(KEY_PATH, documentSnapshot.getReference().getPath());
documentMap.putString(
KEY_PATH,
documentSnapshot
.getReference()
.getPath()
);
if (documentSnapshot.exists()) {
documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
}
// metadata
WritableMap metadata = Arguments.createMap();
metadata.putBoolean("fromCache", documentSnapshot.getMetadata().isFromCache());
metadata.putBoolean("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites());
metadata.putBoolean(
"fromCache",
documentSnapshot
.getMetadata()
.isFromCache()
);
metadata.putBoolean(
"hasPendingWrites",
documentSnapshot
.getMetadata()
.hasPendingWrites()
);
documentMap.putMap(KEY_METADATA, metadata);
return documentMap;
}
@ -77,8 +92,18 @@ public class FirestoreSerialize {
// metadata
WritableMap metadata = Arguments.createMap();
metadata.putBoolean("fromCache", querySnapshot.getMetadata().isFromCache());
metadata.putBoolean("hasPendingWrites", querySnapshot.getMetadata().hasPendingWrites());
metadata.putBoolean(
"fromCache",
querySnapshot
.getMetadata()
.isFromCache()
);
metadata.putBoolean(
"hasPendingWrites",
querySnapshot
.getMetadata()
.hasPendingWrites()
);
queryMap.putMap(KEY_METADATA, metadata);
return queryMap;

View File

@ -28,7 +28,9 @@ class QuerySnapshotSerializeAsyncTask extends AsyncTask<Object, Void, WritableMa
return FirestoreSerialize.snapshotToWritableMap(querySnapshot);
} catch (RuntimeException e) {
if (isAvailable()) {
reactContextWeakReference.get().handleException(e);
reactContextWeakReference
.get()
.handleException(e);
} else {
throw e;
}

View File

@ -34,7 +34,6 @@ import java.util.Map;
import io.invertase.firebase.ErrorUtils;
import io.invertase.firebase.Utils;
public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseFirestore";
private SparseArray<RNFirebaseFirestoreTransactionHandler> transactionHandlers = new SparseArray<>();
@ -83,7 +82,12 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
*/
static WritableMap getJSError(FirebaseFirestoreException nativeException) {
WritableMap errorMap = Arguments.createMap();
errorMap.putInt("nativeErrorCode", nativeException.getCode().value());
errorMap.putInt(
"nativeErrorCode",
nativeException
.getCode()
.value()
);
errorMap.putString("nativeErrorMessage", nativeException.getMessage());
String code;
@ -228,21 +232,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
@ReactMethod
public void disableNetwork(String appName, final Promise promise) {
getFirestoreForApp(appName).disableNetwork().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "disableNetwork:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "disableNetwork:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
getFirestoreForApp(appName)
.disableNetwork()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "disableNetwork:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "disableNetwork:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
@ReactMethod
@ -256,21 +262,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
@ReactMethod
public void enableNetwork(String appName, final Promise promise) {
getFirestoreForApp(appName).enableNetwork().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "enableNetwork:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "enableNetwork:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
getFirestoreForApp(appName)
.enableNetwork()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "enableNetwork:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "enableNetwork:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
@ReactMethod
@ -314,8 +322,10 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
}
@ReactMethod
public void documentBatch(final String appName, final ReadableArray writes,
final Promise promise) {
public void documentBatch(
final String appName, final ReadableArray writes,
final Promise promise
) {
FirebaseFirestore firestore = getFirestoreForApp(appName);
WriteBatch batch = firestore.batch();
final List<Object> writesArray = FirestoreSerialize.parseDocumentBatches(firestore, writes);
@ -346,18 +356,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
}
}
batch.commit().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "documentBatch:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "documentBatch:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException) task.getException());
batch
.commit()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "documentBatch:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "documentBatch:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
@ReactMethod
@ -421,17 +436,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
if (settings.hasKey("host")) {
firestoreSettings.setHost(settings.getString("host"));
} else {
firestoreSettings.setHost(firestore.getFirestoreSettings().getHost());
firestoreSettings.setHost(firestore
.getFirestoreSettings()
.getHost());
}
if (settings.hasKey("persistence")) {
firestoreSettings.setPersistenceEnabled(settings.getBoolean("persistence"));
} else {
firestoreSettings.setPersistenceEnabled(firestore.getFirestoreSettings().isPersistenceEnabled());
firestoreSettings.setPersistenceEnabled(firestore
.getFirestoreSettings()
.isPersistenceEnabled());
}
if (settings.hasKey("ssl")) {
firestoreSettings.setSslEnabled(settings.getBoolean("ssl"));
} else {
firestoreSettings.setSslEnabled(firestore.getFirestoreSettings().isSslEnabled());
firestoreSettings.setSslEnabled(firestore
.getFirestoreSettings()
.isSslEnabled());
}
// if (settings.hasKey("timestampsInSnapshots")) {
@ -731,8 +752,18 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("deleteFieldValue", FieldValue.delete().toString());
constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp().toString());
constants.put(
"deleteFieldValue",
FieldValue
.delete()
.toString()
);
constants.put(
"serverTimestampFieldValue",
FieldValue
.serverTimestamp()
.toString()
);
return constants;
}
}

View File

@ -89,21 +89,23 @@ class RNFirebaseFirestoreCollectionReference {
}
};
query.get(source).addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, "get:onComplete:success");
serializeAsyncTask.execute(task.getResult());
} else {
Log.e(TAG, "get:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
query
.get(source)
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, "get:onComplete:success");
serializeAsyncTask.execute(task.getResult());
} else {
Log.e(TAG, "get:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
void onSnapshot(final String listenerId, final ReadableMap queryListenOptions) {

View File

@ -39,7 +39,9 @@ public class RNFirebaseFirestoreDocumentReference {
this.path = path;
this.appName = appName;
this.reactContext = reactContext;
this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path);
this.ref = RNFirebaseFirestore
.getFirestoreForApp(appName)
.document(path);
}
static void offSnapshot(final String listenerId) {
@ -50,21 +52,23 @@ public class RNFirebaseFirestoreDocumentReference {
}
void delete(final Promise promise) {
this.ref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "delete:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "delete:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
this.ref
.delete()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "delete:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "delete:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
void get(final ReadableMap getOptions, final Promise promise) {
@ -92,21 +96,23 @@ public class RNFirebaseFirestoreDocumentReference {
}
};
this.ref.get(source).addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, "get:onComplete:success");
serializeAsyncTask.execute(task.getResult());
} else {
Log.e(TAG, "get:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
this.ref
.get(source)
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, "get:onComplete:success");
serializeAsyncTask.execute(task.getResult());
} else {
Log.e(TAG, "get:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
void onSnapshot(final String listenerId, final ReadableMap docListenOptions) {
@ -187,21 +193,23 @@ public class RNFirebaseFirestoreDocumentReference {
data
);
this.ref.update(map).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "update:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "update:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
this.ref
.update(map)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "update:onComplete:success");
promise.resolve(null);
} else {
Log.e(TAG, "update:onComplete:failure", task.getException());
RNFirebaseFirestore.promiseRejectException(
promise,
(FirebaseFirestoreException) task.getException()
);
}
}
}
});
});
}
/*

View File

@ -41,7 +41,10 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
@ReactMethod
public void httpsCallable(final String name, ReadableMap wrapper, final Promise promise) {
Object input = wrapper.toHashMap().get(DATA_KEY);
Object input = wrapper
.toHashMap()
.get(DATA_KEY);
Log.d(TAG, "function:call:input:" + name + ":" + (input != null ? input.toString() : "null"));
HttpsCallableReference httpsCallableReference = FirebaseFunctions
@ -60,10 +63,14 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
TAG,
"function:call:onSuccess:" + name
);
Log.d(
TAG,
"function:call:onSuccess:result:type:" + name + ":" + (result != null ? result.getClass().getName() : "null")
"function:call:onSuccess:result:type:" + name + ":" + (result != null ? result
.getClass()
.getName() : "null")
);
Log.d(
TAG,
"function:call:onSuccess:result:data:" + name + ":" + (result != null ? result.toString() : "null")
@ -71,7 +78,6 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
Utils.mapPutValue(DATA_KEY, result, map);
promise.resolve(map);
}
})
.addOnFailureListener(new OnFailureListener() {
@ -87,7 +93,9 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
if (exception instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) exception;
details = ffe.getDetails();
code = ffe.getCode().name();
code = ffe
.getCode()
.name();
message = ffe.getLocalizedMessage();
} else {
message = exception.getLocalizedMessage();

View File

@ -1,8 +1,6 @@
package io.invertase.firebase.instanceid;
import java.io.IOException;
import android.util.Log;
import com.facebook.react.bridge.Promise;
@ -28,10 +26,12 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule {
}
@ReactMethod
public void delete(Promise promise){
public void delete(Promise promise) {
try {
Log.d(TAG, "Deleting instance id");
FirebaseInstanceId.getInstance().deleteInstanceId();
FirebaseInstanceId
.getInstance()
.deleteInstanceId();
promise.resolve(null);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
@ -40,15 +40,19 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule {
}
@ReactMethod
public void get(Promise promise){
String id = FirebaseInstanceId.getInstance().getId();
public void get(Promise promise) {
String id = FirebaseInstanceId
.getInstance()
.getId();
promise.resolve(id);
}
@ReactMethod
public void getToken(String authorizedEntity, String scope, Promise promise) {
try {
String token = FirebaseInstanceId.getInstance().getToken(authorizedEntity, scope);
String token = FirebaseInstanceId
.getInstance()
.getToken(authorizedEntity, scope);
Log.d(TAG, "Firebase token for " + authorizedEntity + ": " + token);
promise.resolve(token);
} catch (IOException e) {
@ -59,7 +63,9 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule {
@ReactMethod
public void deleteToken(String authorizedEntity, String scope, Promise promise) {
try {
FirebaseInstanceId.getInstance().deleteToken(authorizedEntity, scope);
FirebaseInstanceId
.getInstance()
.deleteToken(authorizedEntity, scope);
Log.d(TAG, "Firebase token deleted for " + authorizedEntity);
promise.resolve(null);
} catch (IOException e) {

View File

@ -28,7 +28,6 @@ import java.util.HashMap;
import java.util.Map;
import io.invertase.firebase.Utils;
import io.invertase.firebase.links.RNFirebaseLinks;
public class RNFirebaseInvites extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
private static final String TAG = "RNFirebaseInvites";
@ -58,21 +57,28 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
}
} else {
if (getCurrentActivity() != null) {
FirebaseDynamicLinks.getInstance()
FirebaseDynamicLinks
.getInstance()
.getDynamicLink(getCurrentActivity().getIntent())
.addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
@Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
if (pendingDynamicLinkData != null) {
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData);
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(
pendingDynamicLinkData);
if (invite == null) {
promise.resolve(null);
return;
}
mInitialDeepLink = pendingDynamicLinkData.getLink().toString();
mInitialDeepLink = pendingDynamicLinkData
.getLink()
.toString();
mInitialInvitationId = invite.getInvitationId();
promise.resolve(buildInvitationMap(mInitialDeepLink, mInitialInvitationId));
promise.resolve(buildInvitationMap(
mInitialDeepLink,
mInitialInvitationId
));
} else {
promise.resolve(null);
}
@ -83,7 +89,11 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "getInitialInvitation: failed to resolve invitation", e);
promise.reject("invites/initial-invitation-error", e.getMessage(), e);
promise.reject(
"invites/initial-invitation-error",
e.getMessage(),
e
);
}
});
} else {
@ -96,15 +106,22 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
@ReactMethod
public void sendInvitation(ReadableMap invitationMap, Promise promise) {
if (!invitationMap.hasKey("message")) {
promise.reject("invites/invalid-invitation", "The supplied invitation is missing a 'message' field");
promise.reject(
"invites/invalid-invitation",
"The supplied invitation is missing a 'message' field"
);
return;
}
if (!invitationMap.hasKey("title")) {
promise.reject("invites/invalid-invitation", "The supplied invitation is missing a 'title' field");
promise.reject(
"invites/invalid-invitation",
"The supplied invitation is missing a 'title' field"
);
return;
}
AppInviteInvitation.IntentBuilder ib = new AppInviteInvitation.IntentBuilder(invitationMap.getString("title"));
AppInviteInvitation.IntentBuilder ib = new AppInviteInvitation.IntentBuilder(invitationMap.getString(
"title"));
if (invitationMap.hasKey("androidMinimumVersionCode")) {
Double androidMinimumVersionCode = invitationMap.getDouble("androidMinimumVersionCode");
ib = ib.setAndroidMinimumVersionCode(androidMinimumVersionCode.intValue());
@ -121,7 +138,8 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
if (invitationMap.hasKey("iosClientId")) {
ib = ib.setOtherPlatformsTargetApplication(
AppInviteInvitation.IntentBuilder.PlatformMode.PROJECT_PLATFORM_IOS,
invitationMap.getString("iosClientId"));
invitationMap.getString("iosClientId")
);
}
ib = ib.setMessage(invitationMap.getString("message"));
@ -155,7 +173,9 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
this.mPromise = promise;
// Start the intent
this.getCurrentActivity().startActivityForResult(invitationIntent, REQUEST_INVITE);
this
.getCurrentActivity()
.startActivityForResult(invitationIntent, REQUEST_INVITE);
}
//////////////////////////////////////////////////////////////////////
@ -179,22 +199,33 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
@Override
public void onNewIntent(Intent intent) {
FirebaseDynamicLinks.getInstance()
FirebaseDynamicLinks
.getInstance()
.getDynamicLink(intent)
.addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
@Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
if (pendingDynamicLinkData != null) {
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData);
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(
pendingDynamicLinkData);
if (invite == null) {
// this is a dynamic link, not an invitation
return;
}
String deepLink = pendingDynamicLinkData.getLink().toString();
String deepLink = pendingDynamicLinkData
.getLink()
.toString();
String invitationId = invite.getInvitationId();
WritableMap invitationMap = buildInvitationMap(deepLink, invitationId);
Utils.sendEvent(getReactApplicationContext(), "invites_invitation_received", invitationMap);
WritableMap invitationMap = buildInvitationMap(
deepLink,
invitationId
);
Utils.sendEvent(
getReactApplicationContext(),
"invites_invitation_received",
invitationMap
);
}
}
});

View File

@ -13,17 +13,15 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.appinvite.FirebaseAppInvite;
import com.google.firebase.dynamiclinks.DynamicLink;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import com.google.firebase.dynamiclinks.ShortDynamicLink;
import com.google.firebase.dynamiclinks.PendingDynamicLinkData;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.firebase.dynamiclinks.ShortDynamicLink;
import io.invertase.firebase.Utils;
@ -47,7 +45,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
public void createDynamicLink(final ReadableMap linkData, final Promise promise) {
try {
DynamicLink.Builder builder = getDynamicLinkBuilder(linkData);
String link = builder.buildDynamicLink().getUri().toString();
String link = builder
.buildDynamicLink()
.getUri()
.toString();
Log.d(TAG, "created dynamic link: " + link);
promise.resolve(link);
} catch (Exception ex) {
@ -57,7 +58,11 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
}
@ReactMethod
public void createShortDynamicLink(final ReadableMap linkData, final String type, final Promise promise) {
public void createShortDynamicLink(
final ReadableMap linkData,
final String type,
final Promise promise
) {
try {
DynamicLink.Builder builder = getDynamicLinkBuilder(linkData);
Task<ShortDynamicLink> shortLinkTask;
@ -70,16 +75,30 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
}
shortLinkTask.addOnCompleteListener(new OnCompleteListener<ShortDynamicLink>() {
@Override
public void onComplete(@NonNull Task<ShortDynamicLink> task) {
if (task.isSuccessful()) {
String shortLink = task.getResult().getShortLink().toString();
Log.d(TAG, "created short dynamic link: " + shortLink);
promise.resolve(shortLink);
} else {
Log.e(TAG, "create short dynamic link failure " + task.getException().getMessage());
promise.reject("links/failure", task.getException().getMessage(), task.getException());
}
@Override
public void onComplete(@NonNull Task<ShortDynamicLink> task) {
if (task.isSuccessful()) {
String shortLink = task
.getResult()
.getShortLink()
.toString();
Log.d(TAG, "created short dynamic link: " + shortLink);
promise.resolve(shortLink);
} else {
Log.e(
TAG,
"create short dynamic link failure " + task
.getException()
.getMessage()
);
promise.reject(
"links/failure",
task
.getException()
.getMessage(),
task.getException()
);
}
}
});
} catch (Exception ex) {
@ -94,7 +113,8 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
promise.resolve(mInitialLink);
} else {
if (getCurrentActivity() != null) {
FirebaseDynamicLinks.getInstance()
FirebaseDynamicLinks
.getInstance()
.getDynamicLink(getCurrentActivity().getIntent())
.addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
@Override
@ -102,7 +122,9 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
if (pendingDynamicLinkData != null
&& !isInvitation(pendingDynamicLinkData)) {
mInitialLink = pendingDynamicLinkData.getLink().toString();
mInitialLink = pendingDynamicLinkData
.getLink()
.toString();
}
Log.d(TAG, "getInitialLink: link is: " + mInitialLink);
mInitialLinkInitialized = true;
@ -133,15 +155,22 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
@Override
public void onNewIntent(Intent intent) {
FirebaseDynamicLinks.getInstance()
FirebaseDynamicLinks
.getInstance()
.getDynamicLink(intent)
.addOnSuccessListener(new OnSuccessListener<PendingDynamicLinkData>() {
@Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
if (pendingDynamicLinkData != null
&& !isInvitation(pendingDynamicLinkData)) {
String link = pendingDynamicLinkData.getLink().toString();
Utils.sendEvent(getReactApplicationContext(), "links_link_received", link);
String link = pendingDynamicLinkData
.getLink()
.toString();
Utils.sendEvent(
getReactApplicationContext(),
"links_link_received",
link
);
}
}
});
@ -175,14 +204,18 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
// Looks at the internals of the link data to detect whether it's an invitation or not
private boolean isInvitation(PendingDynamicLinkData pendingDynamicLinkData) {
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData);
if (invite != null && invite.getInvitationId() != null && !invite.getInvitationId().isEmpty()) {
if (invite != null && invite.getInvitationId() != null && !invite
.getInvitationId()
.isEmpty()) {
return true;
}
return false;
}
private DynamicLink.Builder getDynamicLinkBuilder(final ReadableMap linkData) {
DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance().createDynamicLink();
DynamicLink.Builder builder = FirebaseDynamicLinks
.getInstance()
.createDynamicLink();
try {
builder.setLink(Uri.parse(linkData.getString("link")));
builder.setDynamicLinkDomain(linkData.getString("dynamicLinkDomain"));
@ -199,7 +232,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
return builder;
}
private void setAnalyticsParameters(final ReadableMap analyticsData, final DynamicLink.Builder builder) {
private void setAnalyticsParameters(
final ReadableMap analyticsData,
final DynamicLink.Builder builder
) {
DynamicLink.GoogleAnalyticsParameters.Builder analyticsParameters = new DynamicLink.GoogleAnalyticsParameters.Builder();
if (analyticsData.hasKey("campaign")) {
@ -220,9 +256,13 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
builder.setGoogleAnalyticsParameters(analyticsParameters.build());
}
private void setAndroidParameters(final ReadableMap androidData, final DynamicLink.Builder builder) {
private void setAndroidParameters(
final ReadableMap androidData,
final DynamicLink.Builder builder
) {
if (androidData.hasKey("packageName")) {
DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder(androidData.getString("packageName"));
DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder(
androidData.getString("packageName"));
if (androidData.hasKey("fallbackUrl")) {
androidParameters.setFallbackUrl(Uri.parse(androidData.getString("fallbackUrl")));
@ -261,7 +301,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
}
}
private void setITunesParameters(final ReadableMap itunesData, final DynamicLink.Builder builder) {
private void setITunesParameters(
final ReadableMap itunesData,
final DynamicLink.Builder builder
) {
DynamicLink.ItunesConnectAnalyticsParameters.Builder itunesParameters = new DynamicLink.ItunesConnectAnalyticsParameters.Builder();
if (itunesData.hasKey("affiliateToken")) {
@ -276,16 +319,23 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ
builder.setItunesConnectAnalyticsParameters(itunesParameters.build());
}
private void setNavigationParameters(final ReadableMap navigationData, final DynamicLink.Builder builder) {
private void setNavigationParameters(
final ReadableMap navigationData,
final DynamicLink.Builder builder
) {
DynamicLink.NavigationInfoParameters.Builder navigationParameters = new DynamicLink.NavigationInfoParameters.Builder();
if (navigationData.hasKey("forcedRedirectEnabled")) {
navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean("forcedRedirectEnabled"));
navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean(
"forcedRedirectEnabled"));
}
builder.setNavigationInfoParameters(navigationParameters.build());
}
private void setSocialParameters(final ReadableMap socialData, final DynamicLink.Builder builder) {
private void setSocialParameters(
final ReadableMap socialData,
final DynamicLink.Builder builder
) {
DynamicLink.SocialMetaTagParameters.Builder socialParameters = new DynamicLink.SocialMetaTagParameters.Builder();
if (socialData.hasKey("descriptionText")) {

View File

@ -1,7 +1,6 @@
package io.invertase.firebase.links;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.UIManagerModule;

View File

@ -39,9 +39,9 @@ import java.util.Map;
* com.facebook.internal is solely for the use of other packages within the Facebook SDK for
* Android. Use of any of the classes in this package is unsupported, and they may be modified or
* removed without warning at any time.
*
* <p>
* A helper class that can round trip between JSON and Bundle objects that contains the types:
* Boolean, Integer, Long, Double, String
* Boolean, Integer, Long, Double, String
* If other types are found, an IllegalArgumentException is thrown.
*/
public class BundleJSONConverter {
@ -126,13 +126,13 @@ public class BundleJSONConverter {
} else if (jsonArray.get(0) instanceof Boolean) {
boolean[] booleanArray = new boolean[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
booleanArray[i] = (Boolean)jsonArray.get(i);
booleanArray[i] = (Boolean) jsonArray.get(i);
}
bundle.putBooleanArray(key, booleanArray);
} else if (jsonArray.get(0) instanceof Double) {
double[] doubleArray = new double[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
doubleArray[i] = (Double)jsonArray.get(i);
doubleArray[i] = (Double) jsonArray.get(i);
}
bundle.putDoubleArray(key, doubleArray);
} else if (jsonArray.get(0) instanceof Long) {
@ -143,12 +143,14 @@ public class BundleJSONConverter {
bundle.putLongArray(key, longArray);
} else if (jsonArray.get(0) instanceof JSONObject) {
ArrayList<Bundle> bundleArrayList = new ArrayList<>();
for (int i =0; i < jsonArray.length(); i++) {
for (int i = 0; i < jsonArray.length(); i++) {
bundleArrayList.add(convertToBundle((JSONObject) jsonArray.get(i)));
}
bundle.putSerializable(key, bundleArrayList);
} else {
throw new IllegalArgumentException("Unexpected type in an array: " + jsonArray.get(0).getClass());
throw new IllegalArgumentException("Unexpected type in an array: " + jsonArray
.get(0)
.getClass());
}
}
@ -159,12 +161,6 @@ public class BundleJSONConverter {
});
}
public interface Setter {
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException;
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException;
}
public static JSONObject convertToJSON(Bundle bundle) throws JSONException {
JSONObject json = new JSONObject();
@ -239,4 +235,10 @@ public class BundleJSONConverter {
return bundle;
}
public interface Setter {
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException;
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException;
}
}

View File

@ -6,7 +6,6 @@ import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;
public class MessagingSerializer {
public static WritableMap parseRemoteMessage(RemoteMessage message) {
WritableMap messageMap = Arguments.createMap();
@ -17,7 +16,9 @@ public class MessagingSerializer {
}
if (message.getData() != null) {
for (Map.Entry<String, String> e : message.getData().entrySet()) {
for (Map.Entry<String, String> e : message
.getData()
.entrySet()) {
dataMap.putString(e.getKey(), e.getValue());
}
}

View File

@ -4,7 +4,6 @@ import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import com.google.firebase.messaging.RemoteMessage;
@ -13,7 +12,8 @@ import javax.annotation.Nullable;
public class RNFirebaseBackgroundMessagingService extends HeadlessJsTaskService {
@Override
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
protected @Nullable
HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
RemoteMessage message = intent.getParcelableExtra("message");

View File

@ -1,6 +1,5 @@
package io.invertase.firebase.messaging;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
@ -8,8 +7,8 @@ import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceIdService;
public class RNFirebaseInstanceIdService extends FirebaseInstanceIdService {
private static final String TAG = "RNFInstanceIdService";
public static final String TOKEN_REFRESH_EVENT = "messaging-token-refresh";
private static final String TAG = "RNFInstanceIdService";
@Override
public void onTokenRefresh() {
@ -19,6 +18,8 @@ public class RNFirebaseInstanceIdService extends FirebaseInstanceIdService {
Intent tokenRefreshEvent = new Intent(TOKEN_REFRESH_EVENT);
// Broadcast it so it is only available to the RN Application
LocalBroadcastManager.getInstance(this).sendBroadcast(tokenRefreshEvent);
LocalBroadcastManager
.getInstance(this)
.sendBroadcast(tokenRefreshEvent);
}
}

View File

@ -5,8 +5,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.facebook.react.bridge.Promise;
@ -32,12 +32,16 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
// Subscribe to message events
localBroadcastManager.registerReceiver(new MessageReceiver(),
new IntentFilter(RNFirebaseMessagingService.MESSAGE_EVENT));
localBroadcastManager.registerReceiver(
new MessageReceiver(),
new IntentFilter(RNFirebaseMessagingService.MESSAGE_EVENT)
);
// Subscribe to token refresh events
localBroadcastManager.registerReceiver(new RefreshTokenReceiver(),
new IntentFilter(RNFirebaseInstanceIdService.TOKEN_REFRESH_EVENT));
localBroadcastManager.registerReceiver(
new RefreshTokenReceiver(),
new IntentFilter(RNFirebaseInstanceIdService.TOKEN_REFRESH_EVENT)
);
}
@Override
@ -47,7 +51,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
@ReactMethod
public void getToken(Promise promise) {
String token = FirebaseInstanceId.getInstance().getToken();
String token = FirebaseInstanceId
.getInstance()
.getToken();
Log.d(TAG, "Firebase token: " + token);
promise.resolve(token);
}
@ -60,7 +66,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
// Non Web SDK methods
@ReactMethod
public void hasPermission(Promise promise) {
Boolean enabled = NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled();
Boolean enabled = NotificationManagerCompat
.from(getReactApplicationContext())
.areNotificationsEnabled();
promise.resolve(enabled);
}
@ -94,7 +102,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
}
}
FirebaseMessaging.getInstance().send(mb.build());
FirebaseMessaging
.getInstance()
.send(mb.build());
// TODO: Listen to onMessageSent and onSendError for better feedback?
promise.resolve(null);
@ -102,36 +112,42 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
@ReactMethod
public void subscribeToTopic(String topic, final Promise promise) {
FirebaseMessaging.getInstance().subscribeToTopic(topic).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "subscribeToTopic:onComplete:success");
promise.resolve(null);
} else {
Exception exception = task.getException();
Log.e(TAG, "subscribeToTopic:onComplete:failure", exception);
promise.reject(exception);
FirebaseMessaging
.getInstance()
.subscribeToTopic(topic)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "subscribeToTopic:onComplete:success");
promise.resolve(null);
} else {
Exception exception = task.getException();
Log.e(TAG, "subscribeToTopic:onComplete:failure", exception);
promise.reject(exception);
}
}
}
});
});
}
@ReactMethod
public void unsubscribeFromTopic(String topic, final Promise promise) {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "unsubscribeFromTopic:onComplete:success");
promise.resolve(null);
} else {
Exception exception = task.getException();
Log.e(TAG, "unsubscribeFromTopic:onComplete:failure", exception);
promise.reject(exception);
FirebaseMessaging
.getInstance()
.unsubscribeFromTopic(topic)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "unsubscribeFromTopic:onComplete:success");
promise.resolve(null);
} else {
Exception exception = task.getException();
Log.e(TAG, "unsubscribeFromTopic:onComplete:failure", exception);
promise.reject(exception);
}
}
}
});
});
}
private class MessageReceiver extends BroadcastReceiver {
@ -152,7 +168,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
@Override
public void onReceive(Context context, Intent intent) {
if (getReactApplicationContext().hasActiveCatalystInstance()) {
String token = FirebaseInstanceId.getInstance().getToken();
String token = FirebaseInstanceId
.getInstance()
.getToken();
Log.d(TAG, "Received new FCM token: " + token);
Utils.sendEvent(getReactApplicationContext(), "messaging_token_refreshed", token);

View File

@ -11,9 +11,9 @@ import com.google.firebase.messaging.RemoteMessage;
import io.invertase.firebase.Utils;
public class RNFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "RNFMessagingService";
public static final String MESSAGE_EVENT = "messaging-message";
public static final String REMOTE_NOTIFICATION_EVENT = "notifications-remote-notification";
private static final String TAG = "RNFMessagingService";
@Override
public void onMessageReceived(RemoteMessage message) {
@ -25,7 +25,9 @@ public class RNFirebaseMessagingService extends FirebaseMessagingService {
notificationEvent.putExtra("notification", message);
// Broadcast it to the (foreground) RN Application
LocalBroadcastManager.getInstance(this).sendBroadcast(notificationEvent);
LocalBroadcastManager
.getInstance(this)
.sendBroadcast(notificationEvent);
} else {
// It's a data message
// If the app is in the foreground we send it to the Messaging module
@ -33,16 +35,27 @@ public class RNFirebaseMessagingService extends FirebaseMessagingService {
Intent messagingEvent = new Intent(MESSAGE_EVENT);
messagingEvent.putExtra("message", message);
// Broadcast it so it is only available to the RN Application
LocalBroadcastManager.getInstance(this).sendBroadcast(messagingEvent);
LocalBroadcastManager
.getInstance(this)
.sendBroadcast(messagingEvent);
} else {
try {
// If the app is in the background we send it to the Headless JS Service
Intent headlessIntent = new Intent(this.getApplicationContext(), RNFirebaseBackgroundMessagingService.class);
Intent headlessIntent = new Intent(
this.getApplicationContext(),
RNFirebaseBackgroundMessagingService.class
);
headlessIntent.putExtra("message", message);
this.getApplicationContext().startService(headlessIntent);
this
.getApplicationContext()
.startService(headlessIntent);
HeadlessJsTaskService.acquireWakeLockNow(this.getApplicationContext());
} catch (IllegalStateException ex) {
Log.e(TAG, "Background messages will only work if the message priority is set to 'high'", ex);
Log.e(
TAG,
"Background messages will only work if the message priority is set to 'high'",
ex
);
}
}
}

View File

@ -37,9 +37,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
private final Promise promise;
private ReactApplicationContext reactContext;
public DisplayNotificationTask(Context context, ReactApplicationContext reactContext,
NotificationManager notificationManager,
Bundle notification, Promise promise) {
public DisplayNotificationTask(
Context context, ReactApplicationContext reactContext,
NotificationManager notificationManager,
Bundle notification, Promise promise
) {
this.context = context;
this.notification = notification;
this.notificationManager = notificationManager;
@ -53,7 +55,10 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
Class intentClass = getMainActivityClass();
if (intentClass == null) {
if (promise != null) {
promise.reject("notification/display_notification_error", "Could not find main activity class");
promise.reject(
"notification/display_notification_error",
"Could not find main activity class"
);
}
return null;
}
@ -77,7 +82,10 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
nb = nb.setExtras(notification.getBundle("data"));
}
if (notification.containsKey("sound")) {
Uri sound = RNFirebaseNotificationManager.getSound(context, notification.getString("sound"));
Uri sound = RNFirebaseNotificationManager.getSound(
context,
notification.getString("sound")
);
nb = nb.setSound(sound);
}
if (notification.containsKey("subtitle")) {
@ -148,7 +156,7 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
if (defaults == 0) {
ArrayList<Integer> defaultsArray = android.getIntegerArrayList("defaults");
if(defaultsArray != null) {
if (defaultsArray != null) {
for (Integer defaultValue : defaultsArray) {
defaults |= defaultValue;
}
@ -210,7 +218,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
Bundle progress = android.getBundle("progress");
Double max = progress.getDouble("max");
Double progressI = progress.getDouble("progress");
nb = nb.setProgress(max.intValue(), progressI.intValue(), progress.getBoolean("indeterminate"));
nb = nb.setProgress(
max.intValue(),
progressI.intValue(),
progress.getBoolean("indeterminate")
);
}
// TODO: Public version of notification
/* if (android.containsKey("publicVersion")) {
@ -253,10 +265,12 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
if (android.containsKey("vibrate")) {
ArrayList<Integer> vibrate = android.getIntegerArrayList("vibrate");
if(vibrate != null) {
if (vibrate != null) {
long[] vibrateArray = new long[vibrate.size()];
for (int i = 0; i < vibrate.size(); i++) {
vibrateArray[i] = vibrate.get(i).longValue();
vibrateArray[i] = vibrate
.get(i)
.longValue();
}
nb = nb.setVibrate(vibrateArray);
}
@ -281,11 +295,15 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
String tag = null;
if (android.containsKey("tag")) {
tag = android.getString("tag");
tag = android.getString("tag");
}
// Create the notification intent
PendingIntent contentIntent = createIntent(intentClass, notification, android.getString("clickAction"));
PendingIntent contentIntent = createIntent(
intentClass,
notification,
android.getString("clickAction")
);
nb = nb.setContentIntent(contentIntent);
// Build the notification and send it
@ -293,7 +311,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
notificationManager.notify(tag, notificationId.hashCode(), builtNotification);
if (reactContext != null) {
Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification));
Utils.sendEvent(
reactContext,
"notifications_notification_displayed",
Arguments.fromBundle(notification)
);
}
if (promise != null) {
@ -310,8 +332,13 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
return null;
}
private NotificationCompat.Action createAction(Bundle action, Class intentClass, Bundle notification) {
boolean showUserInterface = action.containsKey("showUserInterface") && action.getBoolean("showUserInterface");
private NotificationCompat.Action createAction(
Bundle action,
Class intentClass,
Bundle notification
) {
boolean showUserInterface = action.containsKey("showUserInterface") && action.getBoolean(
"showUserInterface");
String actionKey = action.getString("action");
PendingIntent actionIntent = showUserInterface ?
createIntent(intentClass, notification, actionKey) :
@ -319,7 +346,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
int icon = getIcon(action.getString("icon"));
String title = action.getString("title");
NotificationCompat.Action.Builder ab = new NotificationCompat.Action.Builder(icon, title, actionIntent);
NotificationCompat.Action.Builder ab = new NotificationCompat.Action.Builder(
icon,
title,
actionIntent
);
if (action.containsKey("allowGeneratedReplies")) {
ab = ab.setAllowGeneratedReplies(action.getBoolean("allowGeneratedReplies"));
@ -353,7 +384,12 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
String notificationId = notification.getString("notificationId");
return PendingIntent.getActivity(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
return PendingIntent.getActivity(
context,
notificationId.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT
);
}
private PendingIntent createBroadcastIntent(Bundle notification, String action) {
@ -365,7 +401,12 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
intent.setAction("io.invertase.firebase.notifications.BackgroundAction");
intent.putExtra("action", action);
intent.putExtra("notification", notification);
return PendingIntent.getBroadcast(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
return PendingIntent.getBroadcast(
context,
notificationId.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT
);
}
private RemoteInput createRemoteInput(Bundle remoteInput) {
@ -417,18 +458,22 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
private int getIcon(String icon) {
int resourceId = RNFirebaseNotificationManager.getResourceId(context,"mipmap", icon);
int resourceId = RNFirebaseNotificationManager.getResourceId(context, "mipmap", icon);
if (resourceId == 0) {
resourceId = RNFirebaseNotificationManager.getResourceId(context,"drawable", icon);
resourceId = RNFirebaseNotificationManager.getResourceId(context, "drawable", icon);
}
return resourceId;
}
private Class getMainActivityClass() {
String packageName = context.getPackageName();
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
Intent launchIntent = context
.getPackageManager()
.getLaunchIntentForPackage(packageName);
try {
return Class.forName(launchIntent.getComponent().getClassName());
return Class.forName(launchIntent
.getComponent()
.getClassName());
} catch (ClassNotFoundException e) {
Log.e(TAG, "Failed to get main activity class", e);
return null;

View File

@ -36,12 +36,18 @@ public class RNFirebaseBackgroundNotificationActionReceiver extends BroadcastRec
if (Utils.isAppInForeground(context)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);
ReactApplication reactApplication = (ReactApplication)context.getApplicationContext();
ReactContext reactContext = reactApplication.getReactNativeHost().getReactInstanceManager().getCurrentReactContext();
ReactApplication reactApplication = (ReactApplication) context.getApplicationContext();
ReactContext reactContext = reactApplication
.getReactNativeHost()
.getReactInstanceManager()
.getCurrentReactContext();
Utils.sendEvent(reactContext, "notifications_notification_opened", notificationOpenMap);
} else {
Intent serviceIntent = new Intent(context, RNFirebaseBackgroundNotificationActionsService.class);
Intent serviceIntent = new Intent(
context,
RNFirebaseBackgroundNotificationActionsService.class
);
serviceIntent.putExtras(intent.getExtras());
context.startService(serviceIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);

View File

@ -13,7 +13,8 @@ import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificati
public class RNFirebaseBackgroundNotificationActionsService extends HeadlessJsTaskService {
@Override
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
protected @Nullable
HeadlessJsTaskConfig getTaskConfig(Intent intent) {
if (isBackgroundNotficationIntent(intent)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);

View File

@ -2,7 +2,6 @@ package io.invertase.firebase.notifications;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
@ -10,8 +9,6 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.net.Uri;
@ -19,8 +16,6 @@ import android.os.Build;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
@ -33,9 +28,6 @@ import com.facebook.react.bridge.ReadableMap;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -45,8 +37,8 @@ import io.invertase.firebase.Utils;
import io.invertase.firebase.messaging.BundleJSONConverter;
public class RNFirebaseNotificationManager {
private static final String PREFERENCES_KEY = "RNFNotifications";
public static final String SCHEDULED_NOTIFICATION_EVENT = "notifications-scheduled-notification";
private static final String PREFERENCES_KEY = "RNFNotifications";
private static final String TAG = "RNFNotificationManager";
private AlarmManager alarmManager;
private Context context;
@ -62,31 +54,63 @@ public class RNFirebaseNotificationManager {
public RNFirebaseNotificationManager(Context context) {
this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
this.context = context;
this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
this.preferences = context.getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE);
}
public static int getResourceId(Context context, String type, String image) {
return context
.getResources()
.getIdentifier(image, type, context.getPackageName());
}
public static Uri getSound(Context context, String sound) {
if (sound == null) {
return null;
} else if (sound.contains("://")) {
return Uri.parse(sound);
} else if (sound.equalsIgnoreCase("default")) {
return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
} else {
int soundResourceId = getResourceId(context, "raw", sound);
if (soundResourceId == 0) {
soundResourceId = getResourceId(context, "raw", sound.substring(0, sound.lastIndexOf('.')));
}
return Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId);
}
}
public void cancelAllNotifications(Promise promise) {
try {
Map<String, ?> notifications = preferences.getAll();
for(String notificationId : notifications.keySet()){
for (String notificationId : notifications.keySet()) {
cancelAlarm(notificationId);
}
preferences.edit().clear().apply();
preferences
.edit()
.clear()
.apply();
promise.resolve(null);
} catch (SecurityException e) {
// TODO: Identify what these situations are
// In some devices/situations cancelAllLocalNotifications can throw a SecurityException.
Log.e(TAG, e.getMessage());
promise.reject("notification/cancel_notifications_error", "Could not cancel notifications", e);
promise.reject(
"notification/cancel_notifications_error",
"Could not cancel notifications",
e
);
}
}
public void cancelNotification(String notificationId, Promise promise) {
try {
cancelAlarm(notificationId);
preferences.edit().remove(notificationId).apply();
preferences
.edit()
.remove(notificationId)
.apply();
promise.resolve(null);
} catch (SecurityException e) {
// TODO: Identify what these situations are
@ -151,10 +175,17 @@ public class RNFirebaseNotificationManager {
public void displayScheduledNotification(Bundle notification) {
// If this isn't a repeated notification, clear it from the scheduled notifications list
if (!notification.getBundle("schedule").containsKey("repeated")
|| !notification.getBundle("schedule").getBoolean("repeated")) {
if (!notification
.getBundle("schedule")
.containsKey("repeated")
|| !notification
.getBundle("schedule")
.getBoolean("repeated")) {
String notificationId = notification.getString("notificationId");
preferences.edit().remove(notificationId).apply();
preferences
.edit()
.remove(notificationId)
.apply();
}
if (Utils.isAppInForeground(context)) {
@ -162,21 +193,23 @@ public class RNFirebaseNotificationManager {
// It is up to the JS to decide whether to display the notification
Intent scheduledNotificationEvent = new Intent(SCHEDULED_NOTIFICATION_EVENT);
scheduledNotificationEvent.putExtra("notification", notification);
LocalBroadcastManager.getInstance(context).sendBroadcast(scheduledNotificationEvent);
LocalBroadcastManager
.getInstance(context)
.sendBroadcast(scheduledNotificationEvent);
} else {
// If the app is in the background, then we display it automatically
displayNotification(notification, null);
}
}
public ArrayList<Bundle> getScheduledNotifications(){
public ArrayList<Bundle> getScheduledNotifications() {
ArrayList<Bundle> array = new ArrayList<>();
Map<String, ?> notifications = preferences.getAll();
for(String notificationId : notifications.keySet()){
for (String notificationId : notifications.keySet()) {
try {
JSONObject json = new JSONObject((String)notifications.get(notificationId));
JSONObject json = new JSONObject((String) notifications.get(notificationId));
Bundle bundle = BundleJSONConverter.convertToBundle(json);
array.add(bundle);
} catch (JSONException e) {
@ -199,16 +232,16 @@ public class RNFirebaseNotificationManager {
public void removeDeliveredNotificationsByTag(String tag, Promise promise) {
StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
for (StatusBarNotification statusBarNotification : statusBarNotifications) {
if (statusBarNotification.getTag() == tag) {
notificationManager.cancel(statusBarNotification.getTag(), statusBarNotification.getId());
}
if (statusBarNotification.getTag() == tag) {
notificationManager.cancel(statusBarNotification.getTag(), statusBarNotification.getId());
}
}
promise.resolve(null);
}
public void rescheduleNotifications() {
ArrayList<Bundle> bundles = getScheduledNotifications();
for(Bundle bundle: bundles){
for (Bundle bundle : bundles) {
scheduleNotification(bundle, null);
}
}
@ -221,32 +254,23 @@ public class RNFirebaseNotificationManager {
private void cancelAlarm(String notificationId) {
Intent notificationIntent = new Intent(context, RNFirebaseNotificationReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
notificationId.hashCode(),
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
alarmManager.cancel(pendingIntent);
}
private void displayNotification(Bundle notification, Promise promise) {
new DisplayNotificationTask(context, reactContext, notificationManager, notification, promise).execute();
}
public static int getResourceId(Context context, String type, String image) {
return context.getResources().getIdentifier(image, type, context.getPackageName());
}
public static Uri getSound(Context context, String sound) {
if (sound == null) {
return null;
} else if (sound.contains("://")) {
return Uri.parse(sound);
} else if (sound.equalsIgnoreCase("default")) {
return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
} else {
int soundResourceId = getResourceId(context,"raw", sound);
if (soundResourceId == 0) {
soundResourceId = getResourceId(context,"raw", sound.substring(0, sound.lastIndexOf('.')));
}
return Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId);
}
new DisplayNotificationTask(
context,
reactContext,
notificationManager,
notification,
promise
).execute();
}
private NotificationChannelGroup parseChannelGroupMap(ReadableMap channelGroupMap) {
@ -356,20 +380,31 @@ public class RNFirebaseNotificationManager {
// We store them so that they can be re-scheduled when the phone restarts in RNFirebaseNotificationsRebootReceiver
try {
JSONObject json = BundleJSONConverter.convertToJSON(notification);
preferences.edit().putString(notificationId, json.toString()).apply();
preferences
.edit()
.putString(notificationId, json.toString())
.apply();
} catch (JSONException e) {
if (promise == null) {
Log.e(TAG, "Failed to store notification");
} else {
promise.reject("notification/schedule_notification_error", "Failed to store notification", e);
promise.reject(
"notification/schedule_notification_error",
"Failed to store notification",
e
);
}
return;
}
Intent notificationIntent = new Intent(context, RNFirebaseNotificationReceiver.class);
notificationIntent.putExtras(notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(),
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
notificationId.hashCode(),
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
if (schedule.containsKey("repeatInterval")) {
// If fireDate you specify is in the past, the alarm triggers immediately.

View File

@ -41,6 +41,7 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
private SharedPreferences sharedPreferences = null;
private RNFirebaseNotificationManager notificationManager;
public RNFirebaseNotifications(ReactApplicationContext context) {
super(context);
context.addActivityEventListener(this);
@ -51,12 +52,16 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
// Subscribe to remote notification events
localBroadcastManager.registerReceiver(new RemoteNotificationReceiver(),
new IntentFilter(RNFirebaseMessagingService.REMOTE_NOTIFICATION_EVENT));
localBroadcastManager.registerReceiver(
new RemoteNotificationReceiver(),
new IntentFilter(RNFirebaseMessagingService.REMOTE_NOTIFICATION_EVENT)
);
// Subscribe to scheduled notification events
localBroadcastManager.registerReceiver(new ScheduledNotificationReceiver(),
new IntentFilter(RNFirebaseNotificationManager.SCHEDULED_NOTIFICATION_EVENT));
localBroadcastManager.registerReceiver(
new ScheduledNotificationReceiver(),
new IntentFilter(RNFirebaseNotificationManager.SCHEDULED_NOTIFICATION_EVENT)
);
}
@Override
@ -123,7 +128,10 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
@ReactMethod
public void setBadge(int badge, Promise promise) {
// Store the badge count for later retrieval
sharedPreferences.edit().putInt(BADGE_KEY, badge).apply();
sharedPreferences
.edit()
.putInt(BADGE_KEY, badge)
.apply();
if (badge == 0) {
Log.d(TAG, "Remove badge count");
ShortcutBadger.removeCount(this.getReactApplicationContext());
@ -193,7 +201,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
public void onNewIntent(Intent intent) {
WritableMap notificationOpenMap = parseIntentForNotification(intent);
if (notificationOpenMap != null) {
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_opened", notificationOpenMap);
Utils.sendEvent(
getReactApplicationContext(),
"notifications_notification_opened",
notificationOpenMap
);
}
}
@ -277,7 +289,9 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
notificationMap.putString("body", body);
}
if (message.getData() != null) {
for (Map.Entry<String, String> e : message.getData().entrySet()) {
for (Map.Entry<String, String> e : message
.getData()
.entrySet()) {
dataMap.putString(e.getKey(), e.getValue());
}
}
@ -315,27 +329,33 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
return notificationMap;
}
private @Nullable String getNotificationBody(RemoteMessage.Notification notification) {
private @Nullable
String getNotificationBody(RemoteMessage.Notification notification) {
String body = notification.getBody();
String bodyLocKey = notification.getBodyLocalizationKey();
if (bodyLocKey != null) {
String[] bodyLocArgs = notification.getBodyLocalizationArgs();
Context ctx = getReactApplicationContext();
int resId = getResId(ctx, bodyLocKey);
return ctx.getResources().getString(resId, (Object[]) bodyLocArgs);
return ctx
.getResources()
.getString(resId, (Object[]) bodyLocArgs);
} else {
return body;
}
}
private @Nullable String getNotificationTitle(RemoteMessage.Notification notification) {
private @Nullable
String getNotificationTitle(RemoteMessage.Notification notification) {
String title = notification.getTitle();
String titleLocKey = notification.getTitleLocalizationKey();
if (titleLocKey != null) {
String[] titleLocArgs = notification.getTitleLocalizationArgs();
Context ctx = getReactApplicationContext();
int resId = getResId(ctx, titleLocKey);
return ctx.getResources().getString(resId, (Object[]) titleLocArgs);
return ctx
.getResources()
.getString(resId, (Object[]) titleLocArgs);
} else {
return title;
}
@ -350,7 +370,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
RemoteMessage message = intent.getParcelableExtra("notification");
WritableMap messageMap = parseRemoteMessage(message);
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_received", messageMap);
Utils.sendEvent(
getReactApplicationContext(),
"notifications_notification_received",
messageMap
);
}
}
}
@ -364,7 +388,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
Bundle notification = intent.getBundleExtra("notification");
WritableMap messageMap = parseNotificationBundle(notification);
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_received", messageMap);
Utils.sendEvent(
getReactApplicationContext(),
"notifications_notification_received",
messageMap
);
}
}
}

View File

@ -3,18 +3,24 @@ package io.invertase.firebase.perf;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.google.firebase.perf.FirebasePerformance;
import com.google.firebase.perf.metrics.Trace;
import com.google.firebase.perf.metrics.HttpMetric;
import java.util.HashMap;
import java.util.Map;
public class RNFirebasePerformance extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebasePerformance";
private HashMap<String, Trace> traces = new HashMap<>();
private HashMap<String, HttpMetric> httpMetrics = new HashMap<>();
public RNFirebasePerformance(ReactApplicationContext reactContext) {
super(reactContext);
@ -30,19 +36,79 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule {
}
@ReactMethod
public void setPerformanceCollectionEnabled(Boolean enabled) {
public void setPerformanceCollectionEnabled(Boolean enabled, Promise promise) {
FirebasePerformance.getInstance().setPerformanceCollectionEnabled(enabled);
promise.resolve(null);
}
/**
* Trace
*/
@ReactMethod
public void getTraceAttribute(String identifier, String attribute, Promise promise) {
promise.resolve(getOrCreateTrace(identifier).getAttribute(attribute));
}
@ReactMethod
public void start(String identifier) {
public void getTraceAttributes(String identifier, Promise promise) {
Map<String, String> attributes = getOrCreateTrace(identifier).getAttributes();
WritableMap map = Arguments.createMap();
for (Map.Entry<String, String> entry : attributes.entrySet()) {
map.putString(entry.getKey(), entry.getValue());
}
promise.resolve(map);
}
@ReactMethod
public void getTraceLongMetric(String identifier, String metricName, Promise promise) {
Integer value = Long.valueOf(getOrCreateTrace(identifier).getLongMetric(metricName)).intValue();
promise.resolve(value);
}
@ReactMethod
public void incrementTraceMetric(String identifier, String metricName, Integer incrementBy, Promise promise) {
getOrCreateTrace(identifier).incrementMetric(metricName, incrementBy.longValue());
promise.resolve(null);
}
@ReactMethod
public void putTraceAttribute(String identifier, String attribute, String value, Promise promise) {
getOrCreateTrace(identifier).putAttribute(attribute, value);
// Docs say it returns a bool, actually void so we internally check attributes
Map<String, String> attributes = getOrCreateTrace(identifier).getAttributes();
if (attributes.containsKey(attribute)) {
promise.resolve(true);
} else {
promise.resolve(false);
}
}
@ReactMethod
public void putTraceMetric(String identifier, String metricName, Integer value, Promise promise) {
getOrCreateTrace(identifier).putMetric(metricName, value.longValue());
promise.resolve(null);
}
@ReactMethod
public void removeTraceAttribute(String identifier, String attribute, Promise promise) {
getOrCreateTrace(identifier).removeAttribute(attribute);
promise.resolve(null);
}
@ReactMethod
public void startTrace(String identifier, Promise promise) {
getOrCreateTrace(identifier).start();
promise.resolve(null);
}
@ReactMethod
public void stop(String identifier) {
public void stopTrace(String identifier, Promise promise) {
getOrCreateTrace(identifier).stop();
traces.remove(identifier);
promise.resolve(null);
}
@ReactMethod
@ -50,6 +116,86 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule {
getOrCreateTrace(identifier).incrementCounter(event);
}
/**
* Http Metric
*/
@ReactMethod
public void getHttpMetricAttribute(String url, String httpMethod, String attribute, Promise promise) {
promise.resolve(getOrCreateHttpMetric(url, httpMethod).getAttribute(attribute));
}
@ReactMethod
public void getHttpMetricAttributes(String url, String httpMethod, Promise promise) {
Map<String, String> attributes = getOrCreateHttpMetric(url, httpMethod).getAttributes();
WritableMap map = Arguments.createMap();
for (Map.Entry<String, String> entry : attributes.entrySet()) {
map.putString(entry.getKey(), entry.getValue());
}
promise.resolve(map);
}
@ReactMethod
public void putHttpMetricAttribute(String url, String httpMethod, String attribute, String value, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).putAttribute(attribute, value);
// Docs say it returns a bool, actually void so we internally check attributes
Map<String, String> attributes = getOrCreateHttpMetric(url, httpMethod).getAttributes();
if (attributes.containsKey(attribute)) {
promise.resolve( true);
} else {
promise.resolve(false);
}
}
@ReactMethod
public void removeHttpMetricAttribute(String url, String httpMethod, String attribute, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).removeAttribute(attribute);
promise.resolve(null);
}
@ReactMethod
public void setHttpMetricResponseCode(String url, String httpMethod, Integer code, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).setHttpResponseCode(code);
promise.resolve(null);
}
@ReactMethod
public void setHttpMetricRequestPayloadSize(String url, String httpMethod, Integer bytes, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).setRequestPayloadSize(bytes.longValue());
promise.resolve(null);
}
@ReactMethod
public void setHttpMetricResponseContentType(String url, String httpMethod, String type, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).setResponseContentType(type);
promise.resolve(null);
}
@ReactMethod
public void setHttpMetricResponsePayloadSize(String url, String httpMethod, Integer bytes, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).setResponsePayloadSize(bytes.longValue());
promise.resolve(null);
}
@ReactMethod
public void startHttpMetric(String url, String httpMethod, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).start();
promise.resolve(null);
}
@ReactMethod
public void stopHttpMetric(String url, String httpMethod, Promise promise) {
getOrCreateHttpMetric(url, httpMethod).stop();
httpMetrics.remove(url + httpMethod);
promise.resolve(null);
}
/**
* Private
*/
private Trace getOrCreateTrace(String identifier) {
if (traces.containsKey(identifier)) {
return traces.get(identifier);
@ -58,4 +204,39 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule {
traces.put(identifier, trace);
return trace;
}
private HttpMetric getOrCreateHttpMetric(String url, String httpMethod) {
String identifier = url + httpMethod;
if (httpMetrics.containsKey(identifier)) {
return httpMetrics.get(identifier);
}
HttpMetric httpMetric = FirebasePerformance.getInstance().newHttpMetric(url, this.mapStringToMethod(httpMethod));
httpMetrics.put(identifier, httpMetric);
return httpMetric;
}
private String mapStringToMethod(String value) {
switch (value) {
case "CONNECT":
return FirebasePerformance.HttpMethod.CONNECT;
case "DELETE":
return FirebasePerformance.HttpMethod.DELETE;
case "GET":
return FirebasePerformance.HttpMethod.GET;
case "HEAD":
return FirebasePerformance.HttpMethod.HEAD;
case "OPTIONS":
return FirebasePerformance.HttpMethod.OPTIONS;
case "PATCH":
return FirebasePerformance.HttpMethod.PATCH;
case "POST":
return FirebasePerformance.HttpMethod.POST;
case "PUT":
return FirebasePerformance.HttpMethod.PUT;
case "TRACE":
return FirebasePerformance.HttpMethod.TRACE;
}
return "";
}
}

View File

@ -41,7 +41,6 @@ import com.google.firebase.storage.OnProgressListener;
import io.invertase.firebase.Utils;
@SuppressWarnings("WeakerAccess")
public class RNFirebaseStorage extends ReactContextBaseJavaModule {
@ -111,17 +110,20 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
@ReactMethod
public void delete(String appName, final String path, final Promise promise) {
StorageReference reference = this.getReference(path, appName);
reference.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
promise.resolve(null);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
reference
.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
promise.resolve(null);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
}
/**
@ -162,17 +164,20 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
@ReactMethod
public void getMetadata(String appName, final String path, final Promise promise) {
StorageReference reference = this.getReference(path, appName);
reference.getMetadata().addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
@Override
public void onSuccess(StorageMetadata storageMetadata) {
promise.resolve(getMetadataAsMap(storageMetadata));
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
reference
.getMetadata()
.addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
@Override
public void onSuccess(StorageMetadata storageMetadata) {
promise.resolve(getMetadataAsMap(storageMetadata));
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
}
/**
@ -184,22 +189,30 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
*/
@ReactMethod
public void updateMetadata(String appName, final String path, final ReadableMap metadata, final Promise promise) {
public void updateMetadata(
String appName,
final String path,
final ReadableMap metadata,
final Promise promise
) {
StorageReference reference = this.getReference(path, appName);
StorageMetadata md = buildMetadataFromMap(metadata, null);
reference.updateMetadata(md).addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
@Override
public void onSuccess(StorageMetadata storageMetadata) {
WritableMap data = getMetadataAsMap(storageMetadata);
promise.resolve(data);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
reference
.updateMetadata(md)
.addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
@Override
public void onSuccess(StorageMetadata storageMetadata) {
WritableMap data = getMetadataAsMap(storageMetadata);
promise.resolve(data);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
promiseRejectStorageException(promise, exception);
}
});
}
@ -212,7 +225,12 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#downloadFile
*/
@ReactMethod
public void downloadFile(final String appName, final String path, final String localPath, final Promise promise) {
public void downloadFile(
final String appName,
final String path,
final String localPath,
final Promise promise
) {
if (!isExternalStorageWritable()) {
promise.reject(
"storage/invalid-device-file-path",
@ -225,59 +243,70 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
Log.d(TAG, "downloadFile path: " + path);
StorageReference reference = this.getReference(path, appName);
reference.getStream(new StreamDownloadTask.StreamProcessor() {
@Override
public void doInBackground(StreamDownloadTask.TaskSnapshot taskSnapshot, InputStream inputStream) throws IOException {
int indexOfLastSlash = localPath.lastIndexOf("/");
String pathMinusFileName = indexOfLastSlash > 0 ? localPath.substring(0, indexOfLastSlash) + "/" : "/";
String filename = indexOfLastSlash > 0 ? localPath.substring(indexOfLastSlash + 1) : localPath;
File fileWithJustPath = new File(pathMinusFileName);
reference
.getStream(new StreamDownloadTask.StreamProcessor() {
@Override
public void doInBackground(
StreamDownloadTask.TaskSnapshot taskSnapshot,
InputStream inputStream
) throws IOException {
int indexOfLastSlash = localPath.lastIndexOf("/");
String pathMinusFileName = indexOfLastSlash > 0 ? localPath.substring(
0,
indexOfLastSlash
) + "/" : "/";
String filename = indexOfLastSlash > 0 ? localPath.substring(indexOfLastSlash + 1) : localPath;
File fileWithJustPath = new File(pathMinusFileName);
// directoriesCreated assignment for not consumed warning
Boolean directoriesCreated = fileWithJustPath.mkdirs();
File fileWithFullPath = new File(pathMinusFileName, filename);
FileOutputStream output = new FileOutputStream(fileWithFullPath);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
// directoriesCreated assignment for not consumed warning
Boolean directoriesCreated = fileWithJustPath.mkdirs();
File fileWithFullPath = new File(pathMinusFileName, filename);
FileOutputStream output = new FileOutputStream(fileWithFullPath);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len;
while ((len = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, len);
int len;
while ((len = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
output.close();
}
output.close();
}
}).addOnProgressListener(new OnProgressListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onProgress(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile progress " + taskSnapshot);
WritableMap event = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
}).addOnPausedListener(new OnPausedListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onPaused(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile paused " + taskSnapshot);
WritableMap event = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
}).addOnSuccessListener(new OnSuccessListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile success" + taskSnapshot);
WritableMap resp = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_DOWNLOAD_SUCCESS, path, resp);
resp = getDownloadTaskAsMap(taskSnapshot);
promise.resolve(resp);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
Log.e(TAG, "downloadFile failure " + exception.getMessage());
// TODO sendJS error event
promiseRejectStorageException(promise, exception);
}
});
})
.addOnProgressListener(new OnProgressListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onProgress(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile progress " + taskSnapshot);
WritableMap event = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
})
.addOnPausedListener(new OnPausedListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onPaused(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile paused " + taskSnapshot);
WritableMap event = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
})
.addOnSuccessListener(new OnSuccessListener<StreamDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "downloadFile success" + taskSnapshot);
WritableMap resp = getDownloadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_DOWNLOAD_SUCCESS, path, resp);
resp = getDownloadTaskAsMap(taskSnapshot);
promise.resolve(resp);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
Log.e(TAG, "downloadFile failure " + exception.getMessage());
// TODO sendJS error event
promiseRejectStorageException(promise, exception);
}
});
}
/**
@ -332,7 +361,13 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putFile
*/
@ReactMethod
public void putFile(final String appName, final String path, final String localPath, final ReadableMap metadata, final Promise promise) {
public void putFile(
final String appName,
final String path,
final String localPath,
final ReadableMap metadata,
final Promise promise
) {
StorageReference reference = this.getReference(path, appName);
Log.i(TAG, "putFile: " + localPath + " to " + path);
@ -436,7 +471,9 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
private Uri getURI(final String uri) {
Uri parsed = Uri.parse(uri);
if (parsed.getScheme() == null || parsed.getScheme().isEmpty()) {
if (parsed.getScheme() == null || parsed
.getScheme()
.isEmpty()) {
return Uri.fromFile(new File(uri));
}
return parsed;
@ -470,14 +507,18 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
} else if (file != null) {
String mimeType = null;
if (file.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
if (file
.getScheme()
.equals(ContentResolver.SCHEME_CONTENT)) {
ContentResolver cr = getReactApplicationContext().getContentResolver();
mimeType = cr.getType(file);
} else {
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(file
.toString());
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
fileExtension.toLowerCase());
.toString());
mimeType = MimeTypeMap
.getSingleton()
.getMimeTypeFromExtension(
fileExtension.toLowerCase());
}
if (mimeType != null) metadataBuilder.setContentType(mimeType);
@ -498,7 +539,12 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
private WritableMap getDownloadTaskAsMap(final StreamDownloadTask.TaskSnapshot taskSnapshot) {
WritableMap resp = Arguments.createMap();
resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred());
resp.putString("ref", taskSnapshot.getStorage().getPath());
resp.putString(
"ref",
taskSnapshot
.getStorage()
.getPath()
);
resp.putString("state", this.getTaskStatus(taskSnapshot.getTask()));
resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount());
@ -512,29 +558,40 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @param taskSnapshot
* @return
*/
private void getUploadTaskAsMap(final UploadTask.TaskSnapshot taskSnapshot, final OnSuccessListener<WritableMap> listener) {
private void getUploadTaskAsMap(
final UploadTask.TaskSnapshot taskSnapshot,
final OnSuccessListener<WritableMap> listener
) {
if (taskSnapshot != null) {
taskSnapshot.getStorage().getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri downloadUrl) {
WritableMap resp = Arguments.createMap();
taskSnapshot
.getStorage()
.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri downloadUrl) {
WritableMap resp = Arguments.createMap();
resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred());
resp.putString("downloadURL", downloadUrl.toString());
resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred());
resp.putString("downloadURL", downloadUrl.toString());
StorageMetadata d = taskSnapshot.getMetadata();
if (d != null) {
WritableMap metadata = getMetadataAsMap(d);
resp.putMap("metadata", metadata);
StorageMetadata d = taskSnapshot.getMetadata();
if (d != null) {
WritableMap metadata = getMetadataAsMap(d);
resp.putMap("metadata", metadata);
}
resp.putString(
"ref",
taskSnapshot
.getStorage()
.getPath()
);
resp.putString("state", RNFirebaseStorage.this.getTaskStatus(taskSnapshot.getTask()));
resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount());
listener.onSuccess(resp);
}
resp.putString("ref", taskSnapshot.getStorage().getPath());
resp.putString("state", RNFirebaseStorage.this.getTaskStatus(taskSnapshot.getTask()));
resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount());
listener.onSuccess(resp);
}
});
});
} else {
listener.onSuccess(Arguments.createMap());
}
@ -683,10 +740,33 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put(DocumentDirectoryPath, this.getReactApplicationContext().getFilesDir().getAbsolutePath());
constants.put(TemporaryDirectoryPath, this.getReactApplicationContext().getCacheDir().getAbsolutePath());
constants.put(PicturesDirectoryPath, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
constants.put(CachesDirectoryPath, this.getReactApplicationContext().getCacheDir().getAbsolutePath());
constants.put(
DocumentDirectoryPath,
this
.getReactApplicationContext()
.getFilesDir()
.getAbsolutePath()
);
constants.put(
TemporaryDirectoryPath,
this
.getReactApplicationContext()
.getCacheDir()
.getAbsolutePath()
);
constants.put(
PicturesDirectoryPath,
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
.getAbsolutePath()
);
constants.put(
CachesDirectoryPath,
this
.getReactApplicationContext()
.getCacheDir()
.getAbsolutePath()
);
constants.put(FileTypeRegular, 0);
constants.put(FileTypeDirectory, 1);
@ -697,7 +777,9 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
constants.put(ExternalStorageDirectoryPath, null);
}
File externalDirectory = this.getReactApplicationContext().getExternalFilesDir(null);
File externalDirectory = this
.getReactApplicationContext()
.getExternalFilesDir(null);
if (externalDirectory != null) {
constants.put(ExternalDirectoryPath, externalDirectory.getAbsolutePath());
} else {

View File

@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.google.gms:google-services:4.0.1'
classpath 'com.google.firebase:firebase-plugins:1.1.1'
classpath 'com.google.firebase:firebase-plugins:1.1.5'
classpath 'io.fabric.tools:gradle:1.25.4'
}
}

View File

@ -0,0 +1,93 @@
describe('perf()', () => {
describe('HttpMetric', () => {
it('start() & stop()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.stop();
});
it('removeAttribute()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.putAttribute('foo', 'bar');
const value = await httpMetric.getAttribute('foo');
should.equal(value, 'bar');
await httpMetric.removeAttribute('foo');
const value2 = await httpMetric.getAttribute('foo');
should.equal(value2, null);
await httpMetric.stop();
});
it('getAttribute() should return null', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
const value = await httpMetric.getAttribute('foo');
should.equal(value, null);
await httpMetric.removeAttribute('foo');
await httpMetric.stop();
});
it('getAttribute() should return string value', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.putAttribute('foo', 'bar');
const value = await httpMetric.getAttribute('foo');
should.equal(value, 'bar');
await httpMetric.removeAttribute('foo');
await httpMetric.stop();
});
it('putAttribute()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.putAttribute('foo', 'bar');
const value = await httpMetric.getAttribute('foo');
value.should.equal('bar');
await httpMetric.removeAttribute('foo');
await httpMetric.stop();
});
it('getAttributes()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.putAttribute('foo', 'bar');
await httpMetric.putAttribute('bar', 'baz');
const value = await httpMetric.getAttributes();
value.should.deepEqual({
foo: 'bar',
bar: 'baz',
});
await httpMetric.removeAttribute('foo');
await httpMetric.removeAttribute('bar');
await httpMetric.stop();
});
it('setHttpResponseCode()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.setHttpResponseCode(500);
await httpMetric.stop();
});
it('setRequestPayloadSize()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.setRequestPayloadSize(1234567);
await httpMetric.stop();
});
it('setResponseContentType()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.setResponseContentType('application/foobar');
await httpMetric.stop();
});
it('setResponsePayloadSize()', async () => {
const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET');
await httpMetric.start();
await httpMetric.setResponsePayloadSize(123456789);
await httpMetric.stop();
});
});
});

View File

@ -8,9 +8,10 @@ describe('perf()', () => {
await firebase.perf().setPerformanceCollectionEnabled(false);
});
xit('errors if not boolean', async () => {
// TODO add validations to lib
await firebase.perf().setPerformanceCollectionEnabled();
it('errors if not boolean', async () => {
(() => firebase.perf().setPerformanceCollectionEnabled()).should.throw(
'firebase.perf().setPerformanceCollectionEnabled() requires a boolean value'
);
});
});
@ -20,15 +21,27 @@ describe('perf()', () => {
trace.constructor.name.should.be.equal('Trace');
});
xit('errors if identifier not a string', async () => {
// TODO add validations to lib
try {
firebase.perf().newTrace([1, 2, 3, 4]);
} catch (e) {
return undefined;
}
it('errors if identifier not a string', async () => {
(() => firebase.perf().newTrace([1, 2, 3, 4])).should.throw(
'firebase.perf().newTrace() requires a string value'
);
});
});
throw new Error('Trace did not error on invalid identifier');
describe('newHttpMetric()', () => {
it('returns an instance of HttpMetric', async () => {
const trace = firebase.perf().newHttpMetric('http://foo.com', 'GET');
trace.constructor.name.should.be.equal('HttpMetric');
});
it('errors if url/httpMethod not a string', async () => {
(() => firebase.perf().newHttpMetric(123, [1, 2])).should.throw(
'firebase.perf().newHttpMetric() requires url and httpMethod string values'
);
});
it('errors if httpMethod not a valid type', async () => {
(() => firebase.perf().newHttpMetric('foo', 'FOO')).should.throw(); // TODO error
});
});
});

View File

@ -6,23 +6,83 @@ describe('perf()', () => {
await trace.stop();
});
describe('incrementCounter()', () => {
it('accepts a string event', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.incrementCounter('fooby');
await trace.incrementCounter('fooby');
await trace.incrementCounter('fooby');
await trace.incrementCounter('fooby');
await trace.stop();
});
xit('errors if event is not a string', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.incrementCounter([1, 2, 3, 4]);
await trace.stop();
});
it('getAttribute() should return null', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
const value = await trace.getAttribute('foo');
should.equal(value, null);
await trace.stop();
});
it('getAttribute() should return string value', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putAttribute('foo', 'bar');
const value = await trace.getAttribute('foo');
should.equal(value, 'bar');
await trace.stop();
});
it('putAttribute()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putAttribute('foo', 'bar');
const value = await trace.getAttribute('foo');
value.should.equal('bar');
await trace.stop();
});
it('getAttributes()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putAttribute('foo', 'bar');
await trace.putAttribute('bar', 'baz');
const value = await trace.getAttributes();
value.should.deepEqual({
foo: 'bar',
bar: 'baz',
});
await trace.stop();
});
it('removeAttribute()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putAttribute('foobar', 'bar');
const value = await trace.getAttribute('foobar');
value.should.equal('bar');
await trace.removeAttribute('foobar');
const removed = await trace.getAttribute('foobar');
should.equal(removed, null);
await trace.stop();
});
it('getMetric()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
const metric = await trace.getMetric('foo');
metric.should.equal(0);
await trace.stop();
});
it('putMetric()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putMetric('baz', 1);
const metric = await trace.getMetric('baz');
metric.should.equal(1);
await trace.stop();
});
it('incrementMetric()', async () => {
const trace = firebase.perf().newTrace('bar');
await trace.start();
await trace.putMetric('baz', 1);
await trace.incrementMetric('baz', 2);
const metric = await trace.getMetric('baz');
metric.should.equal(3);
await trace.stop();
});
});
});

View File

@ -10,6 +10,7 @@
}
@property NSMutableDictionary *traces;
@property NSMutableDictionary *httpMetrics;
@end

View File

@ -2,6 +2,7 @@
#if __has_include(<FirebasePerformance/FIRPerformance.h>)
#import <FirebasePerformance/FIRPerformance.h>
#import <FirebasePerformance/FIRHTTPMetric.h>
@implementation RNFirebasePerformance
RCT_EXPORT_MODULE();
@ -9,10 +10,25 @@ RCT_EXPORT_MODULE();
self = [super init];
if (self != nil) {
_traces = [[NSMutableDictionary alloc] init];
_httpMetrics = [[NSMutableDictionary alloc] init];
}
return self;
}
- (FIRHTTPMethod) mapStringToMethod:(NSString *) value {
if ([value compare:@"get" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodGET;
if ([value compare:@"put" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPUT;
if ([value compare:@"post" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPUT;
if ([value compare:@"delete" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodDELETE;
if ([value compare:@"head" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodHEAD;
if ([value compare:@"patch" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPATCH;
if ([value compare:@"options" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodOPTIONS;
if ([value compare:@"trace" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodTRACE;
if ([value compare:@"connect" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodCONNECT;
return FIRHTTPMethodGET;
}
- (FIRTrace *)getOrCreateTrace:(NSString *)identifier {
if (_traces[identifier]) {
return _traces[identifier];
@ -22,27 +38,223 @@ RCT_EXPORT_MODULE();
return trace;
}
- (FIRHTTPMetric *)getOrCreateHttpMetric:(NSString *)url httpMethod:(NSString *) httpMethod {
NSString *identifier = [NSString stringWithFormat:@"%@%@", url, httpMethod];
if (_httpMetrics[identifier]) {
return _httpMetrics[identifier];
}
NSURL * toURL = [NSURL URLWithString:url];
FIRHTTPMethod method = [self mapStringToMethod:httpMethod];
FIRHTTPMetric *httpMetric = [[FIRHTTPMetric alloc] initWithURL:toURL HTTPMethod:method];
_httpMetrics[identifier] = httpMetric;
return httpMetric;
}
RCT_EXPORT_METHOD(setPerformanceCollectionEnabled:
(BOOL *) enabled) {
[FIRPerformance sharedInstance].dataCollectionEnabled = (BOOL) enabled;
}
RCT_EXPORT_METHOD(start:
(NSString *) identifier) {
/**
* Trace
*/
RCT_EXPORT_METHOD(startTrace:
(NSString *) identifier
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateTrace:identifier] start];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(stop:
(NSString *) identifier) {
RCT_EXPORT_METHOD(stopTrace:
(NSString *) identifier
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateTrace:identifier] stop];
_traces[identifier] = nil;
[_traces removeObjectForKey:identifier];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(incrementCounter:
(NSString *) identifier
event:
(NSString *) event) {
[[self getOrCreateTrace:identifier] incrementCounterNamed:event];
RCT_EXPORT_METHOD(getTraceAttribute:
(NSString *) identifier
attribute:(NSString *) attribute
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString *value = [[self getOrCreateTrace:identifier] valueForAttribute:attribute];
resolve(value ? value : [NSNull null]);
}
RCT_EXPORT_METHOD(getTraceAttributes:
(NSString *) identifier
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
resolve([[self getOrCreateTrace:identifier] attributes]);
}
RCT_EXPORT_METHOD(getTraceLongMetric:
(NSString *) identifier
metricName:(NSString *) metricName
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
int64_t value = [[self getOrCreateTrace:identifier] valueForIntMetric:metricName];
resolve(@(value));
}
RCT_EXPORT_METHOD(incrementTraceMetric:
(NSString *) identifier
metricName:(NSString *) metricName
incrementBy:(NSNumber *) incrementBy
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
int64_t byInt = [incrementBy intValue];
[[self getOrCreateTrace:identifier] incrementMetric:metricName byInt:byInt];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(putTraceAttribute:
(NSString *) identifier
attribute:(NSString *) attribute
value:(NSString *) value
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
FIRTrace * trace = [self getOrCreateTrace:identifier];
[trace setValue:value forAttribute:attribute];
if (trace.attributes[attribute] != nil) {
resolve(@(YES));
} else {
resolve(@(NO));
}
}
RCT_EXPORT_METHOD(putTraceMetric:
(NSString *) identifier
attribute:(NSString *) attribute
value:(NSNumber *) value
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
int64_t byInt = [value intValue];
[[self getOrCreateTrace:identifier] setIntValue:byInt forMetric:attribute];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(removeTraceAttribute:
(NSString *) identifier
attribute:(NSString *) attribute
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateTrace:identifier] removeAttribute:attribute];
resolve([NSNull null]);
}
/**
* HTTP Metric
*/
RCT_EXPORT_METHOD(startHttpMetric:
(NSString *) url
httpMethod:(NSString *) httpMethod
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] start];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(stopHttpMetric:
(NSString *) url
httpMethod:(NSString *) httpMethod
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] stop];
[_httpMetrics removeObjectForKey:[NSString stringWithFormat:@"%@%@", url, httpMethod]];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(getHttpMetricAttribute:
(NSString *) url
httpMethod:(NSString *) httpMethod
attribute:(NSString *) attribute
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString *value = [[self getOrCreateHttpMetric:url httpMethod:httpMethod] valueForAttribute:attribute];
resolve(value ? value : [NSNull null]);
}
RCT_EXPORT_METHOD(getHttpMetricAttributes:
(NSString *) url
httpMethod:(NSString *) httpMethod
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
resolve([[self getOrCreateHttpMetric:url httpMethod:httpMethod] attributes]);
}
RCT_EXPORT_METHOD(putHttpMetricAttribute:
(NSString *) url
httpMethod:(NSString *) httpMethod
attribute:(NSString *) attribute
value:(NSString *) value
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
FIRHTTPMetric * httpMetric = [self getOrCreateHttpMetric:url httpMethod:httpMethod];
[httpMetric setValue:value forAttribute:attribute];
if (httpMetric.attributes[attribute] != nil) {
resolve(@(YES));
} else {
resolve(@(NO));
}
}
RCT_EXPORT_METHOD(removeHttpMetricAttribute:
(NSString *) url
httpMethod:(NSString *) httpMethod
attribute:(NSString *) attribute
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] removeAttribute:attribute];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setHttpMetricResponseCode:
(NSString *) url
httpMethod:(NSString *) httpMethod
code:(NSNumber *) code
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponseCode:[code integerValue]];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setHttpMetricRequestPayloadSize:
(NSString *) url
httpMethod:(NSString *) httpMethod
bytes:(NSNumber *) bytes
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] setRequestPayloadSize:[bytes longLongValue]];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setHttpMetricResponseContentType:
(NSString *) url
httpMethod:(NSString *) httpMethod
type:(NSString *) type
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponseContentType:type];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setHttpMetricResponsePayloadSize:
(NSString *) url
httpMethod:(NSString *) httpMethod
bytes:(NSNumber *) bytes
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponsePayloadSize:[bytes longLongValue]];
resolve([NSNull null]);
}
+ (BOOL)requiresMainQueueSetup

133
lib/index.d.ts vendored
View File

@ -53,7 +53,7 @@ declare module 'react-native-firebase' {
RNFirebase.notifications.Notifications,
RNFirebase.notifications.NotificationsStatics
>;
// perf: FirebaseModuleAndStatics<RNFirebase.perf.Perf>;
perf: FirebaseModuleAndStatics<RNFirebase.perf.Perf>;
storage: FirebaseModuleAndStatics<RNFirebase.storage.Storage>;
// utils: FirebaseModuleAndStatics<RNFirebase.utils.Utils>;
initializeApp(options: Firebase.Options, name: string): App;
@ -90,7 +90,7 @@ declare module 'react-native-firebase' {
links(): RNFirebase.links.Links;
messaging(): RNFirebase.messaging.Messaging;
notifications(): RNFirebase.notifications.Notifications;
// perf(): RNFirebase.perf.Performance;
perf(): RNFirebase.perf.Perf;
storage(): RNFirebase.storage.Storage;
// utils(): RNFirebase.utils.Utils;
readonly name: string;
@ -1546,6 +1546,135 @@ declare module 'react-native-firebase' {
}
}
namespace perf {
type HttpMethod =
| 'CONNECT'
| 'DELETE'
| 'GET'
| 'HEAD'
| 'OPTIONS'
| 'PATCH'
| 'POST'
| 'PUT'
| 'TRACE';
interface Perf {
/**
* Globally enable or disable performance monitoring.
*/
setPerformanceCollectionEnabled(enabled: boolean): void;
/**
* Returns a new Trace instance.
*/
newTrace(trace: string): Trace;
/**
* Returns a new HTTP Metric instance.
*/
newHttpMetric(url: string, httpMethod: HttpMethod): HttpMetric;
}
interface Trace {
/**
* Return an attribute by name, or null if it does not exist.
*/
getAttribute(attribute: string): Promise<string | null>;
/**
* Return an object of key-value attributes.
*/
getAttributes(): Promise<Object>;
/**
* Get a metric by name. Returns 0 if it does not exist.
*/
getMetric(metricName: string): Promise<number>;
/**
* Increment a metric by name and value.
*/
incrementMetric(metricName: string, incrementBy: number): Promise<null>;
/**
* Set an attribute. Returns true if it was set, false if it was not.
*/
putAttribute(attribute: string, value: string): Promise<true | false>;
/**
* Set a metric.
*/
putMetric(metricName: string, value: number): Promise<null>;
/**
* Remove an attribute by name.
*/
removeAttribute(attribute: string): Promise<null>;
/**
* Start a Trace instance.
*/
start(): Promise<null>;
/**
* Stop a Trace instance.
*/
stop(): Promise<null>;
}
interface HttpMetric {
/**
* Return an attribute by name, or null if it does not exist.
*/
getAttribute(attribute: string): Promise<string | null>;
/**
* Return an object of key-value attributes.
*/
getAttributes(): Promise<Object>
/**
* Set an attribute. Returns true if it was set, false if it was not.
*/
putAttribute(attribute: string, value: string): Promise<true | false>;
/**
* Remove an attribute by name.
*/
removeAttribute(attribute: string): Promise<null>;
/**
* Set the request HTTP response code.
*/
setHttpResponseCode(code: number): Promise<null>;
/**
* Set the request payload size, in bytes.
*/
setRequestPayloadSize(bytes: number): Promise<null>;
/**
* Set the response content type.
*/
setResponseContentType(type: string): Promise<null>;
/**
* Set the response payload size, in bytes.
*/
setResponsePayloadSize(bytes: number): Promise<null>;
/**
* Start a HttpMetric instance.
*/
start(): Promise<null>;
/**
* Stop a HttpMetric instance.
*/
stop(): Promise<null>;
}
}
namespace crashlytics {
interface Crashlytics {
/**

View File

@ -0,0 +1,96 @@
/**
* @flow
* Trace representation wrapper
*/
import { getNativeModule } from '../../utils/native';
import type PerformanceMonitoring from './';
export default class HttpMetric {
url: string;
httpMethod: string;
_perf: PerformanceMonitoring;
constructor(perf: PerformanceMonitoring, url: string, httpMethod: string) {
this._perf = perf;
this.url = url;
this.httpMethod = httpMethod;
}
getAttribute(attribute: string): Promise<string | null> {
return getNativeModule(this._perf).getHttpMetricAttribute(
this.url,
this.httpMethod,
attribute
);
}
getAttributes(): Promise<Object> {
return getNativeModule(this._perf).getHttpMetricAttributes(
this.url,
this.httpMethod
);
}
putAttribute(attribute: string, value: string): Promise<true | false> {
return getNativeModule(this._perf).putHttpMetricAttribute(
this.url,
this.httpMethod,
attribute,
value
);
}
removeAttribute(attribute: string): Promise<null> {
return getNativeModule(this._perf).removeHttpMetricAttribute(
this.url,
this.httpMethod,
attribute
);
}
setHttpResponseCode(code: number): Promise<null> {
return getNativeModule(this._perf).setHttpMetricResponseCode(
this.url,
this.httpMethod,
code
);
}
setRequestPayloadSize(bytes: number): Promise<null> {
return getNativeModule(this._perf).setHttpMetricRequestPayloadSize(
this.url,
this.httpMethod,
bytes
);
}
setResponseContentType(type: string): Promise<null> {
return getNativeModule(this._perf).setHttpMetricResponseContentType(
this.url,
this.httpMethod,
type
);
}
setResponsePayloadSize(bytes: number): Promise<null> {
return getNativeModule(this._perf).setHttpMetricResponsePayloadSize(
this.url,
this.httpMethod,
bytes
);
}
start(): Promise<null> {
return getNativeModule(this._perf).startHttpMetric(
this.url,
this.httpMethod
);
}
stop(): Promise<null> {
return getNativeModule(this._perf).stopHttpMetric(
this.url,
this.httpMethod
);
}
}

View File

@ -14,15 +14,60 @@ export default class Trace {
this.identifier = identifier;
}
start(): void {
getNativeModule(this._perf).start(this.identifier);
getAttribute(attribute: string): Promise<string | null> {
return getNativeModule(this._perf).getTraceAttribute(
this.identifier,
attribute
);
}
stop(): void {
getNativeModule(this._perf).stop(this.identifier);
getAttributes(): Promise<Object> {
return getNativeModule(this._perf).getTraceAttributes(this.identifier);
}
incrementCounter(event: string): void {
getNativeModule(this._perf).incrementCounter(this.identifier, event);
getMetric(metricName: string): Promise<number> {
return getNativeModule(this._perf).getTraceLongMetric(
this.identifier,
metricName
);
}
incrementMetric(metricName: string, incrementBy: number): Promise<null> {
return getNativeModule(this._perf).incrementTraceMetric(
this.identifier,
metricName,
incrementBy
);
}
putAttribute(attribute: string, value: string): Promise<true | false> {
return getNativeModule(this._perf).putTraceAttribute(
this.identifier,
attribute,
value
);
}
putMetric(metricName: string, value: number): Promise<null> {
return getNativeModule(this._perf).putTraceMetric(
this.identifier,
metricName,
value
);
}
removeAttribute(attribute: string): Promise<null> {
return getNativeModule(this._perf).removeTraceAttribute(
this.identifier,
attribute
);
}
start(): Promise<null> {
return getNativeModule(this._perf).startTrace(this.identifier);
}
stop(): Promise<null> {
return getNativeModule(this._perf).stopTrace(this.identifier);
}
}

View File

@ -3,6 +3,7 @@
* Performance monitoring representation wrapper
*/
import Trace from './Trace';
import HttpMetric from './HttpMetric';
import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
@ -11,6 +12,29 @@ import type App from '../core/app';
export const MODULE_NAME = 'RNFirebasePerformance';
export const NAMESPACE = 'perf';
const HTTP_METHODS = {
CONNECT: true,
DELETE: true,
GET: true,
HEAD: true,
OPTIONS: true,
PATCH: true,
POST: true,
PUT: true,
TRACE: true,
};
type HttpMethod =
| 'CONNECT'
| 'DELETE'
| 'GET'
| 'HEAD'
| 'OPTIONS'
| 'PATCH'
| 'POST'
| 'PUT'
| 'TRACE';
export default class PerformanceMonitoring extends ModuleBase {
constructor(app: App) {
super(app, {
@ -27,7 +51,13 @@ export default class PerformanceMonitoring extends ModuleBase {
* @returns {*}
*/
setPerformanceCollectionEnabled(enabled: boolean): void {
getNativeModule(this).setPerformanceCollectionEnabled(enabled);
if (typeof enabled !== 'boolean') {
throw new Error(
'firebase.perf().setPerformanceCollectionEnabled() requires a boolean value'
);
}
return getNativeModule(this).setPerformanceCollectionEnabled(enabled);
}
/**
@ -35,8 +65,36 @@ export default class PerformanceMonitoring extends ModuleBase {
* @param trace
*/
newTrace(trace: string): Trace {
if (typeof trace !== 'string') {
throw new Error('firebase.perf().newTrace() requires a string value');
}
return new Trace(this, trace);
}
/**
* Return a new HttpMetric instance
* @param url
* @param httpMethod
* @returns {HttpMetric}
*/
newHttpMetric(url: string, httpMethod: HttpMethod): HttpMetric {
if (typeof url !== 'string' || typeof httpMethod !== 'string') {
throw new Error(
'firebase.perf().newHttpMetric() requires url and httpMethod string values'
);
}
if (!HTTP_METHODS[httpMethod]) {
throw new Error(
`firebase.perf().newHttpMetric() httpMethod should be one of ${Object.keys(
HTTP_METHODS
).join(', ')}`
);
}
return new HttpMetric(this, url, httpMethod);
}
}
export const statics = {};