merge master

This commit is contained in:
David Gruseck
2018-07-13 09:29:10 +02:00
89 changed files with 9582 additions and 8200 deletions

View File

@@ -1,20 +1,19 @@
---
name: ⚠️ Bug/Issue report
about: Please provide as much detail as possible to help us with a bug or issue. Issues
name: ⚠️ Bug/Issue report
about: Please provide as much detail as possible to help us with a bug or issue. Issues
will be closed if they do not follow the template.
---
<!---
BEFORE YOU MAKE AN ISSUE
The issue list of this repo is exclusively for bug reports.
1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests
2) For questions and support please use our Discord chat: https://discord.gg/C9aK28N or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
<!---
BEFORE YOU MAKE AN ISSUE
The issue list of this repo is exclusively for bug reports.
1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests
2) For questions and support please use our Discord chat: https://discord.gg/C9aK28N or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
-->
### Issue
@@ -23,29 +22,38 @@ The issue list of this repo is exclusively for bug reports.
### Environment
<!--- (e.g. iOS, Android, Both) --->
1. Application Target Platform:
<!--- (e.g. macOS Sierra, Windows 10) --->
<!--- (e.g. iOS, Android, Both) --->
2. Development Operating System:
<!--- (Xcode or Android Studio version, iOS or Android SDK version - if relevant) --->
<!--- (e.g. macOS Sierra, Windows 10) --->
3. Build Tools:
<!--- (e.g. 0.45.1) --->
<!--- (Xcode or Android Studio version, iOS or Android SDK version - if relevant) --->
4. React Native version:
4. `React Native` version:
<!--- (e.g. 2.1.3) --->
<!--- (e.g. 0.52.0) --->
5. RNFirebase Version:
5. `React Native Firebase` Version:
<!--- (e.g. 4.3.0) --->
6. `Firebase` Module:
<!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) --->
6. Firebase Module:
7. Are you using `typescript`?
<!-- Love react-native-firebase? Please consider supporting our collective:
👉 https://opencollective.com/react-native-firebase/donate -->
<!--- yes/no --->
---
Loving `react-native-firebase`? Please consider supporting them with any of the below:
* 👉 Back financially via [Open Collective](https://opencollective.com/react-native-firebase/donate)
* 👉 Follow [`React Native Firebase`](https://twitter.com/rnfirebase) and [`Invertase`](https://twitter.com/invertaseio) on Twitter
* 👉 Star this repo on GitHub ⭐️

View File

@@ -75,9 +75,15 @@ coverage
yarn.lock
tests
bridge/
lib/.watchmanconfig
buddybuild_postclone.sh
bin/test.js
.github
example
codorials
.vscode
.nyc_output
React-Native-Firebase.svg
CONTRIBUTING.md
CODE_OF_CONDUCT.md
android/.settings
README.md

View File

@@ -35,40 +35,40 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
> '**?**' indicates partial support
| Firebase Features | v2.2.x | v3.3.x | v4.0.x | Web SDK |
| -------------------------- | :----: | :----: | :----: | :-----: |
| **AdMob** | ✅ | ✅ | ✅ | ❌ |
| **Analytics**             | ✅ | ✅ | ✅ | ❌ |
| **App Indexing**           | ❌ | ❌ | ❌ | ❌ |
| **Authentication** | ✅ | ✅ | ✅ | ✅ |
| _-- Phone Auth_ | ❌ | ✅ | ✅ | ❌ |
| **Core** | **?** | ✅ | ✅ | ✅ |
| _-- Multiple Apps_ | ❌ | ✅ | ✅ | ✅ |
| **Cloud Firestore** | ❌ | ✅ | ✅ | **?** |
| **Cloud Messaging (FCM)** | **?** | **?** | ✅ | ❌ |
| **Crashlytics**           | ❌ | ✅ | ✅ | ❌ |
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
| **Dynamic Links** | ❌ | ✅ | ✅ | ❌ |
| **[Functions Callable](https://firebase.googleblog.com/2018/04/launching-cloud-functions-for-firebase-1-0.html?m=1)** | | | [v4.1+](https://github.com/invertase/react-native-firebase/milestone/6) | ✅ |
| **Invites** | ❌ | ❌ | ✅ | ❌ |
| **Instance ID**          | ❌ | ❌ | **?** | ❌ |
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
| _-- Offline Persistence_ | ✅ | ✅ | ✅ | **?** |
| **Remote Config** | ✅ | ✅ | ✅ | ❌ |
| **Storage** | ✅ | ✅ | ✅ | **?** |
| Firebase Features | v2.2.x | v3.3.x | v4.2.x | Web SDK |
| --------------------------------------------------------------------------------------------------------------------------------- | :----: | :----: | :----: | :-----: |
| **AdMob** | ✅ | ✅ | ✅ | ❌ |
| **Analytics**             | ✅ | ✅ | ✅ | ❌ |
| **App Indexing**           | ❌ | ❌ | ❌ | ❌ |
| **Authentication** | ✅ | ✅ | ✅ | ✅ |
| _-- Phone Auth_ | ❌ | ✅ | ✅ | ❌ |
| **Core** | **?** | ✅ | ✅ | ✅ |
| _-- Multiple Apps_ | ❌ | ✅ | ✅ | ✅ |
| **Cloud Firestore** | ❌ | ✅ | ✅ | **?** |
| **Cloud Messaging (FCM)** | **?** | **?** | ✅ | ❌ |
| **Crashlytics**           | ❌ | ✅ | ✅ | ❌ |
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
| **Dynamic Links** | ❌ | ✅ | ✅ | ❌ |
| **[Functions Callable](https://firebase.googleblog.com/2018/04/launching-cloud-functions-for-firebase-1-0.html?m=1)**             |    |    | |    |
| **Invites** | ❌ | ❌ | ✅ | ❌ |
| **Instance ID**          | ❌ | ❌ | **?** | ❌ |
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
| _-- Offline Persistence_ | ✅ | ✅ | ✅ | **?** |
| **Remote Config** | ✅ | ✅ | ✅ | ❌ |
| **Storage** | ✅ | ✅ | ✅ | **?** |
---
### Supported versions - React Native / Firebase
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`.
| | 2.2.x | 3.3.x | 4.0.x |
|------------------------|----------|----------|----------|
| React Native | 0.47 + | 0.50 + | 0.52 + |
| Firebase Android SDK | 11.0.0 + | 11.8.0 + | 12.0.0 + |
| Firebase iOS SDK | 4.0.0 + | 4.7.0 + | 4.11.0 + |
| | 2.2.x | 3.3.x | 4.0.x | 4.1.x | 4.2.x |
| -------------------- | -------- | -------- | -------- | -------- | --------- |
| React Native | 0.47 + | 0.50 + | 0.52 + | 0.52 + | 0.52-55.x |
| Firebase Android SDK | 11.0.0 + | 11.8.0 + | 12.0.0 + | 15.0.0 + | 15.0.0 + |
| Firebase iOS SDK | 4.0.0 + | 4.7.0 + | 4.11.0 + | 4.13.0 + | 5.0.0 + |
---

View File

@@ -1,14 +1,14 @@
buildscript {
repositories {
jcenter()
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0'
classpath 'io.fabric.tools:gradle:1.25.1'
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'io.fabric.tools:gradle:1.25.4'
}
}
@@ -17,7 +17,6 @@ apply plugin: 'com.android.library'
def DEFAULT_COMPILE_SDK_VERSION = 27
def DEFAULT_BUILD_TOOLS_VERSION = "27.0.3"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_FIREBASE_VERSION = "12.0.0"
def DEFAULT_SUPPORT_LIB_VERSION = "27.0.2"
android {
@@ -39,15 +38,6 @@ android {
}
}
allprojects {
repositories {
jcenter()
mavenLocal()
google()
}
}
rootProject.gradle.buildFinished { buildResult ->
if (buildResult.getFailure() != null) {
try {
@@ -82,28 +72,29 @@ rootProject.gradle.buildFinished { buildResult ->
}
}
def firebaseVersion = rootProject.hasProperty('googlePlayServicesVersion') ? rootProject.googlePlayServicesVersion : DEFAULT_FIREBASE_VERSION
def supportVersion = rootProject.hasProperty('supportLibVersion') ? rootProject.supportLibVersion : DEFAULT_SUPPORT_LIB_VERSION
dependencies {
// compile fileTree(include: ['*.jar'], dir: 'libs')
api "com.facebook.react:react-native:+" // From node_modules
api "com.android.support:support-v4:$supportVersion"
compileOnly 'me.leolin:ShortcutBadger:1.1.21@aar'
compileOnly "com.google.android.gms:play-services-base:$firebaseVersion"
compileOnly "com.google.firebase:firebase-core:$firebaseVersion"
compileOnly "com.google.firebase:firebase-config:$firebaseVersion"
compileOnly "com.google.firebase:firebase-auth:$firebaseVersion"
compileOnly "com.google.firebase:firebase-database:$firebaseVersion"
compileOnly "com.google.firebase:firebase-storage:$firebaseVersion"
compileOnly "com.google.firebase:firebase-messaging:$firebaseVersion"
compileOnly "com.google.firebase:firebase-crash:$firebaseVersion"
compileOnly "com.google.firebase:firebase-perf:$firebaseVersion"
compileOnly "com.google.firebase:firebase-ads:$firebaseVersion"
compileOnly "com.google.firebase:firebase-firestore:$firebaseVersion"
compileOnly "com.google.firebase:firebase-invites:$firebaseVersion"
compileOnly "com.google.firebase:firebase-functions:$firebaseVersion"
compileOnly('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
// Firebase SDKs
compileOnly('com.crashlytics.sdk.android:crashlytics:2.9.3@aar') {
transitive = true
}
compileOnly "com.google.android.gms:play-services-base:15.0.1"
compileOnly "com.google.firebase:firebase-ads:15.0.1"
compileOnly "com.google.firebase:firebase-auth:16.0.2"
compileOnly "com.google.firebase:firebase-config:16.0.0"
compileOnly "com.google.firebase:firebase-core:16.0.1"
compileOnly "com.google.firebase:firebase-crash:16.0.1"
compileOnly "com.google.firebase:firebase-database:16.0.1"
compileOnly "com.google.firebase:firebase-firestore:17.0.2"
compileOnly "com.google.firebase:firebase-functions:16.0.1"
compileOnly "com.google.firebase:firebase-invites:16.0.1"
compileOnly "com.google.firebase:firebase-storage:16.0.1"
compileOnly "com.google.firebase:firebase-messaging:17.1.0"
compileOnly "com.google.firebase:firebase-perf:16.0.0"
compileOnly 'me.leolin:ShortcutBadger:1.1.21@aar'
}

View File

@@ -69,11 +69,21 @@ public class Utils {
case "java.lang.String":
map.putString(key, (String) value);
break;
case "org.json.JSONObject$1":
map.putString(key, value.toString());
break;
default:
if (List.class.isAssignableFrom(value.getClass())) {
map.putArray(key, Arguments.makeNativeArray((List<Object>) value));
} else if (Map.class.isAssignableFrom(value.getClass())) {
map.putMap(key, Arguments.makeNativeMap((Map<String, Object>) value));
WritableMap childMap = Arguments.createMap();
Map<String, Object> valueMap = (Map<String, Object>) value;
for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
mapPutValue(entry.getKey(), entry.getValue(), childMap);
}
map.putMap(key, childMap);
} else {
Log.d(TAG, "utils:mapPutValue:unknownType:" + type);
map.putNull(key);

View File

@@ -41,7 +41,7 @@ import com.google.firebase.auth.GithubAuthProvider;
import com.google.firebase.auth.OAuthProvider;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;
import com.google.firebase.auth.ProviderQueryResult;
import com.google.firebase.auth.SignInMethodQueryResult;
import com.google.firebase.auth.TwitterAuthProvider;
import com.google.firebase.auth.UserInfo;
import com.google.firebase.auth.UserProfileChangeRequest;
@@ -55,10 +55,12 @@ import com.google.firebase.auth.EmailAuthProvider;
import io.invertase.firebase.Utils;
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "JavaDoc"})
class RNFirebaseAuth extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseAuth";
private String mVerificationId;
private String mLastPhoneNumber;
private PhoneAuthProvider.ForceResendingToken mForceResendingToken;
private PhoneAuthCredential mCredential;
private ReactContext mReactContext;
private HashMap<String, FirebaseAuth.AuthStateListener> mAuthListeners = new HashMap<>();
@@ -203,7 +205,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
signInAnonymously(appName, promise, true);
}
public void signInAnonymously(String appName, final Promise promise, final boolean withData) {
private void signInAnonymously(String appName, final Promise promise, final boolean withData) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -246,7 +248,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
createUserWithEmailAndPassword(appName, email, password, promise, true);
}
public void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
private void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
Log.d(TAG, "createUserWithEmailAndPassword");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -289,7 +291,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
signInWithEmailAndPassword(appName, email, password, promise, true);
}
public void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
private void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
Log.d(TAG, "signInWithEmailAndPassword");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -315,6 +317,37 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
});
}
/**
* Signs in using an email and sign-in email link.
*
* @param appName
* @param email
* @param emailLink
* @param promise
*/
@ReactMethod
private void signInWithEmailLink(String appName, final String email, final String emailLink, final Promise promise) {
Log.d(TAG, "signInWithEmailLink");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
firebaseAuth.signInWithEmailLink(email, emailLink)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Log.d(TAG, "signInWithEmailLink:onComplete:success");
promiseWithAuthResult(authResult, promise);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception);
promiseRejectAuthException(promise, exception);
}
});
}
@ReactMethod
public void signInWithCustomToken(String appName, final String token, final Promise promise) {
@@ -327,7 +360,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
signInWithCustomToken(appName, token, promise, true);
}
public void signInWithCustomToken(String appName, final String token, final Promise promise, final boolean withData) {
private void signInWithCustomToken(String appName, final String token, final Promise promise, final boolean withData) {
Log.d(TAG, "signInWithCustomToken");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -360,8 +393,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
* @param promise
*/
@ReactMethod
public void sendPasswordResetEmail(String appName, final String email,
ReadableMap actionCodeSettings, final Promise promise) {
public void sendPasswordResetEmail(String appName, final String email, ReadableMap actionCodeSettings, final Promise promise) {
Log.d(TAG, "sendPasswordResetEmail");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -388,6 +420,39 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
}
/**
* sendSignInLinkToEmail
*
* @param email
* @param promise
*/
@ReactMethod
public void sendSignInLinkToEmail(String appName, String email, ReadableMap actionCodeSettings, final Promise promise) {
Log.d(TAG, "sendSignInLinkToEmail");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
OnCompleteListener<Void> listener = new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "sendSignInLinkToEmail:onComplete:success");
promiseNoUser(promise, false);
} else {
Exception exception = task.getException();
Log.e(TAG, "sendSignInLinkToEmail:onComplete:failure", exception);
promiseRejectAuthException(promise, exception);
}
}
};
ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings);
firebaseAuth.sendSignInLinkToEmail(email, settings).addOnCompleteListener(listener);
}
/* ----------------------
* .currentUser methods
* ---------------------- */
@@ -395,7 +460,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
/**
* delete
*
* @param promise
* @param promise Promise
*/
@ReactMethod
public void delete(String appName, final Promise promise) {
@@ -628,7 +693,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
signInWithCredential(appName, provider, authToken, authSecret, promise, true);
}
public void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
private void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -666,76 +731,105 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
* @param phoneNumber
*/
@ReactMethod
public void signInWithPhoneNumber(String appName, final String phoneNumber, final Promise promise) {
public void signInWithPhoneNumber(String appName, final String phoneNumber, final boolean forceResend, final Promise promise) {
Log.d(TAG, "signInWithPhoneNumber");
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
Activity activity = mReactContext.getCurrentActivity();
// reset force resending token if phone number changes
if (!phoneNumber.equals(mLastPhoneNumber)) {
mForceResendingToken = null;
mLastPhoneNumber = phoneNumber;
}
// Reset the verification Id
mVerificationId = null;
PhoneAuthProvider.getInstance(firebaseAuth).verifyPhoneNumber(phoneNumber, 60, TimeUnit.SECONDS,
mReactContext.getCurrentActivity(), new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
private boolean promiseResolved = false;
PhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
private boolean promiseResolved = false;
@Override
public void onVerificationCompleted(final PhoneAuthCredential phoneAuthCredential) {
// User has been automatically verified, log them in
firebaseAuth.signInWithCredential(phoneAuthCredential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// onAuthStateChanged will pick up the user change
Log.d(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:success");
// To ensure that there is no hanging promise, we resolve it with a null verificationId
// as calling ConfirmationResult.confirm(code) is invalid in this case anyway
if (!promiseResolved) {
WritableMap verificationMap = Arguments.createMap();
verificationMap.putNull("verificationId");
promise.resolve(verificationMap);
}
} else {
// With phone auth, the credential will only every be rejected if the user
// account linked to the phone number has been disabled
Exception exception = task.getException();
Log.e(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:failure", exception);
if (promiseResolved) {
// In the scenario where an SMS code has been sent, we have no way to report
// back to the front-end that as the promise has already been used
} else {
promiseRejectAuthException(promise, exception);
}
@Override
public void onVerificationCompleted(final PhoneAuthCredential phoneAuthCredential) {
// User has been automatically verified, log them in
firebaseAuth.signInWithCredential(phoneAuthCredential)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// onAuthStateChanged will pick up the user change
Log.d(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:success");
// To ensure that there is no hanging promise, we resolve it with a null verificationId
// as calling ConfirmationResult.confirm(code) is invalid in this case anyway
if (!promiseResolved) {
WritableMap verificationMap = Arguments.createMap();
verificationMap.putNull("verificationId");
promise.resolve(verificationMap);
}
} else {
// With phone auth, the credential will only every be rejected if the user
// account linked to the phone number has been disabled
Exception exception = task.getException();
Log.e(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:failure", exception);
// In the scenario where an SMS code has been sent, we have no way to report
// back to the front-end that as the promise has already been used
if (!promiseResolved) {
promiseRejectAuthException(promise, exception);
}
}
});
}
}
});
}
@Override
public void onVerificationFailed(FirebaseException e) {
// This callback is invoked in an invalid request for verification is made,
// e.g. phone number format is incorrect, or the SMS quota for the project
// has been exceeded
Log.d(TAG, "signInWithPhoneNumber:verification:failed");
promiseRejectAuthException(promise, e);
}
@Override
public void onVerificationFailed(FirebaseException e) {
// This callback is invoked in an invalid request for verification is made,
// e.g. phone number format is incorrect, or the SMS quota for the project
// has been exceeded
Log.d(TAG, "signInWithPhoneNumber:verification:failed");
promiseRejectAuthException(promise, e);
}
@Override
public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
// TODO: This isn't being saved anywhere if the activity gets restarted when going to the SMS app
mVerificationId = verificationId;
WritableMap verificationMap = Arguments.createMap();
verificationMap.putString("verificationId", verificationId);
promise.resolve(verificationMap);
promiseResolved = true;
}
@Override
public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
// TODO: This isn't being saved anywhere if the activity gets restarted when going to the SMS app
mVerificationId = verificationId;
mForceResendingToken = forceResendingToken;
WritableMap verificationMap = Arguments.createMap();
verificationMap.putString("verificationId", verificationId);
promise.resolve(verificationMap);
promiseResolved = true;
}
@Override
public void onCodeAutoRetrievalTimeOut(String verificationId) {
super.onCodeAutoRetrievalTimeOut(verificationId);
// Purposefully not doing anything with this at the moment
}
});
@Override
public void onCodeAutoRetrievalTimeOut(String verificationId) {
super.onCodeAutoRetrievalTimeOut(verificationId);
// Purposefully not doing anything with this at the moment
}
};
if (activity != null) {
if (forceResend && mForceResendingToken != null) {
PhoneAuthProvider.getInstance(firebaseAuth)
.verifyPhoneNumber(
phoneNumber,
60,
TimeUnit.SECONDS,
activity,
callbacks,
mForceResendingToken
);
} else {
PhoneAuthProvider.getInstance(firebaseAuth)
.verifyPhoneNumber(
phoneNumber,
60,
TimeUnit.SECONDS,
activity,
callbacks
);
}
}
}
@ReactMethod
@@ -769,13 +863,19 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
* @param timeout
*/
@ReactMethod
public void verifyPhoneNumber(final String appName, final String phoneNumber, final String requestKey, final int timeout) {
public void verifyPhoneNumber(final String appName, final String phoneNumber, final String requestKey, final int timeout, final boolean forceResend) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
final Activity activity = mReactContext.getCurrentActivity();
Log.d(TAG, "verifyPhoneNumber:" + phoneNumber);
// reset force resending token if phone number changes
if (!phoneNumber.equals(mLastPhoneNumber)) {
mForceResendingToken = null;
mLastPhoneNumber = phoneNumber;
}
// Reset the credential
mCredential = null;
@@ -820,9 +920,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
@Override
public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) {
Log.d(TAG, "verifyPhoneNumber:verification:onCodeSent");
mForceResendingToken = forceResendingToken;
WritableMap state = Arguments.createMap();
state.putString("verificationId", verificationId);
// todo forceResendingToken - it's actually just an empty class ... no actual token >.>
// Parcel parcel = Parcel.obtain();
// forceResendingToken.writeToParcel(parcel, 0);
@@ -850,15 +952,26 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
};
if (activity != null) {
PhoneAuthProvider.getInstance(firebaseAuth)
.verifyPhoneNumber(
phoneNumber,
timeout,
TimeUnit.SECONDS,
activity,
callbacks
//, PhoneAuthProvider.ForceResendingToken.zzboe() // TODO FORCE RESENDING
);
if (forceResend && mForceResendingToken != null) {
PhoneAuthProvider.getInstance(firebaseAuth)
.verifyPhoneNumber(
phoneNumber,
timeout,
TimeUnit.SECONDS,
activity,
callbacks,
mForceResendingToken
);
} else {
PhoneAuthProvider.getInstance(firebaseAuth)
.verifyPhoneNumber(
phoneNumber,
timeout,
TimeUnit.SECONDS,
activity,
callbacks
);
}
}
}
@@ -961,6 +1074,9 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
case ActionCodeResult.PASSWORD_RESET:
actionType = "PASSWORD_RESET";
break;
case ActionCodeResult.SIGN_IN_WITH_EMAIL_LINK:
actionType = "EMAIL_SIGNIN";
break;
}
writableMap.putString("actionType", actionType);
@@ -1067,7 +1183,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
reauthenticate(appName, provider, authToken, authSecret, promise, true);
}
public void reauthenticate(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
private void reauthenticate(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
@@ -1131,7 +1247,13 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
return PhoneAuthProvider.getCredential(authToken, authSecret);
case "password":
// authToken = email
// authSecret = password
return EmailAuthProvider.getCredential(authToken, authSecret);
case "emailLink":
// authToken = email
// authSecret = link
return EmailAuthProvider.getCredentialWithLink(authToken, authSecret);
default:
return null;
}
@@ -1166,19 +1288,19 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
@ReactMethod
public void fetchProvidersForEmail(String appName, String email, final Promise promise) {
public void fetchSignInMethodsForEmail(String appName, String email, final Promise promise) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
Log.d(TAG, "fetchProvidersForEmail");
firebaseAuth.fetchProvidersForEmail(email)
.addOnCompleteListener(new OnCompleteListener<ProviderQueryResult>() {
firebaseAuth.fetchSignInMethodsForEmail(email)
.addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
@Override
public void onComplete(@NonNull Task<ProviderQueryResult> task) {
public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "fetchProvidersForEmail:onComplete:success");
List<String> providers = task.getResult().getProviders();
List<String> providers = task.getResult().getSignInMethods();
WritableArray array = Arguments.createArray();
if (providers != null) {
@@ -1282,8 +1404,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
WritableMap additionalUserInfoMap = Arguments.createMap();
additionalUserInfoMap.putBoolean("isNewUser", authResult.getAdditionalUserInfo().isNewUser());
if (authResult.getAdditionalUserInfo().getProfile() != null) {
WritableMap profileMap = mapToWritableMap(authResult.getAdditionalUserInfo().getProfile());
additionalUserInfoMap.putMap("profile", profileMap);
Utils.mapPutValue("profile", authResult.getAdditionalUserInfo().getProfile(), additionalUserInfoMap);
}
if (authResult.getAdditionalUserInfo().getProviderId() != null) {
additionalUserInfoMap.putString("providerId", authResult.getAdditionalUserInfo().getProviderId());
@@ -1300,65 +1421,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
}
private WritableMap mapToWritableMap(Map<String, Object> map) {
WritableMap writableMap = Arguments.createMap();
for (String key : map.keySet()) {
Object value = map.get(key);
if (value == null) {
writableMap.putNull(key);
} else if (value instanceof Boolean) {
writableMap.putBoolean(key, (Boolean) value);
} else if (value instanceof Integer) {
writableMap.putDouble(key, ((Integer) value).doubleValue());
} else if (value instanceof Long) {
writableMap.putDouble(key, ((Long) value).doubleValue());
} else if (value instanceof Double) {
writableMap.putDouble(key, (Double) value);
} else if (value instanceof Float) {
writableMap.putDouble(key, ((Float) value).doubleValue());
} else if (value instanceof String) {
writableMap.putString(key, (String) value);
} else if (Map.class.isAssignableFrom(value.getClass())) {
writableMap.putMap(key, mapToWritableMap((Map<String, Object>) value));
} else if (List.class.isAssignableFrom(value.getClass())) {
writableMap.putArray(key, listToWritableArray((List<Object>) value));
} else {
Log.e(TAG, "mapToWritableMap: Cannot convert object of type " + value.getClass());
}
}
return writableMap;
}
private WritableArray listToWritableArray(List<Object> list) {
WritableArray writableArray = Arguments.createArray();
for (Object item : list) {
if (item == null) {
writableArray.pushNull();
} else if (item instanceof Boolean) {
writableArray.pushBoolean((Boolean) item);
} else if (item instanceof Integer) {
writableArray.pushDouble(((Integer) item).doubleValue());
} else if (item instanceof Long) {
writableArray.pushDouble(((Long) item).doubleValue());
} else if (item instanceof Double) {
writableArray.pushDouble((Double) item);
} else if (item instanceof Float) {
writableArray.pushDouble(((Float) item).doubleValue());
} else if (item instanceof String) {
writableArray.pushString((String) item);
} else if (Map.class.isAssignableFrom(item.getClass())) {
writableArray.pushMap(mapToWritableMap((Map<String, Object>) item));
} else if (List.class.isAssignableFrom(item.getClass())) {
writableArray.pushArray(listToWritableArray((List<Object>) item));
} else {
Log.e(TAG, "listToWritableArray: Cannot convert object of type " + item.getClass());
}
}
return writableArray;
}
/**
* promiseRejectAuthException
*
@@ -1387,7 +1449,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
error.putString("nativeErrorCode", code);
message = authException.getMessage();
} catch (Exception e) {
Matcher matcher = Pattern.compile("\\[(.*):.*\\]").matcher(message);
Matcher matcher = Pattern.compile("([A-Z]*_[A-Z]*)").matcher(message);
if (matcher.find()) {
code = matcher.group(1).trim();
switch (code) {
@@ -1439,6 +1501,10 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
case "OPERATION_NOT_ALLOWED":
message = "This operation is not allowed. You must enable this service in the console.";
break;
case "INVALID_IDENTIFIER":
code = "INVALID_EMAIL";
message = invalidEmail;
break;
}
}
}
@@ -1576,7 +1642,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
ReadableMap ios = actionCodeSettings.getMap("iOS");
String url = actionCodeSettings.getString("url");
if (android != null) {
boolean installApp = android.hasKey("installApp") ? android.getBoolean("installApp") : false;
boolean installApp = android.hasKey("installApp") && android.getBoolean("installApp");
String minimumVersion = android.hasKey("minimumVersion") ? android.getString("minimumVersion") : null;
String packageName = android.getString("packageName");
builder = builder.setAndroidPackageName(packageName, installApp, minimumVersion);

View File

@@ -500,7 +500,12 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) {
FirebaseDatabase firebaseDatabase;
if(dbURL != null && dbURL.length() > 0) {
firebaseDatabase = FirebaseDatabase.getInstance(dbURL);
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);

View File

@@ -91,9 +91,10 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
@ReactMethod
public void collectionGet(String appName, String path, ReadableArray filters,
ReadableArray orders, ReadableMap options, final Promise promise) {
ReadableArray orders, ReadableMap options, ReadableMap getOptions,
final Promise promise) {
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
ref.get(promise);
ref.get(getOptions, promise);
}
@ReactMethod
@@ -165,14 +166,9 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
}
@ReactMethod
public void documentGet(String appName, String path, final Promise promise) {
public void documentGet(String appName, String path, ReadableMap getOptions, final Promise promise) {
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
ref.get(promise);
}
@ReactMethod
public void documentGetAll(String appName, ReadableArray documents, final Promise promise) {
// Not supported on Android out of the box
ref.get(getOptions, promise);
}
@ReactMethod
@@ -205,12 +201,18 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
FirebaseFirestoreSettings.Builder firestoreSettings = new FirebaseFirestoreSettings.Builder();
if (settings.hasKey("host")) {
firestoreSettings.setHost(settings.getString("host"));
} else {
firestoreSettings.setHost(firestore.getFirestoreSettings().getHost());
}
if (settings.hasKey("persistence")) {
firestoreSettings.setPersistenceEnabled(settings.getBoolean("persistence"));
} else {
firestoreSettings.setPersistenceEnabled(firestore.getFirestoreSettings().isPersistenceEnabled());
}
if (settings.hasKey("ssl")) {
firestoreSettings.setSslEnabled(settings.getBoolean("ssl"));
} else {
firestoreSettings.setSslEnabled(firestore.getFirestoreSettings().isSslEnabled());
}
if (settings.hasKey("timestampsInSnapshots")) {
// TODO: Not supported on Android yet

View File

@@ -12,15 +12,15 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.DocumentListenOptions;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FieldPath;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.MetadataChanges;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QueryListenOptions;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.firebase.firestore.Source;
import java.util.ArrayList;
import java.util.HashMap;
@@ -53,8 +53,21 @@ public class RNFirebaseFirestoreCollectionReference {
this.reactContext = reactContext;
}
void get(final Promise promise) {
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
void get(ReadableMap getOptions, final Promise promise) {
Source source;
if (getOptions != null && getOptions.hasKey("source")) {
String optionsSource = getOptions.getString("source");
if ("server".equals(optionsSource)) {
source = Source.SERVER;
} else if ("cache".equals(optionsSource)) {
source = Source.CACHE;
} else {
source = Source.DEFAULT;
}
} else {
source = Source.DEFAULT;
}
query.get(source).addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
@@ -92,19 +105,17 @@ public class RNFirebaseFirestoreCollectionReference {
}
}
};
QueryListenOptions options = new QueryListenOptions();
if (queryListenOptions != null) {
if (queryListenOptions.hasKey("includeDocumentMetadataChanges")
&& queryListenOptions.getBoolean("includeDocumentMetadataChanges")) {
options.includeDocumentMetadataChanges();
}
if (queryListenOptions.hasKey("includeQueryMetadataChanges")
&& queryListenOptions.getBoolean("includeQueryMetadataChanges")) {
options.includeQueryMetadataChanges();
}
MetadataChanges metadataChanges;
if (queryListenOptions != null
&& queryListenOptions.hasKey("includeMetadataChanges")
&& queryListenOptions.getBoolean("includeMetadataChanges")) {
metadataChanges = MetadataChanges.INCLUDE;
} else {
metadataChanges = MetadataChanges.EXCLUDE;
}
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(options, listener);
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(metadataChanges, listener);
collectionSnapshotListeners.put(listenerId, listenerRegistration);
}
}

View File

@@ -10,13 +10,14 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.DocumentListenOptions;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.MetadataChanges;
import com.google.firebase.firestore.SetOptions;
import com.google.firebase.firestore.Source;
import java.util.HashMap;
import java.util.Map;
@@ -55,8 +56,21 @@ public class RNFirebaseFirestoreDocumentReference {
});
}
void get(final Promise promise) {
this.ref.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
void get(final ReadableMap getOptions, final Promise promise) {
Source source;
if (getOptions != null && getOptions.hasKey("source")) {
String optionsSource = getOptions.getString("source");
if ("server".equals(optionsSource)) {
source = Source.SERVER;
} else if ("cache".equals(optionsSource)) {
source = Source.CACHE;
} else {
source = Source.DEFAULT;
}
} else {
source = Source.DEFAULT;
}
this.ref.get(source).addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
@@ -94,11 +108,15 @@ public class RNFirebaseFirestoreDocumentReference {
}
}
};
DocumentListenOptions options = new DocumentListenOptions();
if (docListenOptions != null && docListenOptions.hasKey("includeMetadataChanges") && docListenOptions.getBoolean("includeMetadataChanges")) {
options.includeMetadataChanges();
MetadataChanges metadataChanges;
if (docListenOptions != null
&& docListenOptions.hasKey("includeMetadataChanges")
&& docListenOptions.getBoolean("includeMetadataChanges")) {
metadataChanges = MetadataChanges.INCLUDE;
} else {
metadataChanges = MetadataChanges.EXCLUDE;
}
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(options, listener);
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(metadataChanges, listener);
documentSnapshotListeners.put(listenerId, listenerRegistration);
}
}

View File

@@ -1,6 +1,8 @@
package io.invertase.firebase.instanceid;
import java.io.IOException;
import android.util.Log;
import com.facebook.react.bridge.Promise;
@@ -42,4 +44,26 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule {
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);
Log.d(TAG, "Firebase token for " + authorizedEntity + ": " + token);
promise.resolve(token);
} catch (IOException e) {
promise.reject("iid/request-failed", "getToken request failed", e);
}
}
@ReactMethod
public void deleteToken(String authorizedEntity, String scope, Promise promise) {
try {
FirebaseInstanceId.getInstance().deleteToken(authorizedEntity, scope);
Log.d(TAG, "Firebase token deleted for " + authorizedEntity);
promise.resolve(null);
} catch (IOException e) {
promise.reject("iid/request-failed", "deleteToken request failed", e);
}
}
}

View File

@@ -140,13 +140,13 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act
ib = ib.setAdditionalReferralParameters(arpMap);
}
if (androidMap.hasKey("emailHtmlContent")) {
ib = ib.setEmailHtmlContent(invitationMap.getString("emailHtmlContent"));
ib = ib.setEmailHtmlContent(androidMap.getString("emailHtmlContent"));
}
if (androidMap.hasKey("emailSubject")) {
ib = ib.setEmailSubject(invitationMap.getString("emailSubject"));
ib = ib.setEmailSubject(androidMap.getString("emailSubject"));
}
if (androidMap.hasKey("googleAnalyticsTrackingId")) {
ib = ib.setGoogleAnalyticsTrackingId(invitationMap.getString("googleAnalyticsTrackingId"));
ib = ib.setGoogleAnalyticsTrackingId(androidMap.getString("googleAnalyticsTrackingId"));
}
}

View File

@@ -174,7 +174,11 @@ 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) {
return FirebaseAppInvite.getInvitation(pendingDynamicLinkData) != null;
FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData);
if (invite != null && invite.getInvitationId() != null && !invite.getInvitationId().isEmpty()) {
return true;
}
return false;
}
private DynamicLink.Builder getDynamicLinkBuilder(final ReadableMap linkData) {

View File

@@ -4,7 +4,9 @@ import android.content.BroadcastReceiver;
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.util.Log;
import com.facebook.react.bridge.Promise;
@@ -14,6 +16,8 @@ import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.RemoteMessage;
@@ -56,7 +60,8 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
// Non Web SDK methods
@ReactMethod
public void hasPermission(Promise promise) {
promise.resolve(true);
Boolean enabled = NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled();
promise.resolve(enabled);
}
@ReactMethod
@@ -96,15 +101,37 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
}
@ReactMethod
public void subscribeToTopic(String topic, Promise promise) {
FirebaseMessaging.getInstance().subscribeToTopic(topic);
promise.resolve(null);
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);
}
}
});
}
@ReactMethod
public void unsubscribeFromTopic(String topic, Promise promise) {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic);
promise.resolve(null);
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);
}
}
});
}
private class MessageReceiver extends BroadcastReceiver {

View File

@@ -142,12 +142,19 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
if (android.containsKey("contentInfo")) {
nb = nb.setContentInfo(android.getString("contentInfo"));
}
if (notification.containsKey("defaults")) {
double[] defaultsArray = android.getDoubleArray("defaults");
int defaults = 0;
for (Double d : defaultsArray) {
defaults |= d.intValue();
if (android.containsKey("defaults")) {
Double defaultValues = android.getDouble("defaults");
int defaults = defaultValues.intValue();
if (defaults == 0) {
ArrayList<Integer> defaultsArray = android.getIntegerArrayList("defaults");
if(defaultsArray != null) {
for (Integer defaultValue : defaultsArray) {
defaults |= defaultValue;
}
}
}
nb = nb.setDefaults(defaults);
}
if (android.containsKey("group")) {
@@ -200,7 +207,7 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
nb = nb.setPriority(priority.intValue());
}
if (android.containsKey("progress")) {
Bundle progress = android.getBundle("lights");
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"));
@@ -288,6 +295,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
if (reactContext != null) {
Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification));
}
if (promise != null) {
promise.resolve(null);
}
} catch (Exception e) {
Log.e(TAG, "Failed to send notification", e);
if (promise != null) {
@@ -299,9 +311,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
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 = createIntent(intentClass, notification, actionKey);
PendingIntent actionIntent = showUserInterface ?
createIntent(intentClass, notification, actionKey) :
createBroadcastIntent(notification, actionKey);
int icon = getIcon(action.getString("icon"));
String title = action.getString("title");
@@ -339,10 +353,21 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
String notificationId = notification.getString("notificationId");
return PendingIntent.getActivity(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent createBroadcastIntent(Bundle notification, String action) {
Intent intent = new Intent(context, RNFirebaseBackgroundNotificationActionReceiver.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
String notificationId = notification.getString("notificationId") + action;
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);
}
private RemoteInput createRemoteInput(Bundle remoteInput) {
String resultKey = remoteInput.getString("resultKey");
@@ -374,7 +399,7 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
} else if (image.startsWith("file://")) {
return BitmapFactory.decodeFile(image.replace("file://", ""));
} else {
int largeIconResId = RNFirebaseNotificationManager.getResourceId(context,"mipmap", image);
int largeIconResId = getIcon(image);
return BitmapFactory.decodeResource(context.getResources(), largeIconResId);
}
}
@@ -392,11 +417,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
}
private int getIcon(String icon) {
int smallIconResourceId = RNFirebaseNotificationManager.getResourceId(context,"mipmap", icon);
if (smallIconResourceId == 0) {
smallIconResourceId = RNFirebaseNotificationManager.getResourceId(context,"drawable", icon);
int resourceId = RNFirebaseNotificationManager.getResourceId(context,"mipmap", icon);
if (resourceId == 0) {
resourceId = RNFirebaseNotificationManager.getResourceId(context,"drawable", icon);
}
return smallIconResourceId;
return resourceId;
}
private Class getMainActivityClass() {

View File

@@ -0,0 +1,50 @@
package io.invertase.firebase.notifications;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.ReactApplication;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import io.invertase.firebase.Utils;
public class RNFirebaseBackgroundNotificationActionReceiver extends BroadcastReceiver {
static boolean isBackgroundNotficationIntent(Intent intent) {
return intent.getExtras() != null && intent.hasExtra("action") && intent.hasExtra("notification");
}
static WritableMap toNotificationOpenMap(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap notificationMap = Arguments.makeNativeMap(extras.getBundle("notification"));
WritableMap notificationOpenMap = Arguments.createMap();
notificationOpenMap.putString("action", extras.getString("action"));
notificationOpenMap.putMap("notification", notificationMap);
return notificationOpenMap;
}
@Override
public void onReceive(Context context, Intent intent) {
if (!isBackgroundNotficationIntent(intent)) {
return;
}
if (Utils.isAppInForeground(context)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);
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);
serviceIntent.putExtras(intent.getExtras());
context.startService(serviceIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}
}

View File

@@ -0,0 +1,29 @@
package io.invertase.firebase.notifications;
import android.content.Intent;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import javax.annotation.Nullable;
import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificationActionReceiver.isBackgroundNotficationIntent;
import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificationActionReceiver.toNotificationOpenMap;
public class RNFirebaseBackgroundNotificationActionsService extends HeadlessJsTaskService {
@Override
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
if (isBackgroundNotficationIntent(intent)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);
return new HeadlessJsTaskConfig(
"RNFirebaseBackgroundNotificationAction",
notificationOpenMap,
60000,
true
);
}
return null;
}
}

View File

@@ -37,6 +37,7 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
@@ -86,6 +87,7 @@ public class RNFirebaseNotificationManager {
try {
cancelAlarm(notificationId);
preferences.edit().remove(notificationId).apply();
promise.resolve(null);
} catch (SecurityException e) {
// TODO: Identify what these situations are
// In some devices/situations cancelAllLocalNotifications can throw a SecurityException.
@@ -130,6 +132,18 @@ public class RNFirebaseNotificationManager {
}
}
public void deleteChannelGroup(String groupId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.deleteNotificationChannelGroup(groupId);
}
}
public void deleteChannel(String channelId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.deleteNotificationChannel(channelId);
}
}
public void displayNotification(ReadableMap notification, Promise promise) {
Bundle notificationBundle = Arguments.toBundle(notification);
displayNotification(notificationBundle, promise);
@@ -319,17 +333,19 @@ public class RNFirebaseNotificationManager {
// fireDate is stored in the Bundle as Long after notifications are rescheduled.
// This would lead to a fireDate of 0.0 when trying to extract a Double from the bundle.
// Instead always try extract a Long
Long fireDate = schedule.getLong("fireDate", -1);
if (fireDate == -1) {
Long fireDate = -1L;
try {
fireDate = (long) schedule.getDouble("fireDate", -1);
if (fireDate == -1) {
if (promise == null) {
Log.e(TAG, "Missing schedule information");
} else {
promise.reject("notification/schedule_notification_error", "Missing fireDate information");
}
return;
} catch (ClassCastException e) {
fireDate = schedule.getLong("fireDate", -1);
}
if (fireDate == -1) {
if (promise == null) {
Log.e(TAG, "Missing schedule information");
} else {
promise.reject("notification/schedule_notification_error", "Missing fireDate information");
}
return;
}
// Scheduled alarms are cleared on restart
@@ -352,6 +368,21 @@ public class RNFirebaseNotificationManager {
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (schedule.containsKey("repeatInterval")) {
// If fireDate you specify is in the past, the alarm triggers immediately.
// So we need to adjust the time for correct operation.
if (fireDate < System.currentTimeMillis()) {
Calendar newFireDate = Calendar.getInstance();
Calendar currentFireDate = Calendar.getInstance();
currentFireDate.setTimeInMillis(fireDate);
newFireDate.add(Calendar.DATE, 1);
newFireDate.set(Calendar.HOUR_OF_DAY, currentFireDate.get(Calendar.HOUR_OF_DAY));
newFireDate.set(Calendar.MINUTE, currentFireDate.get(Calendar.MINUTE));
newFireDate.set(Calendar.SECOND, currentFireDate.get(Calendar.SECOND));
fireDate = newFireDate.getTimeInMillis();
}
Long interval = null;
switch (schedule.getString("repeatInterval")) {
case "minute":

View File

@@ -162,6 +162,18 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
notificationManager.createChannels(channelsArray);
promise.resolve(null);
}
@ReactMethod
public void deleteChannelGroup(String channelId, Promise promise) {
notificationManager.deleteChannelGroup(channelId);
promise.resolve(null);
}
@ReactMethod
public void deleteChannel(String channelId, Promise promise) {
notificationManager.deleteChannel(channelId);
promise.resolve(null);
}
//////////////////////////////////////////////////////////////////////
// End Android specific methods
//////////////////////////////////////////////////////////////////////

View File

@@ -1,5 +1,7 @@
package io.invertase.firebase.storage;
import android.content.ContentResolver;
import android.support.annotation.Nullable;
import android.util.Log;
import android.os.Environment;
@@ -7,16 +9,15 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.webkit.MimeTypeMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
@@ -49,7 +50,7 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
private static final String ExternalDirectoryPath = "EXTERNAL_DIRECTORY_PATH";
private static final String ExternalStorageDirectoryPath = "EXTERNAL_STORAGE_DIRECTORY_PATH";
private static final String PicturesDirectoryPath = "PICTURES_DIRECTORY_PATH";
private static final String TemporaryDirectoryPath = "TEMPORARY_DIRECTORY_PATH";
private static final String TemporaryDirectoryPath = "TEMP_DIRECTORY_PATH";
private static final String CachesDirectoryPath = "CACHES_DIRECTORY_PATH";
private static final String FileTypeRegular = "FILETYPE_REGULAR";
@@ -185,7 +186,7 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
@ReactMethod
public void updateMetadata(String appName, final String path, final ReadableMap metadata, final Promise promise) {
StorageReference reference = this.getReference(path, appName);
StorageMetadata md = buildMetadataFromMap(metadata);
StorageMetadata md = buildMetadataFromMap(metadata, null);
reference.updateMetadata(md).addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
@Override
@@ -338,7 +339,7 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
try {
Uri file = getURI(localPath);
StorageMetadata md = buildMetadataFromMap(metadata);
StorageMetadata md = buildMetadataFromMap(metadata, file);
UploadTask uploadTask = reference.putFile(file, md);
// register observers to listen for when the download is done or if it fails
@@ -356,30 +357,51 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "putFile success " + taskSnapshot);
WritableMap resp = getUploadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, resp);
// to avoid readable map already consumed errors we run this three times
getUploadTaskAsMap(taskSnapshot, new OnSuccessListener<WritableMap>() {
@Override
public void onSuccess(WritableMap event) {
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
});
// to avoid readable map already consumed errors
resp = getUploadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_UPLOAD_SUCCESS, path, resp);
getUploadTaskAsMap(taskSnapshot, new OnSuccessListener<WritableMap>() {
@Override
public void onSuccess(WritableMap event) {
sendJSEvent(appName, STORAGE_UPLOAD_SUCCESS, path, event);
}
});
resp = getUploadTaskAsMap(taskSnapshot);
promise.resolve(resp);
getUploadTaskAsMap(taskSnapshot, new OnSuccessListener<WritableMap>() {
@Override
public void onSuccess(WritableMap event) {
promise.resolve(event);
}
});
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "putFile progress " + taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, getUploadTaskAsMap(taskSnapshot));
getUploadTaskAsMap(taskSnapshot, new OnSuccessListener<WritableMap>() {
@Override
public void onSuccess(WritableMap event) {
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
});
}
})
.addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
@Override
public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "putFile paused " + taskSnapshot);
WritableMap event = getUploadTaskAsMap(taskSnapshot);
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
getUploadTaskAsMap(taskSnapshot, new OnSuccessListener<WritableMap>() {
@Override
public void onSuccess(WritableMap event) {
sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event);
}
});
}
});
} catch (Exception exception) {
@@ -426,13 +448,11 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @param metadata
* @return
*/
private StorageMetadata buildMetadataFromMap(ReadableMap metadata) {
private StorageMetadata buildMetadataFromMap(ReadableMap metadata, @Nullable Uri file) {
StorageMetadata.Builder metadataBuilder = new StorageMetadata.Builder();
try {
Map<String, Object> m = Utils.recursivelyDeconstructReadableMap(metadata);
Map<String, Object> customMetadata = (Map<String, Object>) m.get("customMetadata");
if (customMetadata != null) {
for (Map.Entry<String, Object> entry : customMetadata.entrySet()) {
@@ -444,8 +464,24 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
metadataBuilder.setContentDisposition((String) m.get("contentDisposition"));
metadataBuilder.setContentEncoding((String) m.get("contentEncoding"));
metadataBuilder.setContentLanguage((String) m.get("contentLanguage"));
metadataBuilder.setContentType((String) m.get("contentType"));
if (metadata.hasKey("contentType")) {
metadataBuilder.setContentType((String) m.get("contentType"));
} else if (file != null) {
String mimeType = null;
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());
}
if (mimeType != null) metadataBuilder.setContentType(mimeType);
}
} catch (Exception e) {
Log.e(TAG, "error while building meta data " + e.getMessage());
}
@@ -476,24 +512,32 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
* @param taskSnapshot
* @return
*/
private WritableMap getUploadTaskAsMap(UploadTask.TaskSnapshot taskSnapshot) {
WritableMap resp = Arguments.createMap();
private void getUploadTaskAsMap(final UploadTask.TaskSnapshot taskSnapshot, final OnSuccessListener<WritableMap> listener) {
if (taskSnapshot != null) {
resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred());
resp.putString("downloadURL", taskSnapshot.getDownloadUrl() != null ? taskSnapshot.getDownloadUrl().toString() : null);
taskSnapshot.getStorage().getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri downloadUrl) {
WritableMap resp = Arguments.createMap();
StorageMetadata d = taskSnapshot.getMetadata();
if (d != null) {
WritableMap metadata = getMetadataAsMap(d);
resp.putMap("metadata", metadata);
}
resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred());
resp.putString("downloadURL", downloadUrl.toString());
resp.putString("ref", taskSnapshot.getStorage().getPath());
resp.putString("state", this.getTaskStatus(taskSnapshot.getTask()));
resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount());
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);
}
});
} else {
listener.onSuccess(Arguments.createMap());
}
return resp;
}
/**
@@ -519,17 +563,6 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
metadata.putString("contentLanguage", storageMetadata.getContentLanguage());
metadata.putString("contentType", storageMetadata.getContentType());
WritableArray downloadURLs = Arguments.createArray();
List<Uri> _downloadURLS = storageMetadata.getDownloadUrls();
if (_downloadURLS != null) {
for (Uri uri : _downloadURLS) {
downloadURLs.pushString(uri.getPath());
}
}
metadata.putArray("downloadURLs", downloadURLs);
WritableMap customMetadata = Arguments.createMap();
for (String key : storageMetadata.getCustomMetadataKeys()) {
customMetadata.putString(key, storageMetadata.getCustomMetadata(key));
@@ -568,12 +601,10 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
*/
private void sendJSEvent(String appName, final String name, final String path, WritableMap body) {
WritableMap event = Arguments.createMap();
event.putString("appName", appName);
event.putString("eventName", name);
event.putString("path", path);
event.putMap("body", body);
event.putString("path", path);
event.putString("eventName", name);
event.putString("appName", appName);
Utils.sendEvent(this.getReactApplicationContext(), STORAGE_EVENT, event);
}
@@ -653,7 +684,7 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule {
final Map<String, Object> constants = new HashMap<>();
constants.put(DocumentDirectoryPath, this.getReactApplicationContext().getFilesDir().getAbsolutePath());
constants.put(TemporaryDirectoryPath, null);
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);

View File

@@ -15,7 +15,7 @@ def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 27
buildToolsVersion '27.0.2'
// buildToolsVersion '27.0.2'
defaultConfig {
applicationId "com.testing"
@@ -78,40 +78,46 @@ android {
}
}
project.ext.firebaseVersion = '12.0.0'
dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation(project(':react-native-firebase')) {
implementation project(':react-native-firebase')
implementation(project(':bridge')) {
transitive = false
}
implementation project(':bridge')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.google.android.gms:play-services-base:$firebaseVersion"
implementation "com.google.firebase:firebase-ads:$firebaseVersion"
implementation "com.google.firebase:firebase-auth:$firebaseVersion"
implementation "com.google.firebase:firebase-config:$firebaseVersion"
implementation "com.google.firebase:firebase-core:$firebaseVersion"
implementation "com.google.firebase:firebase-crash:$firebaseVersion"
implementation "com.google.firebase:firebase-database:$firebaseVersion"
implementation "com.google.firebase:firebase-messaging:$firebaseVersion"
implementation "com.google.firebase:firebase-perf:$firebaseVersion"
implementation "com.google.firebase:firebase-storage:$firebaseVersion"
implementation "com.google.firebase:firebase-firestore:$firebaseVersion"
implementation "com.google.firebase:firebase-invites:$firebaseVersion"
implementation "com.google.firebase:firebase-functions:$firebaseVersion"
implementation('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
implementation('com.crashlytics.sdk.android:crashlytics:2.9.3@aar') {
transitive = true
}
// RNFirebase required dependencies
implementation "com.google.firebase:firebase-core:16.0.1"
implementation "com.google.android.gms:play-services-base:15.0.1"
// RNFirebase optional dependencies
implementation "com.google.firebase:firebase-ads:15.0.1"
implementation "com.google.firebase:firebase-auth:16.0.2"
implementation "com.google.firebase:firebase-config:16.0.0"
implementation "com.google.firebase:firebase-crash:16.0.1"
implementation "com.google.firebase:firebase-database:16.0.1"
implementation "com.google.firebase:firebase-firestore:17.0.2"
implementation "com.google.firebase:firebase-functions:16.0.1"
implementation "com.google.firebase:firebase-invites:16.0.1"
implementation "com.google.firebase:firebase-storage:16.0.1"
implementation "com.google.firebase:firebase-messaging:17.1.0"
implementation "com.google.firebase:firebase-perf:16.0.0"
implementation "com.facebook.react:react-native:+"
implementation "com.android.support:appcompat-v7:27.1.0"
implementation 'com.android.support:support-annotations:27.1.1'
implementation fileTree(dir: "libs", include: ["*.jar"])
// Tests
androidTestImplementation(project(path: ":detox"))
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test:rules:1.0.1'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
}
// Run this once to be able to run the application with BUCK

View File

@@ -1,71 +1,111 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testing">
xmlns:tools="http://schemas.android.com/tools"
package="com.testing">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="com.testing.MainApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/AppTheme">
<service
android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<application
android:name="com.testing.MainApplication"
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/AppTheme">
<service
android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService"
android:enabled="true"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service
android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService" />
<service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService" />
<receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"/>
<receiver android:enabled="true" android:exported="true" android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver" />
<receiver
android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<!-- App Links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="je786.app.goo.gl" android:scheme="http"/>
<data android:host="je786.app.goo.gl" android:scheme="https"/>
</intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity
android:name="com.testing.MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
<activity
android:name="com.testing.MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- App Links -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="http"
android:host="je786.app.goo.gl" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="http"
android:host="je786.app.goo.gl" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="je786.app.goo.gl" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="je786.app.goo.gl" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

View File

@@ -32,6 +32,10 @@ public class MainActivity extends ReactActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkWindowPerms();
// ATTENTION: This was auto-generated to handle app links.
Intent appLinkIntent = getIntent();
String appLinkAction = appLinkIntent.getAction();
Uri appLinkData = appLinkIntent.getData();
}
public void checkWindowPerms() {

View File

@@ -21,7 +21,7 @@ import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
import io.invertase.firebase.functions.RNFirebaseFunctionsPackage;
import io.invertase.firebase.instanceid.RNFirebaseInstanceIdPackage;
import io.invertase.firebase.invites.RNFirebaseInvitesPackage;
import io.invertase.firebase.links.RNFirebaseLinksPackage;
//import io.invertase.firebase.links.RNFirebaseLinksPackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
@@ -55,7 +55,7 @@ public class MainApplication extends Application implements ReactApplication {
new RNFirebaseFunctionsPackage(),
new RNFirebaseInstanceIdPackage(),
new RNFirebaseInvitesPackage(),
new RNFirebaseLinksPackage(),
// new RNFirebaseLinksPackage(),
new RNFirebaseMessagingPackage(),
new RNFirebaseNotificationsPackage(),
new RNFirebasePerformancePackage(),

View File

@@ -1,24 +1,24 @@
buildscript {
repositories {
jcenter()
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.google.gms:google-services:3.1.2'
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 'io.fabric.tools:gradle:1.25.1'
classpath 'io.fabric.tools:gradle:1.25.4'
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
google()
jcenter()
maven {
url "$rootDir/../node_modules/react-native/android"
}
@@ -28,7 +28,7 @@ allprojects {
subprojects {
ext {
compileSdk = 27
buildTools = "27.0.2"
buildTools = "27.0.3"
minSdk = 18
targetSdk = 26
}
@@ -47,4 +47,3 @@ subprojects {
}
}
}

View File

@@ -1,12 +1,9 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
@@ -14,11 +11,8 @@ org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useDeprecatedNdk=true
android.enableAapt2=false

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View File

@@ -21,7 +21,8 @@ describe('auth()', () => {
});
describe('checkActionCode()', () => {
it('errors on invalid code', async () => {
// todo Android has changed the format of the error response
xit('errors on invalid code', async () => {
try {
await firebase.auth().checkActionCode('fooby shooby dooby');
} catch (e) {
@@ -35,7 +36,8 @@ describe('auth()', () => {
});
describe('verifyPasswordResetCode()', () => {
it('errors on invalid code', async () => {
// todo Android has changed the format of the error response
xit('errors on invalid code', async () => {
try {
await firebase.auth().verifyPasswordResetCode('fooby shooby dooby');
} catch (e) {
@@ -49,7 +51,8 @@ describe('auth()', () => {
});
describe('confirmPasswordReset()', () => {
it('errors on invalid code', async () => {
// todo Android has changed the format of the error response
xit('errors on invalid code', async () => {
try {
await firebase
.auth()
@@ -924,7 +927,7 @@ describe('auth()', () => {
});
});
describe('fetchProvidersForEmail()', () => {
describe('fetchProvidersForEmail/fetchSignInMethodsForEmail()', () => {
it('it should return password provider for an email address', () =>
new Promise((resolve, reject) => {
const successCb = providers => {
@@ -958,7 +961,7 @@ describe('auth()', () => {
return firebase
.auth()
.fetchProvidersForEmail('test@i-do-not-exist.com')
.fetchSignInMethodsForEmail('test@i-do-not-exist.com')
.then(successCb)
.catch(failureCb);
}));
@@ -977,7 +980,7 @@ describe('auth()', () => {
return firebase
.auth()
.fetchProvidersForEmail('foobar')
.fetchSignInMethodsForEmail('foobar')
.then(successCb)
.catch(failureCb);
}));
@@ -1099,9 +1102,7 @@ describe('auth()', () => {
} catch (error) {
// Reject
await firebase.auth().currentUser.delete();
Promise.reject(
new Error('sendPasswordResetEmail() caused an error', error)
);
throw new Error('sendPasswordResetEmail() caused an error', error);
}
});
});

View File

@@ -0,0 +1,55 @@
describe('auth() -> emailLink Provider', () => {
describe('sendSignInLinkToEmail', () => {
it('should send email', async () => {
const random = randomString(12, '#aA');
const email = `${random}@${random}.com`;
// const email = 'MANUAL TEST EMAIL HERE';
const actionCodeSettings = {
url: 'http://localhost:1337/authLinkFoo?bar=1234',
handleCodeInApp: true,
iOS: {
bundleId: 'com.testing',
},
android: {
packageName: 'com.testing',
installApp: true,
minimumVersion: '12',
},
};
await firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings);
});
});
describe('isSignInWithEmailLink', () => {
it('should return true/false', async () => {
const emailLink1 =
'https://www.example.com/action?mode=signIn&oobCode=oobCode';
const emailLink2 =
'https://www.example.com/action?mode=verifyEmail&oobCode=oobCode';
const emailLink3 = 'https://www.example.com/action?mode=signIn';
const emailLink4 =
'https://x59dg.app.goo.gl/?link=https://rnfirebase-b9ad4.firebaseapp.com/__/auth/action?apiKey%3Dfoo%26mode%3DsignIn%26oobCode%3Dbar';
should.equal(true, firebase.auth().isSignInWithEmailLink(emailLink1));
should.equal(false, firebase.auth().isSignInWithEmailLink(emailLink2));
should.equal(false, firebase.auth().isSignInWithEmailLink(emailLink3));
should.equal(true, firebase.auth().isSignInWithEmailLink(emailLink4));
});
});
// FOR MANUAL TESTING ONLY
xdescribe('signInWithEmailLink', () => {
it('should signIn', async () => {
const email = 'MANUAL TEST EMAIL HERE';
const emailLink = 'MANUAL TEST CODE HERE';
const userCredential = await firebase
.auth()
.signInWithEmailLink(email, emailLink);
userCredential.user.email.should.equal(email);
await await firebase.auth().signOut();
});
});
});

View File

@@ -22,6 +22,36 @@ describe('auth() -> Providers', () => {
});
});
describe('credentialWithLink', () => {
it('should return a credential object', () => {
const email = 'email@email.com';
const link = 'link';
const credential = firebase.auth.EmailAuthProvider.credentialWithLink(
email,
link
);
credential.providerId.should.equal('emailLink');
credential.token.should.equal(email);
credential.secret.should.equal(link);
});
});
describe('EMAIL_PASSWORD_SIGN_IN_METHOD', () => {
it('should return password', () => {
firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD.should.equal(
'password'
);
});
});
describe('EMAIL_LINK_SIGN_IN_METHOD', () => {
it('should return emailLink', () => {
firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD.should.equal(
'emailLink'
);
});
});
describe('PROVIDER_ID', () => {
it('should return password', () => {
firebase.auth.EmailAuthProvider.PROVIDER_ID.should.equal('password');

View File

@@ -70,7 +70,8 @@ describe('config()', () => {
should.equal(keys.length, 2);
});
it('get all keys as an array if no prefix provided', async () => {
xit('get all keys as an array if no prefix provided', async () => {
// TODO flakey on Android
const keys = await firebase.config().getKeysByPrefix();
keys.should.be.Array();
should.equal(keys.length, 4);

View File

@@ -122,6 +122,52 @@ describe('firestore()', () => {
documentSnapshot.should.be.instanceOf(DocumentSnapshot);
});
});
it('should support GetOptions source=`default`', async () => {
const collection = testCollection(TEST_COLLECTION_NAME);
const querySnapshot = await collection.get({ source: 'default' });
should.equal(querySnapshot.size >= 1, true);
querySnapshot.metadata.should.be.an.Object();
should.equal(querySnapshot.metadata.fromCache, false);
});
it('should support GetOptions source=`server`', async () => {
const collection = testCollection(TEST_COLLECTION_NAME);
const querySnapshot = await collection.get({ source: 'server' });
should.equal(querySnapshot.size >= 1, true);
querySnapshot.metadata.should.be.an.Object();
should.equal(querySnapshot.metadata.fromCache, false);
});
// TODO: Investigate why this isn't returning `fromCache=true`
xit('should support GetOptions source=`cache`', async () => {
const collection = testCollection(TEST_COLLECTION_NAME);
const querySnapshot = await collection.get({ source: 'cache' });
should.equal(querySnapshot.size >= 1, true);
querySnapshot.metadata.should.be.an.Object();
should.equal(querySnapshot.metadata.fromCache, true);
});
it('should error with invalid GetOptions source option', async () => {
const collectionRef = testCollection(TEST_COLLECTION_NAME);
try {
await collectionRef.get(() => {});
return Promise.reject(
new Error('get() did not reject with invalid argument.')
);
} catch (e) {
// do nothing
}
try {
await collectionRef.get({ source: 'invalid' });
return Promise.reject(
new Error('get() did not reject with invalid source property.')
);
} catch (e) {
// do nothing
}
return Promise.resolve();
});
});
describe('onSnapshot()', () => {
@@ -415,8 +461,7 @@ describe('firestore()', () => {
// await new Promise(resolve2 => {
// unsubscribe = collectionRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeDocumentMetadataChanges: true,
// includeMetadataChanges: true,
// },
// snapshot => {
// snapshot.forEach(doc => callback(doc.data()));
@@ -504,8 +549,7 @@ describe('firestore()', () => {
// };
// unsubscribe = collectionRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeDocumentMetadataChanges: true,
// includeMetadataChanges: true,
// },
// observer
// );
@@ -555,7 +599,7 @@ describe('firestore()', () => {
// (() => {
// colRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeMetadataChanges: true,
// },
// () => {},
// 'error'
@@ -566,7 +610,7 @@ describe('firestore()', () => {
// (() => {
// colRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeMetadataChanges: true,
// },
// {
// next: () => {},
@@ -579,7 +623,7 @@ describe('firestore()', () => {
// (() => {
// colRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeMetadataChanges: true,
// },
// {
// next: 'error',
@@ -591,7 +635,7 @@ describe('firestore()', () => {
// (() => {
// colRef.onSnapshot(
// {
// includeQueryMetadataChanges: true,
// includeMetadataChanges: true,
// },
// 'error'
// );

View File

@@ -67,6 +67,62 @@ describe('firestore()', () => {
snapshot.id.should.equal(COL2_DOC_1_ID);
snapshot.metadata.should.be.an.Object();
});
it('should support GetOptions source=`default`', async () => {
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
const snapshot = await test2DocRef(COL2_DOC_1_ID).get({
source: 'default',
});
snapshot.id.should.equal(COL2_DOC_1_ID);
snapshot.metadata.should.be.an.Object();
should.equal(snapshot.metadata.fromCache, false);
});
it('should support GetOptions source=`server`', async () => {
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
const snapshot = await test2DocRef(COL2_DOC_1_ID).get({
source: 'server',
});
snapshot.id.should.equal(COL2_DOC_1_ID);
snapshot.metadata.should.be.an.Object();
should.equal(snapshot.metadata.fromCache, false);
});
// TODO: For some reason when using `cache` it's not seeing the data as available, even if
// first requesting it from the server, although interestingly it works fine in the old
// tests app
xit('should support GetOptions source=`cache`', async () => {
await resetTestCollectionDoc(COL2_DOC_1_PATH, COL2_DOC_1());
const ref = test2DocRef(COL2_DOC_1_ID);
// Make sure the reference data is populated in the cache
await ref.get({ source: 'server' });
// Retrieve the cached version
const snapshot = await ref.get({ source: 'cache' });
snapshot.id.should.equal(COL2_DOC_1_ID);
snapshot.metadata.should.be.an.Object();
should.equal(snapshot.metadata.fromCache, true);
});
it('should error with invalid GetOptions source option', async () => {
const docRef = test2DocRef(COL2_DOC_1_ID);
try {
await docRef.get(() => {});
return Promise.reject(
new Error('get() did not reject with invalid argument.')
);
} catch (e) {
// do nothing
}
try {
await docRef.get({ source: 'invalid' });
return Promise.reject(
new Error('get() did not reject with invalid source property.')
);
} catch (e) {
// do nothing
}
return Promise.resolve();
});
});
describe('onSnapshot()', () => {

View File

@@ -0,0 +1,147 @@
describe('storage()', () => {
describe('ref()', () => {
describe('toString()', () => {
it('returns the correct bucket path to the file', () => {
const app = firebase.app();
firebase
.storage()
.ref('/uploadNope.jpeg')
.toString()
.should.equal(`gs://${app.options.storageBucket}/uploadNope.jpeg`);
});
});
describe('downloadFile()', () => {
it('errors if permission denied', async () => {
try {
await firebase
.storage()
.ref('/not.jpg')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/not.jpg`
);
return Promise.reject(new Error('No permission denied error'));
} catch (error) {
error.code.should.equal('storage/unauthorized');
error.message.includes('not authorized').should.be.true();
return Promise.resolve();
}
});
it('downloads a file', async () => {
const meta = await firebase
.storage()
.ref('/ok.jpeg')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
);
meta.state.should.eql(firebase.storage.TaskState.SUCCESS);
meta.bytesTransferred.should.eql(meta.totalBytes);
});
});
describe('putFile()', () => {
before(async () => {
await firebase
.storage()
.ref('/ok.jpeg')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
);
await firebase
.storage()
.ref('/cat.gif')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/cat.gif`
);
await firebase
.storage()
.ref('/hei.heic')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/hei.heic`
);
});
it('errors if permission denied', async () => {
try {
await firebase
.storage()
.ref('/uploadNope.jpeg')
.putFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
);
return Promise.reject(new Error('No permission denied error'));
} catch (error) {
error.code.should.equal('storage/unauthorized');
error.message.includes('not authorized').should.be.true();
return Promise.resolve();
}
});
it('uploads a file', async () => {
const uploadTaskSnapshot = await firebase
.storage()
.ref('/uploadOk.jpeg')
.putFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
);
await firebase
.storage()
.ref('/uploadCat.gif')
.putFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/cat.gif`
);
await firebase
.storage()
.ref('/uploadHei.heic')
.putFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/hei.heic`
);
uploadTaskSnapshot.state.should.eql(firebase.storage.TaskState.SUCCESS);
uploadTaskSnapshot.bytesTransferred.should.eql(
uploadTaskSnapshot.totalBytes
);
uploadTaskSnapshot.metadata.should.be.an.Object();
uploadTaskSnapshot.downloadURL.should.be.a.String();
});
});
describe('on()', () => {
before(async () => {
await firebase
.storage()
.ref('/ok.jpeg')
.downloadFile(
`${firebase.storage.Native.DOCUMENT_DIRECTORY_PATH}/ok.jpeg`
);
});
it('listens to upload state', () => {
const { resolve, reject, promise } = Promise.defer();
const path = `${
firebase.storage.Native.DOCUMENT_DIRECTORY_PATH
}/ok.jpeg`;
const ref = firebase.storage().ref('/uploadOk.jpeg');
const unsubscribe = ref.putFile(path).on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
if (snapshot.state === firebase.storage.TaskState.SUCCESS) {
resolve();
}
},
error => {
unsubscribe();
reject(error);
}
);
return promise;
});
});
});
});

View File

@@ -93,6 +93,25 @@ console.log = (...args) => {
return originalLog(...args);
};
/**
* Old style deferred promise shim - for niceness
*
* @returns {{resolve: null, reject: null}}
*/
Promise.defer = function defer() {
const deferred = {
resolve: null,
reject: null,
};
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
};
global.TestHelpers = {
functions: {
data: require('./../functions/test-data'),

View File

@@ -18,21 +18,21 @@ target 'testing' do
'RCTWebSocket',
]
pod 'Firebase/AdMob'
pod 'Firebase/Auth'
pod 'Firebase/Core'
pod 'Firebase/Crash'
pod 'Firebase/Database'
pod 'Firebase/Functions'
pod 'Firebase/DynamicLinks'
pod 'Firebase/Firestore'
pod 'Firebase/Invites'
pod 'Firebase/Messaging'
pod 'Firebase/RemoteConfig'
pod 'Firebase/Storage'
pod 'Firebase/Performance'
pod 'Firebase/AdMob', '~> 5.3.0'
pod 'Firebase/Auth', '~> 5.3.0'
pod 'Firebase/Core', '~> 5.3.0'
pod 'Firebase/Crash', '~> 5.3.0'
pod 'Firebase/Database', '~> 5.3.0'
pod 'Firebase/Functions', '~> 5.3.0'
pod 'Firebase/DynamicLinks', '~> 5.3.0'
pod 'Firebase/Firestore', '~> 5.3.0'
pod 'Firebase/Invites', '~> 5.3.0'
pod 'Firebase/Messaging', '~> 5.3.0'
pod 'Firebase/RemoteConfig', '~> 5.3.0'
pod 'Firebase/Storage', '~> 5.3.0'
pod 'Firebase/Performance', '~> 5.3.0'
pod 'Fabric', '~> 1.7.5'
pod 'Crashlytics', '~> 3.10.1'
pod 'Crashlytics', '~> 3.10.4'
pod 'RNFirebase', :path => '../../ios/RNFirebase.podspec'

View File

@@ -1,184 +1,188 @@
PODS:
- BoringSSL (10.0.2):
- BoringSSL/Implementation (= 10.0.2)
- BoringSSL/Interface (= 10.0.2)
- BoringSSL/Implementation (10.0.2):
- BoringSSL/Interface (= 10.0.2)
- BoringSSL/Interface (10.0.2)
- Crashlytics (3.10.1):
- Fabric (~> 1.7.5)
- Fabric (1.7.6)
- Firebase/AdMob (4.13.0):
- BoringSSL (10.0.5):
- BoringSSL/Implementation (= 10.0.5)
- BoringSSL/Interface (= 10.0.5)
- BoringSSL/Implementation (10.0.5):
- BoringSSL/Interface (= 10.0.5)
- BoringSSL/Interface (10.0.5)
- Crashlytics (3.10.4):
- Fabric (~> 1.7.9)
- Fabric (1.7.9)
- Firebase/AdMob (5.3.0):
- Firebase/Core
- Google-Mobile-Ads-SDK (= 7.30.0)
- Firebase/Auth (4.13.0):
- Google-Mobile-Ads-SDK (= 7.31.0)
- Firebase/Auth (5.3.0):
- Firebase/CoreOnly
- FirebaseAuth (= 5.0.1)
- Firebase/Core (5.3.0):
- Firebase/CoreOnly
- FirebaseAnalytics (= 5.0.1)
- Firebase/CoreOnly (5.3.0):
- FirebaseCore (= 5.0.4)
- Firebase/Crash (5.3.0):
- Firebase/Core
- FirebaseAuth (= 4.6.1)
- Firebase/Core (4.13.0):
- FirebaseAnalytics (= 4.2.0)
- FirebaseCore (= 4.0.20)
- Firebase/Crash (4.13.0):
- FirebaseCrash (= 3.0.0)
- Firebase/Database (5.3.0):
- Firebase/CoreOnly
- FirebaseDatabase (= 5.0.1)
- Firebase/DynamicLinks (5.3.0):
- Firebase/Core
- FirebaseCrash (= 2.0.2)
- Firebase/Database (4.13.0):
- FirebaseDynamicLinks (= 3.0.1)
- Firebase/Firestore (5.3.0):
- Firebase/CoreOnly
- FirebaseFirestore (= 0.12.4)
- Firebase/Functions (5.3.0):
- Firebase/CoreOnly
- FirebaseFunctions (= 2.0.0)
- Firebase/Invites (5.3.0):
- Firebase/Core
- FirebaseDatabase (= 4.1.5)
- Firebase/DynamicLinks (4.13.0):
- FirebaseInvites (= 3.0.0)
- Firebase/Messaging (5.3.0):
- Firebase/CoreOnly
- FirebaseMessaging (= 3.0.2)
- Firebase/Performance (5.3.0):
- Firebase/Core
- FirebaseDynamicLinks (= 2.3.2)
- Firebase/Firestore (4.13.0):
- FirebasePerformance (= 2.0.1)
- Firebase/RemoteConfig (5.3.0):
- Firebase/Core
- FirebaseFirestore (= 0.11.0)
- Firebase/Functions (4.13.0):
- Firebase/Core
- FirebaseFunctions (= 1.0.0)
- Firebase/Invites (4.13.0):
- Firebase/Core
- FirebaseInvites (= 2.0.2)
- Firebase/Messaging (4.13.0):
- Firebase/Core
- FirebaseMessaging (= 2.2.0)
- Firebase/Performance (4.13.0):
- Firebase/Core
- FirebasePerformance (= 1.1.3)
- Firebase/RemoteConfig (4.13.0):
- Firebase/Core
- FirebaseRemoteConfig (= 2.1.3)
- Firebase/Storage (4.13.0):
- Firebase/Core
- FirebaseStorage (= 2.2.0)
- FirebaseABTesting (1.0.0):
- FirebaseCore (~> 4.0)
- Protobuf (~> 3.1)
- FirebaseAnalytics (4.2.0):
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseRemoteConfig (= 3.0.0)
- Firebase/Storage (5.3.0):
- Firebase/CoreOnly
- FirebaseStorage (= 3.0.0)
- FirebaseABTesting (2.0.0):
- FirebaseCore (~> 5.0)
- Protobuf (~> 3.5)
- FirebaseAnalytics (5.0.1):
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- nanopb (~> 0.3)
- FirebaseAuth (4.6.1):
- FirebaseAnalytics (~> 4.2)
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
- FirebaseAuth (5.0.1):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- FirebaseCore (4.0.20):
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseCrash (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- FirebaseCore (5.0.4):
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- FirebaseCrash (3.0.0):
- FirebaseAnalytics (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.1)
- FirebaseDatabase (4.1.5):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- Protobuf (~> 3.5)
- FirebaseDatabase (5.0.1):
- FirebaseCore (~> 5.0)
- leveldb-library (~> 1.18)
- FirebaseDynamicLinks (2.3.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseFirestore (0.11.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseDynamicLinks (3.0.1):
- FirebaseAnalytics (~> 5.0)
- FirebaseFirestore (0.12.4):
- FirebaseCore (~> 5.0)
- FirebaseFirestore/abseil-cpp (= 0.12.4)
- gRPC-ProtoRPC (~> 1.0)
- leveldb-library (~> 1.18)
- Protobuf (~> 3.5)
- FirebaseFunctions (1.0.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- Protobuf (~> 3.1)
- FirebaseFirestore/abseil-cpp (0.12.4):
- FirebaseCore (~> 5.0)
- gRPC-ProtoRPC (~> 1.0)
- leveldb-library (~> 1.18)
- Protobuf (~> 3.1)
- FirebaseFunctions (2.0.0):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- FirebaseInstanceID (2.0.10):
- FirebaseCore (~> 4.0)
- FirebaseInvites (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseDynamicLinks (~> 2.2)
- FirebaseInstanceID (3.1.1):
- FirebaseCore (~> 5.0)
- FirebaseInvites (3.0.0):
- FirebaseAnalytics (~> 5.0)
- FirebaseDynamicLinks (~> 3.0)
- GoogleAPIClientForREST (~> 1.0)
- GoogleSignIn (~> 4.1)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
- GoogleToolboxForMac/NSString+URLArguments (~> 2.1)
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
- "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)"
- GoogleToolboxForMac/StringEncoding (~> 2.1)
- GoogleToolboxForMac/URLBuilder (~> 2.1)
- GTMOAuth2 (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GTMSessionFetcher/Full (~> 1.1)
- Protobuf (~> 3.5)
- FirebaseMessaging (3.0.2):
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- Protobuf (~> 3.1)
- FirebaseMessaging (2.2.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- FirebasePerformance (2.0.1):
- FirebaseAnalytics (~> 5.0)
- FirebaseInstanceID (~> 3.1)
- FirebaseSwizzlingUtilities/ISASwizzling (~> 2.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- Protobuf (~> 3.5)
- FirebasePerformance (1.1.3):
- FirebaseAnalytics (~> 4.1)
- FirebaseInstanceID (~> 2.0)
- FirebaseSwizzlingUtilities/ISASwizzling (~> 1.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (~> 1.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- GTMSessionFetcher/Core (~> 1.1)
- Protobuf (~> 3.5)
- FirebaseRemoteConfig (2.1.3):
- FirebaseABTesting (~> 1.0)
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseRemoteConfig (3.0.0):
- FirebaseABTesting (~> 2.0)
- FirebaseAnalytics (~> 5.0)
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- Protobuf (~> 3.5)
- FirebaseStorage (2.2.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseStorage (3.0.0):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- FirebaseSwizzlingUtilities/ISASwizzling (1.0.1)
- FirebaseSwizzlingUtilities/MethodSwizzling (1.0.1):
- FirebaseCore (~> 4.0)
- Google-Mobile-Ads-SDK (7.30.0)
- FirebaseSwizzlingUtilities/ISASwizzling (2.0.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (2.0.0):
- FirebaseCore (~> 5.0)
- Google-Mobile-Ads-SDK (7.31.0)
- GoogleAPIClientForREST (1.3.4):
- GoogleAPIClientForREST/Core (= 1.3.4)
- GTMSessionFetcher (>= 1.1.7)
- GoogleAPIClientForREST/Core (1.3.4):
- GTMSessionFetcher (>= 1.1.7)
- GoogleSignIn (4.1.2):
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
- GoogleToolboxForMac/NSString+URLArguments (~> 2.1)
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
- "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)"
- GTMOAuth2 (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GoogleToolboxForMac/Core (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/DebugUtils (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/Defines (2.1.3)
- GoogleToolboxForMac/Logger (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSData+zlib (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSDictionary+URLArguments (2.1.3):
- GoogleToolboxForMac/DebugUtils (= 2.1.3)
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (2.1.3)
- GoogleToolboxForMac/StringEncoding (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/URLBuilder (2.1.3):
- GoogleToolboxForMac/Core (= 2.1.3)
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSDictionary+URLArguments (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.3)
- gRPC (1.11.0):
- gRPC-RxLibrary (= 1.11.0)
- gRPC/Main (= 1.11.0)
- gRPC-Core (1.11.0):
- gRPC-Core/Implementation (= 1.11.0)
- gRPC-Core/Interface (= 1.11.0)
- gRPC-Core/Implementation (1.11.0):
- GoogleToolboxForMac/Core (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/DebugUtils (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/Defines (2.1.4)
- GoogleToolboxForMac/Logger (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- "GoogleToolboxForMac/NSData+zlib (2.1.4)":
- GoogleToolboxForMac/Defines (= 2.1.4)
- "GoogleToolboxForMac/NSDictionary+URLArguments (2.1.4)":
- GoogleToolboxForMac/DebugUtils (= 2.1.4)
- GoogleToolboxForMac/Defines (= 2.1.4)
- "GoogleToolboxForMac/NSString+URLArguments (= 2.1.4)"
- "GoogleToolboxForMac/NSString+URLArguments (2.1.4)"
- GoogleToolboxForMac/StringEncoding (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/URLBuilder (2.1.4):
- GoogleToolboxForMac/Core (= 2.1.4)
- GoogleToolboxForMac/Defines (= 2.1.4)
- "GoogleToolboxForMac/NSDictionary+URLArguments (= 2.1.4)"
- "GoogleToolboxForMac/NSString+URLArguments (= 2.1.4)"
- gRPC (1.13.0):
- gRPC-RxLibrary (= 1.13.0)
- gRPC/Main (= 1.13.0)
- gRPC-Core (1.13.0):
- gRPC-Core/Implementation (= 1.13.0)
- gRPC-Core/Interface (= 1.13.0)
- gRPC-Core/Implementation (1.13.0):
- BoringSSL (~> 10.0)
- gRPC-Core/Interface (= 1.11.0)
- gRPC-Core/Interface (= 1.13.0)
- nanopb (~> 0.3)
- gRPC-Core/Interface (1.11.0)
- gRPC-ProtoRPC (1.11.0):
- gRPC (= 1.11.0)
- gRPC-RxLibrary (= 1.11.0)
- gRPC-Core/Interface (1.13.0)
- gRPC-ProtoRPC (1.13.0):
- gRPC-ProtoRPC/Main (= 1.13.0)
- gRPC-ProtoRPC/Main (1.13.0):
- gRPC (= 1.13.0)
- gRPC-RxLibrary (= 1.13.0)
- Protobuf (~> 3.0)
- gRPC-RxLibrary (1.11.0)
- gRPC/Main (1.11.0):
- gRPC-Core (= 1.11.0)
- gRPC-RxLibrary (= 1.11.0)
- gRPC-RxLibrary (1.13.0)
- gRPC/Main (1.13.0):
- gRPC-Core (= 1.13.0)
- gRPC-RxLibrary (= 1.13.0)
- GTMOAuth2 (1.1.6):
- GTMSessionFetcher (~> 1.1)
- GTMSessionFetcher (1.1.15):
@@ -192,7 +196,7 @@ PODS:
- nanopb/encode (= 0.3.8)
- nanopb/decode (0.3.8)
- nanopb/encode (0.3.8)
- Protobuf (3.5.0)
- Protobuf (3.6.0)
- React (0.55.3):
- React/Core (= 0.55.3)
- React/Core (0.55.3):
@@ -208,27 +212,27 @@ PODS:
- React/Core
- React/fishhook
- React/RCTBlob
- RNFirebase (4.0.7):
- RNFirebase (4.2.0):
- Firebase/Core
- React
- yoga (0.55.3.React)
DEPENDENCIES:
- Crashlytics (~> 3.10.1)
- Crashlytics (~> 3.10.4)
- Fabric (~> 1.7.5)
- Firebase/AdMob
- Firebase/Auth
- Firebase/Core
- Firebase/Crash
- Firebase/Database
- Firebase/DynamicLinks
- Firebase/Firestore
- Firebase/Functions
- Firebase/Invites
- Firebase/Messaging
- Firebase/Performance
- Firebase/RemoteConfig
- Firebase/Storage
- Firebase/AdMob (~> 5.3.0)
- Firebase/Auth (~> 5.3.0)
- Firebase/Core (~> 5.3.0)
- Firebase/Crash (~> 5.3.0)
- Firebase/Database (~> 5.3.0)
- Firebase/DynamicLinks (~> 5.3.0)
- Firebase/Firestore (~> 5.3.0)
- Firebase/Functions (~> 5.3.0)
- Firebase/Invites (~> 5.3.0)
- Firebase/Messaging (~> 5.3.0)
- Firebase/Performance (~> 5.3.0)
- Firebase/RemoteConfig (~> 5.3.0)
- Firebase/Storage (~> 5.3.0)
- React/Core (from `../node_modules/react-native`)
- React/RCTNetwork (from `../node_modules/react-native`)
- React/RCTText (from `../node_modules/react-native`)
@@ -236,52 +240,88 @@ DEPENDENCIES:
- RNFirebase (from `../../ios/RNFirebase.podspec`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- BoringSSL
- Crashlytics
- Fabric
- Firebase
- FirebaseABTesting
- FirebaseAnalytics
- FirebaseAuth
- FirebaseCore
- FirebaseCrash
- FirebaseDatabase
- FirebaseDynamicLinks
- FirebaseFirestore
- FirebaseFunctions
- FirebaseInstanceID
- FirebaseInvites
- FirebaseMessaging
- FirebasePerformance
- FirebaseRemoteConfig
- FirebaseStorage
- FirebaseSwizzlingUtilities
- Google-Mobile-Ads-SDK
- GoogleAPIClientForREST
- GoogleSignIn
- GoogleToolboxForMac
- gRPC
- gRPC-Core
- gRPC-ProtoRPC
- gRPC-RxLibrary
- GTMOAuth2
- GTMSessionFetcher
- leveldb-library
- nanopb
- Protobuf
EXTERNAL SOURCES:
React:
:path: ../node_modules/react-native
:path: "../node_modules/react-native"
RNFirebase:
:path: ../../ios/RNFirebase.podspec
:path: "../../ios/RNFirebase.podspec"
yoga:
:path: ../node_modules/react-native/ReactCommon/yoga
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
BoringSSL: 60dd24df4af296bf41d78e5841dbb95d75f88c0d
Crashlytics: aee1a064cbbf99b32efa3f056a5f458d846bc8ff
Fabric: f8d42c893bb187326a7968b62abe55c36a987a46
Firebase: 5ec5e863d269d82d66b4bf56856726f8fb8f0fb3
FirebaseABTesting: d07d0ee833b842d5153549e4c7e2e2cb1c23a3f9
FirebaseAnalytics: 7ef69e76a5142f643aeb47c780e1cdce4e23632e
FirebaseAuth: bf22cacf22c60ab454bf2636f556d8892b10b53f
FirebaseCore: 90cb1c53d69b556f112a1bf72b5fcfaad7650790
FirebaseCrash: a7d980468dc8aa2db9792493c3e02722d601f6ab
FirebaseDatabase: 5f0bc6134c5c237cf55f9e1249d406770a75eafd
FirebaseDynamicLinks: 38b68641d24e78d0277a9205d988ce22875d5a25
FirebaseFirestore: e92a096ce80c7b4b905d4e9d41dbd944adc9d2a5
FirebaseFunctions: 3745fada03bd706a9b5c0b9ae7b2d490fa594d21
FirebaseInstanceID: 8d20d890d65c917f9f7d9950b6e10a760ad34321
FirebaseInvites: ae15e0636f9eb42bdf5c1ef4c8f7bd4a88f9878b
FirebaseMessaging: 75cdb862e86c30e0913a2ff307e48d49357c5b73
FirebasePerformance: 85bdc3f3d630deb629e85695fcab23364d68f5db
FirebaseRemoteConfig: 3e95fb7c072308492e85fa41d59d38b3d6fd2372
FirebaseStorage: 0c223481c8f89ed300cf1239ddd2d9833622c65f
FirebaseSwizzlingUtilities: 6006111d30248d2321ffac0231e246663e704ea3
Google-Mobile-Ads-SDK: 7404f68120ae8682afeb5af001fbf4aad731c78e
BoringSSL: cf3f1793eb6e3c445c4d150456341f149c268a35
Crashlytics: 915a7787b84f635fb2a81f92a90e265c2c413f76
Fabric: a2917d3895e4c1569b9c3170de7320ea1b1e6661
Firebase: 68afeeb05461db02d7c9e3215cda28068670f4aa
FirebaseABTesting: 1f50b8d50f5e3469eea54e7463a7b7fe221d1f5e
FirebaseAnalytics: b3628aea54c50464c32c393fb2ea032566e7ecc2
FirebaseAuth: 463b8ce33bd5d05f706dcd4615499e3212b4132b
FirebaseCore: 62f1b792a49bb9e8b4073f24606d2c93ffc352f0
FirebaseCrash: 8900571fd763fd5bdda04522ec53da979456e3ce
FirebaseDatabase: 482bad9c2abd422bb2321194fb8c937e67426a89
FirebaseDynamicLinks: d624a7adc81a8fd70d52be5a6a47a2bc0644b923
FirebaseFirestore: 53f6fe858494c39dbfd5237655e0641152a88c89
FirebaseFunctions: 141da172b7491276d9da8715b8ca88f9e439ffb6
FirebaseInstanceID: f3f0657372592ecdfdfe2cac604a5a75758376a6
FirebaseInvites: d7534f94d0610b892bac8ee0cf4218a14be46c28
FirebaseMessaging: 6894b8fe0a0cf26c3b13dad729f1131654ae0bdb
FirebasePerformance: 1ebd87ffee5ca814582db1dc9e25651792ba02db
FirebaseRemoteConfig: 3c57e4644bd6976b671ae0b725cd709f198bd1f5
FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b
FirebaseSwizzlingUtilities: 6c22677c50d0b6f5f0dc637c1233f13694a3003f
Google-Mobile-Ads-SDK: 6e529e748b45507a2ca904e0b5a52669ba3920c4
GoogleAPIClientForREST: f7951c455df271bc6259b3ddb4073d0026475ccf
GoogleSignIn: d9ef55b10f0aa401a5de2747f59b725e4b9732ac
GoogleToolboxForMac: 2501e2ad72a52eb3dfe7bd9aee7dad11b858bd20
gRPC: 70703dc9ba31c72341fc7f37745cc1c379edee96
gRPC-Core: 164639cd8ae18ca8b65477fafb2efbaecf4f181a
gRPC-ProtoRPC: bb5fddf3424aa4fad74d76736578a79fe40e244e
gRPC-RxLibrary: 26d53d1b1f306befd4ad4e15bd6de27839a82481
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
gRPC: 81b990caa01d7c32605d300c2ffd1b5ba0ef9e49
gRPC-Core: a56b086a8ef5ced6f6ba5be5bc0a63fca185015a
gRPC-ProtoRPC: 842797fbe05dfcf891afb4a5048e5ccf5f06ef86
gRPC-RxLibrary: fa6852f98d6ec0b73c0ec2f6406c26943099d501
GTMOAuth2: c77fe325e4acd453837e72d91e3b5f13116857b2
GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2
leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
React: 573d89cf10312b17920df6328eaf9ab8059283bf
RNFirebase: 05ef1e1c1681af418f3500fda194a2d17d45be07
yoga: 9403c2451c1b47d8cee3e4f1b6fd0ececc63839c
Protobuf: 0fc0ad8bec688b2a3017a139953e01374fedbd5f
React: aa2040dbb6f317b95314968021bd2888816e03d5
RNFirebase: 2b25fd2e60269f26bb0a76c71dcc942b35a77df0
yoga: a23273df0088bf7f2bb7e5d7b00044ea57a2a54a
PODFILE CHECKSUM: 582ceaad051470812ad9203e13b5ea8ad20c78ac
PODFILE CHECKSUM: af3286375d5c28aa5d912b64dee23c8f7c4f9282
COCOAPODS: 1.3.1
COCOAPODS: 1.5.3

24
bridge/ios/testing.xcodeproj/project.pbxproj Executable file → Normal file
View File

@@ -595,7 +595,6 @@
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
CC0F353E1D461097008BB94F /* Embed Frameworks */,
7D57265F10EEF7CD92D7973F /* Copy Detox Framework */,
4EEB648E968FA6F093B42978 /* [CP] Embed Pods Frameworks */,
CC8D61273332DE7812CFF010 /* [CP] Copy Pods Resources */,
);
buildRules = (
@@ -971,21 +970,6 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
4EEB648E968FA6F093B42978 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-testing/Pods-testing-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
7D57265F10EEF7CD92D7973F /* Copy Detox Framework */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1029,11 +1013,15 @@
"${PODS_ROOT}/FirebaseInvites/Resources/GPPACLPickerResources.bundle",
"${PODS_ROOT}/GTMOAuth2/Source/Touch/GTMOAuth2ViewTouch.xib",
"${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
"$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GINInviteResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GPPACLPickerResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GTMOAuth2ViewTouch.nib",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;

5200
bridge/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
"test-android-reuse": "detox test --configuration android.emu.debug --reuse",
"test-android-cover": "nyc detox test --configuration android.emu.debug",
"test-android-cover-reuse": "nyc detox test --configuration android.emu.debug --reuse",
"test-ios": "detox test --configuration ios.sim.debug",
"test-ios": "detox test --configuration ios.sim.debug --loglevel warn",
"test-ios-reuse": "detox test --configuration ios.sim.debug --reuse --loglevel warn",
"test-ios-cover": "nyc detox test --configuration ios.sim.debug",
"test-ios-cover-reuse": "nyc detox test --configuration ios.sim.debug --reuse --loglevel warn",

View File

@@ -1,6 +1,7 @@
#import "RNFirebase.h"
#import "RNFirebaseUtil.h"
#import <FirebaseCore/FirebaseCore.h>
#import <React/RCTUtils.h>
@implementation RNFirebase
RCT_EXPORT_MODULE(RNFirebase);
@@ -28,7 +29,7 @@ RCT_EXPORT_METHOD(initializeApp:
callback:
(RCTResponseSenderBlock) callback) {
dispatch_sync(dispatch_get_main_queue(), ^{
RCTUnsafeExecuteOnMainQueueSync(^{
FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName];
if (!existingApp) {

View File

@@ -31,6 +31,10 @@
}
- (void)requestAd {
#ifndef __LP64__
return; // prevent crash on 32bit
#endif
if (_unitId == nil || _size == nil || _request == nil) {
[self setRequested:NO];
return;

View File

@@ -1,8 +1,9 @@
#import "RNFirebaseAnalytics.h"
#import <React/RCTUtils.h>
#if __has_include(<FirebaseAnalytics/FIRAnalytics.h>)
#import <FirebaseAnalytics/FIRAnalytics.h>
#import <FirebaseAnalytics/FIRAnalyticsConfiguration.h>
#import <FirebaseCore/FIRAnalyticsConfiguration.h>
@implementation RNFirebaseAnalytics
RCT_EXPORT_MODULE();
@@ -16,7 +17,7 @@ RCT_EXPORT_METHOD(setAnalyticsCollectionEnabled:(BOOL) enabled) {
}
RCT_EXPORT_METHOD(setCurrentScreen:(NSString *) screenName screenClass:(NSString *) screenClassOverriew) {
dispatch_sync(dispatch_get_main_queue(), ^{
RCTUnsafeExecuteOnMainQueueSync(^{
[FIRAnalytics setScreenName:screenName screenClass:screenClassOverriew];
});
}

View File

@@ -128,15 +128,7 @@ RCT_EXPORT_METHOD(signOut:
RCT_EXPORT_METHOD(signInAnonymously:(NSString *) appDisplayName
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
[self signInAnonymously:appDisplayName withData:false resolver:resolve rejecter:reject];
}
/**
@@ -149,13 +141,22 @@ RCT_EXPORT_METHOD(signInAnonymously:(NSString *) appDisplayName
RCT_EXPORT_METHOD(signInAnonymouslyAndRetrieveData:(NSString *) appDisplayName
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self signInAnonymously:appDisplayName withData:true resolver:resolve rejecter:reject];
}
-(void)signInAnonymously:(NSString *)appDisplayName
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInAnonymouslyAndRetrieveDataWithCompletion:^(FIRAuthDataResult *authResult, NSError *error) {
[[FIRAuth authWithApp:firApp] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
@@ -174,15 +175,7 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *) appDisplayName
pass:(NSString *) password
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
[self signInWithEmail:appDisplayName email:email password:password withData:false resolver:resolve rejecter:reject];
}
/**
@@ -196,12 +189,48 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *) appDisplayName
*/
RCT_EXPORT_METHOD(signInAndRetrieveDataWithEmailAndPassword:(NSString *) appDisplayName
email:(NSString *) email
pass:(NSString *) password
password:(NSString *) password
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self signInWithEmail:appDisplayName email:email password:password withData:true resolver:resolve rejecter:reject];
}
-(void)signInWithEmail:(NSString *)appDisplayName
email:(NSString *)email
password:(NSString *)password
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInWithEmail:email password:password completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
/**
signInWithEmailLink
@param NSString NSString email
@param NSString NSString emailLink
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return return
*/
RCT_EXPORT_METHOD(signInWithEmailLink:(NSString *) appDisplayName
email:(NSString *) email
emailLink:(NSString *) emailLink
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithEmail:email password:password completion:^(FIRAuthDataResult *authResult, NSError *error) {
[[FIRAuth authWithApp:firApp] signInWithEmail:email link:emailLink completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
@@ -224,15 +253,7 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *) appDisplayName
pass:(NSString *) password
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
[self createUserWithEmail:appDisplayName email:email password:password withData:false resolver:resolve rejecter:reject];
}
/**
@@ -246,18 +267,28 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *) appDisplayName
*/
RCT_EXPORT_METHOD(createUserAndRetrieveDataWithEmailAndPassword:(NSString *) appDisplayName
email:(NSString *) email
pass:(NSString *) password
password:(NSString *) password
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self createUserWithEmail:appDisplayName email:email password:password withData:true resolver:resolve rejecter:reject];
}
-(void)createUserWithEmail:(NSString *)appDisplayName
email:(NSString *)email
password:(NSString *)password
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] createUserAndRetrieveDataWithEmail:email password:password
completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
}
[[FIRAuth authWithApp:firApp] createUserWithEmail:email password:password completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
@@ -511,21 +542,7 @@ RCT_EXPORT_METHOD(signInWithCredential:(NSString *) appDisplayName
secret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
if (credential == nil) {
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
}
[[FIRAuth authWithApp:firApp] signInWithCredential:credential completion:^(FIRUser *user, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
[self signInWithCredential:appDisplayName provider:provider token:authToken secret:authSecret withData:false resolver:resolve rejecter:reject];
}
/**
@@ -544,6 +561,16 @@ RCT_EXPORT_METHOD(signInAndRetrieveDataWithCredential:(NSString *) appDisplayNam
secret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self signInWithCredential:appDisplayName provider:provider token:authToken secret:authSecret withData:true resolver:resolve rejecter:reject];
}
-(void)signInWithCredential:(NSString *)appDisplayName
provider:(NSString *) provider
token:(NSString *) authToken
secret:(NSString *) authSecret
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
@@ -555,8 +582,10 @@ RCT_EXPORT_METHOD(signInAndRetrieveDataWithCredential:(NSString *) appDisplayNam
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithCredential:credential completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
@@ -655,6 +684,9 @@ RCT_EXPORT_METHOD(checkActionCode:
case FIRActionCodeOperationRecoverEmail:
actionType = @"RECOVER_EMAIL";
break;
case FIRActionCodeOperationEmailLink:
actionType = @"EMAIL_SIGNIN";
break;
}
NSDictionary *result = @{@"data": @{@"email": [info dataForKey:FIRActionCodeEmailKey], @"fromEmail": [info dataForKey:FIRActionCodeFromEmailKey],}, @"actionType": actionType,};
@@ -695,6 +727,35 @@ RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appDisplayName
}
}
/**
sendSignInLinkToEmail
@param NSString email
@param NSDictionary actionCodeSettings
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return
*/
RCT_EXPORT_METHOD(sendSignInLinkToEmail:(NSString *) appDisplayName
email:(NSString *) email
actionCodeSettings:(NSDictionary *) actionCodeSettings
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
id handler = ^(NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseNoUser:resolve rejecter:reject isError:NO];
}
};
FIRActionCodeSettings *settings = [self buildActionCodeSettings:actionCodeSettings];
[[FIRAuth authWithApp:firApp] sendSignInLinkToEmail:email actionCodeSettings:settings completion:handler];
}
/**
signInAndRetrieveDataWithCustomToken
@@ -707,15 +768,7 @@ RCT_EXPORT_METHOD(signInAndRetrieveDataWithCustomToken:(NSString *) appDisplayNa
customToken:(NSString *) customToken
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithCustomToken:customToken completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
}
}];
[self signInWithCustomToken:appDisplayName customToken:customToken withData:true resolver:resolve rejecter:reject];
}
/**
@@ -729,13 +782,23 @@ RCT_EXPORT_METHOD(signInWithCustomToken:(NSString *) appDisplayName
customToken:(NSString *) customToken
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self signInWithCustomToken:appDisplayName customToken:customToken withData:false resolver:resolve rejecter:reject];
}
-(void)signInWithCustomToken:(NSString *)appDisplayName
customToken:(NSString *) customToken
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInWithCustomToken:customToken completion:^(FIRUser *user, NSError *error) {
[[FIRAuth authWithApp:firApp] signInWithCustomToken:customToken completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
@@ -811,11 +874,11 @@ RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appDisplayName
NSString *verificationId = [defaults stringForKey:@"authVerificationID"];
FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationId verificationCode:verificationCode];
[[FIRAuth authWithApp:firApp] signInWithCredential:credential completion:^(FIRUser *user, NSError *error) {
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithCredential:credential completion:^(FIRAuthDataResult *authResult, NSError *error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
}
@@ -836,26 +899,7 @@ RCT_EXPORT_METHOD(linkWithCredential:(NSString *) appDisplayName
authSecret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
if (credential == nil) {
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
}
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) {
[user linkWithCredential:credential completion:^(FIRUser *_Nullable _user, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithUser:resolve rejecter:reject user:_user];
}
}];
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
[self linkWithCredential:appDisplayName provider:provider authToken:authToken authSecret:authSecret withData:false resolver:resolve rejecter:reject];
}
/**
@@ -874,23 +918,35 @@ RCT_EXPORT_METHOD(linkAndRetrieveDataWithCredential:(NSString *) appDisplayName
authSecret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self linkWithCredential:appDisplayName provider:provider authToken:authToken authSecret:authSecret withData:true resolver:resolve rejecter:reject];
}
-(void)linkWithCredential:(NSString *)appDisplayName
provider:(NSString *)provider
authToken:(NSString *)authToken
authSecret:(NSString *)authSecret
withData:(BOOL)withData
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
if (credential == nil) {
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
}
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) {
[user linkAndRetrieveDataWithCredential:credential
completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
}
}];
if (error) {
[self promiseRejectAuthException:reject error:error];
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
@@ -946,28 +1002,7 @@ RCT_EXPORT_METHOD(reauthenticateWithCredential:(NSString *) appDisplayName
authSecret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
if (credential == nil) {
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
}
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) {
[user reauthenticateWithCredential:credential completion:^(NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
FIRUser *userAfterAuth = [FIRAuth authWithApp:firApp].currentUser;
[self promiseWithUser:resolve rejecter:reject user:userAfterAuth];
}
}];
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
[self reauthenticateWithCredential:appDisplayName provider:provider authToken:authToken authSecret:authSecret withData:false resolver:resolve rejecter:reject];
}
/**
@@ -986,6 +1021,16 @@ RCT_EXPORT_METHOD(reauthenticateAndRetrieveDataWithCredential:(NSString *) appDi
authSecret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
[self reauthenticateWithCredential:appDisplayName provider:provider authToken:authToken authSecret:authSecret withData:true resolver:resolve rejecter:reject];
}
-(void)reauthenticateWithCredential:(NSString *) appDisplayName
provider:(NSString *) provider
authToken:(NSString *) authToken
authSecret:(NSString *) authSecret
withData:(BOOL) withData
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
@@ -1000,8 +1045,10 @@ RCT_EXPORT_METHOD(reauthenticateAndRetrieveDataWithCredential:(NSString *) appDi
[user reauthenticateAndRetrieveDataWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
} else if (withData) {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
} else {
[self promiseWithUser:resolve rejecter:reject user:authResult.user];
}
}];
} else {
@@ -1010,14 +1057,14 @@ RCT_EXPORT_METHOD(reauthenticateAndRetrieveDataWithCredential:(NSString *) appDi
}
/**
fetchProvidersForEmail
fetchSignInMethodsForEmail
@param NSString email
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return
*/
RCT_EXPORT_METHOD(fetchProvidersForEmail:
RCT_EXPORT_METHOD(fetchSignInMethodsForEmail:
(NSString *) appDisplayName
email:
(NSString *) email
@@ -1027,7 +1074,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] fetchProvidersForEmail:email completion:^(NSArray<NSString *> *_Nullable providers, NSError *_Nullable error) {
[[FIRAuth authWithApp:firApp] fetchSignInMethodsForEmail:email completion:^(NSArray<NSString *> *_Nullable providers, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else if (!providers) {
@@ -1058,6 +1105,8 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
credential = [FIRGoogleAuthProvider credentialWithIDToken:authToken accessToken:authTokenSecret];
} else if ([provider compare:@"password" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIREmailAuthProvider credentialWithEmail:authToken password:authTokenSecret];
} else if ([provider compare:@"emailLink" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIREmailAuthProvider credentialWithEmail:authToken link:authTokenSecret];
} else if ([provider compare:@"github.com" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIRGitHubAuthProvider credentialWithToken:authToken];
} else if ([provider compare:@"phone" options:NSCaseInsensitiveSearch] == NSOrderedSame) {

View File

@@ -10,14 +10,17 @@
@implementation RNFirebaseDatabase
RCT_EXPORT_MODULE();
// TODO document methods
// Run on a different thread
- (dispatch_queue_t)methodQueue {
return dispatch_queue_create("io.invertase.react-native-firebase.database", DISPATCH_QUEUE_SERIAL);
}
- (id)init {
self = [super init];
if (self != nil) {
_dbReferences = [[NSMutableDictionary alloc] init];
_transactions = [[NSMutableDictionary alloc] init];
_transactionQueue = dispatch_queue_create("io.invertase.react-native-firebase", DISPATCH_QUEUE_CONCURRENT);
_transactionQueue = dispatch_queue_create("io.invertase.react-native-firebase.database.transactions", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
@@ -446,7 +449,3 @@ RCT_EXPORT_METHOD(off:(NSString *)key
@implementation RNFirebaseDatabase
@end
#endif

View File

@@ -2,7 +2,7 @@
#define RNFirebaseCrashlytics_h
#import <Foundation/Foundation.h>
#if __has_include(<Crashlytics/Crashlytics.h>)
#if __has_include(<Crashlytics/Crashlytics/Crashlytics.h>)
#import <React/RCTBridgeModule.h>
@interface RNFirebaseCrashlytics : NSObject <RCTBridgeModule> {

View File

@@ -1,7 +1,7 @@
#import "RNFirebaseCrashlytics.h"
#if __has_include(<Crashlytics/Crashlytics.h>)
#import <Crashlytics/Crashlytics.h>
#if __has_include(<Crashlytics/Crashlytics/Crashlytics.h>)
#import <Crashlytics/Crashlytics/Crashlytics.h>
@implementation RNFirebaseCrashlytics
RCT_EXPORT_MODULE();

View File

@@ -10,11 +10,23 @@
@implementation RNFirebaseFirestore
RCT_EXPORT_MODULE();
static dispatch_queue_t firestoreQueue;
static NSMutableDictionary* initialisedApps;
// Run on a different thread
- (dispatch_queue_t)methodQueue {
if (!firestoreQueue) {
firestoreQueue = dispatch_queue_create("io.invertase.react-native-firebase.firestore", DISPATCH_QUEUE_SERIAL);
}
return firestoreQueue;
}
- (id)init {
self = [super init];
if (self != nil) {
initialisedApps = [[NSMutableDictionary alloc] init];
_transactions = [[NSMutableDictionary alloc] init];
_transactionQueue = dispatch_queue_create("io.invertase.react-native-firebase.firestore", DISPATCH_QUEUE_CONCURRENT);
_transactionQueue = dispatch_queue_create("io.invertase.react-native-firebase.firestore.transactions", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
@@ -152,7 +164,7 @@ RCT_EXPORT_METHOD(transactionBegin:(NSString *)appDisplayName
} else if ([type isEqualToString:@"set"]) {
NSDictionary *options = command[@"options"];
if (options && options[@"merge"]) {
[transaction setData:data forDocument:ref options:[FIRSetOptions merge]];
[transaction setData:data forDocument:ref merge:true];
} else {
[transaction setData:data forDocument:ref];
}
@@ -224,9 +236,10 @@ RCT_EXPORT_METHOD(collectionGet:(NSString *)appDisplayName
filters:(NSArray *)filters
orders:(NSArray *)orders
options:(NSDictionary *)options
getOptions:(NSDictionary *)getOptions
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getCollectionForAppPath:appDisplayName path:path filters:filters orders:orders options:options] get:resolve rejecter:reject];
[[self getCollectionForAppPath:appDisplayName path:path filters:filters orders:orders options:options] get:getOptions resolver:resolve rejecter:reject];
}
RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *)appDisplayName
@@ -268,7 +281,7 @@ RCT_EXPORT_METHOD(documentBatch:(NSString *)appDisplayName
} else if ([type isEqualToString:@"SET"]) {
NSDictionary *options = write[@"options"];
if (options && options[@"merge"]) {
batch = [batch setData:data forDocument:ref options:[FIRSetOptions merge]];
batch = [batch setData:data forDocument:ref merge:true];
} else {
batch = [batch setData:data forDocument:ref];
}
@@ -295,16 +308,10 @@ RCT_EXPORT_METHOD(documentDelete:(NSString *)appDisplayName
RCT_EXPORT_METHOD(documentGet:(NSString *)appDisplayName
path:(NSString *)path
getOptions:(NSDictionary *)getOptions
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[self getDocumentForAppPath:appDisplayName path:path] get:resolve rejecter:reject];
}
RCT_EXPORT_METHOD(documentGetAll:(NSString *)appDisplayName
documents:(NSString *)documents
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
// Not supported on iOS out of the box
[[self getDocumentForAppPath:appDisplayName path:path] get:getOptions resolver:resolve rejecter:reject];
}
RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *)appDisplayName
@@ -344,19 +351,31 @@ RCT_EXPORT_METHOD(settings:(NSString *)appDisplayName
rejecter:(RCTPromiseRejectBlock)reject) {
FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appDisplayName];
FIRFirestoreSettings *firestoreSettings = [[FIRFirestoreSettings alloc] init];
// Make sure the dispatch queue is set correctly
firestoreSettings.dispatchQueue = firestoreQueue;
// Apply the settings passed by the user, or ensure that the current settings are preserved
if (settings[@"host"]) {
firestoreSettings.host = settings[@"host"];
} else {
firestoreSettings.host = firestore.settings.host;
}
if (settings[@"persistence"]) {
firestoreSettings.persistenceEnabled = settings[@"persistence"];
} else {
firestoreSettings.persistenceEnabled = firestore.settings.persistenceEnabled;
}
if (settings[@"ssl"]) {
firestoreSettings.sslEnabled = settings[@"ssl"];
} else {
firestoreSettings.sslEnabled = firestore.settings.sslEnabled;
}
if (settings[@"timestampsInSnapshots"]) {
// TODO: Enable when available on Android
// firestoreSettings.timestampsInSnapshotsEnabled = settings[@"timestampsInSnapshots"];
}
[firestore setSettings:firestoreSettings];
resolve(nil);
}
@@ -371,7 +390,17 @@ RCT_EXPORT_METHOD(settings:(NSString *)appDisplayName
+ (FIRFirestore *)getFirestoreForApp:(NSString *)appDisplayName {
FIRApp *app = [RNFirebaseUtil getApp:appDisplayName];
return [FIRFirestore firestoreForApp:app];
FIRFirestore *firestore = [FIRFirestore firestoreForApp:app];
// This is the first time we've tried to do something on this Firestore instance
// So we need to make sure the dispatch queue is set correctly
if (!initialisedApps[appDisplayName]) {
initialisedApps[appDisplayName] = @(true);
FIRFirestoreSettings *firestoreSettings = [[FIRFirestoreSettings alloc] init];
firestoreSettings.dispatchQueue = firestoreQueue;
[firestore setSettings:firestoreSettings];
}
return firestore;
}
- (RNFirebaseFirestoreCollectionReference *)getCollectionForAppPath:(NSString *)appDisplayName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options {
@@ -495,4 +524,3 @@ RCT_EXPORT_METHOD(settings:(NSString *)appDisplayName
@implementation RNFirebaseFirestore
@end
#endif

View File

@@ -21,7 +21,7 @@
@property FIRQuery *query;
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options;
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
- (void)get:(NSDictionary *)getOptions resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+ (void)offSnapshot:(NSString *)listenerId;
- (void)onSnapshot:(NSString *)listenerId queryListenOptions:(NSDictionary *) queryListenOptions;
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot;

View File

@@ -29,9 +29,22 @@ static NSMutableDictionary *_listeners;
return self;
}
- (void)get:(RCTPromiseResolveBlock) resolve
- (void)get:(NSDictionary *) getOptions
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
[_query getDocumentsWithCompletion:^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
FIRFirestoreSource source;
if (getOptions && getOptions[@"source"]) {
if ([getOptions[@"source"] isEqualToString:@"server"]) {
source = FIRFirestoreSourceServer;
} else if ([getOptions[@"source"] isEqualToString:@"cache"]) {
source = FIRFirestoreSourceCache;
} else {
source = FIRFirestoreSourceDefault;
}
} else {
source = FIRFirestoreSourceDefault;
}
[_query getDocumentsWithSource:source completion:^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
if (error) {
[RNFirebaseFirestore promiseRejectException:reject error:error];
} else {
@@ -65,17 +78,14 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
}
};
FIRQueryListenOptions *options = [[FIRQueryListenOptions alloc] init];
if (queryListenOptions) {
if (queryListenOptions[@"includeDocumentMetadataChanges"]) {
[options includeDocumentMetadataChanges:TRUE];
}
if (queryListenOptions[@"includeQueryMetadataChanges"]) {
[options includeQueryMetadataChanges:TRUE];
}
bool includeMetadataChanges;
if (queryListenOptions && queryListenOptions[@"includeMetadataChanges"]) {
includeMetadataChanges = true;
} else {
includeMetadataChanges = false;
}
id<FIRListenerRegistration> listener = [_query addSnapshotListenerWithOptions:options listener:listenerBlock];
id<FIRListenerRegistration> listener = [_query addSnapshotListenerWithIncludeMetadataChanges:includeMetadataChanges listener:listenerBlock];
_listeners[listenerId] = listener;
}
}

View File

@@ -19,7 +19,7 @@
- (id)initWithPath:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName path:(NSString *)path;
- (void)delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
- (void)get:(NSDictionary *)getOptions resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+ (void)offSnapshot:(NSString *)listenerId;
- (void)onSnapshot:(NSString *)listenerId docListenOptions:(NSDictionary *) docListenOptions;
- (void)set:(NSDictionary *)data options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;

View File

@@ -30,9 +30,22 @@ static NSMutableDictionary *_listeners;
}];
}
- (void)get:(RCTPromiseResolveBlock) resolve
- (void)get:(NSDictionary *) getOptions
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject {
[_ref getDocumentWithCompletion:^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
FIRFirestoreSource source;
if (getOptions && getOptions[@"source"]) {
if ([getOptions[@"source"] isEqualToString:@"server"]) {
source = FIRFirestoreSourceServer;
} else if ([getOptions[@"source"] isEqualToString:@"cache"]) {
source = FIRFirestoreSourceCache;
} else {
source = FIRFirestoreSourceDefault;
}
} else {
source = FIRFirestoreSourceDefault;
}
[_ref getDocumentWithSource:source completion:^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
if (error) {
[RNFirebaseFirestore promiseRejectException:reject error:error];
} else {
@@ -65,11 +78,13 @@ static NSMutableDictionary *_listeners;
[self handleDocumentSnapshotEvent:listenerId documentSnapshot:snapshot];
}
};
FIRDocumentListenOptions *options = [[FIRDocumentListenOptions alloc] init];
bool includeMetadataChanges;
if (docListenOptions && docListenOptions[@"includeMetadataChanges"]) {
[options includeMetadataChanges:TRUE];
includeMetadataChanges = true;
} else {
includeMetadataChanges = false;
}
id<FIRListenerRegistration> listener = [_ref addSnapshotListenerWithOptions:options listener:listenerBlock];
id<FIRListenerRegistration> listener = [_ref addSnapshotListenerWithIncludeMetadataChanges:includeMetadataChanges listener:listenerBlock];
_listeners[listenerId] = listener;
}
}
@@ -80,7 +95,7 @@ static NSMutableDictionary *_listeners;
rejecter:(RCTPromiseRejectBlock) reject {
NSDictionary *dictionary = [RNFirebaseFirestoreDocumentReference parseJSMap:[RNFirebaseFirestore getFirestoreForApp:_appDisplayName] jsMap:data];
if (options && options[@"merge"]) {
[_ref setData:dictionary options:[FIRSetOptions merge] completion:^(NSError * _Nullable error) {
[_ref setData:dictionary merge:true completion:^(NSError * _Nullable error) {
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
}];
} else {

View File

@@ -1,6 +1,7 @@
#import "RNFirebaseInstanceId.h"
#if __has_include(<FirebaseInstanceID/FIRInstanceID.h>)
//#import <FirebaseMessaging/FirebaseMessaging.h>
#import <FirebaseInstanceID/FIRInstanceID.h>
@implementation RNFirebaseInstanceId
@@ -26,6 +27,36 @@ RCT_EXPORT_METHOD(get:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseReject
}];
}
RCT_EXPORT_METHOD(getToken:(NSString *)authorizedEntity
scope:(NSString *)scope
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSDictionary * options = nil;
// if ([FIRMessaging messaging].APNSToken) {
// options = @{@"apns_token": [FIRMessaging messaging].APNSToken};
// }
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:authorizedEntity scope:scope options:options handler:^(NSString * _Nullable identity, NSError * _Nullable error) {
if (error) {
reject(@"instance_id_error", @"Failed to getToken", error);
} else {
resolve(identity);
}
}];
}
RCT_EXPORT_METHOD(deleteToken:(NSString *)authorizedEntity
scope:(NSString *)scope
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[[FIRInstanceID instanceID] deleteTokenWithAuthorizedEntity:authorizedEntity scope:scope handler:^(NSError * _Nullable error) {
if (error) {
reject(@"instance_id_error", @"Failed to deleteToken", error);
} else {
resolve(nil);
}
}];
}
@end
#else

View File

@@ -60,11 +60,11 @@ continueUserActivity:(NSUserActivity *)userActivity
return [[FIRDynamicLinks dynamicLinks]
handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
if (error != nil){
NSLog(@"Failed to handle universal link: %@", [error localizedDescription]);
} else {
NSURL* url = dynamicLink ? dynamicLink.url : userActivity.webpageURL;
if (dynamicLink && dynamicLink.url && error == nil) {
NSURL* url = dynamicLink.url;
[self sendJSEvent:self name:LINKS_LINK_RECEIVED body:url.absoluteString];
} else {
NSLog(@"Failed to handle universal link: %@", userActivity.webpageURL);
}
}];
}

View File

@@ -20,6 +20,7 @@
static RNFirebaseMessaging *theRNFirebaseMessaging = nil;
static bool jsReady = FALSE;
static NSString* initialToken = nil;
static NSMutableArray* pendingMessages = nil;
+ (nonnull instancetype)instance {
return theRNFirebaseMessaging;
@@ -197,6 +198,12 @@ RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro
if (initialToken) {
[self sendJSEvent:self name:MESSAGING_TOKEN_REFRESHED body:initialToken];
}
if (pendingMessages) {
for (id message in pendingMessages) {
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
}
pendingMessages = nil;
}
}
// ** Start internals **
@@ -209,9 +216,13 @@ RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro
} else {
if ([name isEqualToString:MESSAGING_TOKEN_REFRESHED]) {
initialToken = body;
} else if ([name isEqualToString:MESSAGING_MESSAGE_RECEIVED]) {
if (!pendingMessages) {
pendingMessages = [[NSMutableArray alloc] init];
}
[pendingMessages addObject:body];
} else {
// TODO: Is this even possible?
NSLog(@"Received Remote Message before the bridge is ready");
NSLog(@"Received unexpected message type");
}
}
}

View File

@@ -7,6 +7,7 @@
#import <MobileCoreServices/MobileCoreServices.h>
#import <Photos/Photos.h>
#import <Firebase.h>
#import <React/RCTUtils.h>
@implementation RNFirebaseStorage
@@ -14,7 +15,7 @@ RCT_EXPORT_MODULE(RNFirebaseStorage);
// Run on a different thread
- (dispatch_queue_t)methodQueue {
return dispatch_queue_create("com.invertase.firebase.storage", DISPATCH_QUEUE_SERIAL);
return dispatch_queue_create("io.invertase.react-native-firebase.storage", DISPATCH_QUEUE_SERIAL);
}
/**
@@ -118,7 +119,11 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *) appDisplayName
rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
NSURL *localFile = [NSURL fileURLWithPath:localPath];
FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
__block FIRStorageDownloadTask *downloadTask;
RCTUnsafeExecuteOnMainQueueSync(^{
downloadTask = [fileRef writeToFile:localFile];
});
// listen for state changes, errors, and completion of the download.
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
@@ -205,9 +210,10 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageMetadata *firmetadata = [self buildMetadataFromMap:metadata];
if ([localPath hasPrefix:@"assets-library://"] || [localPath hasPrefix:@"ph://"]) {
PHFetchResult *assets;
if ([localPath hasPrefix:@"assets-library://"]) {
NSURL *localFile = [[NSURL alloc] initWithString:localPath];
assets = [PHAsset fetchAssetsWithALAssetURLs:@[localFile] options:nil];
@@ -215,9 +221,9 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
NSString *assetId = [localPath substringFromIndex:@"ph://".length];
assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetId] options:nil];
}
PHAsset *asset = [assets firstObject];
// this is based on http://stackoverflow.com/questions/35241449
if (asset.mediaType == PHAssetMediaTypeImage) {
// images
@@ -253,18 +259,18 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
if (info[PHImageErrorKey] == nil) {
NSURL *tempUrl = [self temporaryFileUrl];
exportSession.outputURL = tempUrl;
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
for (PHAssetResource *resource in resources) {
exportSession.outputFileType = resource.uniformTypeIdentifier;
if (exportSession.outputFileType != nil) break;
}
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
firmetadata.contentType = [self utiToMimeType:exportSession.outputFileType];
[self uploadFile:appDisplayName url:tempUrl firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
// we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time - todo?
// TODO we're not cleaning up the temporary file at the moment, relying on the OS to do it
} else {
reject(@"storage/temporary-file-failure", @"Unable to create temporary file for upload.", nil);
}
@@ -275,11 +281,37 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
}];
}
} else {
// TODO: Content type for file?
NSData *data = [[NSFileManager defaultManager] contentsAtPath:localPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
reject(@"storage/file-not-found", @"File specified at path does not exist.", nil);
return;
}
// TODO large files should not go through 'data', should use file directly
// TODO heic conversion not working here UIImageJPEGRepresentation -> returns nil
// BOOL isHeic = [self isHeic:localPath];
NSData *data = [NSData dataWithContentsOfFile:localPath];
if ([firmetadata valueForKey:@"contentType"] == nil) {
firmetadata.contentType = [self mimeTypeForPath:localPath];
}
// if (isHeic) {
// UIImage *image = [UIImage imageWithData: data];
// data = UIImageJPEGRepresentation(image, 1);
// firmetadata.contentType = @"image/jpeg";
// }
[self uploadData:appDisplayName data:data firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
}
}
-(BOOL) isHeic: (NSString*) path {
return [[path pathExtension] caseInsensitiveCompare:@"heic"] == NSOrderedSame;
}
- (NSString *)utiToMimeType:(NSString *) dataUTI {
return (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)dataUTI, kUTTagClassMIMEType);
}
- (NSURL *)temporaryFileUrl {
@@ -287,19 +319,33 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
return [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:filename];
}
- (NSString *)utiToMimeType:(NSString *) dataUTI {
return (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)dataUTI, kUTTagClassMIMEType);
- (NSString*) mimeTypeForPath: (NSString *) path {
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[path pathExtension], NULL);
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!mimeType) {
return @"application/octet-stream";
}
return (__bridge_transfer NSString *) mimeType;
}
- (void)uploadFile:(NSString *)appDisplayName url:(NSURL *)url firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
FIRStorageUploadTask *uploadTask = [fileRef putFile:url metadata:firmetadata];
__block FIRStorageUploadTask *uploadTask;
RCTUnsafeExecuteOnMainQueueSync(^{
uploadTask = [fileRef putFile:url metadata:firmetadata];
});
[self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject];
}
- (void)uploadData:(NSString *)appDisplayName data:(NSData *)data firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
FIRStorageUploadTask *uploadTask = [fileRef putData:data metadata:firmetadata];
__block FIRStorageUploadTask *uploadTask;
RCTUnsafeExecuteOnMainQueueSync(^{
uploadTask = [fileRef putData:data metadata:firmetadata];
});
[self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject];
}
@@ -307,27 +353,31 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
// listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload resumed, also fires when the upload starts
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
[self getUploadTaskAsDictionary:snapshot handler:^(NSDictionary *event) {
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
}];
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload paused
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
[self getUploadTaskAsDictionary:snapshot handler:^(NSDictionary *event) {
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
}];
[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload reported progress
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
[self getUploadTaskAsDictionary:snapshot handler:^(NSDictionary *event) {
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
}];
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload completed successfully
NSDictionary *resp = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:resp];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:resp];
resolve(resp);
[self getUploadTaskAsDictionary:snapshot handler:^(NSDictionary *event) {
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
[self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:event];
resolve(event);
}];
}];
[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
@@ -352,10 +402,14 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
return @{@"bytesTransferred": @(task.progress.completedUnitCount), @"ref": task.reference.fullPath, @"state": [self getTaskStatus:task.status], @"totalBytes": @(task.progress.totalUnitCount)};
}
- (NSDictionary *)getUploadTaskAsDictionary:(FIRStorageTaskSnapshot *)task {
NSString *downloadUrl = [task.metadata.downloadURL absoluteString];
NSDictionary *metadata = [task.metadata dictionaryRepresentation];
return @{@"bytesTransferred": @(task.progress.completedUnitCount), @"downloadURL": downloadUrl != nil ? downloadUrl : [NSNull null], @"metadata": metadata != nil ? metadata : [NSNull null], @"ref": task.reference.fullPath, @"state": [self getTaskStatus:task.status], @"totalBytes": @(task.progress.totalUnitCount)};
- (void)getUploadTaskAsDictionary:(FIRStorageTaskSnapshot *)task
handler:(void(^)(NSDictionary *))handler {
[[task reference] downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
NSString *downloadUrl = [URL absoluteString];
NSDictionary *metadata = [task.metadata dictionaryRepresentation];
NSDictionary *dictionary = @{@"bytesTransferred": @(task.progress.completedUnitCount), @"downloadURL": downloadUrl != nil ? downloadUrl : [NSNull null], @"metadata": metadata != nil ? metadata : [NSNull null], @"ref": task.reference.fullPath, @"state": [self getTaskStatus:task.status], @"totalBytes": @(task.progress.totalUnitCount)};
handler(dictionary);
}];
}
- (FIRStorageMetadata *)buildMetadataFromMap:(NSDictionary *)metadata {

288
lib/index.d.ts vendored
View File

@@ -1,6 +1,6 @@
// Type definitions for React Native Firebase v1.0.0-alpha7
// Type definitions for React Native Firebase v4.2.0
// Project: https://github.com/invertase/react-native-firebase
// Definitions by: Tal <https://github.com/taljacobson>
// Definitions by: React Native Firebase Contributors
// TypeScript Version: 2.1
declare module 'react-native-firebase' {
@@ -25,7 +25,7 @@ declare module 'react-native-firebase' {
RNFirebase.auth.Auth,
RNFirebase.auth.AuthStatics
>;
// config: FirebaseModule<RNFirebase.config.Config>;
config: FirebaseModuleAndStatics<RNFirebase.config.Config>;
crash: FirebaseModuleAndStatics<RNFirebase.crash.Crash>;
crashlytics: FirebaseModuleAndStatics<RNFirebase.crashlytics.Crashlytics>;
database: FirebaseModuleAndStatics<
@@ -36,6 +36,10 @@ declare module 'react-native-firebase' {
RNFirebase.firestore.Firestore,
RNFirebase.firestore.FirestoreStatics
>;
functions: FirebaseModuleAndStatics<
RNFirebase.functions.Functions,
RNFirebase.functions.FunctionsStatics
>;
iid: FirebaseModuleAndStatics<RNFirebase.iid.InstanceId>;
// invites: FirebaseModuleAndStatics<RNFirebase.invites.Invites>
links: FirebaseModuleAndStatics<
@@ -77,11 +81,12 @@ declare module 'react-native-firebase' {
// admob(): RNFirebase.admob.AdMob;
analytics(): RNFirebase.Analytics;
auth(): RNFirebase.auth.Auth;
// config(): RNFirebase.config.Config;
config(): RNFirebase.config.Config;
crash(): RNFirebase.crash.Crash;
crashlytics(): RNFirebase.crashlytics.Crashlytics;
database(): RNFirebase.database.Database;
firestore(): RNFirebase.firestore.Firestore;
functions(): RNFirebase.functions.Functions;
iid(): RNFirebase.iid.InstanceId;
// invites(): RNFirebase.invites.Invites;
links(): RNFirebase.links.Links;
@@ -328,7 +333,6 @@ declare module 'react-native-firebase' {
interface FullMetadata extends storage.UploadMetadata {
bucket: string;
downloadURLs: string[];
fullPath: string;
generation: string;
metageneration: string;
@@ -801,14 +805,14 @@ declare module 'react-native-firebase' {
interface PhoneAuthListener {
on(
event: string,
observer: () => PhoneAuthSnapshot,
errorCb?: () => PhoneAuthError,
successCb?: () => PhoneAuthSnapshot
observer: (snapshot: PhoneAuthSnapshot) => void,
errorCb?: (error: PhoneAuthError) => void,
successCb?: (snapshot: PhoneAuthSnapshot) => void
): PhoneAuthListener;
then(fn: () => PhoneAuthSnapshot): Promise<any>;
then(fn: (snapshot: PhoneAuthSnapshot) => void): Promise<any>;
catch(fn: () => Error): Promise<any>;
catch(fn: (error: Error) => void): Promise<any>;
}
namespace auth {
@@ -822,6 +826,17 @@ declare module 'react-native-firebase' {
credential: (token: string, secret?: string) => AuthCredential;
};
type EmailAuthProvider = {
PROVIDER_ID: string;
EMAIL_LINK_SIGN_IN_METHOD: string;
EMAIL_PASSWORD_SIGN_IN_METHOD: string;
credential: (email: string, password: string) => AuthCredential;
credentialWithLink: (
email: string,
emailLink: string
) => AuthCredential;
};
interface Auth {
readonly app: App;
/**
@@ -874,6 +889,13 @@ declare module 'react-native-firebase' {
password: string
): Promise<UserCredential>;
signInWithEmailLink(
email: string,
emailLink: string
): Promise<UserCredential>;
isSignInWithEmailLink(emailLink: string): boolean;
/**
* We can create a user by calling the createUserWithEmailAndPassword() function.
* The method accepts two parameters, an email and a password.
@@ -922,7 +944,7 @@ declare module 'react-native-firebase' {
/**
* Asynchronously signs in using a phone number.
*/
signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult>;
signInWithPhoneNumber(phoneNumber: string, forceResend?: boolean): Promise<ConfirmationResult>;
/**
* Returns a PhoneAuthListener to listen to phone verification events,
@@ -931,7 +953,8 @@ declare module 'react-native-firebase' {
*/
verifyPhoneNumber(
phoneNumber: string,
autoVerifyTimeout?: number
autoVerifyTimeoutOrForceResend?: number | boolean,
forceResend?: boolean,
): PhoneAuthListener;
/**
@@ -944,6 +967,11 @@ declare module 'react-native-firebase' {
actionCodeSettings?: ActionCodeSettings
): Promise<void>;
sendSignInLinkToEmail(
email: string,
actionCodeSettings?: ActionCodeSettings
): Promise<void>;
/**
* Completes the password reset process, given a confirmation code and new password.
*/
@@ -970,7 +998,7 @@ declare module 'react-native-firebase' {
}
interface AuthStatics {
EmailAuthProvider: AuthProvider;
EmailAuthProvider: EmailAuthProvider;
PhoneAuthProvider: AuthProvider;
GoogleAuthProvider: AuthProvider;
GithubAuthProvider: AuthProvider;
@@ -1061,6 +1089,8 @@ declare module 'react-native-firebase' {
interface InstanceId {
delete(): Promise<void>;
get(): Promise<string>;
getToken(authorizedEntity: string, scope: string): Promise<string>;
deleteToken(authorizedEntity: string, scope: string): Promise<void>;
}
}
@@ -1072,6 +1102,8 @@ declare module 'react-native-firebase' {
channelGroups: Android.ChannelGroup[]
): Promise<void>;
createChannels(channels: Android.Channel[]): Promise<void>;
deleteChannelGroup(groupId: string): Promise<void>;
deleteChannel(channelId: string): Promise<void>;
}
interface Notifications {
@@ -1454,6 +1486,68 @@ declare module 'react-native-firebase' {
}
}
namespace config {
interface ConfigSnapshot {
source: string;
val(): any;
}
interface Object<ConfigSnapshot> {
[key: string]: ConfigSnapshot;
}
interface Config {
/** Enable Remote Config developer mode to allow for frequent refreshes of the cache. */
enableDeveloperMode(): void;
/**
* Sets default values for the app to use when accessing values.
* Any data fetched and activated will override any default values.
* Any values in the defaults but not on Firebase will be untouched.
*/
setDefaults(defaults: object): void;
/**
* Fetches the remote config data from Firebase, defined in the dashboard.
* If duration is defined (seconds), data will be locally cached for this duration.
*
* The default duration is 43200 seconds (12 hours).
* To force a cache refresh call the method with a duration of 0.
*/
fetch(duration?: number): Promise<string>;
/**
* Fetches the remote config data from Firebase, defined in the dashboard.
* The default expiration duration is 43200 seconds (12 hours)
*/
activateFetched(): Promise<boolean>;
/**
* Gets a config item by key.
* Returns a snapshot containing source (default, remote or static) and val function.
*/
getValue(key: string): Promise<ConfigSnapshot>;
/**
* Gets multiple values by key.
* Returns a snapshot object with snapshot keys e.g. snapshots.foo.val().
*/
getValues(array: Array<string>): Promise<Object<ConfigSnapshot>>;
/**
* Returns all keys as an array by a prefix. If no prefix is defined all keys are returned.
*/
getKeysByPrefix(prefix?: string): Promise<Array<String>>;
/**
* Sets the default values from a resource:
* - Android: Id for the XML resource, which should be in your application's res/xml folder.
* - iOS: The plist file name, with no file name extension.
*/
setDefaultsFromResource(resource: string | number): void;
}
}
namespace crash {
interface Crash {
/** Logs a message that will appear in a subsequent crash report. */
@@ -1597,6 +1691,121 @@ declare module 'react-native-firebase' {
}
}
// Source: https://github.com/firebase/firebase-js-sdk/blob/master/packages/functions-types/index.d.ts
namespace functions {
type HttpsErrorCode = { [name: string]: FunctionsErrorCode };
/**
* The set of Firebase Functions status codes. The codes are the same at the
* ones exposed by gRPC here:
* https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
*
* Possible values:
* - 'cancelled': The operation was cancelled (typically by the caller).
* - 'unknown': Unknown error or an error from a different error domain.
* - 'invalid-argument': Client specified an invalid argument. Note that this
* differs from 'failed-precondition'. 'invalid-argument' indicates
* arguments that are problematic regardless of the state of the system
* (e.g. an invalid field name).
* - 'deadline-exceeded': Deadline expired before operation could complete.
* For operations that change the state of the system, this error may be
* returned even if the operation has completed successfully. For example,
* a successful response from a server could have been delayed long enough
* for the deadline to expire.
* - 'not-found': Some requested document was not found.
* - 'already-exists': Some document that we attempted to create already
* exists.
* - 'permission-denied': The caller does not have permission to execute the
* specified operation.
* - 'resource-exhausted': Some resource has been exhausted, perhaps a
* per-user quota, or perhaps the entire file system is out of space.
* - 'failed-precondition': Operation was rejected because the system is not
* in a state required for the operation's execution.
* - 'aborted': The operation was aborted, typically due to a concurrency
* issue like transaction aborts, etc.
* - 'out-of-range': Operation was attempted past the valid range.
* - 'unimplemented': Operation is not implemented or not supported/enabled.
* - 'internal': Internal errors. Means some invariants expected by
* underlying system has been broken. If you see one of these errors,
* something is very broken.
* - 'unavailable': The service is currently unavailable. This is most likely
* a transient condition and may be corrected by retrying with a backoff.
* - 'data-loss': Unrecoverable data loss or corruption.
* - 'unauthenticated': The request does not have valid authentication
* credentials for the operation.
*/
type FunctionsErrorCode =
| 'ok'
| 'cancelled'
| 'unknown'
| 'invalid-argument'
| 'deadline-exceeded'
| 'not-found'
| 'already-exists'
| 'permission-denied'
| 'resource-exhausted'
| 'failed-precondition'
| 'aborted'
| 'out-of-range'
| 'unimplemented'
| 'internal'
| 'unavailable'
| 'data-loss'
| 'unauthenticated';
/**
* An HttpsCallableResult wraps a single result from a function call.
*/
interface HttpsCallableResult {
readonly data: any;
}
/**
* An HttpsCallable is a reference to a "callable" http trigger in
* Google Cloud Functions.
*/
interface HttpsCallable {
(data?: any): Promise<HttpsCallableResult>;
}
/**
* `FirebaseFunctions` represents a Functions app, and is the entry point for
* all Functions operations.
*/
interface Functions {
/**
* Gets an `HttpsCallable` instance that refers to the function with the given
* name.
*
* @param name The name of the https callable function.
* @return The `HttpsCallable` instance.
*/
httpsCallable(name: string): HttpsCallable;
}
/**
* firebase.functions.X
*/
interface FunctionsStatics {
/**
* Uppercased + underscored variables of @FunctionsErrorCode
*/
HttpsErrorCode: HttpsErrorCode;
}
interface HttpsError extends Error {
/**
* A standard error code that will be returned to the client. This also
* determines the HTTP status code of the response, as defined in code.proto.
*/
readonly code: FunctionsErrorCode;
/**
* Extra data to be converted to JSON and included in the error response.
*/
readonly details?: any;
}
}
namespace firestore {
interface Firestore {
readonly app: App;
@@ -1631,7 +1840,7 @@ declare module 'react-native-firebase' {
endAt(...varargs: any[]): Query;
endBefore(snapshot: DocumentSnapshot): Query;
endBefore(...varargs: any[]): Query;
get(): Promise<QuerySnapshot>;
get(options?: Types.GetOptions): Promise<QuerySnapshot>;
limit(limit: number): Query;
onSnapshot(
onNext: Query.ObserverOnNext,
@@ -1639,12 +1848,12 @@ declare module 'react-native-firebase' {
): () => void;
onSnapshot(observer: Query.Observer): () => void;
onSnapshot(
queryListenOptions: Query.QueryListenOptions,
metadataChanges: MetadataChanges,
onNext: Query.ObserverOnNext,
onError?: Query.ObserverOnError
): () => void;
onSnapshot(
queryListenOptions: Query.QueryListenOptions,
metadataChanges: MetadataChanges,
observer: Query.Observer
): () => void;
orderBy(
@@ -1666,7 +1875,7 @@ declare module 'react-native-firebase' {
readonly doc: DocumentSnapshot;
readonly newIndex: number;
readonly oldIndex: number;
readonly type: string;
readonly type: 'added' | 'modified' | 'removed';
}
interface DocumentReference {
@@ -1676,22 +1885,22 @@ declare module 'react-native-firebase' {
readonly path: string;
collection(collectionPath: string): CollectionReference;
delete(): Promise<void>;
get(): Promise<DocumentSnapshot>;
get(options?: Types.GetOptions): Promise<DocumentSnapshot>;
onSnapshot(
onNext: DocumentReference.ObserverOnNext,
onError?: DocumentReference.ObserverOnError
): () => void;
onSnapshot(observer: DocumentReference.Observer): () => void;
onSnapshot(
documentListenOptions: DocumentReference.DocumentListenOptions,
metadataChanges: MetadataChanges,
onNext: DocumentReference.ObserverOnNext,
onError?: DocumentReference.ObserverOnError
): () => void;
onSnapshot(
documentListenOptions: DocumentReference.DocumentListenOptions,
metadataChanges: MetadataChanges,
observer: DocumentReference.Observer
): () => void;
set(data: object, writeOptions?: Types.WriteOptions): Promise<void>;
set(data: object, writeOptions?: Types.SetOptions): Promise<void>;
update(obj: object): Promise<void>;
update(key1: Types.UpdateKey, val1: any): Promise<void>;
update(
@@ -1732,10 +1941,6 @@ declare module 'react-native-firebase' {
): Promise<void>;
}
namespace DocumentReference {
interface DocumentListenOptions {
includeMetadataChanges: boolean;
}
type ObserverOnNext = (documentSnapshot: DocumentSnapshot) => void;
type ObserverOnError = (err: object) => void;
interface Observer {
@@ -1788,13 +1993,17 @@ declare module 'react-native-firebase' {
parent(): Path | null;
}
type MetadataChanges = {
includeMetadataChanges: boolean;
};
interface Query {
readonly firestore: Firestore;
endAt(snapshot: DocumentSnapshot): Query;
endAt(...varargs: any[]): Query;
endBefore(snapshot: DocumentSnapshot): Query;
endBefore(...varargs: any[]): Query;
get(): Promise<QuerySnapshot>;
get(options?: Types.GetOptions): Promise<QuerySnapshot>;
limit(limit: number): Query;
onSnapshot(
onNext: Query.ObserverOnNext,
@@ -1802,12 +2011,12 @@ declare module 'react-native-firebase' {
): () => void;
onSnapshot(observer: Query.Observer): () => void;
onSnapshot(
queryListenOptions: Query.QueryListenOptions,
metadataChanges: MetadataChanges,
onNext: Query.ObserverOnNext,
onError?: Query.ObserverOnError
): () => void;
onSnapshot(
queryListenOptions: Query.QueryListenOptions,
metadataChanges: MetadataChanges,
observer: Query.Observer
): () => void;
orderBy(
@@ -1852,19 +2061,6 @@ declare module 'react-native-firebase' {
startAt?: any[];
}
// The JS code expects at least one of 'includeDocumentMetadataChanges'
// or 'includeQueryMetadataChanges' to be defined.
interface _IncludeDocumentMetadataChanges {
includeDocumentMetadataChanges: boolean;
}
interface _IncludeQueryMetadataChanges {
includeQueryMetadataChanges: boolean;
}
type QueryListenOptions =
| _IncludeDocumentMetadataChanges
| _IncludeQueryMetadataChanges
| (_IncludeDocumentMetadataChanges & _IncludeQueryMetadataChanges);
type ObserverOnNext = (querySnapshot: QuerySnapshot) => void;
type ObserverOnError = (err: object) => void;
interface Observer {
@@ -1903,7 +2099,7 @@ declare module 'react-native-firebase' {
set(
documentRef: DocumentReference,
data: Object,
options?: Types.WriteOptions
options?: Types.SetOptions
): Transaction;
// multiple overrides for update() to allow strong-typed var_args
update(docRef: DocumentReference, obj: object): WriteBatch;
@@ -1960,7 +2156,7 @@ declare module 'react-native-firebase' {
set(
docRef: DocumentReference,
data: object,
options?: Types.WriteOptions
options?: Types.SetOptions
): WriteBatch;
// multiple overrides for update() to allow strong-typed var_args
update(docRef: DocumentReference, obj: object): WriteBatch;
@@ -2054,7 +2250,11 @@ declare module 'react-native-firebase' {
/** The key in update() function for DocumentReference and WriteBatch. */
type UpdateKey = string | FieldPath;
interface WriteOptions {
interface GetOptions {
source: 'default' | 'server' | 'cache';
}
interface SetOptions {
merge?: boolean;
}
}

View File

@@ -39,8 +39,7 @@ export type { default as DataQuery } from './modules/database/Query';
* Export Firestore types
*/
export type {
DocumentListenOptions,
QueryListenOptions,
MetadataChanges,
SetOptions,
SnapshotMetadata,
} from './modules/firestore/types';

View File

@@ -5,6 +5,7 @@
import User from './User';
import ModuleBase from '../../utils/ModuleBase';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { isAndroid, isBoolean } from '../../utils';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import INTERNALS from '../../utils/internals';
@@ -354,7 +355,16 @@ export default class Auth extends ModuleBase {
* Asynchronously signs in using a phone number.
*
*/
signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult> {
signInWithPhoneNumber(
phoneNumber: string,
forceResend?: boolean
): Promise<ConfirmationResult> {
if (isAndroid) {
return getNativeModule(this)
.signInWithPhoneNumber(phoneNumber, forceResend || false)
.then(result => new ConfirmationResult(this, result.verificationId));
}
return getNativeModule(this)
.signInWithPhoneNumber(phoneNumber)
.then(result => new ConfirmationResult(this, result.verificationId));
@@ -366,19 +376,36 @@ export default class Auth extends ModuleBase {
* authentication purposes.
*
* @param phoneNumber
* @param autoVerifyTimeout Android Only
* @param autoVerifyTimeoutOrForceResend Android Only
* @param forceResend Android Only
* @returns {PhoneAuthListener}
*/
verifyPhoneNumber(
phoneNumber: string,
autoVerifyTimeout?: number
autoVerifyTimeoutOrForceResend?: number | boolean,
forceResend?: boolean
): PhoneAuthListener {
return new PhoneAuthListener(this, phoneNumber, autoVerifyTimeout);
let _forceResend = forceResend;
let _autoVerifyTimeout = 60;
if (isBoolean(autoVerifyTimeoutOrForceResend)) {
_forceResend = autoVerifyTimeoutOrForceResend;
} else {
_autoVerifyTimeout = autoVerifyTimeoutOrForceResend;
}
return new PhoneAuthListener(
this,
phoneNumber,
_autoVerifyTimeout,
_forceResend
);
}
/**
* Send reset password instructions via email
* @param {string} email The email to send password reset instructions
* @param actionCodeSettings
*/
sendPasswordResetEmail(
email: string,
@@ -390,6 +417,50 @@ export default class Auth extends ModuleBase {
);
}
/**
* Sends a sign-in email link to the user with the specified email
* @param {string} email The email account to sign in with.
* @param actionCodeSettings
*/
sendSignInLinkToEmail(
email: string,
actionCodeSettings?: ActionCodeSettings
): Promise<void> {
return getNativeModule(this).sendSignInLinkToEmail(
email,
actionCodeSettings
);
}
/**
* Checks if an incoming link is a sign-in with email link.
* @param {string} emailLink Sign-in email link.
*/
isSignInWithEmailLink(emailLink: string): boolean {
return (
typeof emailLink === 'string' &&
(emailLink.includes('mode=signIn') ||
emailLink.includes('mode%3DsignIn')) &&
(emailLink.includes('oobCode=') || emailLink.includes('oobCode%3D'))
);
}
/**
* Asynchronously signs in using an email and sign-in email link.
*
* @param {string} email The email account to sign in with.
* @param {string} emailLink Sign-in email link.
* @return {Promise} A promise resolved upon completion
*/
signInWithEmailLink(
email: string,
emailLink: string
): Promise<UserCredential> {
return getNativeModule(this)
.signInWithEmailLink(email, emailLink)
.then(userCredential => this._setUserCredential(userCredential));
}
/**
* Completes the password reset process, given a confirmation code and new password.
*
@@ -427,9 +498,21 @@ export default class Auth extends ModuleBase {
/**
* Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address).
* @return {Promise}
* @Deprecated
*/
fetchProvidersForEmail(email: string): Promise<string[]> {
return getNativeModule(this).fetchProvidersForEmail(email);
console.warn(
'Deprecated firebase.auth().fetchProvidersForEmail in favor of firebase.auth().fetchSignInMethodsForEmail()'
);
return getNativeModule(this).fetchSignInMethodsForEmail(email);
}
/**
* Returns a list of authentication methods that can be used to sign in a given user (identified by its main email address).
* @return {Promise}
*/
fetchSignInMethodsForEmail(email: string): Promise<string[]> {
return getNativeModule(this).fetchSignInMethodsForEmail(email);
}
verifyPasswordResetCode(code: string): Promise<string> {

View File

@@ -32,6 +32,7 @@ export default class PhoneAuthListener {
_timeout: number;
_publicEvents: Object;
_internalEvents: Object;
_forceResending: boolean;
_reject: Function | null;
_resolve: Function | null;
_credential: Object | null;
@@ -43,8 +44,14 @@ export default class PhoneAuthListener {
* @param auth
* @param phoneNumber
* @param timeout
* @param forceResend
*/
constructor(auth: Auth, phoneNumber: string, timeout?: number) {
constructor(
auth: Auth,
phoneNumber: string,
timeout?: number,
forceResend?: boolean
) {
this._auth = auth;
this._reject = null;
this._resolve = null;
@@ -52,6 +59,7 @@ export default class PhoneAuthListener {
this._credential = null;
this._timeout = timeout || 20; // 20 secs
this._forceResending = forceResend || false;
this._phoneAuthRequestKey = generatePushID();
// internal events
@@ -86,7 +94,8 @@ export default class PhoneAuthListener {
getNativeModule(this._auth).verifyPhoneNumber(
phoneNumber,
this._phoneAuthRequestKey,
this._timeout
this._timeout,
this._forceResending
);
}
@@ -284,9 +293,9 @@ export default class PhoneAuthListener {
on(
event: string,
observer: () => PhoneAuthSnapshot,
errorCb?: () => PhoneAuthError,
successCb?: () => PhoneAuthSnapshot
observer: PhoneAuthSnapshot => void,
errorCb?: PhoneAuthError => void,
successCb?: PhoneAuthSnapshot => void
): this {
if (!isString(event)) {
throw new Error(
@@ -327,7 +336,7 @@ export default class PhoneAuthListener {
* Promise .then proxy
* @param fn
*/
then(fn: () => PhoneAuthSnapshot) {
then(fn: PhoneAuthSnapshot => void) {
this._promiseDeferred();
// $FlowFixMe: Unsure how to annotate `bind` here
if (this._promise) return this._promise.then.bind(this._promise)(fn);
@@ -338,7 +347,7 @@ export default class PhoneAuthListener {
* Promise .catch proxy
* @param fn
*/
catch(fn: () => Error) {
catch(fn: Error => void) {
this._promiseDeferred();
// $FlowFixMe: Unsure how to annotate `bind` here
if (this._promise) return this._promise.catch.bind(this._promise)(fn);

View File

@@ -4,7 +4,8 @@
*/
import type { AuthCredential } from '../types';
const providerId = 'password';
const linkProviderId = 'emailLink';
const passwordProviderId = 'password';
export default class EmailAuthProvider {
constructor() {
@@ -13,15 +14,37 @@ export default class EmailAuthProvider {
);
}
static get EMAIL_LINK_SIGN_IN_METHOD(): string {
return linkProviderId;
}
static get EMAIL_PASSWORD_SIGN_IN_METHOD(): string {
return passwordProviderId;
}
static get PROVIDER_ID(): string {
return providerId;
return passwordProviderId;
}
static credential(email: string, password: string): AuthCredential {
return {
token: email,
secret: password,
providerId,
providerId: passwordProviderId,
};
}
/**
* Initialize an EmailAuthProvider credential using an email and an email link after a sign in with email link operation.
* @param email Email address.
* @param emailLink Sign-in email link.
* @returns {{token: string, secret: string, providerId: string}}
*/
static credentialWithLink(email: string, emailLink: string): AuthCredential {
return {
token: email,
secret: emailLink,
providerId: linkProviderId,
};
}
}

View File

@@ -22,6 +22,11 @@ type NativeValue = {
export const MODULE_NAME = 'RNFirebaseRemoteConfig';
export const NAMESPACE = 'config';
type ConfigSnapshot = {
source: string,
val(): any,
};
/**
* @class Config
*/
@@ -44,7 +49,7 @@ export default class RemoteConfig extends ModuleBase {
* @returns {*}
* @private
*/
_nativeValueToJS(nativeValue: NativeValue) {
_nativeValueToJS(nativeValue: NativeValue): ConfigSnapshot {
return {
source: nativeValue.source,
val() {
@@ -89,7 +94,7 @@ export default class RemoteConfig extends ModuleBase {
* Call activateFetched to make fetched data available in app
* @returns {*|Promise.<String>}:
*/
fetch(expiration?: number) {
fetch(expiration?: number): Promise<string> {
if (expiration !== undefined) {
getLogger(this).debug(
`Fetching remote config data with expiration ${expiration.toString()}`
@@ -106,7 +111,7 @@ export default class RemoteConfig extends ModuleBase {
* resolves if there was a Fetched Config, and it was activated,
* rejects if no Fetched Config was found, or the Fetched Config was already activated.
*/
activateFetched() {
activateFetched(): Promise<boolean> {
getLogger(this).debug('Activating remote config');
return getNativeModule(this).activateFetched();
}
@@ -124,7 +129,7 @@ export default class RemoteConfig extends ModuleBase {
* "source" : OneOf<String>(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic)
* }
*/
getValue(key: string) {
getValue(key: string): Promise<ConfigSnapshot> {
return getNativeModule(this)
.getValue(key || '')
.then(this._nativeValueToJS);
@@ -144,7 +149,7 @@ export default class RemoteConfig extends ModuleBase {
* "source" : OneOf<String>(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic)
* }
*/
getValues(keys: Array<string>) {
getValues(keys: Array<string>): Promise<{ [string]: ConfigSnapshot }> {
return getNativeModule(this)
.getValues(keys || [])
.then(nativeValues => {
@@ -161,7 +166,7 @@ export default class RemoteConfig extends ModuleBase {
* @param prefix: The key prefix to look for. If prefix is nil or empty, returns all the keys.
* @returns {*|Promise.<Array<String>>}
*/
getKeysByPrefix(prefix?: string) {
getKeysByPrefix(prefix?: string): Promise<string[]> {
return getNativeModule(this).getKeysByPrefix(prefix);
}
@@ -169,7 +174,7 @@ export default class RemoteConfig extends ModuleBase {
* Sets config defaults for parameter keys and values in the default namespace config.
* @param defaults: A dictionary mapping a String key to a Object values.
*/
setDefaults(defaults: Object) {
setDefaults(defaults: Object): void {
getNativeModule(this).setDefaults(defaults);
}
@@ -177,7 +182,7 @@ export default class RemoteConfig extends ModuleBase {
* Sets default configs from plist for default namespace;
* @param resource: The plist file name or resource ID
*/
setDefaultsFromResource(resource: string | number) {
setDefaultsFromResource(resource: string | number): void {
getNativeModule(this).setDefaultsFromResource(resource);
}
}

View File

@@ -892,3 +892,12 @@ export default class Reference extends ReferenceBase {
return SyncTree.removeListenersForRegistrations(registrations);
}
}
// eslint-disable-next-line no-unused-vars
// class ThenableReference<+R> extends Reference {
// then<U>(
// onFulfill?: (value: R) => Promise<U> | U,
// onReject?: (error: any) => Promise<U> | U
// ): Promise<U>;
// catch<U>(onReject?: (error: any) => Promise<U> | U): Promise<R | U>;
// }

View File

@@ -8,8 +8,9 @@ import { firestoreAutoId } from '../../utils';
import type Firestore from './';
import type {
GetOptions,
MetadataChanges,
QueryDirection,
QueryListenOptions,
QueryOperator,
} from './types';
import type FieldPath from './FieldPath';
@@ -71,8 +72,8 @@ export default class CollectionReference {
return this._query.endBefore(snapshotOrVarArgs);
}
get(): Promise<QuerySnapshot> {
return this._query.get();
get(options?: GetOptions): Promise<QuerySnapshot> {
return this._query.get(options);
}
limit(limit: number): Query {
@@ -80,7 +81,7 @@ export default class CollectionReference {
}
onSnapshot(
optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
optionsOrObserverOrOnNext: MetadataChanges | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: ObserverOnError
): () => void {

View File

@@ -14,7 +14,7 @@ export default class DocumentChange {
_document: DocumentSnapshot;
_newIndex: number;
_oldIndex: number;
_type: string;
_type: 'added' | 'modified' | 'removed';
constructor(firestore: Firestore, nativeData: NativeDocumentChange) {
this._document = new DocumentSnapshot(firestore, nativeData.document);

View File

@@ -13,7 +13,8 @@ import { getNativeModule } from '../../utils/native';
import type Firestore from './';
import type {
DocumentListenOptions,
GetOptions,
MetadataChanges,
NativeDocumentSnapshot,
SetOptions,
} from './types';
@@ -70,17 +71,34 @@ export default class DocumentReference {
return getNativeModule(this._firestore).documentDelete(this.path);
}
get(): Promise<DocumentSnapshot> {
get(options?: GetOptions): Promise<DocumentSnapshot> {
if (options) {
if (!isObject(options)) {
return Promise.reject(
new Error(
'DocumentReference.get failed: First argument must be an object.'
)
);
} else if (
options.source &&
(options.source !== 'default' &&
options.source !== 'server' &&
options.source !== 'cache')
) {
return Promise.reject(
new Error(
'DocumentReference.get failed: GetOptions.source must be one of `default`, `server` or `cache`.'
)
);
}
}
return getNativeModule(this._firestore)
.documentGet(this.path)
.documentGet(this.path, options)
.then(result => new DocumentSnapshot(this._firestore, result));
}
onSnapshot(
optionsOrObserverOrOnNext:
| DocumentListenOptions
| Observer
| ObserverOnNext,
optionsOrObserverOrOnNext: MetadataChanges | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: ObserverOnError
) {

View File

@@ -14,9 +14,10 @@ import { getNativeModule } from '../../utils/native';
import type Firestore from './';
import type Path from './Path';
import type {
MetadataChanges,
QueryDirection,
QueryOperator,
QueryListenOptions,
GetOptions,
} from './types';
const DIRECTIONS: { [QueryDirection]: string } = {
@@ -141,13 +142,32 @@ export default class Query {
);
}
get(): Promise<QuerySnapshot> {
get(options?: GetOptions): Promise<QuerySnapshot> {
if (options) {
if (!isObject(options)) {
return Promise.reject(
new Error('Query.get failed: First argument must be an object.')
);
} else if (
options.source &&
(options.source !== 'default' &&
options.source !== 'server' &&
options.source !== 'cache')
) {
return Promise.reject(
new Error(
'Query.get failed: GetOptions.source must be one of `default`, `server` or `cache`.'
)
);
}
}
return getNativeModule(this._firestore)
.collectionGet(
this._referencePath.relativeName,
this._fieldFilters,
this._fieldOrders,
this._queryOptions
this._queryOptions,
options
)
.then(nativeData => new QuerySnapshot(this._firestore, this, nativeData));
}
@@ -170,12 +190,12 @@ export default class Query {
}
onSnapshot(
optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
optionsOrObserverOrOnNext: MetadataChanges | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: ObserverOnError
) {
let observer: Observer;
let queryListenOptions = {};
let metadataChanges = {};
// Called with: onNext, ?onError
if (isFunction(optionsOrObserverOrOnNext)) {
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
@@ -216,14 +236,10 @@ export default class Query {
} else if (
Object.prototype.hasOwnProperty.call(
optionsOrObserverOrOnNext,
'includeDocumentMetadataChanges'
) ||
Object.prototype.hasOwnProperty.call(
optionsOrObserverOrOnNext,
'includeQueryMetadataChanges'
'includeMetadataChanges'
)
) {
queryListenOptions = optionsOrObserverOrOnNext;
metadataChanges = optionsOrObserverOrOnNext;
// Called with: Options, onNext, ?onError
if (isFunction(observerOrOnNextOrOnError)) {
if (onError && !isFunction(onError)) {
@@ -307,7 +323,7 @@ export default class Query {
this._fieldOrders,
this._queryOptions,
listenerId,
queryListenOptions
metadataChanges
);
// Return an unsubscribe method

View File

@@ -2,19 +2,18 @@
* @flow
*/
export type DocumentListenOptions = {
export type MetadataChanges = {|
includeMetadataChanges: boolean,
};
|};
export type QueryDirection = 'DESC' | 'desc' | 'ASC' | 'asc';
export type QueryListenOptions = {|
includeDocumentMetadataChanges: boolean,
includeQueryMetadataChanges: boolean,
|};
export type QueryOperator = '<' | '<=' | '=' | '==' | '>' | '>=';
export type GetOptions = {
source: 'default' | 'server' | 'cache',
};
export type SetOptions = {
merge?: boolean,
};
@@ -28,7 +27,7 @@ export type NativeDocumentChange = {
document: NativeDocumentSnapshot,
newIndex: number,
oldIndex: number,
type: string,
type: 'added' | 'modified' | 'removed',
};
export type NativeDocumentSnapshot = {

View File

@@ -18,6 +18,26 @@ import type {
export const NAMESPACE = 'functions';
export const MODULE_NAME = 'RNFirebaseFunctions';
/**
* -------------
* INTERNALS
* -------------
*/
function errorOrResult(possibleError): HttpsCallablePromise {
if (isObject(possibleError) && possibleError.__error) {
const { code, message, details } = possibleError;
return Promise.reject(
new HttpsError(
statics.HttpsErrorCode[code] || statics.HttpsErrorCode.UNKNOWN,
message,
details
)
);
}
return Promise.resolve(possibleError);
}
export default class Functions extends ModuleBase {
constructor(app: App) {
super(app, {
@@ -41,29 +61,9 @@ export default class Functions extends ModuleBase {
httpsCallable(name: string): HttpsCallable {
return (data?: any): HttpsCallablePromise => {
const promise = getNativeModule(this).httpsCallable(name, { data });
return promise.then(this._errorOrResult);
return promise.then(errorOrResult);
};
}
/**
* -------------
* INTERNALS
* -------------
*/
_errorOrResult(possibleError): HttpsCallablePromise {
if (isObject(possibleError) && possibleError.__error) {
const { code, message, details } = possibleError;
return Promise.reject(
new HttpsError(
statics.HttpsErrorCode[code] || statics.HttpsErrorCode.UNKNOWN,
message,
details
)
);
}
return Promise.resolve(possibleError);
}
}
export const statics: { HttpsErrorCode: HttpsErrorCode } = {

View File

@@ -27,6 +27,14 @@ export default class InstanceId extends ModuleBase {
get(): Promise<string> {
return getNativeModule(this).get();
}
getToken(authorizedEntity: string, scope: string): Promise<string> {
return getNativeModule(this).getToken(authorizedEntity, scope);
}
deleteToken(authorizedEntity: string, scope: string): Promise<void> {
return getNativeModule(this).deleteToken(authorizedEntity, scope);
}
}
export const statics = {};

View File

@@ -21,6 +21,7 @@ export default class AndroidAction {
this._action = action;
this._icon = icon;
this._remoteInputs = [];
this._showUserInterface = true;
this._title = title;
}

View File

@@ -671,6 +671,16 @@ export default class AndroidNotification {
return this._notification;
}
/**
*
* @param visibility
* @returns {Notification}
*/
setVisibility(visibility: VisibilityType): Notification {
this._visibility = visibility;
return this._notification;
}
/**
*
* @param when

View File

@@ -92,20 +92,41 @@ export default class AndroidNotifications {
return Promise.resolve();
}
/**
* Remove a delivered notifications by tag.
* @param tag
*/
removeDeliveredNotificationsByTag(tag: string): Promise<void> {
if (!tag) {
return Promise.reject(
new Error(
'Notifications: removeDeliveredNotificationsByTag expects a `tag`'
)
);
if (Platform.OS === 'android') {
if (typeof tag !== 'string') {
throw new Error(
`AndroidNotifications:removeDeliveredNotificationsByTag expects an 'string' but got type ${typeof tag}`
);
}
return getNativeModule(
this._notifications
).removeDeliveredNotificationsByTag(tag);
}
return getNativeModule(
this._notifications
).removeDeliveredNotificationsByTag(tag);
return Promise.resolve();
}
deleteChannelGroup(groupId: string): Promise<void> {
if (Platform.OS === 'android') {
if (typeof groupId !== 'string') {
throw new Error(
`AndroidNotifications:deleteChannelGroup expects an 'string' but got type ${typeof groupId}`
);
}
return getNativeModule(this._notifications).deleteChannelGroup(groupId);
}
return Promise.resolve();
}
deleteChannel(channelId: string): Promise<void> {
if (Platform.OS === 'android') {
if (typeof channelId !== 'string') {
throw new Error(
`AndroidNotifications:deleteChannel expects an 'string' but got type ${typeof channelId}`
);
}
return getNativeModule(this._notifications).deleteChannel(channelId);
}
return Promise.resolve();
}
}

View File

@@ -44,7 +44,7 @@ export const Importance = {
Low: 2,
Max: 5,
Min: 1,
None: 3,
None: 0,
Unspecified: -1000,
};

View File

@@ -7,6 +7,7 @@ import { NativeModules } from 'react-native';
import StorageRef from './reference';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { stripTrailingSlash } from '../../utils';
import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
@@ -149,16 +150,29 @@ export const statics = {
},
Native: FirebaseStorage
? {
MAIN_BUNDLE_PATH: FirebaseStorage.MAIN_BUNDLE_PATH,
CACHES_DIRECTORY_PATH: FirebaseStorage.CACHES_DIRECTORY_PATH,
DOCUMENT_DIRECTORY_PATH: FirebaseStorage.DOCUMENT_DIRECTORY_PATH,
EXTERNAL_DIRECTORY_PATH: FirebaseStorage.EXTERNAL_DIRECTORY_PATH,
EXTERNAL_STORAGE_DIRECTORY_PATH:
FirebaseStorage.EXTERNAL_STORAGE_DIRECTORY_PATH,
TEMP_DIRECTORY_PATH: FirebaseStorage.TEMP_DIRECTORY_PATH,
LIBRARY_DIRECTORY_PATH: FirebaseStorage.LIBRARY_DIRECTORY_PATH,
FILETYPE_REGULAR: FirebaseStorage.FILETYPE_REGULAR,
FILETYPE_DIRECTORY: FirebaseStorage.FILETYPE_DIRECTORY,
MAIN_BUNDLE_PATH: stripTrailingSlash(FirebaseStorage.MAIN_BUNDLE_PATH),
CACHES_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.CACHES_DIRECTORY_PATH
),
DOCUMENT_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.DOCUMENT_DIRECTORY_PATH
),
EXTERNAL_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.EXTERNAL_DIRECTORY_PATH
),
EXTERNAL_STORAGE_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.EXTERNAL_STORAGE_DIRECTORY_PATH
),
TEMP_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.TEMP_DIRECTORY_PATH
),
LIBRARY_DIRECTORY_PATH: stripTrailingSlash(
FirebaseStorage.LIBRARY_DIRECTORY_PATH
),
FILETYPE_REGULAR: stripTrailingSlash(FirebaseStorage.FILETYPE_REGULAR),
FILETYPE_DIRECTORY: stripTrailingSlash(
FirebaseStorage.FILETYPE_DIRECTORY
),
}
: {},
};

View File

@@ -96,7 +96,8 @@ export default class StorageReference extends ReferenceBase {
* @return {Promise}
*/
putFile(filePath: Object, metadata: Object = {}): Promise<Object> {
const _filePath = filePath.replace('file://', '');
let _filePath = filePath.replace('file://', '');
if (_filePath.includes('%')) _filePath = decodeURI(_filePath);
return new StorageTask(
UPLOAD_TASK,
getNativeModule(this._storage).putFile(this.path, _filePath, metadata),

View File

@@ -190,63 +190,15 @@ export function tryJSONStringify(data: mixed): string | null {
*/
export function noop(): void {}
// /**
// * Delays chunks based on sizes per event loop.
// * @param collection
// * @param chunkSize
// * @param operation
// * @param callback
// * @private
// */
// function _delayChunk(collection: Array<*>,
// chunkSize: number,
// operation: Function,
// callback: Function): void {
// const length = collection.length;
// const iterations = Math.ceil(length / chunkSize);
//
// // noinspection ES6ConvertVarToLetConst
// let thisIteration = 0;
//
// setImmediate(function next() {
// const start = thisIteration * chunkSize;
// const _end = start + chunkSize;
// const end = _end >= length ? length : _end;
// const result = operation(collection.slice(start, end), start, end);
//
// if (thisIteration++ > iterations) {
// callback(null, result);
// } else {
// setImmediate(next);
// }
// });
// }
//
// /**
// * Async each with optional chunk size limit
// * @param array
// * @param chunkSize
// * @param iterator
// * @param cb
// */
// export function each(array: Array<*>,
// chunkSize: number | Function,
// iterator: Function,
// cb?: Function): void {
// if (typeof chunkSize === 'function') {
// cb = iterator;
// iterator = chunkSize;
// chunkSize = DEFAULT_CHUNK_SIZE;
// }
//
// if (cb) {
// _delayChunk(array, chunkSize, (slice, start) => {
// for (let ii = 0, jj = slice.length; ii < jj; ii += 1) {
// iterator(slice[ii], start + ii);
// }
// }, cb);
// }
// }
/**
* Remove a trailing forward slash from a string
* @param str
* @returns {*}
*/
export function stripTrailingSlash(str: string): string {
if (!isString(str)) return str;
return str.endsWith('/') ? str.slice(0, -1) : str;
}
/**
* Returns a string typeof that's valid for Firebase usage
@@ -259,42 +211,6 @@ export function typeOf(value: any): string {
return typeof value;
}
// /**
// * Async map with optional chunk size limit
// * @param array
// * @param chunkSize
// * @param iterator
// * @param cb
// * @returns {*}
// */
// export function map(array: Array<*>,
// chunkSize: number | Function,
// iterator: Function,
// cb?: Function): void {
// if (typeof chunkSize === 'function') {
// cb = iterator;
// iterator = chunkSize;
// chunkSize = DEFAULT_CHUNK_SIZE;
// }
//
// const result = [];
// _delayChunk(array, chunkSize, (slice, start) => {
// for (let ii = 0, jj = slice.length; ii < jj; ii += 1) {
// result.push(iterator(slice[ii], start + ii, array));
// }
// return result;
// }, () => cb && cb(result));
// }
// /**
// *
// * @param string
// * @return {string}
// */
// export function capitalizeFirstLetter(string: string) {
// return `${string.charAt(0).toUpperCase()}${string.slice(1)}`;
// }
// timestamp of last push, used to prevent local collisions if you push twice in one ms.
let lastPushTime = 0;

3778
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
{
"name": "react-native-firebase",
"version": "4.0.7",
"version": "4.3.5",
"author": "Invertase <contact@invertase.io> (http://invertase.io)",
"description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Messaging (FCM), Remote Config, Storage and Performance.",
"description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Storage and more.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
@@ -35,8 +35,8 @@
"setupFiles": [],
"unmockedModulePathPatterns": ["./node_modules/react", "./node_modules/react-native", "./node_modules/react-native-mock", "./node_modules/react-addons-test-utils"]
},
"license": "APACHE-2.0",
"keywords": ["react", "admob", "auth", "config", "digits", "fabric", "phone-auth", "sms", "firestore", "cloud-firestore", "datastore", "remote-config", "transactions", "react-native", "react-native-firebase", "firebase", "fcm", "apn", "gcm", "analytics", "messaging", "database", "android", "ios", "crash", "firestack", "performance", "firestore", "dynamic-links", "crashlytics"],
"license": "Apache-2.0",
"keywords": ["react", "admob", "auth", "config", "digits", "fabric", "functions", "phone-auth", "sms", "firestore", "cloud-firestore", "datastore", "remote-config", "transactions", "react-native", "react-native-firebase", "firebase", "fcm", "apn", "gcm", "analytics", "messaging", "database", "android", "ios", "crash", "firestack", "performance", "firestore", "dynamic-links", "crashlytics"],
"peerDependencies": {
"react": "*",
"react-native": ">= 0.48.0",
@@ -79,12 +79,9 @@
},
"rnpm": {
"android": {
"buildPatch": " compile(project(':react-native-firebase')) {\n transitive = false\n }\n",
"buildPatch": " implementation project(':react-native-firebase')",
"packageImportPath": "import io.invertase.firebase.RNFirebasePackage;",
"packageInstance": "new RNFirebasePackage()"
},
"commands": {
"postlink": "node node_modules/react-native-firebase/scripts/rnpm-postlink"
}
},
"collective": {

View File

@@ -4,7 +4,8 @@ const path = require('path');
const appBuildGradlePath = path.join('android', 'app', 'build.gradle');
const defaultCompileStatement = "compile project(':react-native-firebase')";
const requiredCompileStatement = "compile(project(':react-native-firebase')) {\n transitive = false\n }";
const requiredCompileStatement =
"compile(project(':react-native-firebase')) {\n transitive = false\n }";
// android/build.gradle
// 1) TODO: Add Google Play maven repository
@@ -16,7 +17,10 @@ const requiredCompileStatement = "compile(project(':react-native-firebase')) {\n
let buildGradleContents = fs.readFileSync(appBuildGradlePath, 'utf8');
// 1) Check that react-native-firebase compile statement is the correct format
buildGradleContents = buildGradleContents.replace(defaultCompileStatement, requiredCompileStatement);
buildGradleContents = buildGradleContents.replace(
defaultCompileStatement,
requiredCompileStatement
);
// 2) TODO: Add firebase-core and play-services-base dependencies

View File

@@ -70,29 +70,31 @@ android {
}
}
project.ext.firebaseVersion = '12.0.0'
dependencies {
implementation project(':react-native-vector-icons')
implementation(project(':react-native-firebase')) {
transitive = false
}
implementation project(':react-native-firebase')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.google.android.gms:play-services-base:$firebaseVersion"
implementation "com.google.firebase:firebase-ads:$firebaseVersion"
implementation "com.google.firebase:firebase-auth:$firebaseVersion"
implementation "com.google.firebase:firebase-config:$firebaseVersion"
implementation "com.google.firebase:firebase-core:$firebaseVersion"
implementation "com.google.firebase:firebase-crash:$firebaseVersion"
implementation "com.google.firebase:firebase-database:$firebaseVersion"
implementation "com.google.firebase:firebase-messaging:$firebaseVersion"
implementation "com.google.firebase:firebase-perf:$firebaseVersion"
implementation "com.google.firebase:firebase-storage:$firebaseVersion"
implementation "com.google.firebase:firebase-firestore:$firebaseVersion"
implementation "com.google.firebase:firebase-invites:$firebaseVersion"
implementation('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
implementation('com.crashlytics.sdk.android:crashlytics:2.9.3@aar') {
transitive = true
}
// RNFirebase required dependencies
implementation "com.google.firebase:firebase-core:16.0.1"
implementation "com.google.android.gms:play-services-base:15.0.1"
// RNFirebase optional dependencies
implementation "com.google.firebase:firebase-ads:15.0.1"
implementation "com.google.firebase:firebase-auth:16.0.2"
implementation "com.google.firebase:firebase-config:16.0.0"
implementation "com.google.firebase:firebase-crash:16.0.1"
implementation "com.google.firebase:firebase-database:16.0.1"
implementation "com.google.firebase:firebase-firestore:17.0.2"
implementation "com.google.firebase:firebase-functions:16.0.1"
implementation "com.google.firebase:firebase-invites:16.0.1"
implementation "com.google.firebase:firebase-storage:16.0.1"
implementation "com.google.firebase:firebase-messaging:17.0.0"
implementation "com.google.firebase:firebase-perf:16.0.0"
implementation "com.android.support:appcompat-v7:27.0.2"
implementation "com.facebook.react:react-native:+" // From node_modules
}

View File

@@ -2,29 +2,29 @@
buildscript {
repositories {
jcenter()
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0'
classpath 'com.google.gms:google-services:3.1.2'
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.google.gms:google-services:4.0.1'
classpath 'com.google.firebase:firebase-plugins:1.1.1'
classpath 'io.fabric.tools:gradle:1.25.1'
classpath 'io.fabric.tools:gradle:1.25.4'
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
mavenLocal()
google()
}
}

View File

@@ -1,88 +1,93 @@
PODS:
- boost-for-react-native (1.63.0)
- BoringSSL (10.0.2):
- BoringSSL/Implementation (= 10.0.2)
- BoringSSL/Interface (= 10.0.2)
- BoringSSL/Implementation (10.0.2):
- BoringSSL/Interface (= 10.0.2)
- BoringSSL/Interface (10.0.2)
- Crashlytics (3.10.1):
- Fabric (~> 1.7.5)
- BoringSSL (10.0.5):
- BoringSSL/Implementation (= 10.0.5)
- BoringSSL/Interface (= 10.0.5)
- BoringSSL/Implementation (10.0.5):
- BoringSSL/Interface (= 10.0.5)
- BoringSSL/Interface (10.0.5)
- Crashlytics (3.10.2):
- Fabric (~> 1.7.7)
- DoubleConversion (1.1.5)
- Fabric (1.7.6)
- Firebase/AdMob (4.12.0):
- Fabric (1.7.7)
- Firebase/AdMob (5.3.0):
- Firebase/Core
- Google-Mobile-Ads-SDK (= 7.30.0)
- Firebase/Auth (4.12.0):
- Google-Mobile-Ads-SDK (= 7.31.0)
- Firebase/Auth (5.3.0):
- Firebase/CoreOnly
- FirebaseAuth (= 5.0.1)
- Firebase/Core (5.3.0):
- Firebase/CoreOnly
- FirebaseAnalytics (= 5.0.1)
- Firebase/CoreOnly (5.3.0):
- FirebaseCore (= 5.0.4)
- Firebase/Crash (5.3.0):
- Firebase/Core
- FirebaseAuth (= 4.6.0)
- Firebase/Core (4.12.0):
- FirebaseAnalytics (= 4.1.0)
- FirebaseCore (= 4.0.19)
- Firebase/Crash (4.12.0):
- FirebaseCrash (= 3.0.0)
- Firebase/Database (5.3.0):
- Firebase/CoreOnly
- FirebaseDatabase (= 5.0.1)
- Firebase/DynamicLinks (5.3.0):
- Firebase/Core
- FirebaseCrash (= 2.0.2)
- Firebase/Database (4.12.0):
- FirebaseDynamicLinks (= 3.0.1)
- Firebase/Firestore (5.3.0):
- Firebase/CoreOnly
- FirebaseFirestore (= 0.12.4)
- Firebase/Invites (5.3.0):
- Firebase/Core
- FirebaseDatabase (= 4.1.5)
- Firebase/DynamicLinks (4.12.0):
- FirebaseInvites (= 3.0.0)
- Firebase/Messaging (5.3.0):
- Firebase/CoreOnly
- FirebaseMessaging (= 3.0.2)
- Firebase/Performance (5.3.0):
- Firebase/Core
- FirebaseDynamicLinks (= 2.3.2)
- Firebase/Firestore (4.12.0):
- FirebasePerformance (= 2.0.1)
- Firebase/RemoteConfig (5.3.0):
- Firebase/Core
- FirebaseFirestore (= 0.11.0)
- Firebase/Invites (4.12.0):
- Firebase/Core
- FirebaseInvites (= 2.0.2)
- Firebase/Messaging (4.12.0):
- Firebase/Core
- FirebaseMessaging (= 2.2.0)
- Firebase/Performance (4.12.0):
- Firebase/Core
- FirebasePerformance (= 1.1.3)
- Firebase/RemoteConfig (4.12.0):
- Firebase/Core
- FirebaseRemoteConfig (= 2.1.3)
- Firebase/Storage (4.12.0):
- Firebase/Core
- FirebaseStorage (= 2.2.0)
- FirebaseABTesting (1.0.0):
- FirebaseCore (~> 4.0)
- Protobuf (~> 3.1)
- FirebaseAnalytics (4.1.0):
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- FirebaseRemoteConfig (= 3.0.0)
- Firebase/Storage (5.3.0):
- Firebase/CoreOnly
- FirebaseStorage (= 3.0.0)
- FirebaseABTesting (2.0.0):
- FirebaseCore (~> 5.0)
- Protobuf (~> 3.5)
- FirebaseAnalytics (5.0.1):
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- nanopb (~> 0.3)
- FirebaseAuth (4.6.0):
- FirebaseAnalytics (~> 4.1)
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
- FirebaseAuth (5.0.1):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- FirebaseCore (4.0.19):
- FirebaseCore (5.0.4):
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseCrash (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- FirebaseCrash (3.0.0):
- FirebaseAnalytics (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.1)
- FirebaseDatabase (4.1.5):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- Protobuf (~> 3.5)
- FirebaseDatabase (5.0.1):
- FirebaseCore (~> 5.0)
- leveldb-library (~> 1.18)
- FirebaseDynamicLinks (2.3.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseFirestore (0.11.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseDynamicLinks (3.0.1):
- FirebaseAnalytics (~> 5.0)
- FirebaseFirestore (0.12.4):
- FirebaseCore (~> 5.0)
- FirebaseFirestore/abseil-cpp (= 0.12.4)
- gRPC-ProtoRPC (~> 1.0)
- leveldb-library (~> 1.18)
- Protobuf (~> 3.5)
- FirebaseInstanceID (2.0.10):
- FirebaseCore (~> 4.0)
- FirebaseInvites (2.0.2):
- FirebaseAnalytics (~> 4.0)
- FirebaseDynamicLinks (~> 2.2)
- Protobuf (~> 3.1)
- FirebaseFirestore/abseil-cpp (0.12.4):
- FirebaseCore (~> 5.0)
- gRPC-ProtoRPC (~> 1.0)
- leveldb-library (~> 1.18)
- Protobuf (~> 3.1)
- FirebaseInstanceID (3.1.1):
- FirebaseCore (~> 5.0)
- FirebaseInvites (3.0.0):
- FirebaseAnalytics (~> 5.0)
- FirebaseDynamicLinks (~> 3.0)
- GoogleAPIClientForREST (~> 1.0)
- GoogleSignIn (~> 4.1)
- GoogleToolboxForMac/Logger (~> 2.1)
@@ -93,42 +98,40 @@ PODS:
- GTMOAuth2 (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GTMSessionFetcher/Full (~> 1.1)
- Protobuf (~> 3.5)
- FirebaseMessaging (3.0.2):
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- Protobuf (~> 3.1)
- FirebaseMessaging (2.2.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- Protobuf (~> 3.5)
- FirebasePerformance (1.1.3):
- FirebaseAnalytics (~> 4.1)
- FirebaseInstanceID (~> 2.0)
- FirebaseSwizzlingUtilities/ISASwizzling (~> 1.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (~> 1.0)
- FirebasePerformance (2.0.1):
- FirebaseAnalytics (~> 5.0)
- FirebaseInstanceID (~> 3.1)
- FirebaseSwizzlingUtilities/ISASwizzling (~> 2.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- GTMSessionFetcher/Core (~> 1.1)
- Protobuf (~> 3.5)
- FirebaseRemoteConfig (2.1.3):
- FirebaseABTesting (~> 1.0)
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- FirebaseRemoteConfig (3.0.0):
- FirebaseABTesting (~> 2.0)
- FirebaseAnalytics (~> 5.0)
- FirebaseCore (~> 5.0)
- FirebaseInstanceID (~> 3.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.5)
- FirebaseStorage (2.2.0):
- FirebaseAnalytics (~> 4.1)
- FirebaseCore (~> 4.0)
- FirebaseStorage (3.0.0):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- FirebaseSwizzlingUtilities/ISASwizzling (1.0.1)
- FirebaseSwizzlingUtilities/MethodSwizzling (1.0.1):
- FirebaseCore (~> 4.0)
- FirebaseSwizzlingUtilities/ISASwizzling (2.0.0)
- FirebaseSwizzlingUtilities/MethodSwizzling (2.0.0):
- FirebaseCore (~> 5.0)
- Folly (2016.09.26.00):
- boost-for-react-native
- DoubleConversion
- glog
- glog (0.3.4)
- Google-Mobile-Ads-SDK (7.30.0)
- Google-Mobile-Ads-SDK (7.31.0)
- GoogleAPIClientForREST (1.3.4):
- GoogleAPIClientForREST/Core (= 1.3.4)
- GTMSessionFetcher (>= 1.1.7)
@@ -139,46 +142,46 @@ PODS:
- GoogleToolboxForMac/NSString+URLArguments (~> 2.1)
- GTMOAuth2 (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GoogleToolboxForMac/Core (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/DebugUtils (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/Defines (2.1.3)
- GoogleToolboxForMac/Logger (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSData+zlib (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSDictionary+URLArguments (2.1.3):
- GoogleToolboxForMac/DebugUtils (= 2.1.3)
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (2.1.3)
- GoogleToolboxForMac/StringEncoding (2.1.3):
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/URLBuilder (2.1.3):
- GoogleToolboxForMac/Core (= 2.1.3)
- GoogleToolboxForMac/Defines (= 2.1.3)
- GoogleToolboxForMac/NSDictionary+URLArguments (= 2.1.3)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.3)
- gRPC (1.10.0):
- gRPC-RxLibrary (= 1.10.0)
- gRPC/Main (= 1.10.0)
- gRPC-Core (1.10.0):
- gRPC-Core/Implementation (= 1.10.0)
- gRPC-Core/Interface (= 1.10.0)
- gRPC-Core/Implementation (1.10.0):
- GoogleToolboxForMac/Core (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/DebugUtils (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/Defines (2.1.4)
- GoogleToolboxForMac/Logger (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/NSData+zlib (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/NSDictionary+URLArguments (2.1.4):
- GoogleToolboxForMac/DebugUtils (= 2.1.4)
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.4)
- GoogleToolboxForMac/NSString+URLArguments (2.1.4)
- GoogleToolboxForMac/StringEncoding (2.1.4):
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/URLBuilder (2.1.4):
- GoogleToolboxForMac/Core (= 2.1.4)
- GoogleToolboxForMac/Defines (= 2.1.4)
- GoogleToolboxForMac/NSDictionary+URLArguments (= 2.1.4)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.4)
- gRPC (1.12.0):
- gRPC-RxLibrary (= 1.12.0)
- gRPC/Main (= 1.12.0)
- gRPC-Core (1.12.0):
- gRPC-Core/Implementation (= 1.12.0)
- gRPC-Core/Interface (= 1.12.0)
- gRPC-Core/Implementation (1.12.0):
- BoringSSL (~> 10.0)
- gRPC-Core/Interface (= 1.10.0)
- gRPC-Core/Interface (= 1.12.0)
- nanopb (~> 0.3)
- gRPC-Core/Interface (1.10.0)
- gRPC-ProtoRPC (1.10.0):
- gRPC (= 1.10.0)
- gRPC-RxLibrary (= 1.10.0)
- gRPC-Core/Interface (1.12.0)
- gRPC-ProtoRPC (1.12.0):
- gRPC (= 1.12.0)
- gRPC-RxLibrary (= 1.12.0)
- Protobuf (~> 3.0)
- gRPC-RxLibrary (1.10.0)
- gRPC/Main (1.10.0):
- gRPC-Core (= 1.10.0)
- gRPC-RxLibrary (= 1.10.0)
- gRPC-RxLibrary (1.12.0)
- gRPC/Main (1.12.0):
- gRPC-Core (= 1.12.0)
- gRPC-RxLibrary (= 1.12.0)
- GTMOAuth2 (1.1.6):
- GTMSessionFetcher (~> 1.1)
- GTMSessionFetcher (1.1.15):
@@ -192,7 +195,7 @@ PODS:
- nanopb/encode (= 0.3.8)
- nanopb/decode (0.3.8)
- nanopb/encode (0.3.8)
- Protobuf (3.5.0)
- Protobuf (3.6.0)
- React (0.54.4):
- React/Core (= 0.54.4)
- React/Core (0.54.4):
@@ -222,7 +225,8 @@ PODS:
- React/Core
- React/fishhook
- React/RCTBlob
- RNFirebase (4.0.2):
- RNFirebase (4.2.0):
- Firebase/Core
- React
- yoga (0.54.4.React)
@@ -259,43 +263,43 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BoringSSL: 60dd24df4af296bf41d78e5841dbb95d75f88c0d
Crashlytics: aee1a064cbbf99b32efa3f056a5f458d846bc8ff
BoringSSL: cf3f1793eb6e3c445c4d150456341f149c268a35
Crashlytics: 0360624eea1c978a743feddb2fb1ef8b37fb7a0d
DoubleConversion: e22e0762848812a87afd67ffda3998d9ef29170c
Fabric: f8d42c893bb187326a7968b62abe55c36a987a46
Firebase: d7fdf40e4d6c841849c52919f437fd3a0009ded0
FirebaseABTesting: d07d0ee833b842d5153549e4c7e2e2cb1c23a3f9
FirebaseAnalytics: 3dfae28d4a5e06f86c4fae830efc2ad3fadb19bc
FirebaseAuth: 85a1b118a89838efc6f6ab3f2b1f94747d72a915
FirebaseCore: ff49ebb37e0f63a570d78c4f1c1c0befe8659d5c
FirebaseCrash: a7d980468dc8aa2db9792493c3e02722d601f6ab
FirebaseDatabase: 5f0bc6134c5c237cf55f9e1249d406770a75eafd
FirebaseDynamicLinks: 38b68641d24e78d0277a9205d988ce22875d5a25
FirebaseFirestore: e92a096ce80c7b4b905d4e9d41dbd944adc9d2a5
FirebaseInstanceID: 8d20d890d65c917f9f7d9950b6e10a760ad34321
FirebaseInvites: ae15e0636f9eb42bdf5c1ef4c8f7bd4a88f9878b
FirebaseMessaging: 75cdb862e86c30e0913a2ff307e48d49357c5b73
FirebasePerformance: 85bdc3f3d630deb629e85695fcab23364d68f5db
FirebaseRemoteConfig: 3e95fb7c072308492e85fa41d59d38b3d6fd2372
FirebaseStorage: 0c223481c8f89ed300cf1239ddd2d9833622c65f
FirebaseSwizzlingUtilities: 6006111d30248d2321ffac0231e246663e704ea3
Fabric: bda89e242bce1b7b8ab264248cf3407774ce0095
Firebase: 68afeeb05461db02d7c9e3215cda28068670f4aa
FirebaseABTesting: 1f50b8d50f5e3469eea54e7463a7b7fe221d1f5e
FirebaseAnalytics: b3628aea54c50464c32c393fb2ea032566e7ecc2
FirebaseAuth: 463b8ce33bd5d05f706dcd4615499e3212b4132b
FirebaseCore: 62f1b792a49bb9e8b4073f24606d2c93ffc352f0
FirebaseCrash: 8900571fd763fd5bdda04522ec53da979456e3ce
FirebaseDatabase: 482bad9c2abd422bb2321194fb8c937e67426a89
FirebaseDynamicLinks: d624a7adc81a8fd70d52be5a6a47a2bc0644b923
FirebaseFirestore: 53f6fe858494c39dbfd5237655e0641152a88c89
FirebaseInstanceID: f3f0657372592ecdfdfe2cac604a5a75758376a6
FirebaseInvites: d7534f94d0610b892bac8ee0cf4218a14be46c28
FirebaseMessaging: 6894b8fe0a0cf26c3b13dad729f1131654ae0bdb
FirebasePerformance: 1ebd87ffee5ca814582db1dc9e25651792ba02db
FirebaseRemoteConfig: 3c57e4644bd6976b671ae0b725cd709f198bd1f5
FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b
FirebaseSwizzlingUtilities: 6c22677c50d0b6f5f0dc637c1233f13694a3003f
Folly: 211775e49d8da0ca658aebc8eab89d642935755c
glog: 1de0bb937dccdc981596d3b5825ebfb765017ded
Google-Mobile-Ads-SDK: 7404f68120ae8682afeb5af001fbf4aad731c78e
Google-Mobile-Ads-SDK: 6e529e748b45507a2ca904e0b5a52669ba3920c4
GoogleAPIClientForREST: f7951c455df271bc6259b3ddb4073d0026475ccf
GoogleSignIn: d9ef55b10f0aa401a5de2747f59b725e4b9732ac
GoogleToolboxForMac: 2501e2ad72a52eb3dfe7bd9aee7dad11b858bd20
gRPC: f54f0e6d603052b4562447da442ce2ff30bcdacc
gRPC-Core: a030b1678ded49c88ec5ba7c90ee8ee5f47ec6e1
gRPC-ProtoRPC: 22712b23eb1bda656a59715fa5c1da0ea1493ea4
gRPC-RxLibrary: a41a4652d220f230ba1c0491a94ce2ee04c6180a
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
gRPC: 9362451032695e2dfb7bafcd3740e3a27939e4ff
gRPC-Core: 9696b220565b283e021cf2722d473a4a74b7622a
gRPC-ProtoRPC: a1bd56fb1991a8dae4581250d7259eddabb66779
gRPC-RxLibrary: 1ed5314e8b38cd6e55c9bfa048387136ae925ce9
GTMOAuth2: c77fe325e4acd453837e72d91e3b5f13116857b2
GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2
leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
Protobuf: 0fc0ad8bec688b2a3017a139953e01374fedbd5f
React: c237e42de9c70e5cac6eeb52b4cfd3a0910c1f00
RNFirebase: dff98ceb517ef0b5e1858deb59eca186acc6edb0
RNFirebase: 2b25fd2e60269f26bb0a76c71dcc942b35a77df0
yoga: 55da126afc384965b96bff46652464373b330add
PODFILE CHECKSUM: b776d6f4d08bbd51cda6d929b57bfaa8031e7ead

4768
tests/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -389,8 +389,7 @@ function collectionReferenceTests({
await new Promise(resolve2 => {
unsubscribe = collectionRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeDocumentMetadataChanges: true,
includeMetadataChanges: true,
},
snapshot => {
snapshot.forEach(doc => callback(doc.data()));
@@ -478,8 +477,7 @@ function collectionReferenceTests({
};
unsubscribe = collectionRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeDocumentMetadataChanges: true,
includeMetadataChanges: true,
},
observer
);
@@ -531,7 +529,7 @@ function collectionReferenceTests({
(() => {
colRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeMetadataChanges: true,
},
() => {},
'error'
@@ -542,7 +540,7 @@ function collectionReferenceTests({
(() => {
colRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeMetadataChanges: true,
},
{
next: () => {},
@@ -555,7 +553,7 @@ function collectionReferenceTests({
(() => {
colRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeMetadataChanges: true,
},
{
next: 'error',
@@ -567,7 +565,7 @@ function collectionReferenceTests({
(() => {
colRef.onSnapshot(
{
includeQueryMetadataChanges: true,
includeMetadataChanges: true,
},
'error'
);

View File

@@ -93,6 +93,26 @@ function documentReferenceTests({
snapshot.id.should.equal('doc1');
snapshot.metadata.should.be.an.Object();
});
it('should support GetOptions source=`default`', async () => {
const snapshot = await firebase.native
.firestore()
.doc('document-tests/doc1')
.get({ source: 'default' });
snapshot.id.should.equal('doc1');
snapshot.metadata.should.be.an.Object();
should.equal(snapshot.metadata.fromCache, false);
});
it('should support GetOptions source=`cache`', async () => {
const snapshot = await firebase.native
.firestore()
.doc('document-tests/doc1')
.get({ source: 'cache' });
snapshot.id.should.equal('doc1');
snapshot.metadata.should.be.an.Object();
should.equal(snapshot.metadata.fromCache, true);
});
});
context('onSnapshot()', () => {

View File

@@ -0,0 +1,35 @@
import should from 'should';
function iidTests({ describe, it, firebase }) {
describe('iid', () => {
it('should delete the iid token', async () => {
await firebase.native.iid().delete();
});
it('it should return iid token from get', async () => {
const token = await firebase.native.iid().get();
token.should.be.a.String();
});
it('should return an FCM token from getToken with arguments', async () => {
await firebase.native.iid().delete();
const otherSenderIdToken = await firebase.native
.iid()
.getToken('305229645282', '*');
otherSenderIdToken.should.be.a.String();
});
it('should return nil from deleteToken', async () => {
const token = await firebase.native
.iid()
.deleteToken('305229645282', '*');
should.not.exist(token);
});
});
}
export default iidTests;

View File

@@ -0,0 +1,10 @@
import firebase from '../../firebase';
import TestSuite from '../../../lib/TestSuite';
import iidTests from './iidTests';
const suite = new TestSuite('Iid', 'firebase.id()', firebase);
suite.addTests(iidTests);
export default suite;

View File

@@ -12,6 +12,7 @@ import performance from './perf';
import admob from './admob';
import firestore from './firestore';
import links from './links/index';
import iid from './iid';
window.getCoverage = function getCoverage() {
return JSON.stringify(global.__coverage__);
@@ -31,6 +32,7 @@ const testSuiteInstances = [
performance,
storage,
links,
iid,
];
/*