mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-01-12 22:50:20 +08:00
merge master into omer_links
This commit is contained in:
30
README.md
30
README.md
@@ -5,9 +5,17 @@
|
||||
[](http://packagequality.com/#?package=react-native-firebase)
|
||||
[](https://discord.gg/t6bdqMs)
|
||||
[](https://www.patreon.com/invertase)
|
||||
[](https://twitter.com/rnfirebase)
|
||||
|
||||
|
||||
**RNFirebase** makes using [Firebase](http://firebase.com) with React Native simple.
|
||||
**RNFirebase** makes using [Firebase](http://firebase.com) with React Native simple.
|
||||
|
||||
---
|
||||
|
||||
We also support **both** databases: Realtime Database and Cloud Firestore!
|
||||
|
||||
---
|
||||
|
||||
|
||||
<!---
|
||||
[](/LICENSE)
|
||||
@@ -15,7 +23,7 @@
|
||||
|
||||
<hr>
|
||||
|
||||
> [Current Docs](http://invertase.link/docs) <b>|</b> [@next Docs](http://invertase.link/v3) <b>|</b> [iOS Install Guide](http://invertase.link/ios) <b>|</b> [Android Install Guide](http://invertase.link/android) <b>|</b> [FAQs](http://invertase.io/react-native-firebase/#/faqs) <b>|</b> [Feature Requests](http://invertase.link/requests)
|
||||
> [Docs](http://invertase.link/v3-docs) <b>|</b> [iOS Install Guide](http://invertase.link/ios) <b>|</b> [Android Install Guide](http://invertase.link/android) <b>|</b> [FAQs](http://invertase.io/react-native-firebase/#/faqs) <b>|</b> [Feature Requests](http://invertase.link/requests)
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -57,6 +65,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
||||
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ |**?**|
|
||||
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Dynamic Links** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Firestore** | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Invites** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
|
||||
@@ -68,18 +77,13 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
||||
---
|
||||
### Supported versions - React Native / Firebase
|
||||
|
||||
> The table below shows the supported version of `react-native-firebase` for different React Native versions
|
||||
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
|
||||
|
||||
| | v0.36 - v0.39 | v0.40 - v0.46 | v0.47 +
|
||||
| ------------------------------- | :---: | :---: | :---: |
|
||||
| react-native-firebase | 1.X.X | 2.X.X | 2.1.X |
|
||||
|
||||
> The table below shows the minimum supported versions of the Firebase SDKs for each version of `react-native-firebase`
|
||||
|
||||
| | v1 | v2 | v3 |
|
||||
| ---------------------- | :---: | :---: | :---: |
|
||||
| Firebase Android SDK | 10.2.0+ | 11.0.0 + | 11.2.0 + |
|
||||
| Firebase iOS SDK | 3.15.0+ | 4.0.0 + | 4.0.0 + |
|
||||
| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X |
|
||||
|------------------------|-------------|-------------|-----------------|----------|
|
||||
| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + |
|
||||
| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + |
|
||||
| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.firebaseVersion = '11.2.0'
|
||||
ext.firebaseVersion = '11.4.2'
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
@@ -33,6 +33,10 @@ android {
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,5 +89,6 @@ dependencies {
|
||||
compile "com.google.firebase:firebase-crash:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-perf:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-firestore:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-invites:$firebaseVersion"
|
||||
}
|
||||
|
||||
27
android/src/main/java/io/invertase/firebase/ErrorUtils.java
Normal file
27
android/src/main/java/io/invertase/firebase/ErrorUtils.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package io.invertase.firebase;
|
||||
|
||||
public class ErrorUtils {
|
||||
/**
|
||||
* Wrap a message string with the specified service name e.g. 'Database'
|
||||
*
|
||||
* @param message
|
||||
* @param service
|
||||
* @param fullCode
|
||||
* @return
|
||||
*/
|
||||
public static String getMessageWithService(String message, String service, String fullCode) {
|
||||
// Service: Error message (service/code).
|
||||
return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
|
||||
*
|
||||
* @param service
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
public static String getCodeWithService(String service, String code) {
|
||||
return service.toLowerCase() + "/" + code.toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -31,18 +31,6 @@ public class RNFirebasePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -78,7 +78,6 @@ public class Utils {
|
||||
|
||||
/**
|
||||
* @param dataSnapshot
|
||||
* @param registration
|
||||
* @param previousChildName
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -29,18 +29,6 @@ public class RNFirebaseAdMobPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -33,18 +33,6 @@ public class RNFirebaseAnalyticsPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -813,7 +813,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
TimeUnit.SECONDS,
|
||||
activity,
|
||||
callbacks
|
||||
// ,PhoneAuthProvider.ForceResendingToken.zzboe() // TODO FORCE RESENDING
|
||||
//, PhoneAuthProvider.ForceResendingToken.zzboe() // TODO FORCE RESENDING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseAuthPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseRemoteConfigPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseCrashPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.ErrorUtils;
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
@@ -522,30 +523,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||
return existingRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a message string with the specified service name e.g. 'Database'
|
||||
*
|
||||
* @param message
|
||||
* @param service
|
||||
* @param fullCode
|
||||
* @return
|
||||
*/
|
||||
private static String getMessageWithService(String message, String service, String fullCode) {
|
||||
// Service: Error message (service/code).
|
||||
return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
|
||||
*
|
||||
* @param service
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
private static String getCodeWithService(String service, String code) {
|
||||
return service.toLowerCase() + "/" + code.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert as firebase DatabaseError instance into a writable map
|
||||
* with the correct web-like error codes.
|
||||
@@ -564,56 +541,56 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
|
||||
|
||||
switch (nativeError.getCode()) {
|
||||
case DatabaseError.DATA_STALE:
|
||||
code = getCodeWithService(service, "data-stale");
|
||||
message = getMessageWithService("The transaction needs to be run again with current data.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "data-stale");
|
||||
message = ErrorUtils.getMessageWithService("The transaction needs to be run again with current data.", service, code);
|
||||
break;
|
||||
case DatabaseError.OPERATION_FAILED:
|
||||
code = getCodeWithService(service, "failure");
|
||||
message = getMessageWithService("The server indicated that this operation failed.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "failure");
|
||||
message = ErrorUtils.getMessageWithService("The server indicated that this operation failed.", service, code);
|
||||
break;
|
||||
case DatabaseError.PERMISSION_DENIED:
|
||||
code = getCodeWithService(service, "permission-denied");
|
||||
message = getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "permission-denied");
|
||||
message = ErrorUtils.getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
|
||||
break;
|
||||
case DatabaseError.DISCONNECTED:
|
||||
code = getCodeWithService(service, "disconnected");
|
||||
message = getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "disconnected");
|
||||
message = ErrorUtils.getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
|
||||
break;
|
||||
case DatabaseError.EXPIRED_TOKEN:
|
||||
code = getCodeWithService(service, "expired-token");
|
||||
message = getMessageWithService("The supplied auth token has expired.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "expired-token");
|
||||
message = ErrorUtils.getMessageWithService("The supplied auth token has expired.", service, code);
|
||||
break;
|
||||
case DatabaseError.INVALID_TOKEN:
|
||||
code = getCodeWithService(service, "invalid-token");
|
||||
message = getMessageWithService("The supplied auth token was invalid.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "invalid-token");
|
||||
message = ErrorUtils.getMessageWithService("The supplied auth token was invalid.", service, code);
|
||||
break;
|
||||
case DatabaseError.MAX_RETRIES:
|
||||
code = getCodeWithService(service, "max-retries");
|
||||
message = getMessageWithService("The transaction had too many retries.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "max-retries");
|
||||
message = ErrorUtils.getMessageWithService("The transaction had too many retries.", service, code);
|
||||
break;
|
||||
case DatabaseError.OVERRIDDEN_BY_SET:
|
||||
code = getCodeWithService(service, "overridden-by-set");
|
||||
message = getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "overridden-by-set");
|
||||
message = ErrorUtils.getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
|
||||
break;
|
||||
case DatabaseError.UNAVAILABLE:
|
||||
code = getCodeWithService(service, "unavailable");
|
||||
message = getMessageWithService("The service is unavailable.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "unavailable");
|
||||
message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code);
|
||||
break;
|
||||
case DatabaseError.USER_CODE_EXCEPTION:
|
||||
code = getCodeWithService(service, "user-code-exception");
|
||||
message = getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "user-code-exception");
|
||||
message = ErrorUtils.getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
|
||||
break;
|
||||
case DatabaseError.NETWORK_ERROR:
|
||||
code = getCodeWithService(service, "network-error");
|
||||
message = getMessageWithService("The operation could not be performed due to a network error.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "network-error");
|
||||
message = ErrorUtils.getMessageWithService("The operation could not be performed due to a network error.", service, code);
|
||||
break;
|
||||
case DatabaseError.WRITE_CANCELED:
|
||||
code = getCodeWithService(service, "write-cancelled");
|
||||
message = getMessageWithService("The write was canceled by the user.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "write-cancelled");
|
||||
message = ErrorUtils.getMessageWithService("The write was canceled by the user.", service, code);
|
||||
break;
|
||||
default:
|
||||
code = getCodeWithService(service, "unknown");
|
||||
message = getMessageWithService("An unknown error occurred.", service, code);
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
|
||||
}
|
||||
|
||||
errorMap.putString("code", code);
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseDatabasePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -29,8 +29,8 @@ class RNFirebaseDatabaseReference {
|
||||
private String appName;
|
||||
private ReactContext reactContext;
|
||||
private static final String TAG = "RNFirebaseDBReference";
|
||||
private HashMap<String, ChildEventListener> childEventListeners;
|
||||
private HashMap<String, ValueEventListener> valueEventListeners;
|
||||
private HashMap<String, ChildEventListener> childEventListeners = new HashMap<>();
|
||||
private HashMap<String, ValueEventListener> valueEventListeners = new HashMap<>();
|
||||
|
||||
/**
|
||||
* RNFirebase wrapper around FirebaseDatabaseReference,
|
||||
@@ -47,8 +47,6 @@ class RNFirebaseDatabaseReference {
|
||||
query = null;
|
||||
appName = app;
|
||||
reactContext = context;
|
||||
childEventListeners = new HashMap<>();
|
||||
valueEventListeners = new HashMap<>();
|
||||
buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.firebase.firestore.DocumentChange;
|
||||
import com.google.firebase.firestore.DocumentSnapshot;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FirestoreSerialize {
|
||||
private static final String KEY_CHANGES = "changes";
|
||||
private static final String KEY_DATA = "data";
|
||||
private static final String KEY_DOC_CHANGE_DOCUMENT = "document";
|
||||
private static final String KEY_DOC_CHANGE_NEW_INDEX = "newIndex";
|
||||
private static final String KEY_DOC_CHANGE_OLD_INDEX = "oldIndex";
|
||||
private static final String KEY_DOC_CHANGE_TYPE = "type";
|
||||
private static final String KEY_DOCUMENTS = "documents";
|
||||
private static final String KEY_METADATA = "metadata";
|
||||
private static final String KEY_PATH = "path";
|
||||
|
||||
/**
|
||||
* Convert a DocumentSnapshot instance into a React Native WritableMap
|
||||
*
|
||||
* @param documentSnapshot DocumentSnapshot
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap snapshotToWritableMap(DocumentSnapshot documentSnapshot) {
|
||||
WritableMap documentMap = Arguments.createMap();
|
||||
|
||||
documentMap.putString(KEY_PATH, documentSnapshot.getReference().getPath());
|
||||
if (documentSnapshot.exists()) {
|
||||
documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
|
||||
}
|
||||
// metadata
|
||||
if (documentSnapshot.getMetadata() != null) {
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean("fromCache", documentSnapshot.getMetadata().isFromCache());
|
||||
metadata.putBoolean("hasPendingWrites", documentSnapshot.getMetadata().hasPendingWrites());
|
||||
documentMap.putMap(KEY_METADATA, metadata);
|
||||
}
|
||||
|
||||
return documentMap;
|
||||
}
|
||||
|
||||
public static WritableMap snapshotToWritableMap(QuerySnapshot querySnapshot) {
|
||||
WritableMap queryMap = Arguments.createMap();
|
||||
|
||||
List<DocumentChange> documentChanges = querySnapshot.getDocumentChanges();
|
||||
queryMap.putArray(KEY_CHANGES, documentChangesToWritableArray(documentChanges));
|
||||
|
||||
// documents
|
||||
WritableArray documents = Arguments.createArray();
|
||||
List<DocumentSnapshot> documentSnapshots = querySnapshot.getDocuments();
|
||||
for (DocumentSnapshot documentSnapshot : documentSnapshots) {
|
||||
documents.pushMap(snapshotToWritableMap(documentSnapshot));
|
||||
}
|
||||
queryMap.putArray(KEY_DOCUMENTS, documents);
|
||||
|
||||
// metadata
|
||||
if (querySnapshot.getMetadata() != null) {
|
||||
WritableMap metadata = Arguments.createMap();
|
||||
metadata.putBoolean("fromCache", querySnapshot.getMetadata().isFromCache());
|
||||
metadata.putBoolean("hasPendingWrites", querySnapshot.getMetadata().hasPendingWrites());
|
||||
queryMap.putMap(KEY_METADATA, metadata);
|
||||
}
|
||||
|
||||
return queryMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a List of DocumentChange instances into a React Native WritableArray
|
||||
*
|
||||
* @param documentChanges List<DocumentChange>
|
||||
* @return WritableArray
|
||||
*/
|
||||
static WritableArray documentChangesToWritableArray(List<DocumentChange> documentChanges) {
|
||||
WritableArray documentChangesWritable = Arguments.createArray();
|
||||
for (DocumentChange documentChange : documentChanges) {
|
||||
documentChangesWritable.pushMap(documentChangeToWritableMap(documentChange));
|
||||
}
|
||||
return documentChangesWritable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a DocumentChange instance into a React Native WritableMap
|
||||
*
|
||||
* @param documentChange DocumentChange
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap documentChangeToWritableMap(DocumentChange documentChange) {
|
||||
WritableMap documentChangeMap = Arguments.createMap();
|
||||
|
||||
switch (documentChange.getType()) {
|
||||
case ADDED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "added");
|
||||
break;
|
||||
case REMOVED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "removed");
|
||||
break;
|
||||
case MODIFIED:
|
||||
documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "modified");
|
||||
}
|
||||
|
||||
documentChangeMap.putMap(KEY_DOC_CHANGE_DOCUMENT,
|
||||
snapshotToWritableMap(documentChange.getDocument()));
|
||||
documentChangeMap.putInt(KEY_DOC_CHANGE_NEW_INDEX, documentChange.getNewIndex());
|
||||
documentChangeMap.putInt(KEY_DOC_CHANGE_OLD_INDEX, documentChange.getOldIndex());
|
||||
|
||||
return documentChangeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Object Map into a React Native WritableMap.
|
||||
*
|
||||
* @param map Map<String, Object>
|
||||
* @return WritableMap
|
||||
*/
|
||||
static WritableMap objectMapToWritable(Map<String, Object> map) {
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
putValue(writableMap, entry.getKey(), entry.getValue());
|
||||
}
|
||||
return writableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Object array into a React Native WritableArray.
|
||||
*
|
||||
* @param array Object[]
|
||||
* @return WritableArray
|
||||
*/
|
||||
static WritableArray objectArrayToWritable(Object[] array) {
|
||||
WritableArray writableArray = Arguments.createArray();
|
||||
|
||||
for (Object item : array) {
|
||||
if (item == null) {
|
||||
writableArray.pushNull();
|
||||
continue;
|
||||
}
|
||||
|
||||
Class itemClass = item.getClass();
|
||||
|
||||
if (itemClass == Boolean.class) {
|
||||
writableArray.pushBoolean((Boolean) item);
|
||||
} else if (itemClass == Integer.class) {
|
||||
writableArray.pushDouble(((Integer) item).doubleValue());
|
||||
} else if (itemClass == Double.class) {
|
||||
writableArray.pushDouble((Double) item);
|
||||
} else if (itemClass == Float.class) {
|
||||
writableArray.pushDouble(((Float) item).doubleValue());
|
||||
} else if (itemClass == String.class) {
|
||||
writableArray.pushString(item.toString());
|
||||
} else if (itemClass == Map.class) {
|
||||
writableArray.pushMap((objectMapToWritable((Map<String, Object>) item)));
|
||||
} else if (itemClass == Arrays.class) {
|
||||
writableArray.pushArray(objectArrayToWritable((Object[]) item));
|
||||
} else if (itemClass == List.class || itemClass == ArrayList.class) {
|
||||
List<Object> list = (List<Object>) item;
|
||||
Object[] listAsArray = list.toArray(new Object[list.size()]);
|
||||
writableArray.pushArray(objectArrayToWritable(listAsArray));
|
||||
} else {
|
||||
throw new RuntimeException("Cannot convert object of type " + item);
|
||||
}
|
||||
}
|
||||
|
||||
return writableArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects an objects type and calls the relevant WritableMap setter method to add the value.
|
||||
*
|
||||
* @param map WritableMap
|
||||
* @param key String
|
||||
* @param value Object
|
||||
*/
|
||||
static void putValue(WritableMap map, String key, Object value) {
|
||||
if (value == null) {
|
||||
map.putNull(key);
|
||||
} else {
|
||||
Class valueClass = value.getClass();
|
||||
|
||||
if (valueClass == Boolean.class) {
|
||||
map.putBoolean(key, (Boolean) value);
|
||||
} else if (valueClass == Integer.class) {
|
||||
map.putDouble(key, ((Integer) value).doubleValue());
|
||||
} else if (valueClass == Double.class) {
|
||||
map.putDouble(key, (Double) value);
|
||||
} else if (valueClass == Float.class) {
|
||||
map.putDouble(key, ((Float) value).doubleValue());
|
||||
} else if (valueClass == String.class) {
|
||||
map.putString(key, value.toString());
|
||||
} else if (valueClass == Map.class) {
|
||||
map.putMap(key, (objectMapToWritable((Map<String, Object>) value)));
|
||||
} else if (valueClass == Arrays.class) {
|
||||
map.putArray(key, objectArrayToWritable((Object[]) value));
|
||||
} else if (valueClass == List.class || valueClass == ArrayList.class) {
|
||||
List<Object> list = (List<Object>) value;
|
||||
Object[] array = list.toArray(new Object[list.size()]);
|
||||
map.putArray(key, objectArrayToWritable(array));
|
||||
} else {
|
||||
throw new RuntimeException("Cannot convert object of type " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.firestore.DocumentReference;
|
||||
import com.google.firebase.firestore.FieldValue;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.SetOptions;
|
||||
import com.google.firebase.firestore.WriteBatch;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.ErrorUtils;
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "RNFirebaseFirestore";
|
||||
// private SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();
|
||||
|
||||
RNFirebaseFirestore(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* REACT NATIVE METHODS
|
||||
*/
|
||||
@ReactMethod
|
||||
public void collectionGet(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, final Promise promise) {
|
||||
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||
ref.get(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void collectionOffSnapshot(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, String listenerId) {
|
||||
RNFirebaseFirestoreCollectionReference.offSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void collectionOnSnapshot(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, String listenerId) {
|
||||
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||
ref.onSnapshot(listenerId);
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void documentBatch(final String appName, final ReadableArray writes,
|
||||
final Promise promise) {
|
||||
FirebaseFirestore firestore = getFirestoreForApp(appName);
|
||||
WriteBatch batch = firestore.batch();
|
||||
final List<Object> writesArray = Utils.recursivelyDeconstructReadableArray(writes);
|
||||
|
||||
for (Object w : writesArray) {
|
||||
Map<String, Object> write = (Map) w;
|
||||
String type = (String) write.get("type");
|
||||
String path = (String) write.get("path");
|
||||
Map<String, Object> data = (Map) write.get("data");
|
||||
|
||||
DocumentReference ref = firestore.document(path);
|
||||
switch (type) {
|
||||
case "DELETE":
|
||||
batch = batch.delete(ref);
|
||||
break;
|
||||
case "SET":
|
||||
Map<String, Object> options = (Map) write.get("options");
|
||||
if (options != null && options.containsKey("merge") && (boolean)options.get("merge")) {
|
||||
batch = batch.set(ref, data, SetOptions.merge());
|
||||
} else {
|
||||
batch = batch.set(ref, data);
|
||||
}
|
||||
|
||||
break;
|
||||
case "UPDATE":
|
||||
batch = batch.update(ref, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
batch.commit().addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "documentBatch:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "documentBatch:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentCollections(String appName, String path, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.collections(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentCreate(String appName, String path, ReadableMap data, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.create(data, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentDelete(String appName, String path, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.delete(promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentGet(String appName, String path, 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
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentOffSnapshot(String appName, String path, String listenerId) {
|
||||
RNFirebaseFirestoreDocumentReference.offSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentOnSnapshot(String appName, String path, String listenerId) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.onSnapshot(listenerId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentSet(String appName, String path, ReadableMap data, ReadableMap options, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.set(data, options, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentUpdate(String appName, String path, ReadableMap data, final Promise promise) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.update(data, promise);
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a js-like error from an exception and rejects the provided promise with it.
|
||||
*
|
||||
* @param exception Exception Exception normally from a task result.
|
||||
* @param promise Promise react native promise
|
||||
*/
|
||||
static void promiseRejectException(Promise promise, FirebaseFirestoreException exception) {
|
||||
WritableMap jsError = getJSError(exception);
|
||||
promise.reject(
|
||||
jsError.getString("code"),
|
||||
jsError.getString("message"),
|
||||
exception
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a database instance for a specific firebase app instance
|
||||
*
|
||||
* @param appName
|
||||
* @return
|
||||
*/
|
||||
static FirebaseFirestore getFirestoreForApp(String appName) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
return FirebaseFirestore.getInstance(firebaseApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection reference for a specific app and path
|
||||
*
|
||||
* @param appName
|
||||
* @param filters
|
||||
* @param orders
|
||||
* @param options
|
||||
* @param path @return
|
||||
*/
|
||||
private RNFirebaseFirestoreCollectionReference getCollectionForAppPath(String appName, String path,
|
||||
ReadableArray filters,
|
||||
ReadableArray orders,
|
||||
ReadableMap options) {
|
||||
return new RNFirebaseFirestoreCollectionReference(this.getReactApplicationContext(), appName, path, filters, orders, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a document reference for a specific app and path
|
||||
*
|
||||
* @param appName
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
private RNFirebaseFirestoreDocumentReference getDocumentForAppPath(String appName, String path) {
|
||||
return new RNFirebaseFirestoreDocumentReference(this.getReactApplicationContext(), appName, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert as firebase DatabaseError instance into a writable map
|
||||
* with the correct web-like error codes.
|
||||
*
|
||||
* @param nativeException
|
||||
* @return
|
||||
*/
|
||||
static WritableMap getJSError(FirebaseFirestoreException nativeException) {
|
||||
WritableMap errorMap = Arguments.createMap();
|
||||
errorMap.putInt("nativeErrorCode", nativeException.getCode().value());
|
||||
errorMap.putString("nativeErrorMessage", nativeException.getMessage());
|
||||
|
||||
String code;
|
||||
String message;
|
||||
String service = "Firestore";
|
||||
|
||||
// TODO: Proper error mappings
|
||||
switch (nativeException.getCode()) {
|
||||
case OK:
|
||||
code = ErrorUtils.getCodeWithService(service, "ok");
|
||||
message = ErrorUtils.getMessageWithService("Ok.", service, code);
|
||||
break;
|
||||
case CANCELLED:
|
||||
code = ErrorUtils.getCodeWithService(service, "cancelled");
|
||||
message = ErrorUtils.getMessageWithService("The operation was cancelled.", service, code);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("Unknown error or an error from a different error domain.", service, code);
|
||||
break;
|
||||
case INVALID_ARGUMENT:
|
||||
code = ErrorUtils.getCodeWithService(service, "invalid-argument");
|
||||
message = ErrorUtils.getMessageWithService("Client specified an invalid argument.", service, code);
|
||||
break;
|
||||
case DEADLINE_EXCEEDED:
|
||||
code = ErrorUtils.getCodeWithService(service, "deadline-exceeded");
|
||||
message = ErrorUtils.getMessageWithService("Deadline expired before operation could complete.", service, code);
|
||||
break;
|
||||
case NOT_FOUND:
|
||||
code = ErrorUtils.getCodeWithService(service, "not-found");
|
||||
message = ErrorUtils.getMessageWithService("Some requested document was not found.", service, code);
|
||||
break;
|
||||
case ALREADY_EXISTS:
|
||||
code = ErrorUtils.getCodeWithService(service, "already-exists");
|
||||
message = ErrorUtils.getMessageWithService("Some document that we attempted to create already exists.", service, code);
|
||||
break;
|
||||
case PERMISSION_DENIED:
|
||||
code = ErrorUtils.getCodeWithService(service, "permission-denied");
|
||||
message = ErrorUtils.getMessageWithService("The caller does not have permission to execute the specified operation.", service, code);
|
||||
break;
|
||||
case RESOURCE_EXHAUSTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "resource-exhausted");
|
||||
message = ErrorUtils.getMessageWithService("Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.", service, code);
|
||||
break;
|
||||
case FAILED_PRECONDITION:
|
||||
code = ErrorUtils.getCodeWithService(service, "failed-precondition");
|
||||
message = ErrorUtils.getMessageWithService("Operation was rejected because the system is not in a state required for the operation`s execution.", service, code);
|
||||
break;
|
||||
case ABORTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "aborted");
|
||||
message = ErrorUtils.getMessageWithService("The operation was aborted, typically due to a concurrency issue like transaction aborts, etc.", service, code);
|
||||
break;
|
||||
case OUT_OF_RANGE:
|
||||
code = ErrorUtils.getCodeWithService(service, "out-of-range");
|
||||
message = ErrorUtils.getMessageWithService("Operation was attempted past the valid range.", service, code);
|
||||
break;
|
||||
case UNIMPLEMENTED:
|
||||
code = ErrorUtils.getCodeWithService(service, "unimplemented");
|
||||
message = ErrorUtils.getMessageWithService("Operation is not implemented or not supported/enabled.", service, code);
|
||||
break;
|
||||
case INTERNAL:
|
||||
code = ErrorUtils.getCodeWithService(service, "internal");
|
||||
message = ErrorUtils.getMessageWithService("Internal errors.", service, code);
|
||||
break;
|
||||
case UNAVAILABLE:
|
||||
code = ErrorUtils.getCodeWithService(service, "unavailable");
|
||||
message = ErrorUtils.getMessageWithService("The service is currently unavailable.", service, code);
|
||||
break;
|
||||
case DATA_LOSS:
|
||||
code = ErrorUtils.getCodeWithService(service, "data-loss");
|
||||
message = ErrorUtils.getMessageWithService("Unrecoverable data loss or corruption.", service, code);
|
||||
break;
|
||||
case UNAUTHENTICATED:
|
||||
code = ErrorUtils.getCodeWithService(service, "unauthenticated");
|
||||
message = ErrorUtils.getMessageWithService("The request does not have valid authentication credentials for the operation.", service, code);
|
||||
break;
|
||||
default:
|
||||
code = ErrorUtils.getCodeWithService(service, "unknown");
|
||||
message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
|
||||
}
|
||||
|
||||
errorMap.putString("code", code);
|
||||
errorMap.putString("message", message);
|
||||
return errorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* React Method - returns this module name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNFirebaseFirestore";
|
||||
}
|
||||
|
||||
/**
|
||||
* React Native constants for RNFirebaseFirestore
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
final Map<String, Object> constants = new HashMap<>();
|
||||
constants.put("deleteFieldValue", FieldValue.delete().toString());
|
||||
constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp().toString());
|
||||
return constants;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
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.EventListener;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.ListenerRegistration;
|
||||
import com.google.firebase.firestore.Query;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
public class RNFirebaseFirestoreCollectionReference {
|
||||
private static final String TAG = "RNFSCollectionReference";
|
||||
private static Map<String, ListenerRegistration> collectionSnapshotListeners = new HashMap<>();
|
||||
|
||||
private final String appName;
|
||||
private final String path;
|
||||
private final ReadableArray filters;
|
||||
private final ReadableArray orders;
|
||||
private final ReadableMap options;
|
||||
private final Query query;
|
||||
private ReactContext reactContext;
|
||||
|
||||
RNFirebaseFirestoreCollectionReference(ReactContext reactContext, String appName, String path,
|
||||
ReadableArray filters, ReadableArray orders,
|
||||
ReadableMap options) {
|
||||
this.appName = appName;
|
||||
this.path = path;
|
||||
this.filters = filters;
|
||||
this.orders = orders;
|
||||
this.options = options;
|
||||
this.query = buildQuery();
|
||||
this.reactContext = reactContext;
|
||||
}
|
||||
|
||||
void get(final Promise promise) {
|
||||
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<QuerySnapshot> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "get:onComplete:success");
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
|
||||
promise.resolve(data);
|
||||
} else {
|
||||
Log.e(TAG, "get:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void offSnapshot(final String listenerId) {
|
||||
ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
if (!collectionSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<QuerySnapshot> listener = new EventListener<QuerySnapshot>() {
|
||||
@Override
|
||||
public void onEvent(QuerySnapshot querySnapshot, FirebaseFirestoreException exception) {
|
||||
if (exception == null) {
|
||||
handleQuerySnapshotEvent(listenerId, querySnapshot);
|
||||
} else {
|
||||
ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
handleQuerySnapshotError(listenerId, exception);
|
||||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(listener);
|
||||
collectionSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
boolean hasListeners() {
|
||||
return !collectionSnapshotListeners.isEmpty();
|
||||
}
|
||||
|
||||
private Query buildQuery() {
|
||||
Query query = RNFirebaseFirestore.getFirestoreForApp(appName).collection(path);
|
||||
query = applyFilters(query);
|
||||
query = applyOrders(query);
|
||||
query = applyOptions(query);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyFilters(Query query) {
|
||||
List<Object> filtersList = Utils.recursivelyDeconstructReadableArray(filters);
|
||||
|
||||
for (Object f : filtersList) {
|
||||
Map<String, Object> filter = (Map) f;
|
||||
String fieldPath = (String) filter.get("fieldPath");
|
||||
String operator = (String) filter.get("operator");
|
||||
Object value = filter.get("value");
|
||||
|
||||
switch (operator) {
|
||||
case "EQUAL":
|
||||
query = query.whereEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN":
|
||||
query = query.whereGreaterThan(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN_OR_EQUAL":
|
||||
query = query.whereGreaterThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN":
|
||||
query = query.whereLessThan(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN_OR_EQUAL":
|
||||
query = query.whereLessThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyOrders(Query query) {
|
||||
List<Object> ordersList = Utils.recursivelyDeconstructReadableArray(orders);
|
||||
for (Object o : ordersList) {
|
||||
Map<String, Object> order = (Map) o;
|
||||
String direction = (String) order.get("direction");
|
||||
String fieldPath = (String) order.get("fieldPath");
|
||||
|
||||
query = query.orderBy(fieldPath, Query.Direction.valueOf(direction));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
private Query applyOptions(Query query) {
|
||||
if (options.hasKey("endAt")) {
|
||||
ReadableArray endAtArray = options.getArray("endAt");
|
||||
query = query.endAt(Utils.recursivelyDeconstructReadableArray(endAtArray));
|
||||
}
|
||||
if (options.hasKey("endBefore")) {
|
||||
ReadableArray endBeforeArray = options.getArray("endBefore");
|
||||
query = query.endBefore(Utils.recursivelyDeconstructReadableArray(endBeforeArray));
|
||||
}
|
||||
if (options.hasKey("limit")) {
|
||||
int limit = options.getInt("limit");
|
||||
query = query.limit(limit);
|
||||
}
|
||||
if (options.hasKey("offset")) {
|
||||
// Android doesn't support offset
|
||||
}
|
||||
if (options.hasKey("selectFields")) {
|
||||
// Android doesn't support selectFields
|
||||
}
|
||||
if (options.hasKey("startAfter")) {
|
||||
ReadableArray startAfterArray = options.getArray("startAfter");
|
||||
query = query.startAfter(Utils.recursivelyDeconstructReadableArray(startAfterArray));
|
||||
}
|
||||
if (options.hasKey("startAt")) {
|
||||
ReadableArray startAtArray = options.getArray("startAt");
|
||||
query = query.startAt(Utils.recursivelyDeconstructReadableArray(startAtArray));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles documentSnapshot events.
|
||||
*
|
||||
* @param listenerId
|
||||
* @param querySnapshot
|
||||
*/
|
||||
private void handleQuerySnapshotEvent(String listenerId, QuerySnapshot querySnapshot) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(querySnapshot);
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("querySnapshot", data);
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a documentSnapshot error event
|
||||
*
|
||||
* @param listenerId
|
||||
* @param exception
|
||||
*/
|
||||
private void handleQuerySnapshotError(String listenerId, FirebaseFirestoreException exception) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("error", RNFirebaseFirestore.getJSError(exception));
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
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.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.SetOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
|
||||
public class RNFirebaseFirestoreDocumentReference {
|
||||
private static final String TAG = "RNFBFSDocumentReference";
|
||||
private static Map<String, ListenerRegistration> documentSnapshotListeners = new HashMap<>();
|
||||
|
||||
private final String appName;
|
||||
private final String path;
|
||||
private ReactContext reactContext;
|
||||
private final DocumentReference ref;
|
||||
|
||||
RNFirebaseFirestoreDocumentReference(ReactContext reactContext, String appName, String path) {
|
||||
this.appName = appName;
|
||||
this.path = path;
|
||||
this.reactContext = reactContext;
|
||||
this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path);
|
||||
}
|
||||
|
||||
public void collections(Promise promise) {
|
||||
// Not supported on Android
|
||||
}
|
||||
|
||||
public void create(ReadableMap data, Promise promise) {
|
||||
// Not supported on Android out of the box
|
||||
}
|
||||
|
||||
public void delete(final Promise promise) {
|
||||
this.ref.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "delete:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "delete:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void get(final Promise promise) {
|
||||
this.ref.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "get:onComplete:success");
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
|
||||
promise.resolve(data);
|
||||
} else {
|
||||
Log.e(TAG, "get:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void offSnapshot(final String listenerId) {
|
||||
ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
if (!documentSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<DocumentSnapshot> listener = new EventListener<DocumentSnapshot>() {
|
||||
@Override
|
||||
public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException exception) {
|
||||
if (exception == null) {
|
||||
handleDocumentSnapshotEvent(listenerId, documentSnapshot);
|
||||
} else {
|
||||
ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
|
||||
if (listenerRegistration != null) {
|
||||
listenerRegistration.remove();
|
||||
}
|
||||
handleDocumentSnapshotError(listenerId, exception);
|
||||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(listener);
|
||||
documentSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(final ReadableMap data, final ReadableMap options, final Promise promise) {
|
||||
Map<String, Object> map = Utils.recursivelyDeconstructReadableMap(data);
|
||||
Task<Void> task;
|
||||
SetOptions setOptions = null;
|
||||
if (options != null && options.hasKey("merge") && options.getBoolean("merge")) {
|
||||
task = this.ref.set(map, SetOptions.merge());
|
||||
} else {
|
||||
task = this.ref.set(map);
|
||||
}
|
||||
task.addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "set:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "set:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update(final ReadableMap data, final Promise promise) {
|
||||
Map<String, Object> map = Utils.recursivelyDeconstructReadableMap(data);
|
||||
this.ref.update(map).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "update:onComplete:success");
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
Log.e(TAG, "update:onComplete:failure", task.getException());
|
||||
RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
|
||||
boolean hasListeners() {
|
||||
return !documentSnapshotListeners.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles documentSnapshot events.
|
||||
*
|
||||
* @param listenerId
|
||||
* @param documentSnapshot
|
||||
*/
|
||||
private void handleDocumentSnapshotEvent(String listenerId, DocumentSnapshot documentSnapshot) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap data = FirestoreSerialize.snapshotToWritableMap(documentSnapshot);
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("documentSnapshot", data);
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a documentSnapshot error event
|
||||
*
|
||||
* @param listenerId
|
||||
* @param exception
|
||||
*/
|
||||
private void handleDocumentSnapshotError(String listenerId, FirebaseFirestoreException exception) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
|
||||
event.putString("appName", appName);
|
||||
event.putString("path", path);
|
||||
event.putString("listenerId", listenerId);
|
||||
event.putMap("error", RNFirebaseFirestore.getJSError(exception));
|
||||
|
||||
Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.invertase.firebase.firestore;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class RNFirebaseFirestorePackage implements ReactPackage {
|
||||
public RNFirebaseFirestorePackage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext react application context that can be used to create modules
|
||||
* @return list of native modules to register with the newly created catalyst instance
|
||||
*/
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
modules.add(new RNFirebaseFirestore(reactContext));
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
*/
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -28,18 +28,6 @@ public class RNFirebaseMessagingPackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -28,18 +28,6 @@ public class RNFirebasePerformancePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatability
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -33,18 +33,6 @@ public class RNFirebaseStoragePackage implements ReactPackage {
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of JS modules to register with the newly created catalyst instance.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that only modules that needs to be accessible from the native code should be
|
||||
* listed here. Also listing a native module here doesn't imply that the JS implementation of it
|
||||
* will be automatically included in the JS bundle.
|
||||
*/
|
||||
// TODO: Removed in 0.47.0. Here for backwards compatibility
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reactContext
|
||||
* @return a list of view managers that should be registered with {@link UIManagerModule}
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
---
|
||||
|
||||
!> These docs are for the [v3 pre-release](https://github.com/invertase/react-native-firebase/releases/tag/v3.0.0) version, for the currently published release version see the [v2 docs](/v2/)
|
||||
|
||||
---
|
||||
|
||||
<div style="text-align: center;">
|
||||
[](https://www.npmjs.com/package/react-native-firebase)
|
||||
@@ -11,6 +6,7 @@
|
||||
[](/LICENSE)
|
||||
[](https://discord.gg/t6bdqMs)
|
||||
[](https://www.patreon.com/invertase)
|
||||
[](https://twitter.com/rnfirebase)
|
||||
</div>
|
||||
|
||||
---
|
||||
@@ -46,6 +42,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
||||
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ |**?**|
|
||||
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Dynamic Links** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Firestore** | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Invites** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
|
||||
@@ -57,15 +54,10 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
||||
---
|
||||
### Supported versions - React Native / Firebase
|
||||
|
||||
> The table below shows the supported version of `react-native-firebase` for different React Native versions
|
||||
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
|
||||
|
||||
| | v0.36 - v0.39 | v0.40 - v0.46 | v0.47 +
|
||||
| ------------------------------- | :---: | :---: | :---: |
|
||||
| react-native-firebase | 1.X.X | 2.X.X | 2.1.X |
|
||||
|
||||
> The table below shows the minimum supported versions of the Firebase SDKs for each version of `react-native-firebase`
|
||||
|
||||
| | v1 | v2 | v3 |
|
||||
| ---------------------- | :---: | :---: | :---: |
|
||||
| Firebase Android SDK | 10.2.0+ | 11.0.0 + | 11.2.0 + |
|
||||
| Firebase iOS SDK | 3.15.0+ | 4.0.0 + | 4.0.0 + |
|
||||
| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X |
|
||||
|------------------------|-------------|-------------|-----------------|----------|
|
||||
| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + |
|
||||
| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + |
|
||||
| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + |
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
---
|
||||
|
||||
- Core
|
||||
- [App](/core/app)
|
||||
- [Configure default app instance](/core/config-default-app)
|
||||
- [Apps](/core/app)
|
||||
- [Default App](/core/default-app)
|
||||
- [Dynamically Initialize Apps](/core/initialize-apps)
|
||||
- [Firebase](/core/firebase)
|
||||
- [Configure RNFirebase](/core/config-rnfirebase)
|
||||
|
||||
@@ -24,6 +25,7 @@
|
||||
- [Cloud Messaging](/modules/cloud-messaging)
|
||||
- [Crash Reporting](/modules/crash)
|
||||
- [Database](/modules/database)
|
||||
- [Firestore (Beta)](/modules/firestore)
|
||||
- [Remote Config](/modules/config)
|
||||
- [Storage](/modules/storage)
|
||||
- [Transactions](/modules/transactions)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
# App - firebase.app(): FirebaseApp
|
||||
## Apps
|
||||
|
||||
RNFirebase supports both initializing apps natively and also via js code over the RN bridge.
|
||||
?> For the **default** app see: [Default App](/core/default-app)
|
||||
|
||||
Apps initialized natively are available immediately at app runtime, there is no need to call `initializeApp` for them.
|
||||
?> For initializing **additional apps** natively and also via js code over the RN bridge see: [Dynamically Initializing Apps](/core/initialize-apps)
|
||||
|
||||
For example, to access the default app initialized via the `Google-Services` `plist` or `json` file:
|
||||
### Reading App Options
|
||||
|
||||
!> `<app>.options.clientId` is not available on the **Android Firebase SDK** so will return null for Android, see the issue: [firebase/firebase-ios-sdk#140 (comment)](https://github.com/firebase/firebase-ios-sdk/issues/140#issuecomment-315953708)
|
||||
|
||||
Just like the Firebase web sdk you can view options used to initialize an app instance in the same way, for example:
|
||||
|
||||
```js
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
const defaultApp = firebase.app();
|
||||
|
||||
defaultApp.database().ref('foobar').once('value', (snapshot) => {
|
||||
// snapshot from default app
|
||||
});
|
||||
|
||||
// get the default app name/options that were initialized natively
|
||||
// get the default app name/options that the app initialized with
|
||||
console.log("name", defaultApp.name);
|
||||
console.log("apiKey", defaultApp.options.apiKey);
|
||||
console.log("applicationId", defaultApp.options.applicationId);
|
||||
@@ -26,9 +26,3 @@ console.log("storageBucket", defaultApp.options.projectId);
|
||||
```
|
||||
|
||||
|
||||
<!-- TODO api ref docs: -->
|
||||
<!-- - name: String -->
|
||||
<!-- - options: Object -->
|
||||
<!-- - delete(): Promise -->
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<!-- TODO -->
|
||||
|
||||
### Enable Database Persistence
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<!-- TODO -->
|
||||
### Log Options
|
||||
|
||||
TODO - PR's welcome
|
||||
|
||||
### Debug Options
|
||||
|
||||
TODO - PR's welcome
|
||||
|
||||
27
docs/core/default-app.md
Normal file
27
docs/core/default-app.md
Normal file
@@ -0,0 +1,27 @@
|
||||
### Default Firebase App
|
||||
|
||||
After following the iOS & Android install guides and correctly setting up your google services plist/json files; the default app is automatically initialized and available for use in react-native-firebase.
|
||||
|
||||
There's no need to call `initializeApp(opt)` in your JS code for the default app, import RNFirebase and use the default app straight away:
|
||||
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
console.log(firebase.database().app.name); // '[DEFAULT]'
|
||||
```
|
||||
|
||||
!> Calling `initializeApp()` for the default app will throw an 'app already initialized' error in a later release.
|
||||
|
||||
### Enable Database Persistence
|
||||
|
||||
Enabling database persistence (setPersistence) via JS for the default app is no longer supported. This breaking change was added in v3 to prevent several race condition issues around.
|
||||
|
||||
You can still however easily enable this natively for the default app instance:
|
||||
|
||||
#### Android
|
||||
|
||||
Add `FirebaseDatabase.getInstance().setPersistenceEnabled(true);` inside your `MainActivity.java` files `onCreate()` method.
|
||||
|
||||
#### iOS
|
||||
|
||||
Add `[FIRDatabase database].persistenceEnabled = YES;` after the `[FIRApp configure];` line inside your `AppDelegate.m` files `didFinishLaunchingWithOptions` method.
|
||||
@@ -1,9 +1,10 @@
|
||||
# Firebase
|
||||
|
||||
<!-- TODO api ref docs -->
|
||||
<!-- TODO - apps(): Array<FirebaseApp> -->
|
||||
<!-- TODO - app(): FirebaseApp -->
|
||||
<!-- TODO - initializeApp(): FirebaseApp -->
|
||||
<!-- TODO - setLogLevel() -->
|
||||
<!-- TODO - SDK_VERSION: String -->
|
||||
<!-- TODO - googleApiAvailability: Object -->
|
||||
TODO Reference Docs:
|
||||
|
||||
- apps(): Array<FirebaseApp>
|
||||
- app(): FirebaseApp
|
||||
- initializeApp(): FirebaseApp
|
||||
- setLogLevel()
|
||||
- SDK_VERSION: String
|
||||
- googleApiAvailability: Object
|
||||
|
||||
93
docs/core/initialize-apps.md
Normal file
93
docs/core/initialize-apps.md
Normal file
@@ -0,0 +1,93 @@
|
||||
## Initializing Apps
|
||||
|
||||
!> The **default** firebase app instance can **not** be initialized via JS, please setup your google services plist/json files in your android studio / xcode projects. See [Default App](/core/default-app) for more information.
|
||||
|
||||
App initialization in RNFirebase is for the most part the same as the web sdk, with only a few minor differences.
|
||||
|
||||
### Supported Modules
|
||||
|
||||
Only 4 modules on the official firebase native SDK's support multiple apps, they are as follows:
|
||||
|
||||
- Authentication
|
||||
- Database
|
||||
- Firestore
|
||||
- Storage
|
||||
|
||||
### Initialize via JavaScript
|
||||
|
||||
#### Cross Platform Example
|
||||
|
||||
```javascript
|
||||
import { Platform } from 'react-native';
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
// pluck values from your `GoogleService-Info.plist` you created on the firebase console
|
||||
const iosConfig = {
|
||||
clientId: 'x',
|
||||
appId: 'x',
|
||||
apiKey: 'x',
|
||||
databaseURL: 'x',
|
||||
storageBucket: 'x',
|
||||
messagingSenderId: 'x',
|
||||
projectId: 'x',
|
||||
|
||||
// enable persistence by adding the below flag
|
||||
persistence: true,
|
||||
};
|
||||
|
||||
// pluck values from your `google-services.json` file you created on the firebase console
|
||||
const androidConfig = {
|
||||
clientId: 'x',
|
||||
appId: 'x',
|
||||
apiKey: 'x',
|
||||
databaseURL: 'x',
|
||||
storageBucket: 'x',
|
||||
messagingSenderId: 'x',
|
||||
projectId: 'x',
|
||||
|
||||
// enable persistence by adding the below flag
|
||||
persistence: true,
|
||||
};
|
||||
|
||||
const kittensApp = firebase.initializeApp(
|
||||
// use platform specific firebase config
|
||||
Platform.OS === 'ios' ? iosConfig : androidConfig,
|
||||
// name of this app
|
||||
'kittens',
|
||||
);
|
||||
|
||||
// dynamically created apps aren't available immediately due to the
|
||||
// asynchronous nature of react native bridging, therefore you must
|
||||
// wait for an `onReady` state before calling any modules/methods
|
||||
// otherwise you will most likely run into `app not initialized` exceptions
|
||||
kittensApp.onReady().then((app) => {
|
||||
// --- ready ---
|
||||
// use `app` arg, kittensApp var or `app('kittens')` to access modules
|
||||
// and their methods. e.g:
|
||||
firebase.app('kittens').auth().signInAnonymously().then((user) => {
|
||||
console.log('kittensApp user ->', user.toJSON());
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Initialize via Android/iOS native code
|
||||
|
||||
If you're familiar with native code you can create apps natively also (or if you are already initializing additional apps natively on app boot) - these apps automatically become available for use inside RNFirebase.
|
||||
|
||||
For example, if you created an app natively called `dogs` then the following would work:
|
||||
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
const dogsApp = firebase.app('dogs');
|
||||
|
||||
dogsApp.auth().signInAnonymously().then((user) => {
|
||||
console.log('dogsApp user ->', user.toJSON());
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Deleting an app instance
|
||||
|
||||
Currently it's not possible to provide cross platform 'delete app' functionality as the Firebase Android SDK is missing the app delete method, this has been flagged with firebase ([firebase/firebase-ios-sdk#140 (comment)](https://github.com/firebase/firebase-ios-sdk/issues/140#issuecomment-315953708)).
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
],
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
<!--<script>-->
|
||||
<!--if (typeof navigator.serviceWorker !== 'undefined') {-->
|
||||
<!--navigator.serviceWorker.register('sw.js')-->
|
||||
<!--}-->
|
||||
<!--</script>-->
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
|
||||
<style>
|
||||
.markdown-section pre>code {
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
// ...
|
||||
dependencies {
|
||||
// ...
|
||||
classpath 'com.google.gms:google-services:3.0.0'
|
||||
classpath 'com.google.gms:google-services:3.1.1'
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -42,31 +42,40 @@ dependencies {
|
||||
compile(project(':react-native-firebase')) {
|
||||
transitive = false
|
||||
}
|
||||
compile "com.google.firebase:firebase-core:11.2.0"
|
||||
compile "com.google.firebase:firebase-core:11.4.2"
|
||||
|
||||
// If you are receiving Google Play API availability issues, add the following dependency
|
||||
compile "com.google.android.gms:play-services-base:11.2.0"
|
||||
compile "com.google.android.gms:play-services-base:11.4.2"
|
||||
|
||||
// RNFirebase optional dependencies
|
||||
compile "com.google.firebase:firebase-ads:11.2.0"
|
||||
compile "com.google.firebase:firebase-auth:11.2.0"
|
||||
compile "com.google.firebase:firebase-config:11.2.0"
|
||||
compile "com.google.firebase:firebase-crash:11.2.0"
|
||||
compile "com.google.firebase:firebase-database:11.2.0"
|
||||
compile "com.google.firebase:firebase-messaging:11.2.0"
|
||||
compile "com.google.firebase:firebase-perf:11.2.0"
|
||||
compile "com.google.firebase:firebase-storage:11.2.0"
|
||||
compile "com.google.firebase:firebase-ads:11.4.2"
|
||||
compile "com.google.firebase:firebase-auth:11.4.2"
|
||||
compile "com.google.firebase:firebase-config:11.4.2"
|
||||
compile "com.google.firebase:firebase-crash:11.4.2"
|
||||
compile "com.google.firebase:firebase-database:11.4.2"
|
||||
compile "com.google.firebase:firebase-firestore:11.4.2"
|
||||
compile "com.google.firebase:firebase-messaging:11.4.2"
|
||||
compile "com.google.firebase:firebase-perf:11.4.2"
|
||||
compile "com.google.firebase:firebase-storage:11.4.2"
|
||||
}
|
||||
```
|
||||
|
||||
Google Play services from 11.2.0 onwards require their dependencies to be downloaded from Google's Maven respository so add the
|
||||
Google Play services from 11.4.2 onwards require their dependencies to be downloaded from Google's Maven respository so add the
|
||||
required reference to the repositories section of the *project* level build.gradle
|
||||
`android/build.gradle`
|
||||
|
||||
```groovy
|
||||
allprojects {
|
||||
repositories {
|
||||
// ...
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url "$rootDir/../node_modules/react-native/android"
|
||||
}
|
||||
// -------------------------------------------------
|
||||
// Add this below the existing maven property above
|
||||
// -------------------------------------------------
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
@@ -88,6 +97,7 @@ import io.invertase.firebase.auth.RNFirebaseAuthPackage; // Firebase Auth
|
||||
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage; // Firebase Remote Config
|
||||
import io.invertase.firebase.crash.RNFirebaseCrashPackage; // Firebase Crash Reporting
|
||||
import io.invertase.firebase.database.RNFirebaseDatabasePackage; // Firebase Realtime Database
|
||||
import io.invertase.firebase.firestore.RNFirebaseFirestorePackage; // Firebase Firestore
|
||||
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; // Firebase Cloud Messaging
|
||||
import io.invertase.firebase.perf.RNFirebasePerformancePackage; // Firebase Performance
|
||||
import io.invertase.firebase.storage.RNFirebaseStoragePackage; // Firebase Storage
|
||||
@@ -107,6 +117,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
new RNFirebaseRemoteConfigPackage(),
|
||||
new RNFirebaseCrashPackage(),
|
||||
new RNFirebaseDatabasePackage(),
|
||||
new RNFirebaseFirestorePackage(),
|
||||
new RNFirebaseMessagingPackage(),
|
||||
new RNFirebasePerformancePackage(),
|
||||
new RNFirebaseStoragePackage()
|
||||
@@ -193,6 +204,6 @@ In the same file, add the `firebase-perf` module to your dependencies:
|
||||
```groovy
|
||||
dependencies {
|
||||
// ...
|
||||
compile "com.google.firebase:firebase-perf:11.2.0"
|
||||
compile "com.google.firebase:firebase-perf:11.4.2"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -69,6 +69,7 @@ pod 'Firebase/Auth'
|
||||
pod 'Firebase/Crash'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/DynamicLinks'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
|
||||
@@ -2,7 +2,98 @@
|
||||
|
||||
## From v2 to v3
|
||||
|
||||
<!-- TODO -->
|
||||
The below is a quick summary of steps to take when migrating from v2 to v3 of RNFirebase. Please see the [v3 change log](https://github.com/invertase/react-native-firebase/releases/tag/v3.0.0) for detailed changes.
|
||||
|
||||
** Please note, we're now using `Apache License 2.0` to license this library. **
|
||||
|
||||
##### 1) Install the latest version of RNFirebase:
|
||||
> `npm i react-native-firebase@latest --save`
|
||||
|
||||
|
||||
|
||||
|
||||
##### 2) Upgrade react-native version (only if you're currently lower than v0.48):
|
||||
|
||||
- Follow the instructions [here](https://facebook.github.io/react-native/docs/upgrading.html)
|
||||
|
||||
|
||||
|
||||
|
||||
##### 3) Update your code to reflect deprecations/breaking changes if needed:
|
||||
|
||||
-  **[breaking]** [database] enabling database persistence (setPersistence) via JS is no longer supported - this is to prevent several race conditions. See sub points on how to enable these natively.
|
||||
- [android] add `FirebaseDatabase.getInstance().setPersistenceEnabled(true);` to your `MainActivity` `onCreate` method.
|
||||
- [ios] add `[FIRDatabase database].persistenceEnabled = YES;` after the `[FIRApp configure];` line inside your `AppDelegate` `didFinishLaunchingWithOptions` method.
|
||||
-  **[breaking]** [app] `new RNFirebase()` is no longer supported. See below for information about app initialisation.
|
||||
-  **[deprecated]** [app] `initializeApp()` for apps that are already initialised natively (i.e. the default app initialised via google-services plist/json) will now log a deprecation warning.
|
||||
- As these apps are already initialised natively there's no need to call `initializeApp` in your JS code. For now, calling it will just return the app that's already internally initialised - in a future version this will throw an `already initialized` exception.
|
||||
- Accessing apps can now be done the same way as the web sdk, simply call `firebase.app()` to get the default app, or with the name of specific app as the first arg, e.g. `const meow = firebase.app('catsApp');` to get a specific app.
|
||||
-  **[breaking]** [auth] Third party providers now user `providerId` rather than `provider` as per the Web SDK. If you are manually creating your credentials, you will need to update the field name.
|
||||
-  **[breaking]** [database] Error messages and codes internally re-written to match the web sdk
|
||||
-  **[breaking]** [database] `ref.isEqual` now checks the query modifiers as well as the ref path (was just path before). With the release of multi apps/core support this check now also includes whether the refs are for the same app.
|
||||
-  **[breaking]** [database] on/off behaviour changes. Previous `off` behaviour was incorrect. A `SyncTree/Repo` implementation was added to provide the correct behaviour you'd expect in the web sdk. Whilst this is a breaking change it shouldn't be much of an issue if you've previously setup your on/off handling correctly. See #160 for specifics of this change.
|
||||
-  **[breaking]** [storage] UploadTaskSnapshot -> `downloadUrl` renamed to `downloadURL` to match web sdk
|
||||
|
||||
|
||||
|
||||
##### 4) Android - Update `android/build.gradle`:
|
||||
|
||||
|
||||
- Check you are using google-services 3.1.0 or greater:
|
||||
- You must add `maven { url 'https://maven.google.com' }` to your `android/build.gradle` as follows:
|
||||
|
||||
```groovy
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||
classpath 'com.google.gms:google-services:3.1.0' // CHECK VERSION HERE
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url "$rootDir/../node_modules/react-native/android"
|
||||
}
|
||||
// -------------------------------------------------
|
||||
// Add this below the existing maven property above
|
||||
// -------------------------------------------------
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##### 5) Android - Update `app/build.gradle`:
|
||||
|
||||
|
||||
- You must update all your Firebase & play services dependencies to 11.4.2.
|
||||
|
||||
|
||||
|
||||
##### 6) iOS - Update podfile:
|
||||
|
||||
- You need to check that you're running at least version 4.3.0 of the Firebase Pods
|
||||
- Run `pod outdated`
|
||||
- Run `pod update`
|
||||
|
||||
Add the `Firebase/Firestore` if you plan on using firestore.
|
||||
|
||||
## From v1 to v2
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AdMob
|
||||
|
||||
The admob allows you to display adverts in your app, using your account from [AdMob by Google](https://www.google.co.uk/admob/). RNFirebase allows you to display Banners, Interstitials, NativeExpress Ads & Rewarded Videos.
|
||||
The admob module allows you to display adverts in your app, using your account from [AdMob by Google](https://www.google.co.uk/admob/). RNFirebase allows you to display Banners, Interstitials, NativeExpress Ads & Rewarded Videos.
|
||||
|
||||
## Initialize
|
||||
|
||||
|
||||
190
docs/modules/firestore.md
Normal file
190
docs/modules/firestore.md
Normal file
@@ -0,0 +1,190 @@
|
||||
|
||||
# Firestore (Beta)
|
||||
|
||||
RNFirebase mimics the [Firestore Web SDK](https://firebase.google.com/docs/reference/js/firebase.firestore) by providing a bridge to the native Android and iOS Firestore SDK's.
|
||||
|
||||
All Firestore operations are accessed via `firebase.firestore()`. For detailed documentation of the supported methods demonstrated below please use the official firestore web sdk guides.
|
||||
|
||||
?> Please note that Persistence (offline support) is enabled by default with Firestore on iOS and Android.
|
||||
|
||||
## Add and Manage Data
|
||||
|
||||
### Collections
|
||||
|
||||
Read information about a collection example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.collection('posts')
|
||||
.get()
|
||||
.then(querySnapshot => {
|
||||
// Access all the documents in the collection
|
||||
const docs = querySnapshot.docs;
|
||||
// Access the list of document changes for the collection
|
||||
const changes = querySnapshot.docChanges;
|
||||
// Loop through the documents
|
||||
querySnapshot.forEach((doc) => {
|
||||
const value = doc.data();
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
Add to a collection example (generated ID):
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.collection('posts')
|
||||
.add({
|
||||
title: 'Amazing post',
|
||||
})
|
||||
.then(() => {
|
||||
// Document added to collection and ID generated
|
||||
// Will have path: `posts/{generatedId}`
|
||||
})
|
||||
```
|
||||
|
||||
Add to a collection example (manual ID):
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.collection('posts')
|
||||
.doc('post1')
|
||||
.set({
|
||||
title: 'My awesome post',
|
||||
content: 'Some awesome content',
|
||||
})
|
||||
.then(() => {
|
||||
// Document added to collection with path: `posts/post1`
|
||||
})
|
||||
```
|
||||
|
||||
### Documents
|
||||
|
||||
There are multiple ways to read a document. The following are equivalent examples:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.doc('posts/posts1')
|
||||
.get((documentSnapshot) => {
|
||||
const value = documentSnapshot.data();
|
||||
});
|
||||
|
||||
firebase.firestore()
|
||||
.collection('posts')
|
||||
.doc('posts1')
|
||||
.get((documentSnapshot) => {
|
||||
const value = documentSnapshot.data();
|
||||
});
|
||||
```
|
||||
|
||||
Create a document example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.doc('posts/posts1')
|
||||
.set({
|
||||
title: 'My awesome post',
|
||||
content: 'Some awesome content',
|
||||
})
|
||||
.then(() => {
|
||||
// Document created
|
||||
});
|
||||
```
|
||||
|
||||
Updating a document example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.doc('posts/posts1')
|
||||
.update({
|
||||
title: 'My awesome post',
|
||||
})
|
||||
.then(() => {
|
||||
// Document created
|
||||
});
|
||||
```
|
||||
|
||||
Deleting a document example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.doc('posts/posts1')
|
||||
.delete()
|
||||
.then(() => {
|
||||
// Document deleted
|
||||
});
|
||||
```
|
||||
|
||||
### Batching document updates
|
||||
|
||||
Writes, updates and deletes to documents can be batched and committed atomically as follows:
|
||||
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
const ayRef = firebase.firestore().doc('places/AY');
|
||||
const lRef = firebase.firestore().doc('places/LON');
|
||||
const nycRef = firebase.firestore().doc('places/NYC');
|
||||
const sfRef = firebase.firestore().doc('places/SF');
|
||||
|
||||
firebase.firestore()
|
||||
.batch()
|
||||
.set(ayRef, { name: 'Aylesbury' })
|
||||
.set(lRef, { name: 'London' })
|
||||
.set(nycRef, { name: 'New York City' })
|
||||
.set(sfRef, { name: 'San Francisco' })
|
||||
.update(nycRef, { population: 1000000 })
|
||||
.update(sfRef, { name: 'San Fran' })
|
||||
.set(lRef, { population: 3000000 }, { merge: true })
|
||||
.delete(ayRef)
|
||||
.commit()
|
||||
.then(() => {
|
||||
// Would end up with three documents in the collection: London, New York City and San Francisco
|
||||
});
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
Coming soon
|
||||
|
||||
## Realtime Updates
|
||||
|
||||
### Collections
|
||||
|
||||
Listen to collection updates example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.collection('cities')
|
||||
.where('state', '==', 'CA')
|
||||
.onSnapshot((querySnapshot) => {
|
||||
querySnapshot.forEach((doc) => {
|
||||
// DocumentSnapshot available
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
The snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified).
|
||||
|
||||
### Documents
|
||||
|
||||
Listen to document updates example:
|
||||
```javascript
|
||||
import firebase from 'react-native-firebase';
|
||||
|
||||
firebase.firestore()
|
||||
.doc('posts/post1')
|
||||
.onSnapshot((documentSnapshot) => {
|
||||
// DocumentSnapshot available
|
||||
})
|
||||
```
|
||||
|
||||
The snapshot handler will receive the current contents of the document, and any subsequent changes to the document.
|
||||
@@ -1,7 +1,5 @@
|
||||
# Performance Monitoring
|
||||
|
||||
!> Performance monitoring requires react-native-firebase version 1.2.0.
|
||||
|
||||
?> Android: If you plan on using this module in your own application, please ensure the optional setup instructions for
|
||||
[Android](http://invertase.io/react-native-firebase/#/installation-android?id=_4-performance-monitoring-optional) have been followed.
|
||||
|
||||
|
||||
238
docs/redux.md
238
docs/redux.md
@@ -3,6 +3,126 @@
|
||||
Although RNFirebase usage requires a React Native environment, it isn't tightly coupled which allows for full flexibility
|
||||
when it comes to integrating with other modules such a [`react-redux`](https://github.com/reactjs/react-redux).
|
||||
|
||||
## Standalone Integration
|
||||
|
||||
Although the following example works for a basic redux setup, it may differ when integrating with other redux middleware.
|
||||
Imagine a simple TODO app, with redux we're able to abstract the Firebase logic out of components which allows for greater
|
||||
testability and maintainability.
|
||||
|
||||
?> We use [`redux-thunk`](https://github.com/gaearon/redux-thunk) to provide async actions.
|
||||
|
||||
### Action Creators
|
||||
|
||||
```js
|
||||
// Actions
|
||||
export const subscribe = () => {
|
||||
return (dispatch) => {
|
||||
firebase.database().ref('todos').on('value', (snapshot) => {
|
||||
const todos = [];
|
||||
|
||||
snapshot.forEach((childSnapshot) => {
|
||||
todos.push({
|
||||
id: childSnapshot.key,
|
||||
...(childSnapshot.val()),
|
||||
})
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'TODO_UPDATE',
|
||||
todos,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
export const addTodo = text => {
|
||||
firebase.database().ref('todos').push({
|
||||
text,
|
||||
visible: true,
|
||||
})
|
||||
}
|
||||
|
||||
export const completeTodo = id => {
|
||||
firebase.database().ref(`todos/${id}`).update({
|
||||
visible: false,
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Instead of creating multiple actions which the reducers handle, we instead subscribe to the database ref and on any changes,
|
||||
send a single action for the reducers to handle with the data which is constantly updating.
|
||||
|
||||
### Reducers
|
||||
|
||||
Our reducer now becomes really simple, as we're able to simply update the reducers state with whatever data has been returned
|
||||
from our Firebase subscription.
|
||||
|
||||
```js
|
||||
const todos = (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case 'TODO_UPDATE':
|
||||
return { ...action.todos };
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export default todos;
|
||||
```
|
||||
|
||||
### Component
|
||||
|
||||
We can now easily subscribe to the todos in redux state and get live updates when Firebase updates.
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { subscribe, addTodo, completeTodo } from '../actions/TodoActions.js';
|
||||
...
|
||||
|
||||
class Todos extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(
|
||||
subscribe()
|
||||
);
|
||||
}
|
||||
|
||||
onComplete = (id) => {
|
||||
this.props.dispatch(
|
||||
completeTodo(id)
|
||||
);
|
||||
};
|
||||
|
||||
onAdd = (text) => {
|
||||
this.props.dispatch(
|
||||
addTodo(text)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FlatList
|
||||
data={this.props.todos}
|
||||
...
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
todos: state.todos,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Todos);
|
||||
```
|
||||
|
||||
|
||||
## React Redux Firebase
|
||||
|
||||
[`react-redux-firebase`](http://docs.react-redux-firebase.com/history/v2.0.0) provides simplified and standardized common redux/firebase logic.
|
||||
@@ -212,121 +332,3 @@ For more details, please visit [`react-redux-firebase`'s react-native section](h
|
||||
);
|
||||
```
|
||||
|
||||
## Standalone Integration
|
||||
|
||||
Although the following example works for a basic redux setup, it may differ when integrating with other redux middleware.
|
||||
Imagine a simple TODO app, with redux we're able to abstract the Firebase logic out of components which allows for greater
|
||||
testability and maintainability.
|
||||
|
||||
?> We use [`redux-thunk`](https://github.com/gaearon/redux-thunk) to provide async actions.
|
||||
|
||||
### Action Creators
|
||||
|
||||
```js
|
||||
// Actions
|
||||
export const subscribe = () => {
|
||||
return (dispatch) => {
|
||||
firebase.database().ref('todos').on('value', (snapshot) => {
|
||||
const todos = [];
|
||||
|
||||
snapshot.forEach((childSnapshot) => {
|
||||
todos.push({
|
||||
id: childSnapshot.key,
|
||||
...(childSnapshot.val()),
|
||||
})
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'TODO_UPDATE',
|
||||
todos,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
export const addTodo = text => {
|
||||
firebase.database().ref('todos').push({
|
||||
text,
|
||||
visible: true,
|
||||
})
|
||||
}
|
||||
|
||||
export const completeTodo = id => {
|
||||
firebase.database().ref(`todos/${id}`).update({
|
||||
visible: false,
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Instead of creating multiple actions which the reducers handle, we instead subscribe to the database ref and on any changes,
|
||||
send a single action for the reducers to handle with the data which is constantly updating.
|
||||
|
||||
### Reducers
|
||||
|
||||
Our reducer now becomes really simple, as we're able to simply update the reducers state with whatever data has been returned
|
||||
from our Firebase subscription.
|
||||
|
||||
```js
|
||||
const todos = (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case 'TODO_UPDATE':
|
||||
return { ...action.todos };
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export default todos;
|
||||
```
|
||||
|
||||
### Component
|
||||
|
||||
We can now easily subscribe to the todos in redux state and get live updates when Firebase updates.
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { subscribe, addTodo, completeTodo } from '../actions/TodoActions.js';
|
||||
...
|
||||
|
||||
class Todos extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(
|
||||
subscribe()
|
||||
);
|
||||
}
|
||||
|
||||
onComplete = (id) => {
|
||||
this.props.dispatch(
|
||||
completeTodo(id)
|
||||
);
|
||||
};
|
||||
|
||||
onAdd = (text) => {
|
||||
this.props.dispatch(
|
||||
addTodo(text)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FlatList
|
||||
data={this.props.todos}
|
||||
...
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
todos: state.todos,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Todos);
|
||||
```
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
-  Viewing old RNFirebase version 
|
||||
|
||||
- Getting started
|
||||
- [Initial setup](/v2/initial-setup)
|
||||
- [Installation - iOS](/v2/installation-ios)
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
8323CF071F6FBD870071420B /* NativeExpressComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF011F6FBD870071420B /* NativeExpressComponent.m */; };
|
||||
8323CF081F6FBD870071420B /* RNFirebaseAdMobBannerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF031F6FBD870071420B /* RNFirebaseAdMobBannerManager.m */; };
|
||||
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF051F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m */; };
|
||||
8376F7141F7C149100D45A85 /* RNFirebaseFirestoreDocumentReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */; };
|
||||
8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */; };
|
||||
8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */; };
|
||||
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */; };
|
||||
839D916D1EF3E20B0077C7C8 /* RNFirebaseAdMobInterstitial.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91511EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.m */; };
|
||||
839D916E1EF3E20B0077C7C8 /* RNFirebaseAdMobRewardedVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91531EF3E20A0077C7C8 /* RNFirebaseAdMobRewardedVideo.m */; };
|
||||
@@ -53,6 +56,12 @@
|
||||
8323CF031F6FBD870071420B /* RNFirebaseAdMobBannerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMobBannerManager.m; sourceTree = "<group>"; };
|
||||
8323CF041F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMobNativeExpressManager.h; sourceTree = "<group>"; };
|
||||
8323CF051F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMobNativeExpressManager.m; sourceTree = "<group>"; };
|
||||
8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestoreDocumentReference.m; sourceTree = "<group>"; };
|
||||
8376F70F1F7C149000D45A85 /* RNFirebaseFirestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestore.h; sourceTree = "<group>"; };
|
||||
8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestore.m; sourceTree = "<group>"; };
|
||||
8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestoreCollectionReference.m; sourceTree = "<group>"; };
|
||||
8376F7121F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestoreDocumentReference.h; sourceTree = "<group>"; };
|
||||
8376F7131F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestoreCollectionReference.h; sourceTree = "<group>"; };
|
||||
839D914E1EF3E20A0077C7C8 /* RNFirebaseAdMob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMob.h; sourceTree = "<group>"; };
|
||||
839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMob.m; sourceTree = "<group>"; };
|
||||
839D91501EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMobInterstitial.h; sourceTree = "<group>"; };
|
||||
@@ -119,6 +128,7 @@
|
||||
839D915A1EF3E20A0077C7C8 /* config */,
|
||||
839D915D1EF3E20A0077C7C8 /* crash */,
|
||||
839D91601EF3E20A0077C7C8 /* database */,
|
||||
8376F70D1F7C141500D45A85 /* firestore */,
|
||||
839D91631EF3E20A0077C7C8 /* messaging */,
|
||||
839D91661EF3E20A0077C7C8 /* perf */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
@@ -129,6 +139,20 @@
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8376F70D1F7C141500D45A85 /* firestore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8376F70F1F7C149000D45A85 /* RNFirebaseFirestore.h */,
|
||||
8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */,
|
||||
8376F7131F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.h */,
|
||||
8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */,
|
||||
8376F7121F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.h */,
|
||||
8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */,
|
||||
);
|
||||
name = firestore;
|
||||
path = RNFirebase/firestore;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
839D914D1EF3E20A0077C7C8 /* admob */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -292,9 +316,12 @@
|
||||
839D916E1EF3E20B0077C7C8 /* RNFirebaseAdMobRewardedVideo.m in Sources */,
|
||||
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */,
|
||||
17AF4F6B1F59CDBF00C02336 /* RNFirebaseLinks.m in Sources */,
|
||||
8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */,
|
||||
839D91761EF3E20B0077C7C8 /* RNFirebaseStorage.m in Sources */,
|
||||
8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */,
|
||||
839D91701EF3E20B0077C7C8 /* RNFirebaseAuth.m in Sources */,
|
||||
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */,
|
||||
8376F7141F7C149100D45A85 /* RNFirebaseFirestoreDocumentReference.m in Sources */,
|
||||
839D916F1EF3E20B0077C7C8 /* RNFirebaseAnalytics.m in Sources */,
|
||||
839D91711EF3E20B0077C7C8 /* RNFirebaseRemoteConfig.m in Sources */,
|
||||
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
|
||||
|
||||
@@ -79,7 +79,7 @@ RCT_EXPORT_METHOD(deleteApp:
|
||||
|
||||
/**
|
||||
* React native constant exports - exports native firebase apps mainly
|
||||
* @return
|
||||
* @return NSDictionary
|
||||
*/
|
||||
- (NSDictionary *)constantsToExport {
|
||||
NSMutableDictionary *constants = [NSMutableDictionary new];
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
static NSString *const AUTH_CHANGED_EVENT = @"auth_state_changed";
|
||||
static NSString *const AUTH_ID_TOKEN_CHANGED_EVENT = @"auth_id_token_changed";
|
||||
static NSString *const PHONE_AUTH_STATE_CHANGED_EVENT = @"phone_auth_state_changed";
|
||||
|
||||
// Database
|
||||
static NSString *const DATABASE_SYNC_EVENT = @"database_sync_event";
|
||||
@@ -16,6 +17,10 @@ static NSString *const DATABASE_CHILD_MODIFIED_EVENT = @"child_changed";
|
||||
static NSString *const DATABASE_CHILD_REMOVED_EVENT = @"child_removed";
|
||||
static NSString *const DATABASE_CHILD_MOVED_EVENT = @"child_moved";
|
||||
|
||||
// Firestore
|
||||
static NSString *const FIRESTORE_COLLECTION_SYNC_EVENT = @"firestore_collection_sync_event";
|
||||
static NSString *const FIRESTORE_DOCUMENT_SYNC_EVENT = @"firestore_document_sync_event";
|
||||
|
||||
// Storage
|
||||
static NSString *const STORAGE_EVENT = @"storage_event";
|
||||
static NSString *const STORAGE_ERROR = @"storage_error";
|
||||
|
||||
@@ -558,6 +558,9 @@ RCT_EXPORT_METHOD(checkActionCode:
|
||||
case FIRActionCodeOperationUnknown:
|
||||
actionType = @"UNKNOWN";
|
||||
break;
|
||||
case FIRActionCodeOperationRecoverEmail:
|
||||
actionType = @"RECOVER_EMAIL";
|
||||
break;
|
||||
}
|
||||
|
||||
NSDictionary *result = @{@"data": @{@"email": [info dataForKey:FIRActionCodeEmailKey], @"fromEmail": [info dataForKey:FIRActionCodeFromEmailKey],}, @"actionType": actionType,};
|
||||
@@ -654,7 +657,7 @@ RCT_EXPORT_METHOD(signInWithPhoneNumber:(NSString *) appName
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||
|
||||
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
|
||||
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
@@ -667,6 +670,41 @@ RCT_EXPORT_METHOD(signInWithPhoneNumber:(NSString *) appName
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
verifyPhoneNumber
|
||||
|
||||
@param string phoneNumber
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appName
|
||||
phoneNumber:(NSString *) phoneNumber
|
||||
requestKey:(NSString *) requestKey) {
|
||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||
|
||||
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
NSDictionary * jsError = [self getJSError:(error)];
|
||||
NSMutableDictionary * props = [@{
|
||||
@"type": @"onVerificationFailed",
|
||||
@"requestKey":requestKey,
|
||||
@"state": @{@"error": jsError},
|
||||
} mutableCopy];
|
||||
[self sendJSEventWithAppName:appName title:PHONE_AUTH_STATE_CHANGED_EVENT props: props];
|
||||
} else {
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setObject:verificationID forKey:@"authVerificationID"];
|
||||
NSMutableDictionary * props = [@{
|
||||
@"type": @"onCodeSent",
|
||||
@"requestKey":requestKey,
|
||||
@"state": @{@"verificationId": verificationID},
|
||||
} mutableCopy];
|
||||
[self sendJSEventWithAppName:appName title:PHONE_AUTH_STATE_CHANGED_EVENT props: props];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appName
|
||||
verificationCode:(NSString *) verificationCode
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
@@ -843,9 +881,9 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
/**
|
||||
getCredentialForProvider
|
||||
|
||||
@param provider
|
||||
@param authToken
|
||||
@param authTokenSecret
|
||||
@param provider string
|
||||
@param authToken string
|
||||
@param authTokenSecret string
|
||||
@return FIRAuthCredential
|
||||
*/
|
||||
- (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider token:(NSString *)authToken secret:(NSString *)authTokenSecret {
|
||||
@@ -893,9 +931,20 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
@param error NSError
|
||||
*/
|
||||
- (void)promiseRejectAuthException:(RCTPromiseRejectBlock)reject error:(NSError *)error {
|
||||
NSDictionary * jsError = [self getJSError:(error)];
|
||||
reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], error);
|
||||
}
|
||||
|
||||
/**
|
||||
Reject a promise with an auth exception
|
||||
|
||||
@param error NSError
|
||||
*/
|
||||
- (NSDictionary *)getJSError:(NSError *)error {
|
||||
NSString *code = @"auth/unknown";
|
||||
NSString *message = [error localizedDescription];
|
||||
|
||||
NSString *nativeErrorMessage = [error localizedDescription];
|
||||
|
||||
switch (error.code) {
|
||||
case FIRAuthErrorCodeInvalidCustomToken:
|
||||
code = @"auth/invalid-custom-token";
|
||||
@@ -969,7 +1018,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
code = @"auth/internal-error";
|
||||
message = @"An internal error has occurred, please try again.";
|
||||
break;
|
||||
|
||||
|
||||
// unsure of the below codes so leaving them as the default error message
|
||||
case FIRAuthErrorCodeTooManyRequests:
|
||||
code = @"auth/too-many-requests";
|
||||
@@ -1004,10 +1053,15 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reject(code, message, error);
|
||||
|
||||
return @{
|
||||
@"code": code,
|
||||
@"message": message,
|
||||
@"nativeErrorMessage": nativeErrorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resolve or reject a promise based on FIRUser value existance
|
||||
|
||||
@@ -1109,7 +1163,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[AUTH_CHANGED_EVENT, AUTH_ID_TOKEN_CHANGED_EVENT];
|
||||
return @[AUTH_CHANGED_EVENT, AUTH_ID_TOKEN_CHANGED_EVENT, PHONE_AUTH_STATE_CHANGED_EVENT];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
RCT_EXPORT_METHOD(log:(NSString *)message) {
|
||||
FIRCrashLog(message);
|
||||
FIRCrashLog(@"%@", message);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(logcat:(nonnull NSNumber *) level tag:(NSString *) tag message:(NSString *) message) {
|
||||
FIRCrashLog(message);
|
||||
FIRCrashLog(@"%@", message);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(report:(NSString *) message) {
|
||||
FIRCrashLog(message);
|
||||
FIRCrashLog(@"%@", message);
|
||||
assert(NO);
|
||||
}
|
||||
|
||||
|
||||
26
ios/RNFirebase/firestore/RNFirebaseFirestore.h
Normal file
26
ios/RNFirebase/firestore/RNFirebaseFirestore.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef RNFirebaseFirestore_h
|
||||
#define RNFirebaseFirestore_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
#import <FirebaseFirestore/FirebaseFirestore.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
@interface RNFirebaseFirestore : RCTEventEmitter <RCTBridgeModule> {}
|
||||
|
||||
+ (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error;
|
||||
|
||||
+ (FIRFirestore *)getFirestoreForApp:(NSString *)appName;
|
||||
+ (NSDictionary *)getJSError:(NSError *)nativeError;
|
||||
|
||||
@end
|
||||
|
||||
#else
|
||||
@interface RNFirebaseFirestore : NSObject
|
||||
@end
|
||||
#endif
|
||||
|
||||
#endif
|
||||
282
ios/RNFirebase/firestore/RNFirebaseFirestore.m
Normal file
282
ios/RNFirebase/firestore/RNFirebaseFirestore.m
Normal file
@@ -0,0 +1,282 @@
|
||||
#import "RNFirebaseFirestore.h"
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
#import <Firebase.h>
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import "RNFirebaseFirestoreCollectionReference.h"
|
||||
#import "RNFirebaseFirestoreDocumentReference.h"
|
||||
|
||||
@implementation RNFirebaseFirestore
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(collectionGet:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
filters:(NSArray *) filters
|
||||
orders:(NSArray *) orders
|
||||
options:(NSDictionary *) options
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options] get:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
filters:(NSArray *) filters
|
||||
orders:(NSArray *) orders
|
||||
options:(NSDictionary *) options
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
[RNFirebaseFirestoreCollectionReference offSnapshot:listenerId];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(collectionOnSnapshot:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
filters:(NSArray *) filters
|
||||
orders:(NSArray *) orders
|
||||
options:(NSDictionary *) options
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
RNFirebaseFirestoreCollectionReference *ref = [self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options];
|
||||
[ref onSnapshot:listenerId];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentBatch:(NSString *) appName
|
||||
writes:(NSArray *) writes
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appName];
|
||||
FIRWriteBatch *batch = [firestore batch];
|
||||
|
||||
for (NSDictionary *write in writes) {
|
||||
NSString *type = write[@"type"];
|
||||
NSString *path = write[@"path"];
|
||||
NSDictionary *data = write[@"data"];
|
||||
|
||||
FIRDocumentReference *ref = [firestore documentWithPath:path];
|
||||
|
||||
if ([type isEqualToString:@"DELETE"]) {
|
||||
batch = [batch deleteDocument:ref];
|
||||
} else if ([type isEqualToString:@"SET"]) {
|
||||
NSDictionary *options = write[@"options"];
|
||||
if (options && options[@"merge"]) {
|
||||
batch = [batch setData:data forDocument:ref options:[FIRSetOptions merge]];
|
||||
} else {
|
||||
batch = [batch setData:data forDocument:ref];
|
||||
}
|
||||
} else if ([type isEqualToString:@"UPDATE"]) {
|
||||
batch = [batch updateData:data forDocument:ref];
|
||||
}
|
||||
}
|
||||
|
||||
[batch commitWithCompletion:^(NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[RNFirebaseFirestore promiseRejectException:reject error:error];
|
||||
} else {
|
||||
resolve(nil);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentCollections:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] get:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentCreate:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
data:(NSDictionary *) data
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] create:data resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentDelete:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] delete:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentGet:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] get:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentGetAll:(NSString *) appName
|
||||
documents:(NSString *) documents
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
// Not supported on iOS out of the box
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
[RNFirebaseFirestoreDocumentReference offSnapshot:listenerId];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentOnSnapshot:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
RNFirebaseFirestoreDocumentReference *ref = [self getDocumentForAppPath:appName path:path];
|
||||
[ref onSnapshot:listenerId];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentSet:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
data:(NSDictionary *) data
|
||||
options:(NSDictionary *) options
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] set:data options:options resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentUpdate:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
data:(NSDictionary *) data
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
[[self getDocumentForAppPath:appName path:path] update:data resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS/UTILS
|
||||
*/
|
||||
+ (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error {
|
||||
NSDictionary *jsError = [RNFirebaseFirestore getJSError:error];
|
||||
reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], error);
|
||||
}
|
||||
|
||||
+ (FIRFirestore *)getFirestoreForApp:(NSString *)appName {
|
||||
FIRApp *app = [FIRApp appNamed:appName];
|
||||
return [FIRFirestore firestoreForApp:app];
|
||||
}
|
||||
|
||||
- (RNFirebaseFirestoreCollectionReference *)getCollectionForAppPath:(NSString *)appName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options {
|
||||
return [[RNFirebaseFirestoreCollectionReference alloc] initWithPathAndModifiers:self app:appName path:path filters:filters orders:orders options:options];
|
||||
}
|
||||
|
||||
- (RNFirebaseFirestoreDocumentReference *)getDocumentForAppPath:(NSString *)appName path:(NSString *)path {
|
||||
return [[RNFirebaseFirestoreDocumentReference alloc] initWithPath:self app:appName path:path];
|
||||
}
|
||||
|
||||
// TODO: Move to error util for use in other modules
|
||||
+ (NSString *)getMessageWithService:(NSString *)message service:(NSString *)service fullCode:(NSString *)fullCode {
|
||||
return [NSString stringWithFormat:@"%@: %@ (%@).", service, message, [fullCode lowercaseString]];
|
||||
}
|
||||
|
||||
+ (NSString *)getCodeWithService:(NSString *)service code:(NSString *)code {
|
||||
return [NSString stringWithFormat:@"%@/%@", [service lowercaseString], [code lowercaseString]];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)getJSError:(NSError *)nativeError {
|
||||
NSMutableDictionary *errorMap = [[NSMutableDictionary alloc] init];
|
||||
[errorMap setValue:@(nativeError.code) forKey:@"nativeErrorCode"];
|
||||
[errorMap setValue:[nativeError localizedDescription] forKey:@"nativeErrorMessage"];
|
||||
|
||||
NSString *code;
|
||||
NSString *message;
|
||||
NSString *service = @"Firestore";
|
||||
|
||||
switch (nativeError.code) {
|
||||
case FIRFirestoreErrorCodeOK:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"ok"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Ok." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeCancelled:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"cancelled"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"The operation was cancelled." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeUnknown:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"unknown"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Unknown error or an error from a different error domain." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeInvalidArgument:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"invalid-argument"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Client specified an invalid argument." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeDeadlineExceeded:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"deadline-exceeded"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Deadline expired before operation could complete." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeNotFound:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"not-found"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Some requested document was not found." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeAlreadyExists:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"already-exists"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Some document that we attempted to create already exists." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodePermissionDenied:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"permission-denied"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"The caller does not have permission to execute the specified operation." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeResourceExhausted:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"resource-exhausted"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeFailedPrecondition:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"failed-precondition"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Operation was rejected because the system is not in a state required for the operation`s execution." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeAborted:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"aborted"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"The operation was aborted, typically due to a concurrency issue like transaction aborts, etc." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeOutOfRange:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"out-of-range"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Operation was attempted past the valid range." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeUnimplemented:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"unimplemented"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Operation is not implemented or not supported/enabled." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeInternal:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"internal"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Internal errors." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeUnavailable:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"unavailable"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"The service is currently unavailable." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeDataLoss:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"data-loss"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"Unrecoverable data loss or corruption." service:service fullCode:code];
|
||||
break;
|
||||
case FIRFirestoreErrorCodeUnauthenticated:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"unauthenticated"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"The request does not have valid authentication credentials for the operation." service:service fullCode:code];
|
||||
break;
|
||||
default:
|
||||
code = [RNFirebaseFirestore getCodeWithService:service code:@"unknown"];
|
||||
message = [RNFirebaseFirestore getMessageWithService:@"An unknown error occurred." service:service fullCode:code];
|
||||
break;
|
||||
}
|
||||
|
||||
[errorMap setValue:code forKey:@"code"];
|
||||
[errorMap setValue:message forKey:@"message"];
|
||||
|
||||
return errorMap;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[FIRESTORE_COLLECTION_SYNC_EVENT, FIRESTORE_DOCUMENT_SYNC_EVENT];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else
|
||||
@implementation RNFirebaseFirestore
|
||||
@end
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef RNFirebaseFirestoreCollectionReference_h
|
||||
#define RNFirebaseFirestoreCollectionReference_h
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
#import <FirebaseFirestore/FirebaseFirestore.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import "RNFirebaseFirestore.h"
|
||||
#import "RNFirebaseFirestoreDocumentReference.h"
|
||||
|
||||
@interface RNFirebaseFirestoreCollectionReference : NSObject
|
||||
@property RCTEventEmitter *emitter;
|
||||
@property NSString *app;
|
||||
@property NSString *path;
|
||||
@property NSArray *filters;
|
||||
@property NSArray *orders;
|
||||
@property NSDictionary *options;
|
||||
@property FIRQuery *query;
|
||||
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options;
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
+ (void)offSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId;
|
||||
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot;
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
@interface RNFirebaseFirestoreCollectionReference : NSObject
|
||||
@end
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,207 @@
|
||||
#import "RNFirebaseFirestoreCollectionReference.h"
|
||||
|
||||
@implementation RNFirebaseFirestoreCollectionReference
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
static NSMutableDictionary *_listeners;
|
||||
|
||||
- (id)initWithPathAndModifiers:(RCTEventEmitter *) emitter
|
||||
app:(NSString *) app
|
||||
path:(NSString *) path
|
||||
filters:(NSArray *) filters
|
||||
orders:(NSArray *) orders
|
||||
options:(NSDictionary *) options {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_emitter = emitter;
|
||||
_app = app;
|
||||
_path = path;
|
||||
_filters = filters;
|
||||
_orders = orders;
|
||||
_options = options;
|
||||
_query = [self buildQuery];
|
||||
}
|
||||
// Initialise the static listeners object if required
|
||||
if (!_listeners) {
|
||||
_listeners = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
[_query getDocumentsWithCompletion:^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[RNFirebaseFirestore promiseRejectException:reject error:error];
|
||||
} else {
|
||||
NSDictionary *data = [RNFirebaseFirestoreCollectionReference snapshotToDictionary:snapshot];
|
||||
resolve(data);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)offSnapshot:(NSString *) listenerId {
|
||||
id<FIRListenerRegistration> listener = _listeners[listenerId];
|
||||
if (listener) {
|
||||
[_listeners removeObjectForKey:listenerId];
|
||||
[listener remove];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onSnapshot:(NSString *) listenerId {
|
||||
if (_listeners[listenerId] == nil) {
|
||||
id listenerBlock = ^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
id<FIRListenerRegistration> listener = _listeners[listenerId];
|
||||
if (listener) {
|
||||
[_listeners removeObjectForKey:listenerId];
|
||||
[listener remove];
|
||||
}
|
||||
[self handleQuerySnapshotError:listenerId error:error];
|
||||
} else {
|
||||
[self handleQuerySnapshotEvent:listenerId querySnapshot:snapshot];
|
||||
}
|
||||
};
|
||||
id<FIRListenerRegistration> listener = [_query addSnapshotListener:listenerBlock];
|
||||
_listeners[listenerId] = listener;
|
||||
}
|
||||
}
|
||||
|
||||
- (FIRQuery *)buildQuery {
|
||||
FIRQuery *query = (FIRQuery*)[[RNFirebaseFirestore getFirestoreForApp:_app] collectionWithPath:_path];
|
||||
query = [self applyFilters:query];
|
||||
query = [self applyOrders:query];
|
||||
query = [self applyOptions:query];
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
- (FIRQuery *)applyFilters:(FIRQuery *) query {
|
||||
for (NSDictionary *filter in _filters) {
|
||||
NSString *fieldPath = filter[@"fieldPath"];
|
||||
NSString *operator = filter[@"operator"];
|
||||
// TODO: Validate this works
|
||||
id value = filter[@"value"];
|
||||
|
||||
if ([operator isEqualToString:@"EQUAL"]) {
|
||||
query = [query queryWhereField:fieldPath isEqualTo:value];
|
||||
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
||||
query = [query queryWhereField:fieldPath isGreaterThan:value];
|
||||
} else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
|
||||
query = [query queryWhereField:fieldPath isGreaterThanOrEqualTo:value];
|
||||
} else if ([operator isEqualToString:@"LESS_THAN"]) {
|
||||
query = [query queryWhereField:fieldPath isLessThan:value];
|
||||
} else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
|
||||
query = [query queryWhereField:fieldPath isLessThanOrEqualTo:value];
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
- (FIRQuery *)applyOrders:(FIRQuery *) query {
|
||||
for (NSDictionary *order in _orders) {
|
||||
NSString *direction = order[@"direction"];
|
||||
NSString *fieldPath = order[@"fieldPath"];
|
||||
|
||||
query = [query queryOrderedByField:fieldPath descending:([direction isEqualToString:@"DESCENDING"])];
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
- (FIRQuery *)applyOptions:(FIRQuery *) query {
|
||||
if (_options[@"endAt"]) {
|
||||
query = [query queryEndingAtValues:_options[@"endAt"]];
|
||||
}
|
||||
if (_options[@"endBefore"]) {
|
||||
query = [query queryEndingBeforeValues:_options[@"endBefore"]];
|
||||
}
|
||||
if (_options[@"offset"]) {
|
||||
// iOS doesn't support offset
|
||||
}
|
||||
if (_options[@"selectFields"]) {
|
||||
// iOS doesn't support selectFields
|
||||
}
|
||||
if (_options[@"startAfter"]) {
|
||||
query = [query queryStartingAfterValues:_options[@"startAfter"]];
|
||||
}
|
||||
if (_options[@"startAt"]) {
|
||||
query = [query queryStartingAtValues:_options[@"startAt"]];
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
- (void)handleQuerySnapshotError:(NSString *)listenerId
|
||||
error:(NSError *)error {
|
||||
NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
|
||||
[event setValue:_app forKey:@"appName"];
|
||||
[event setValue:_path forKey:@"path"];
|
||||
[event setValue:listenerId forKey:@"listenerId"];
|
||||
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
||||
|
||||
[_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
||||
}
|
||||
|
||||
- (void)handleQuerySnapshotEvent:(NSString *)listenerId
|
||||
querySnapshot:(FIRQuerySnapshot *)querySnapshot {
|
||||
NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
|
||||
[event setValue:_app forKey:@"appName"];
|
||||
[event setValue:_path forKey:@"path"];
|
||||
[event setValue:listenerId forKey:@"listenerId"];
|
||||
[event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"];
|
||||
|
||||
[_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot {
|
||||
NSMutableDictionary *snapshot = [[NSMutableDictionary alloc] init];
|
||||
[snapshot setValue:[self documentChangesToArray:querySnapshot.documentChanges] forKey:@"changes"];
|
||||
[snapshot setValue:[self documentSnapshotsToArray:querySnapshot.documents] forKey:@"documents"];
|
||||
if (querySnapshot.metadata) {
|
||||
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
|
||||
[metadata setValue:@(querySnapshot.metadata.fromCache) forKey:@"fromCache"];
|
||||
[metadata setValue:@(querySnapshot.metadata.hasPendingWrites) forKey:@"hasPendingWrites"];
|
||||
[snapshot setValue:metadata forKey:@"metadata"];
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
+ (NSArray *)documentChangesToArray:(NSArray<FIRDocumentChange *> *) documentChanges {
|
||||
NSMutableArray *changes = [[NSMutableArray alloc] init];
|
||||
for (FIRDocumentChange *change in documentChanges) {
|
||||
[changes addObject:[self documentChangeToDictionary:change]];
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)documentChangeToDictionary:(FIRDocumentChange *)documentChange {
|
||||
NSMutableDictionary *change = [[NSMutableDictionary alloc] init];
|
||||
[change setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentChange.document] forKey:@"document"];
|
||||
[change setValue:@(documentChange.newIndex) forKey:@"newIndex"];
|
||||
[change setValue:@(documentChange.oldIndex) forKey:@"oldIndex"];
|
||||
|
||||
if (documentChange.type == FIRDocumentChangeTypeAdded) {
|
||||
[change setValue:@"added" forKey:@"type"];
|
||||
} else if (documentChange.type == FIRDocumentChangeTypeRemoved) {
|
||||
[change setValue:@"removed" forKey:@"type"];
|
||||
} else if (documentChange.type == FIRDocumentChangeTypeModified) {
|
||||
[change setValue:@"modified" forKey:@"type"];
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
+ (NSArray *)documentSnapshotsToArray:(NSArray<FIRDocumentSnapshot *> *) documentSnapshots {
|
||||
NSMutableArray *snapshots = [[NSMutableArray alloc] init];
|
||||
for (FIRDocumentSnapshot *snapshot in documentSnapshots) {
|
||||
[snapshots addObject:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:snapshot]];
|
||||
}
|
||||
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef RNFirebaseFirestoreDocumentReference_h
|
||||
#define RNFirebaseFirestoreDocumentReference_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
#import <FirebaseFirestore/FirebaseFirestore.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import "RNFirebaseFirestore.h"
|
||||
|
||||
@interface RNFirebaseFirestoreDocumentReference : NSObject
|
||||
@property RCTEventEmitter *emitter;
|
||||
@property NSString *app;
|
||||
@property NSString *path;
|
||||
@property FIRDocumentReference *ref;
|
||||
|
||||
- (id)initWithPath:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path;
|
||||
- (void)collections:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)create:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
+ (void)offSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId;
|
||||
- (void)set:(NSDictionary *)data options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)update:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (BOOL)hasListeners;
|
||||
+ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot;
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
@interface RNFirebaseFirestoreDocumentReference : NSObject
|
||||
@end
|
||||
#endif
|
||||
|
||||
#endif
|
||||
160
ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m
Normal file
160
ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m
Normal file
@@ -0,0 +1,160 @@
|
||||
#import "RNFirebaseFirestoreDocumentReference.h"
|
||||
|
||||
@implementation RNFirebaseFirestoreDocumentReference
|
||||
|
||||
#if __has_include(<FirebaseFirestore/FirebaseFirestore.h>)
|
||||
|
||||
static NSMutableDictionary *_listeners;
|
||||
|
||||
- (id)initWithPath:(RCTEventEmitter *)emitter
|
||||
app:(NSString *) app
|
||||
path:(NSString *) path {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_emitter = emitter;
|
||||
_app = app;
|
||||
_path = path;
|
||||
_ref = [[RNFirebaseFirestore getFirestoreForApp:_app] documentWithPath:_path];
|
||||
}
|
||||
// Initialise the static listeners object if required
|
||||
if (!_listeners) {
|
||||
_listeners = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)collections:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
// Not supported on iOS
|
||||
}
|
||||
|
||||
- (void)create:(NSDictionary *) data
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
// Not supported on iOS out of the box
|
||||
}
|
||||
|
||||
- (void)delete:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
[_ref deleteDocumentWithCompletion:^(NSError * _Nullable error) {
|
||||
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
[_ref getDocumentWithCompletion:^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[RNFirebaseFirestore promiseRejectException:reject error:error];
|
||||
} else {
|
||||
NSDictionary *data = [RNFirebaseFirestoreDocumentReference snapshotToDictionary:snapshot];
|
||||
resolve(data);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)offSnapshot:(NSString *) listenerId {
|
||||
id<FIRListenerRegistration> listener = _listeners[listenerId];
|
||||
if (listener) {
|
||||
[_listeners removeObjectForKey:listenerId];
|
||||
[listener remove];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onSnapshot:(NSString *) listenerId {
|
||||
if (_listeners[listenerId] == nil) {
|
||||
id listenerBlock = ^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
id<FIRListenerRegistration> listener = _listeners[listenerId];
|
||||
if (listener) {
|
||||
[_listeners removeObjectForKey:listenerId];
|
||||
[listener remove];
|
||||
}
|
||||
[self handleDocumentSnapshotError:listenerId error:error];
|
||||
} else {
|
||||
[self handleDocumentSnapshotEvent:listenerId documentSnapshot:snapshot];
|
||||
}
|
||||
};
|
||||
|
||||
id<FIRListenerRegistration> listener = [_ref addSnapshotListener:listenerBlock];
|
||||
_listeners[listenerId] = listener;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)set:(NSDictionary *) data
|
||||
options:(NSDictionary *) options
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
if (options && options[@"merge"]) {
|
||||
[_ref setData:data options:[FIRSetOptions merge] completion:^(NSError * _Nullable error) {
|
||||
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
|
||||
}];
|
||||
} else {
|
||||
[_ref setData:data completion:^(NSError * _Nullable error) {
|
||||
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)update:(NSDictionary *) data
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
[_ref updateData:data completion:^(NSError * _Nullable error) {
|
||||
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)hasListeners {
|
||||
return [[_listeners allKeys] count] > 0;
|
||||
}
|
||||
|
||||
+ (void)handleWriteResponse:(NSError *) error
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject {
|
||||
if (error) {
|
||||
[RNFirebaseFirestore promiseRejectException:reject error:error];
|
||||
} else {
|
||||
resolve(nil);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot {
|
||||
NSMutableDictionary *snapshot = [[NSMutableDictionary alloc] init];
|
||||
[snapshot setValue:documentSnapshot.reference.path forKey:@"path"];
|
||||
if (documentSnapshot.exists) {
|
||||
[snapshot setValue:documentSnapshot.data forKey:@"data"];
|
||||
}
|
||||
if (documentSnapshot.metadata) {
|
||||
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
|
||||
[metadata setValue:@(documentSnapshot.metadata.fromCache) forKey:@"fromCache"];
|
||||
[metadata setValue:@(documentSnapshot.metadata.hasPendingWrites) forKey:@"hasPendingWrites"];
|
||||
[snapshot setValue:metadata forKey:@"metadata"];
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
- (void)handleDocumentSnapshotError:(NSString *)listenerId
|
||||
error:(NSError *)error {
|
||||
NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
|
||||
[event setValue:_app forKey:@"appName"];
|
||||
[event setValue:_path forKey:@"path"];
|
||||
[event setValue:listenerId forKey:@"listenerId"];
|
||||
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
|
||||
|
||||
[_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
||||
}
|
||||
|
||||
- (void)handleDocumentSnapshotEvent:(NSString *)listenerId
|
||||
documentSnapshot:(FIRDocumentSnapshot *)documentSnapshot {
|
||||
NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
|
||||
[event setValue:_app forKey:@"appName"];
|
||||
[event setValue:_path forKey:@"path"];
|
||||
[event setValue:listenerId forKey:@"listenerId"];
|
||||
[event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"];
|
||||
|
||||
[_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -4,6 +4,7 @@
|
||||
#if __has_include(<FirebaseMessaging/FirebaseMessaging.h>)
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import <FirebaseMessaging/FirebaseMessaging.h>
|
||||
#import <FirebaseInstanceID/FIRInstanceID.h>
|
||||
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTConvert.h>
|
||||
@@ -258,7 +259,7 @@ RCT_EXPORT_METHOD(getToken:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseR
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(deleteInstanceId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
[FIRInstanceID instanceID] deleteIDWithHandler:^(NSError * _Nullable error) {
|
||||
[[FIRInstanceID instanceID] deleteIDWithHandler:^(NSError * _Nullable error) {
|
||||
if (!error) {
|
||||
resolve(nil);
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,7 @@ import RemoteConfig from './modules/config';
|
||||
import Storage, { statics as StorageStatics } from './modules/storage';
|
||||
import Database, { statics as DatabaseStatics } from './modules/database';
|
||||
import Messaging, { statics as MessagingStatics } from './modules/messaging';
|
||||
import Firestore, { statics as FirestoreStatics } from './modules/firestore';
|
||||
import Links, { statics as LinksStatics } from './modules/links';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
@@ -33,6 +34,7 @@ export default class FirebaseApp {
|
||||
this.config = this._staticsOrModuleInstance({}, RemoteConfig);
|
||||
this.crash = this._staticsOrModuleInstance({}, Crash);
|
||||
this.database = this._staticsOrModuleInstance(DatabaseStatics, Database);
|
||||
this.firestore = this._staticsOrModuleInstance(FirestoreStatics, Firestore);
|
||||
this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging);
|
||||
this.perf = this._staticsOrModuleInstance({}, Performance);
|
||||
this.storage = this._staticsOrModuleInstance(StorageStatics, Storage);
|
||||
@@ -111,13 +113,15 @@ export default class FirebaseApp {
|
||||
* @return {Promise}
|
||||
*/
|
||||
delete() {
|
||||
if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME && this._nativeInitialized) {
|
||||
return Promise.reject(
|
||||
new Error('Unable to delete the default native firebase app instance.'),
|
||||
);
|
||||
}
|
||||
|
||||
return FirebaseCoreModule.deleteApp(this._name);
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete'));
|
||||
// TODO only the ios sdk currently supports delete, add back in when android also supports it
|
||||
// if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME && this._nativeInitialized) {
|
||||
// return Promise.reject(
|
||||
// new Error('Unable to delete the default native firebase app instance.'),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// return FirebaseCoreModule.deleteApp(this._name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import RemoteConfig from './modules/config';
|
||||
import Storage, { statics as StorageStatics } from './modules/storage';
|
||||
import Database, { statics as DatabaseStatics } from './modules/database';
|
||||
import Messaging, { statics as MessagingStatics } from './modules/messaging';
|
||||
import Firestore, { statics as FirestoreStatics } from './modules/firestore';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
@@ -48,6 +49,7 @@ class FirebaseCore {
|
||||
this.config = this._appNamespaceOrStatics({}, RemoteConfig);
|
||||
this.crash = this._appNamespaceOrStatics({}, Crash);
|
||||
this.database = this._appNamespaceOrStatics(DatabaseStatics, Database);
|
||||
this.firestore = this._appNamespaceOrStatics(FirestoreStatics, Firestore);
|
||||
this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging);
|
||||
this.perf = this._appNamespaceOrStatics(DatabaseStatics, Performance);
|
||||
this.storage = this._appNamespaceOrStatics(StorageStatics, Storage);
|
||||
|
||||
@@ -66,11 +66,20 @@ export default class PhoneAuthListener {
|
||||
this._subscribeToEvents();
|
||||
|
||||
// start verification flow natively
|
||||
this._auth._native.verifyPhoneNumber(
|
||||
phoneNumber,
|
||||
this._phoneAuthRequestKey,
|
||||
this._timeout,
|
||||
);
|
||||
if (isAndroid) {
|
||||
this._auth._native.verifyPhoneNumber(
|
||||
phoneNumber,
|
||||
this._phoneAuthRequestKey,
|
||||
this._timeout,
|
||||
);
|
||||
}
|
||||
|
||||
if (isIOS) {
|
||||
this._auth._native.verifyPhoneNumber(
|
||||
phoneNumber,
|
||||
this._phoneAuthRequestKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,8 +23,17 @@ export default class Database extends ModuleBase {
|
||||
this._native.setPersistence(this._options.persistence);
|
||||
}
|
||||
|
||||
// todo serverTimeOffset event/listener - make ref natively and switch to events
|
||||
this._serverTimeOffset = 0; // TODO ----^
|
||||
// server time listener
|
||||
// setTimeout used to avoid setPersistence race conditions
|
||||
// todo move this and persistence to native side, create a db configure() method natively perhaps?
|
||||
// todo and then native can call setPersistence and then emit offset events
|
||||
setTimeout(() => {
|
||||
this._serverTimeOffset = 0;
|
||||
this._offsetRef = this.ref('.info/serverTimeOffset');
|
||||
this._offsetRef.on('value', (snapshot) => {
|
||||
this._serverTimeOffset = snapshot.val() || this._serverTimeOffset;
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +41,7 @@ export default class Database extends ModuleBase {
|
||||
* @return {number}
|
||||
*/
|
||||
getServerTime() {
|
||||
return new Date().getTime() + this._serverTimeOffset;
|
||||
return new Date(Date.now() + this._serverTimeOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -250,10 +250,10 @@ export default class Reference extends ReferenceBase {
|
||||
*/
|
||||
push(value: any, onComplete?: Function): Reference | Promise {
|
||||
if (value === null || value === undefined) {
|
||||
return new Reference(this._database, `${this.path}/${generatePushID(this._database.serverTimeOffset)}`);
|
||||
return new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
||||
}
|
||||
|
||||
const newRef = new Reference(this._database, `${this.path}/${generatePushID(this._database.serverTimeOffset)}`);
|
||||
const newRef = new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
||||
const promise = newRef.set(value);
|
||||
|
||||
// if callback provided then internally call the set promise with value
|
||||
|
||||
105
lib/modules/firestore/CollectionReference.js
Normal file
105
lib/modules/firestore/CollectionReference.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @flow
|
||||
* CollectionReference representation wrapper
|
||||
*/
|
||||
import DocumentReference from './DocumentReference';
|
||||
import Path from './Path';
|
||||
import Query from './Query';
|
||||
import QuerySnapshot from './QuerySnapshot';
|
||||
import { firestoreAutoId } from '../../utils';
|
||||
|
||||
import type { Direction, Operator } from './Query';
|
||||
|
||||
/**
|
||||
* @class CollectionReference
|
||||
*/
|
||||
export default class CollectionReference {
|
||||
_collectionPath: Path;
|
||||
_firestore: Object;
|
||||
_query: Query;
|
||||
|
||||
constructor(firestore: Object, collectionPath: Path) {
|
||||
this._collectionPath = collectionPath;
|
||||
this._firestore = firestore;
|
||||
this._query = new Query(firestore, collectionPath);
|
||||
}
|
||||
|
||||
get firestore(): Object {
|
||||
return this._firestore;
|
||||
}
|
||||
|
||||
get id(): string | null {
|
||||
return this._collectionPath.id;
|
||||
}
|
||||
|
||||
get parent(): DocumentReference | null {
|
||||
const parentPath = this._collectionPath.parent();
|
||||
return parentPath ? new DocumentReference(this._firestore, parentPath) : null;
|
||||
}
|
||||
|
||||
add(data: Object): Promise<DocumentReference> {
|
||||
const documentRef = this.doc();
|
||||
return documentRef.set(data)
|
||||
.then(() => Promise.resolve(documentRef));
|
||||
}
|
||||
|
||||
doc(documentPath?: string): DocumentReference {
|
||||
const newPath = documentPath || firestoreAutoId();
|
||||
|
||||
const path = this._collectionPath.child(newPath);
|
||||
if (!path.isDocument) {
|
||||
throw new Error('Argument "documentPath" must point to a document.');
|
||||
}
|
||||
|
||||
return new DocumentReference(this._firestore, path);
|
||||
}
|
||||
|
||||
// From Query
|
||||
endAt(fieldValues: any): Query {
|
||||
return this._query.endAt(fieldValues);
|
||||
}
|
||||
|
||||
endBefore(fieldValues: any): Query {
|
||||
return this._query.endBefore(fieldValues);
|
||||
}
|
||||
|
||||
get(): Promise<QuerySnapshot> {
|
||||
return this._query.get();
|
||||
}
|
||||
|
||||
limit(n: number): Query {
|
||||
return this._query.limit(n);
|
||||
}
|
||||
|
||||
offset(n: number): Query {
|
||||
return this._query.offset(n);
|
||||
}
|
||||
|
||||
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
||||
return this._query.onSnapshot(onNext, onError);
|
||||
}
|
||||
|
||||
orderBy(fieldPath: string, directionStr?: Direction): Query {
|
||||
return this._query.orderBy(fieldPath, directionStr);
|
||||
}
|
||||
|
||||
select(varArgs: string[]): Query {
|
||||
return this._query.select(varArgs);
|
||||
}
|
||||
|
||||
startAfter(fieldValues: any): Query {
|
||||
return this._query.startAfter(fieldValues);
|
||||
}
|
||||
|
||||
startAt(fieldValues: any): Query {
|
||||
return this._query.startAt(fieldValues);
|
||||
}
|
||||
|
||||
stream(): Stream<DocumentSnapshot> {
|
||||
return this._query.stream();
|
||||
}
|
||||
|
||||
where(fieldPath: string, opStr: Operator, value: any): Query {
|
||||
return this._query.where(fieldPath, opStr, value);
|
||||
}
|
||||
}
|
||||
46
lib/modules/firestore/DocumentChange.js
Normal file
46
lib/modules/firestore/DocumentChange.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @flow
|
||||
* DocumentChange representation wrapper
|
||||
*/
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
|
||||
|
||||
export type DocumentChangeNativeData = {
|
||||
document: DocumentSnapshot,
|
||||
newIndex: number,
|
||||
oldIndex: number,
|
||||
type: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DocumentChange
|
||||
*/
|
||||
export default class DocumentChange {
|
||||
_document: DocumentSnapshot;
|
||||
_newIndex: number;
|
||||
_oldIndex: number;
|
||||
_type: string;
|
||||
|
||||
constructor(nativeData: DocumentChangeNativeData) {
|
||||
this._document = nativeData.document;
|
||||
this._newIndex = nativeData.newIndex;
|
||||
this._oldIndex = nativeData.oldIndex;
|
||||
this._type = nativeData.type;
|
||||
}
|
||||
|
||||
get doc(): DocumentSnapshot {
|
||||
return this._document;
|
||||
}
|
||||
|
||||
get newIndex(): number {
|
||||
return this._newIndex;
|
||||
}
|
||||
|
||||
get oldIndex(): number {
|
||||
return this._oldIndex;
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
return this._type;
|
||||
}
|
||||
}
|
||||
115
lib/modules/firestore/DocumentReference.js
Normal file
115
lib/modules/firestore/DocumentReference.js
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @flow
|
||||
* DocumentReference representation wrapper
|
||||
*/
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import Path from './Path';
|
||||
import { firestoreAutoId } from '../../utils';
|
||||
|
||||
export type WriteOptions = {
|
||||
merge?: boolean,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DocumentReference
|
||||
*/
|
||||
export default class DocumentReference {
|
||||
_documentPath: Path;
|
||||
_firestore: Object;
|
||||
|
||||
constructor(firestore: Object, documentPath: Path) {
|
||||
this._documentPath = documentPath;
|
||||
this._firestore = firestore;
|
||||
}
|
||||
|
||||
get firestore(): Object {
|
||||
return this._firestore;
|
||||
}
|
||||
|
||||
get id(): string | null {
|
||||
return this._documentPath.id;
|
||||
}
|
||||
|
||||
get parent(): CollectionReference {
|
||||
const parentPath = this._documentPath.parent();
|
||||
return new CollectionReference(this._firestore, parentPath);
|
||||
}
|
||||
|
||||
get path(): string {
|
||||
return this._documentPath.relativeName;
|
||||
}
|
||||
|
||||
collection(collectionPath: string): CollectionReference {
|
||||
const path = this._documentPath.child(collectionPath);
|
||||
if (!path.isCollection) {
|
||||
throw new Error('Argument "collectionPath" must point to a collection.');
|
||||
}
|
||||
|
||||
return new CollectionReference(this._firestore, path);
|
||||
}
|
||||
|
||||
delete(): Promise<void> {
|
||||
return this._firestore._native
|
||||
.documentDelete(this.path);
|
||||
}
|
||||
|
||||
get(): Promise<DocumentSnapshot> {
|
||||
return this._firestore._native
|
||||
.documentGet(this.path)
|
||||
.then(result => new DocumentSnapshot(this._firestore, result));
|
||||
}
|
||||
|
||||
onSnapshot(onNext: Function, onError?: Function): () => void {
|
||||
// TODO: Validation
|
||||
const listenerId = firestoreAutoId();
|
||||
|
||||
const listener = (nativeDocumentSnapshot) => {
|
||||
const documentSnapshot = new DocumentSnapshot(this, nativeDocumentSnapshot);
|
||||
onNext(documentSnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`),
|
||||
listener,
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (onError) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`),
|
||||
onError,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the native listener
|
||||
this._firestore._native
|
||||
.documentOnSnapshot(this.path, listenerId);
|
||||
|
||||
// Return an unsubscribe method
|
||||
return this._offDocumentSnapshot.bind(this, listenerId, listener);
|
||||
}
|
||||
|
||||
set(data: Object, writeOptions?: WriteOptions): Promise<void> {
|
||||
return this._firestore._native
|
||||
.documentSet(this.path, data, writeOptions);
|
||||
}
|
||||
|
||||
update(data: Object): Promise<void> {
|
||||
return this._firestore._native
|
||||
.documentUpdate(this.path, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove document snapshot listener
|
||||
* @param listener
|
||||
*/
|
||||
_offDocumentSnapshot(listenerId: number, listener: Function) {
|
||||
this._firestore.log.info('Removing onDocumentSnapshot listener');
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), listener);
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), listener);
|
||||
this._firestore._native
|
||||
.documentOffSnapshot(this.path, listenerId);
|
||||
}
|
||||
}
|
||||
56
lib/modules/firestore/DocumentSnapshot.js
Normal file
56
lib/modules/firestore/DocumentSnapshot.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @flow
|
||||
* DocumentSnapshot representation wrapper
|
||||
*/
|
||||
import DocumentReference from './DocumentReference';
|
||||
import Path from './Path';
|
||||
|
||||
export type SnapshotMetadata = {
|
||||
fromCache: boolean,
|
||||
hasPendingWrites: boolean,
|
||||
}
|
||||
|
||||
export type DocumentSnapshotNativeData = {
|
||||
data: Object,
|
||||
metadata: SnapshotMetadata,
|
||||
path: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DocumentSnapshot
|
||||
*/
|
||||
export default class DocumentSnapshot {
|
||||
_data: Object;
|
||||
_metadata: SnapshotMetadata;
|
||||
_ref: DocumentReference;
|
||||
|
||||
constructor(firestore: Object, nativeData: DocumentSnapshotNativeData) {
|
||||
this._data = nativeData.data;
|
||||
this._metadata = nativeData.metadata;
|
||||
this._ref = new DocumentReference(firestore, Path.fromName(nativeData.path));
|
||||
}
|
||||
|
||||
get exists(): boolean {
|
||||
return this._data !== undefined;
|
||||
}
|
||||
|
||||
get id(): string | null {
|
||||
return this._ref.id;
|
||||
}
|
||||
|
||||
get metadata(): SnapshotMetadata {
|
||||
return _metadata;
|
||||
}
|
||||
|
||||
get ref(): DocumentReference {
|
||||
return this._ref;
|
||||
}
|
||||
|
||||
data(): Object {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
get(fieldPath: string): any {
|
||||
return this._data[fieldPath];
|
||||
}
|
||||
}
|
||||
29
lib/modules/firestore/GeoPoint.js
Normal file
29
lib/modules/firestore/GeoPoint.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @flow
|
||||
* GeoPoint representation wrapper
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class GeoPoint
|
||||
*/
|
||||
export default class GeoPoint {
|
||||
_latitude: number;
|
||||
_longitude: number;
|
||||
|
||||
constructor(latitude: number, longitude: number) {
|
||||
// TODO: Validation
|
||||
// validate.isNumber('latitude', latitude);
|
||||
// validate.isNumber('longitude', longitude);
|
||||
|
||||
this._latitude = latitude;
|
||||
this._longitude = longitude;
|
||||
}
|
||||
|
||||
get latitude() {
|
||||
return this._latitude;
|
||||
}
|
||||
|
||||
get longitude() {
|
||||
return this._longitude;
|
||||
}
|
||||
}
|
||||
59
lib/modules/firestore/Path.js
Normal file
59
lib/modules/firestore/Path.js
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @flow
|
||||
* Path representation wrapper
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class Path
|
||||
*/
|
||||
export default class Path {
|
||||
_parts: string[];
|
||||
|
||||
constructor(pathComponents: string[]) {
|
||||
this._parts = pathComponents;
|
||||
}
|
||||
|
||||
get id(): string | null {
|
||||
if (this._parts.length > 0) {
|
||||
return this._parts[this._parts.length - 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
get isDocument(): boolean {
|
||||
return this._parts.length > 0 && this._parts.length % 2 === 0;
|
||||
}
|
||||
|
||||
get isCollection(): boolean {
|
||||
return this._parts.length % 2 === 1;
|
||||
}
|
||||
|
||||
get relativeName(): string {
|
||||
return this._parts.join('/');
|
||||
}
|
||||
|
||||
child(relativePath: string): Path {
|
||||
return new Path(this._parts.concat(relativePath.split('/')));
|
||||
}
|
||||
|
||||
parent(): Path | null {
|
||||
if (this._parts.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Path(this._parts.slice(0, this._parts.length - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @package
|
||||
*/
|
||||
static fromName(name): Path {
|
||||
const parts = name.split('/');
|
||||
|
||||
if (parts.length === 0) {
|
||||
return new Path([]);
|
||||
}
|
||||
return new Path(parts);
|
||||
}
|
||||
}
|
||||
230
lib/modules/firestore/Query.js
Normal file
230
lib/modules/firestore/Query.js
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @flow
|
||||
* Query representation wrapper
|
||||
*/
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import Path from './Path';
|
||||
import QuerySnapshot from './QuerySnapshot';
|
||||
import INTERNALS from '../../internals';
|
||||
import { firestoreAutoId } from '../../utils';
|
||||
|
||||
const DIRECTIONS = {
|
||||
ASC: 'ASCENDING',
|
||||
asc: 'ASCENDING',
|
||||
DESC: 'DESCENDING',
|
||||
desc: 'DESCENDING',
|
||||
};
|
||||
|
||||
const OPERATORS = {
|
||||
'=': 'EQUAL',
|
||||
'==': 'EQUAL',
|
||||
'>': 'GREATER_THAN',
|
||||
'>=': 'GREATER_THAN_OR_EQUAL',
|
||||
'<': 'LESS_THAN',
|
||||
'<=': 'LESS_THAN_OR_EQUAL',
|
||||
};
|
||||
|
||||
export type Direction = 'DESC' | 'desc' | 'ASC' | 'asc';
|
||||
type FieldFilter = {
|
||||
fieldPath: string,
|
||||
operator: string,
|
||||
value: any,
|
||||
}
|
||||
type FieldOrder = {
|
||||
direction: string,
|
||||
fieldPath: string,
|
||||
}
|
||||
type QueryOptions = {
|
||||
endAt?: any[],
|
||||
endBefore?: any[],
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
selectFields?: string[],
|
||||
startAfter?: any[],
|
||||
startAt?: any[],
|
||||
}
|
||||
export type Operator = '<' | '<=' | '=' | '==' | '>' | '>=';
|
||||
|
||||
/**
|
||||
* @class Query
|
||||
*/
|
||||
export default class Query {
|
||||
_fieldFilters: FieldFilter[];
|
||||
_fieldOrders: FieldOrder[];
|
||||
_firestore: Object;
|
||||
_iid: number;
|
||||
_queryOptions: QueryOptions;
|
||||
_referencePath: Path;
|
||||
|
||||
constructor(firestore: Object, path: Path, fieldFilters?: FieldFilter[],
|
||||
fieldOrders?: FieldOrder[], queryOptions?: QueryOptions) {
|
||||
this._fieldFilters = fieldFilters || [];
|
||||
this._fieldOrders = fieldOrders || [];
|
||||
this._firestore = firestore;
|
||||
this._queryOptions = queryOptions || {};
|
||||
this._referencePath = path;
|
||||
}
|
||||
|
||||
get firestore(): Object {
|
||||
return this._firestore;
|
||||
}
|
||||
|
||||
endAt(fieldValues: any): Query {
|
||||
fieldValues = [].slice.call(arguments);
|
||||
// TODO: Validation
|
||||
const options = {
|
||||
...this._queryOptions,
|
||||
endAt: fieldValues,
|
||||
};
|
||||
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
endBefore(fieldValues: any): Query {
|
||||
fieldValues = [].slice.call(arguments);
|
||||
// TODO: Validation
|
||||
const options = {
|
||||
...this._queryOptions,
|
||||
endBefore: fieldValues,
|
||||
};
|
||||
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
get(): Promise<QuerySnapshot> {
|
||||
return this._firestore._native
|
||||
.collectionGet(
|
||||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
)
|
||||
.then(nativeData => new QuerySnapshot(this._firestore, this, nativeData));
|
||||
}
|
||||
|
||||
limit(limit: number): Query {
|
||||
// TODO: Validation
|
||||
// validate.isInteger('n', n);
|
||||
|
||||
const options = {
|
||||
...this._queryOptions,
|
||||
limit,
|
||||
};
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
||||
// TODO: Validation
|
||||
const listenerId = firestoreAutoId();
|
||||
|
||||
const listener = (nativeQuerySnapshot) => {
|
||||
const querySnapshot = new QuerySnapshot(this._firestore, this, nativeQuerySnapshot);
|
||||
onNext(querySnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`),
|
||||
listener,
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (onError) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`),
|
||||
onError,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the native listener
|
||||
this._firestore._native
|
||||
.collectionOnSnapshot(
|
||||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
listenerId
|
||||
);
|
||||
|
||||
// Return an unsubscribe method
|
||||
return this._offCollectionSnapshot.bind(this, listenerId, listener);
|
||||
}
|
||||
|
||||
orderBy(fieldPath: string, directionStr?: Direction = 'asc'): Query {
|
||||
// TODO: Validation
|
||||
// validate.isFieldPath('fieldPath', fieldPath);
|
||||
// validate.isOptionalFieldOrder('directionStr', directionStr);
|
||||
|
||||
if (this._queryOptions.startAt || this._queryOptions.endAt) {
|
||||
throw new Error('Cannot specify an orderBy() constraint after calling ' +
|
||||
'startAt(), startAfter(), endBefore() or endAt().');
|
||||
}
|
||||
|
||||
const newOrder = {
|
||||
direction: DIRECTIONS[directionStr],
|
||||
fieldPath,
|
||||
};
|
||||
const combinedOrders = this._fieldOrders.concat(newOrder);
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
combinedOrders, this._queryOptions);
|
||||
}
|
||||
|
||||
startAfter(fieldValues: any): Query {
|
||||
fieldValues = [].slice.call(arguments);
|
||||
// TODO: Validation
|
||||
const options = {
|
||||
...this._queryOptions,
|
||||
startAfter: fieldValues,
|
||||
};
|
||||
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
startAt(fieldValues: any): Query {
|
||||
fieldValues = [].slice.call(arguments);
|
||||
// TODO: Validation
|
||||
const options = {
|
||||
...this._queryOptions,
|
||||
startAt: fieldValues,
|
||||
};
|
||||
|
||||
return new Query(this.firestore, this._referencePath, this._fieldFilters,
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
where(fieldPath: string, opStr: Operator, value: any): Query {
|
||||
// TODO: Validation
|
||||
// validate.isFieldPath('fieldPath', fieldPath);
|
||||
// validate.isFieldFilter('fieldFilter', opStr, value);
|
||||
const newFilter = {
|
||||
fieldPath,
|
||||
operator: OPERATORS[opStr],
|
||||
value,
|
||||
};
|
||||
const combinedFilters = this._fieldFilters.concat(newFilter);
|
||||
return new Query(this.firestore, this._referencePath, combinedFilters,
|
||||
this._fieldOrders, this._queryOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove query snapshot listener
|
||||
* @param listener
|
||||
*/
|
||||
_offCollectionSnapshot(listenerId: number, listener: Function) {
|
||||
this._firestore.log.info('Removing onQuerySnapshot listener');
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), listener);
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), listener);
|
||||
this._firestore._native
|
||||
.collectionOffSnapshot(
|
||||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
listenerId
|
||||
);
|
||||
}
|
||||
}
|
||||
66
lib/modules/firestore/QuerySnapshot.js
Normal file
66
lib/modules/firestore/QuerySnapshot.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @flow
|
||||
* QuerySnapshot representation wrapper
|
||||
*/
|
||||
import DocumentChange from './DocumentChange';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import Query from './Query';
|
||||
|
||||
import type { DocumentChangeNativeData } from './DocumentChange';
|
||||
import type { DocumentSnapshotNativeData, SnapshotMetadata } from './DocumentSnapshot';
|
||||
|
||||
type QuerySnapshotNativeData = {
|
||||
changes: DocumentChangeNativeData[],
|
||||
documents: DocumentSnapshotNativeData[],
|
||||
metadata: SnapshotMetadata,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class QuerySnapshot
|
||||
*/
|
||||
export default class QuerySnapshot {
|
||||
_changes: DocumentChange[];
|
||||
_docs: DocumentSnapshot[];
|
||||
_metadata: SnapshotMetadata;
|
||||
_query: Query;
|
||||
|
||||
constructor(firestore: Object, query: Query, nativeData: QuerySnapshotNativeData) {
|
||||
this._changes = nativeData.changes.map(change => new DocumentChange(change));
|
||||
this._docs = nativeData.documents.map(doc => new DocumentSnapshot(firestore, doc));
|
||||
this._metadata = nativeData.metadata;
|
||||
this._query = query;
|
||||
}
|
||||
|
||||
get docChanges(): DocumentChange[] {
|
||||
return this._changes;
|
||||
}
|
||||
|
||||
get docs(): DocumentSnapshot[] {
|
||||
return this._docs;
|
||||
}
|
||||
|
||||
get empty(): boolean {
|
||||
return this._docs.length === 0;
|
||||
}
|
||||
|
||||
get query(): Query {
|
||||
return this._query;
|
||||
}
|
||||
|
||||
get metadata(): SnapshotMetadata {
|
||||
return this._metadata;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._docs.length;
|
||||
}
|
||||
|
||||
forEach(callback: DocumentSnapshot => any) {
|
||||
// TODO: Validation
|
||||
// validate.isFunction('callback', callback);
|
||||
|
||||
for (const doc of this._docs) {
|
||||
callback(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
lib/modules/firestore/WriteBatch.js
Normal file
75
lib/modules/firestore/WriteBatch.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @flow
|
||||
* WriteBatch representation wrapper
|
||||
*/
|
||||
import DocumentReference from './DocumentReference';
|
||||
|
||||
import type { WriteOptions } from './DocumentReference';
|
||||
|
||||
type DocumentWrite = {
|
||||
data?: Object,
|
||||
options?: Object,
|
||||
path: string,
|
||||
type: 'DELETE' | 'SET' | 'UPDATE',
|
||||
}
|
||||
|
||||
/**
|
||||
* @class WriteBatch
|
||||
*/
|
||||
export default class WriteBatch {
|
||||
_firestore: Object;
|
||||
_writes: DocumentWrite[];
|
||||
|
||||
constructor(firestore: Object) {
|
||||
this._firestore = firestore;
|
||||
this._writes = [];
|
||||
}
|
||||
|
||||
commit(): Promise<void> {
|
||||
return this._firestore._native
|
||||
.documentBatch(this._writes);
|
||||
}
|
||||
|
||||
delete(docRef: DocumentReference): WriteBatch {
|
||||
// TODO: Validation
|
||||
// validate.isDocumentReference('docRef', docRef);
|
||||
// validate.isOptionalPrecondition('deleteOptions', deleteOptions);
|
||||
this._writes.push({
|
||||
path: docRef.path,
|
||||
type: 'DELETE',
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
set(docRef: DocumentReference, data: Object, writeOptions?: WriteOptions) {
|
||||
// TODO: Validation
|
||||
// validate.isDocumentReference('docRef', docRef);
|
||||
// validate.isDocument('data', data);
|
||||
// validate.isOptionalPrecondition('writeOptions', writeOptions);
|
||||
|
||||
this._writes.push({
|
||||
data,
|
||||
options: writeOptions,
|
||||
path: docRef.path,
|
||||
type: 'SET',
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Update to new method signature
|
||||
update(docRef: DocumentReference, data: Object): WriteBatch {
|
||||
// TODO: Validation
|
||||
// validate.isDocumentReference('docRef', docRef);
|
||||
// validate.isDocument('data', data, true);
|
||||
|
||||
this._writes.push({
|
||||
data,
|
||||
path: docRef.path,
|
||||
type: 'UPDATE',
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
145
lib/modules/firestore/index.js
Normal file
145
lib/modules/firestore/index.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @flow
|
||||
* Firestore representation wrapper
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentReference from './DocumentReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import GeoPoint from './GeoPoint';
|
||||
import Path from './Path';
|
||||
import WriteBatch from './WriteBatch';
|
||||
import INTERNALS from './../../internals';
|
||||
|
||||
type CollectionSyncEvent = {
|
||||
appName: string,
|
||||
querySnapshot?: QuerySnapshot,
|
||||
error?: Object,
|
||||
listenerId: string,
|
||||
path: string,
|
||||
}
|
||||
|
||||
type DocumentSyncEvent = {
|
||||
appName: string,
|
||||
documentSnapshot?: DocumentSnapshot,
|
||||
error?: Object,
|
||||
listenerId: string,
|
||||
path: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Firestore
|
||||
*/
|
||||
export default class Firestore extends ModuleBase {
|
||||
static _NAMESPACE = 'firestore';
|
||||
static _NATIVE_MODULE = 'RNFirebaseFirestore';
|
||||
|
||||
_referencePath: Path;
|
||||
|
||||
constructor(firebaseApp: Object, options: Object = {}) {
|
||||
super(firebaseApp, options, true);
|
||||
this._referencePath = new Path([]);
|
||||
|
||||
this.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onCollectionSnapshot
|
||||
this._getAppEventName('firestore_collection_sync_event'),
|
||||
this._onCollectionSyncEvent.bind(this),
|
||||
);
|
||||
|
||||
this.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onDocumentSnapshot
|
||||
this._getAppEventName('firestore_document_sync_event'),
|
||||
this._onDocumentSyncEvent.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
batch(): WriteBatch {
|
||||
return new WriteBatch(this);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param collectionPath
|
||||
* @returns {CollectionReference}
|
||||
*/
|
||||
collection(collectionPath: string): CollectionReference {
|
||||
const path = this._referencePath.child(collectionPath);
|
||||
if (!path.isCollection) {
|
||||
throw new Error('Argument "collectionPath" must point to a collection.');
|
||||
}
|
||||
|
||||
return new CollectionReference(this, path);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param documentPath
|
||||
* @returns {DocumentReference}
|
||||
*/
|
||||
doc(documentPath: string): DocumentReference {
|
||||
const path = this._referencePath.child(documentPath);
|
||||
if (!path.isDocument) {
|
||||
throw new Error('Argument "documentPath" must point to a document.');
|
||||
}
|
||||
|
||||
return new DocumentReference(this, path);
|
||||
}
|
||||
|
||||
enablePersistence(): Promise<void> {
|
||||
throw new Error('Persistence is enabled by default on the Firestore SDKs');
|
||||
}
|
||||
|
||||
runTransaction(updateFunction): Promise<any> {
|
||||
throw new Error('firebase.firestore().runTransaction() coming soon');
|
||||
}
|
||||
|
||||
setLogLevel(logLevel: 'debug' | 'error' | 'silent'): void {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Firestore, 'setLogLevel'));
|
||||
}
|
||||
|
||||
settings(settings: Object): void {
|
||||
throw new Error('firebase.firestore().settings() coming soon');
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNALS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal collection sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onCollectionSyncEvent(event: CollectionSyncEvent) {
|
||||
if (event.error) {
|
||||
this.emit(this._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
this.emit(this._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal document sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onDocumentSyncEvent(event: DocumentSyncEvent) {
|
||||
if (event.error) {
|
||||
this.emit(this._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
this.emit(this._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const statics = {
|
||||
FieldValue: {
|
||||
delete: () => NativeModules.RNFirebaseFirestore && NativeModules.RNFirebaseFirestore.deleteFieldValue || {},
|
||||
serverTimestamp: () => NativeModules.RNFirebaseFirestore && NativeModules.RNFirebaseFirestore.serverTimestampFieldValue || {}
|
||||
},
|
||||
GeoPoint,
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Platform } from 'react-native';
|
||||
import { Platform, NativeModules } from 'react-native';
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import RemoteMessage from './RemoteMessage';
|
||||
|
||||
@@ -25,6 +25,8 @@ const WILL_PRESENT_RESULT = {
|
||||
None: 'UNNotificationPresentationOptionNone',
|
||||
};
|
||||
|
||||
const FirebaseMessaging = NativeModules.FirebaseMessaging;
|
||||
|
||||
/**
|
||||
* IOS only finish function
|
||||
* @param data
|
||||
|
||||
@@ -15,6 +15,7 @@ const logs = {};
|
||||
const MULTI_APP_MODULES = [
|
||||
'auth',
|
||||
'database',
|
||||
'firestore',
|
||||
'storage',
|
||||
];
|
||||
|
||||
@@ -31,6 +32,10 @@ const NATIVE_MODULE_EVENTS = {
|
||||
'database_transaction_event',
|
||||
// 'database_server_offset', // TODO
|
||||
],
|
||||
Firestore: [
|
||||
'firestore_collection_sync_event',
|
||||
'firestore_document_sync_event',
|
||||
],
|
||||
};
|
||||
|
||||
const DEFAULTS = {
|
||||
|
||||
@@ -5,10 +5,19 @@ import { Platform } from 'react-native';
|
||||
|
||||
// modeled after base64 web-safe chars, but ordered by ASCII
|
||||
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
|
||||
const AUTO_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
|
||||
// const DEFAULT_CHUNK_SIZE = 50;
|
||||
|
||||
// Source: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical
|
||||
const REGEXP_FIELD_NAME = new RegExp(
|
||||
`^(?:\\.?((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))$`
|
||||
);
|
||||
const REGEXP_FIELD_PATH = new RegExp(
|
||||
`^((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+)(?:\\.((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))*$`
|
||||
);
|
||||
|
||||
/**
|
||||
* Deep get a value from an object.
|
||||
* @website https://github.com/Salakar/deeps
|
||||
@@ -88,6 +97,16 @@ export function isString(value: any): boolean {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Firestore field name/path validator.
|
||||
* @param field
|
||||
* @param paths
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isValidFirestoreField(field, paths) {
|
||||
return (paths ? REGEXP_FIELD_PATH : REGEXP_FIELD_NAME).test(field);
|
||||
}
|
||||
|
||||
// platform checks
|
||||
export const isIOS = Platform.OS === 'ios';
|
||||
export const isAndroid = Platform.OS === 'android';
|
||||
@@ -374,3 +393,16 @@ export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Functi
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a firestore auto id for use with collection/document .add()
|
||||
* @return {string}
|
||||
*/
|
||||
export function firestoreAutoId(): string {
|
||||
let autoId = '';
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
autoId += AUTO_ID_CHARS.charAt(Math.floor(Math.random() * AUTO_ID_CHARS.length));
|
||||
}
|
||||
return autoId;
|
||||
}
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -2624,9 +2624,9 @@
|
||||
}
|
||||
},
|
||||
"flow-bin": {
|
||||
"version": "0.46.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.46.0.tgz",
|
||||
"integrity": "sha1-Bq1/4Z3dsQQiZEOAZKKjL+4SuHI=",
|
||||
"version": "0.55.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.55.0.tgz",
|
||||
"integrity": "sha1-kIPakye9jKtrQHbWPYXyJHp+rhs=",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
|
||||
34
package.json
34
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "react-native-firebase",
|
||||
"version": "3.0.0-alpha.5",
|
||||
"version": "3.0.0",
|
||||
"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 Auth, Database, Messaging (FCM), Remote Config, Storage, Admob, Analytics, Crash Reporting, 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, Messaging (FCM), Remote Config, Storage and Performance.",
|
||||
"main": "index",
|
||||
"scripts": {
|
||||
"flow": "flow",
|
||||
@@ -38,12 +38,20 @@
|
||||
"admob",
|
||||
"auth",
|
||||
"config",
|
||||
"digits",
|
||||
"phone-auth",
|
||||
"sms",
|
||||
"firestore",
|
||||
"cloud-firestore",
|
||||
"datastore",
|
||||
"remote-config",
|
||||
"transactions",
|
||||
"react-native",
|
||||
"react-native-firebase",
|
||||
"firebase",
|
||||
"fcm",
|
||||
"apn",
|
||||
"gcm",
|
||||
"analytics",
|
||||
"messaging",
|
||||
"database",
|
||||
@@ -51,11 +59,12 @@
|
||||
"ios",
|
||||
"crash",
|
||||
"firestack",
|
||||
"performance"
|
||||
"performance",
|
||||
"firestore"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": ">= 0.40.0",
|
||||
"react-native": ">= 0.48.0",
|
||||
"fbjs": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -70,22 +79,25 @@
|
||||
"eslint-plugin-import": "^2.0.1",
|
||||
"eslint-plugin-jsx-a11y": "^2.2.3",
|
||||
"eslint-plugin-react": "^6.4.1",
|
||||
"flow-bin": "^0.46.0",
|
||||
"react": "^15.3.0",
|
||||
"react-dom": "^15.3.0",
|
||||
"react-native": "^0.44.0",
|
||||
"flow-bin": "^0.55.0",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-native": "^0.48.0",
|
||||
"shelljs": "^0.7.8",
|
||||
"wml": "0.0.82"
|
||||
},
|
||||
"dependencies": {
|
||||
"bows": "^1.6.0",
|
||||
"prop-types": "^15.5.10"
|
||||
"prop-types": "^15.6.0"
|
||||
},
|
||||
"rnpm": {
|
||||
"android": {
|
||||
"buildPatch": " compile(project(':react-native-firebase')) {\n transitive = false\n }\n",
|
||||
"packageImportPath": "import io.invertase.firebase.RNFirebasePackage;\nimport io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;",
|
||||
"packageInstance": "new RNFirebasePackage(),\n new RNFirebaseAnalyticsPackage()"
|
||||
"packageImportPath": "import io.invertase.firebase.RNFirebasePackage;",
|
||||
"packageInstance": "new RNFirebasePackage()"
|
||||
},
|
||||
"commands": {
|
||||
"postlink": "node node_modules/react-native-firebase/scripts/rnpm-postlink"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
scripts/rnpm-postlink.js
Normal file
26
scripts/rnpm-postlink.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const fs = require('fs');
|
||||
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 }";
|
||||
|
||||
// android/build.gradle
|
||||
// 1) TODO: Add Google Play maven repository
|
||||
|
||||
// 2) TODO: Add google-services dependency if required
|
||||
|
||||
// android/app/build.gradle
|
||||
// 0) Load the file
|
||||
let buildGradleContents = fs.readFileSync(appBuildGradlePath, 'utf8');
|
||||
|
||||
// 1) Check that react-native-firebase compile statement is the correct format
|
||||
buildGradleContents = buildGradleContents.replace(defaultCompileStatement, requiredCompileStatement);
|
||||
|
||||
// 2) TODO: Add firebase-core and play-services-base dependencies
|
||||
|
||||
// 3) TODO: Add google-services plugin
|
||||
|
||||
// 4) Write file
|
||||
fs.writeFileSync(appBuildGradlePath, buildGradleContents);
|
||||
@@ -41,6 +41,7 @@ android {
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
multiDexEnabled true
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
@@ -71,7 +72,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
project.ext.firebaseVersion = '11.2.0'
|
||||
project.ext.firebaseVersion = '11.4.2'
|
||||
|
||||
dependencies {
|
||||
// compile(project(':react-native-firebase')) {
|
||||
@@ -82,7 +83,6 @@ dependencies {
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.google.android.gms:play-services-base:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-auth:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-config:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-core:$firebaseVersion"
|
||||
@@ -91,6 +91,7 @@ dependencies {
|
||||
compile "com.google.firebase:firebase-messaging:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-perf:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-storage:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-firestore:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-invites:$firebaseVersion"
|
||||
compile "com.android.support:appcompat-v7:26.0.1"
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
BIN
tests/android/app/src/main/assets/fonts/Feather.ttf
Normal file
BIN
tests/android/app/src/main/assets/fonts/Feather.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,9 +10,9 @@ import io.invertase.firebase.auth.RNFirebaseAuthPackage;
|
||||
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage;
|
||||
import io.invertase.firebase.crash.RNFirebaseCrashPackage;
|
||||
import io.invertase.firebase.database.RNFirebaseDatabasePackage;
|
||||
import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
|
||||
import io.invertase.firebase.links.RNFirebaseLinksPackage;
|
||||
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
|
||||
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
|
||||
import io.invertase.firebase.storage.RNFirebaseStoragePackage;
|
||||
import com.oblador.vectoricons.VectorIconsPackage;
|
||||
import com.facebook.react.ReactNativeHost;
|
||||
@@ -43,9 +43,10 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
new RNFirebaseRemoteConfigPackage(),
|
||||
new RNFirebaseCrashPackage(),
|
||||
new RNFirebaseDatabasePackage(),
|
||||
new RNFirebaseFirestorePackage(),
|
||||
new RNFirebaseLinksPackage(),
|
||||
new RNFirebaseMessagingPackage(),
|
||||
new RNFirebasePerformancePackage(),
|
||||
// new RNFirebasePerformancePackage(),
|
||||
new RNFirebaseStoragePackage()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
classpath 'com.google.gms:google-services:3.1.0'
|
||||
classpath 'com.google.firebase:firebase-plugins:1.1.0'
|
||||
classpath 'com.google.gms:google-services:3.1.1'
|
||||
classpath 'com.google.firebase:firebase-plugins:1.1.1'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ allprojects {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url "$rootDir/../node_modules/react-native/android"
|
||||
}
|
||||
mavenLocal()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
<key>DATABASE_URL</key>
|
||||
<string>https://rnfirebase-b9ad4.firebaseio.com</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||
|
||||
@@ -8,10 +8,16 @@ target 'ReactNativeFirebaseDemo' do
|
||||
# use_frameworks!
|
||||
|
||||
react_native_path = "../node_modules/react-native"
|
||||
pod "Yoga", :path => "#{react_native_path}/ReactCommon/yoga"
|
||||
pod "yoga", :path => "#{react_native_path}/ReactCommon/yoga"
|
||||
|
||||
# Pods for ReactNativeFirebaseDemo
|
||||
pod 'React', :path => '../node_modules/react-native'
|
||||
pod 'React', :path => '../node_modules/react-native', :subspecs => [
|
||||
'Core',
|
||||
'BatchedBridge',
|
||||
'RCTText',
|
||||
'RCTNetwork',
|
||||
'RCTWebSocket',
|
||||
]
|
||||
|
||||
pod 'Firebase/AdMob'
|
||||
pod 'Firebase/Auth'
|
||||
@@ -19,6 +25,7 @@ target 'ReactNativeFirebaseDemo' do
|
||||
pod 'Firebase/Crash'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/DynamicLinks'
|
||||
pod 'Firebase/Firestore'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
@@ -26,4 +33,12 @@ target 'ReactNativeFirebaseDemo' do
|
||||
|
||||
|
||||
pod 'RNFirebase', :path => './../../'
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
if target.name == "React"
|
||||
target.remove_from_project
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,83 +1,98 @@
|
||||
PODS:
|
||||
- Firebase/AdMob (4.1.0):
|
||||
- BoringSSL (9.0):
|
||||
- BoringSSL/Implementation (= 9.0)
|
||||
- BoringSSL/Interface (= 9.0)
|
||||
- BoringSSL/Implementation (9.0):
|
||||
- BoringSSL/Interface (= 9.0)
|
||||
- BoringSSL/Interface (9.0)
|
||||
- Firebase/AdMob (4.3.0):
|
||||
- Firebase/Core
|
||||
- Google-Mobile-Ads-SDK (= 7.22.0)
|
||||
- Firebase/Auth (4.1.0):
|
||||
- Google-Mobile-Ads-SDK (= 7.24.1)
|
||||
- Firebase/Auth (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAuth (= 4.1.0)
|
||||
- Firebase/Core (4.1.0):
|
||||
- FirebaseAnalytics (= 4.0.3)
|
||||
- FirebaseCore (= 4.0.5)
|
||||
- Firebase/Crash (4.1.0):
|
||||
- FirebaseAuth (= 4.2.1)
|
||||
- Firebase/Core (4.3.0):
|
||||
- FirebaseAnalytics (= 4.0.4)
|
||||
- FirebaseCore (= 4.0.8)
|
||||
- Firebase/Crash (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseCrash (= 2.0.1)
|
||||
- Firebase/Database (4.1.0):
|
||||
- FirebaseCrash (= 2.0.2)
|
||||
- Firebase/Database (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDatabase (= 4.0.1)
|
||||
- Firebase/DynamicLinks (4.1.0):
|
||||
- FirebaseDatabase (= 4.1.0)
|
||||
- Firebase/DynamicLinks (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDynamicLinks (= 2.1.0)
|
||||
- Firebase/Messaging (4.1.0):
|
||||
- Firebase/Firestore (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseMessaging (= 2.0.1)
|
||||
- Firebase/Performance (4.1.0):
|
||||
- FirebaseFirestore (= 0.8.0)
|
||||
- Firebase/Messaging (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebasePerformance (= 1.0.3)
|
||||
- Firebase/RemoteConfig (4.1.0):
|
||||
- FirebaseMessaging (= 2.0.4)
|
||||
- Firebase/Performance (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseRemoteConfig (= 2.0.2)
|
||||
- Firebase/Storage (4.1.0):
|
||||
- FirebasePerformance (= 1.0.6)
|
||||
- Firebase/RemoteConfig (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseStorage (= 2.0.1)
|
||||
- FirebaseAnalytics (4.0.3):
|
||||
- FirebaseRemoteConfig (= 2.0.3)
|
||||
- Firebase/Storage (4.3.0):
|
||||
- Firebase/Core
|
||||
- FirebaseStorage (= 2.0.2)
|
||||
- FirebaseAnalytics (4.0.4):
|
||||
- FirebaseCore (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseAuth (4.1.0):
|
||||
- FirebaseAuth (4.2.1):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- FirebaseCore (4.0.5):
|
||||
- FirebaseCore (4.0.8):
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseCrash (2.0.1):
|
||||
- FirebaseCrash (2.0.2):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseDatabase (4.0.1):
|
||||
- FirebaseDatabase (4.1.0):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- leveldb-library (~> 1.18)
|
||||
- FirebaseDynamicLinks (2.1.0):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (2.0.1):
|
||||
- FirebaseFirestore (0.8.0):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseAuth (~> 4.2)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- FirebaseMessaging (2.0.1):
|
||||
- gRPC-ProtoRPC (~> 1.0)
|
||||
- leveldb-library (~> 1.18)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseInstanceID (2.0.4)
|
||||
- FirebaseMessaging (2.0.4):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebasePerformance (1.0.3):
|
||||
- FirebasePerformance (1.0.6):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseRemoteConfig (2.0.2):
|
||||
- FirebaseRemoteConfig (2.0.3):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseStorage (2.0.1):
|
||||
- FirebaseStorage (2.0.2):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- Google-Mobile-Ads-SDK (7.22.0)
|
||||
- Google-Mobile-Ads-SDK (7.24.1)
|
||||
- GoogleToolboxForMac/DebugUtils (2.1.1):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/Defines (2.1.1)
|
||||
@@ -90,7 +105,23 @@ PODS:
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (2.1.1)
|
||||
- GTMSessionFetcher/Core (1.1.11)
|
||||
- gRPC (1.6.0):
|
||||
- gRPC-Core (= 1.6.0)
|
||||
- gRPC-RxLibrary (= 1.6.0)
|
||||
- gRPC-Core (1.6.0):
|
||||
- gRPC-Core/Implementation (= 1.6.0)
|
||||
- gRPC-Core/Interface (= 1.6.0)
|
||||
- gRPC-Core/Implementation (1.6.0):
|
||||
- BoringSSL (~> 9.0)
|
||||
- gRPC-Core/Interface (= 1.6.0)
|
||||
- nanopb (~> 0.3)
|
||||
- gRPC-Core/Interface (1.6.0)
|
||||
- gRPC-ProtoRPC (1.6.0):
|
||||
- gRPC (= 1.6.0)
|
||||
- gRPC-RxLibrary (= 1.6.0)
|
||||
- Protobuf (~> 3.0)
|
||||
- gRPC-RxLibrary (1.6.0)
|
||||
- GTMSessionFetcher/Core (1.1.12)
|
||||
- leveldb-library (1.18.3)
|
||||
- nanopb (0.3.8):
|
||||
- nanopb/decode (= 0.3.8)
|
||||
@@ -98,17 +129,30 @@ PODS:
|
||||
- nanopb/decode (0.3.8)
|
||||
- nanopb/encode (0.3.8)
|
||||
- Protobuf (3.4.0)
|
||||
- React (0.44.3):
|
||||
- React/Core (= 0.44.3)
|
||||
- React/Core (0.44.3):
|
||||
- React/cxxreact
|
||||
- Yoga (= 0.44.3.React)
|
||||
- React/cxxreact (0.44.3):
|
||||
- React/jschelpers
|
||||
- React/jschelpers (0.44.3)
|
||||
- RNFirebase (3.0.0-alpha.5):
|
||||
- React (0.49.0-rc.6):
|
||||
- React/Core (= 0.49.0-rc.6)
|
||||
- React/BatchedBridge (0.49.0-rc.6):
|
||||
- React/Core
|
||||
- React/cxxreact_legacy
|
||||
- React/Core (0.49.0-rc.6):
|
||||
- yoga (= 0.49.0-rc.6.React)
|
||||
- React/cxxreact_legacy (0.49.0-rc.6):
|
||||
- React/jschelpers_legacy
|
||||
- React/fishhook (0.49.0-rc.6)
|
||||
- React/jschelpers_legacy (0.49.0-rc.6)
|
||||
- React/RCTBlob (0.49.0-rc.6):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.49.0-rc.6):
|
||||
- React/Core
|
||||
- React/RCTText (0.49.0-rc.6):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.49.0-rc.6):
|
||||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
- RNFirebase (3.0.0):
|
||||
- React
|
||||
- Yoga (0.44.3.React)
|
||||
- yoga (0.49.0-rc.6.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Firebase/AdMob
|
||||
@@ -117,45 +161,56 @@ DEPENDENCIES:
|
||||
- Firebase/Crash
|
||||
- Firebase/Database
|
||||
- Firebase/DynamicLinks
|
||||
- Firebase/Firestore
|
||||
- Firebase/Messaging
|
||||
- Firebase/Performance
|
||||
- Firebase/RemoteConfig
|
||||
- Firebase/Storage
|
||||
- React (from `../node_modules/react-native`)
|
||||
- React/BatchedBridge (from `../node_modules/react-native`)
|
||||
- React/Core (from `../node_modules/react-native`)
|
||||
- React/RCTNetwork (from `../node_modules/react-native`)
|
||||
- React/RCTText (from `../node_modules/react-native`)
|
||||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNFirebase (from `./../../`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
React:
|
||||
:path: "../node_modules/react-native"
|
||||
RNFirebase:
|
||||
:path: "./../../"
|
||||
Yoga:
|
||||
yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Firebase: ebebf41db7f10e0c7668b6eaaa857fbe599aa478
|
||||
FirebaseAnalytics: 76f754d37ca5b04f36856729b6af3ca0152d1069
|
||||
FirebaseAuth: 8d1d2389cf82f891048d6d50d27d044f55ae09a6
|
||||
FirebaseCore: 7d876ea97a830cbe62ba7fbbe7670c833a324ba0
|
||||
FirebaseCrash: bce9fbfb7dd6cc850a41fe39740a2292e6b61f2e
|
||||
FirebaseDatabase: 94c38c783d23dc6679441050772d42e801d06e9e
|
||||
BoringSSL: 19083b821ef3ae0f758fae15482e183003b1e265
|
||||
Firebase: 83283761a1ef6dc9846e03d08059f51421afbd65
|
||||
FirebaseAnalytics: 722b53c7b32bfc7806b06e0093a2f5180d4f2c5a
|
||||
FirebaseAuth: d7f047fbeab98062b98ea933b8d934e0fb1190e2
|
||||
FirebaseCore: 69b1a5ac5f857ba6d5fd9d5fe794f4786dd5e579
|
||||
FirebaseCrash: cded0fc566c03651aea606a101bc156085f333ca
|
||||
FirebaseDatabase: 607284a103e961d7f5863ee603cab5e85f443bd6
|
||||
FirebaseDynamicLinks: ed4cb6c42705aaa5e841ed2d76e3a4bddbec10c1
|
||||
FirebaseInstanceID: 0500e3cb54a1a4e01a8cffcc09323b8bb8fc7e1e
|
||||
FirebaseMessaging: b45ff9ef5d932600d3f78ff43168e7c5707aa7dc
|
||||
FirebasePerformance: 36bdb0500213b459ae991766801d5dc5399ff231
|
||||
FirebaseRemoteConfig: 5b3e3301ef2f237b1b588e8ef3211b5a22e9e15d
|
||||
FirebaseStorage: 661fc1f8d4131891d256b62e82a45ace8b3f0c3b
|
||||
Google-Mobile-Ads-SDK: 1bdf1a4244d0553b1840239874c209c01aef055f
|
||||
FirebaseFirestore: 8e2fd99a621ae6fc6acfac3bdea824fe9d9c128d
|
||||
FirebaseInstanceID: 70c2b877e9338971b2429ea5a4293df6961aa44e
|
||||
FirebaseMessaging: 3dd86bfda2acb680b05c97f3f8ac566e9bb87b2a
|
||||
FirebasePerformance: fa032c27e229eb8c1a8638918793fe2e47465205
|
||||
FirebaseRemoteConfig: 1c982f73af48ec048c8fa8621d5178cfdffac9aa
|
||||
FirebaseStorage: 0cca42d9b889a0227c3a50121f45a4469fc9eb27
|
||||
Google-Mobile-Ads-SDK: ed8004a7265b424568dc84f3d2bbe3ea3fff958f
|
||||
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
|
||||
GTMSessionFetcher: 5ad62e8200fa00ed011fe5e08d27fef72c5b1429
|
||||
gRPC: '07788969b862af21491908f82b83d17ac08c94cd'
|
||||
gRPC-Core: f707ade59c559fe718e27713189607d03b15f571
|
||||
gRPC-ProtoRPC: de7505e493a9d1b6b96c8ea8f976c73100fdf53f
|
||||
gRPC-RxLibrary: 17b9699beb0a838b95b57832244f9ead18e66777
|
||||
GTMSessionFetcher: ebaa1f79a5366922c1735f1566901f50beba23b7
|
||||
leveldb-library: 10fb39c39e243db4af1828441162405bbcec1404
|
||||
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
||||
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
||||
React: 6361345ebeb769a929e10a06baf0c868d6d03ad5
|
||||
RNFirebase: 60be8c01b94551a12e7be5431189e8ee8cefcdd3
|
||||
Yoga: c90474ca3ec1edba44c97b6c381f03e222a9e287
|
||||
React: e6ef6a41ec6dd1b7941417d60ca582bf5e9c739d
|
||||
RNFirebase: 2ceda3aef595ea1379bf5bfcc1cd9ee7d6c05d3b
|
||||
yoga: f9485d2ebf0ca773db2d727ea71b1aa8c9f3e075
|
||||
|
||||
PODFILE CHECKSUM: 46b6a553f3c9fd264b449806b373d33b4af518b5
|
||||
PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45
|
||||
|
||||
COCOAPODS: 1.2.1
|
||||
|
||||
@@ -25,21 +25,9 @@
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
1852BC611C674A2E905975BC /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5F6AF99C2A6F4545B0F74832 /* Foundation.ttf */; };
|
||||
211A77BD015F4D728A9B6E72 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7DD9301D866B4D52A7F83996 /* FontAwesome.ttf */; };
|
||||
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
||||
2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; };
|
||||
2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; };
|
||||
2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; };
|
||||
2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; };
|
||||
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
|
||||
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
|
||||
2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
|
||||
2DCD954D1E0B4F2C00145EB5 /* ReactNativeFirebaseDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeFirebaseDemoTests.m */; };
|
||||
42A0E8F428A74B23B4C7D95A /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FD3DFC8253C74B6298AFD3B7 /* SimpleLineIcons.ttf */; };
|
||||
58EAF3FA628941C98A02BAE4 /* Feather.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 528FC2DCD44F4567A3FE9F59 /* Feather.ttf */; };
|
||||
5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
||||
644044EA167D431D96D0E6C1 /* libLRDRCTSimpleToast.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BBEE706291534F5F948A3805 /* libLRDRCTSimpleToast.a */; };
|
||||
6F307BC16AD047C8BD921730 /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7A6F0C1C198B4A6FB4AB907D /* MaterialCommunityIcons.ttf */; };
|
||||
82FE196A2ADC4D29BB2CB4BF /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 48961CCCEE8947FB9EE3658F /* Ionicons.ttf */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
@@ -116,13 +104,6 @@
|
||||
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
|
||||
remoteInfo = React;
|
||||
};
|
||||
2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
|
||||
remoteInfo = "ReactNativeFirebaseDemo-tvOS";
|
||||
};
|
||||
3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
|
||||
@@ -242,6 +223,48 @@
|
||||
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
|
||||
remoteInfo = RCTText;
|
||||
};
|
||||
8E7D4A501F83AF5200699FE4 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3DBE0D001F3B181A0099AA32;
|
||||
remoteInfo = fishhook;
|
||||
};
|
||||
8E7D4A521F83AF5200699FE4 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32;
|
||||
remoteInfo = "fishhook-tvOS";
|
||||
};
|
||||
8EC7AC341F8397E50041B0FE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
|
||||
remoteInfo = "third-party";
|
||||
};
|
||||
8EC7AC361F8397E50041B0FE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
|
||||
remoteInfo = "third-party-tvOS";
|
||||
};
|
||||
8EC7AC381F8397E50041B0FE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 139D7E881E25C6D100323FB7;
|
||||
remoteInfo = "double-conversion";
|
||||
};
|
||||
8EC7AC3A1F8397E50041B0FE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3D383D621EBD27B9005632C8;
|
||||
remoteInfo = "double-conversion-tvOS";
|
||||
};
|
||||
997890041E69DE2900F6820C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = C7C48FEEC8E34DE4BB5DE211 /* RNFirebase.xcodeproj */;
|
||||
@@ -256,13 +279,6 @@
|
||||
remoteGlobalIDString = 5DBEB1501B18CEA900B34395;
|
||||
remoteInfo = RNVectorIcons;
|
||||
};
|
||||
997890191E6D86E700F6820C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 78C4D9D5FCAA43A384C23C35 /* LRDRCTSimpleToast.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 15209BEF1D250F63000D0F44;
|
||||
remoteInfo = LRDRCTSimpleToast;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -288,17 +304,15 @@
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeFirebaseDemo/main.m; sourceTree = "<group>"; };
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
|
||||
182271FFECD74C3B92960E1D /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; };
|
||||
2D02E47B1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ReactNativeFirebaseDemo-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D02E4901E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ReactNativeFirebaseDemo-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
42C7056622ACE9D1E626AD4C /* libPods-ReactNativeFirebaseDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeFirebaseDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
48961CCCEE8947FB9EE3658F /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
|
||||
4935BEDE99B9436581953E77 /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = "<group>"; };
|
||||
528FC2DCD44F4567A3FE9F59 /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = "<group>"; };
|
||||
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
|
||||
5F6AF99C2A6F4545B0F74832 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
|
||||
739DB016E64944BE99C338C4 /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
|
||||
7791402B6343C1906BE4D13A /* libPods-ReactNativeFirebaseDemoTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeFirebaseDemoTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
|
||||
78C4D9D5FCAA43A384C23C35 /* LRDRCTSimpleToast.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = LRDRCTSimpleToast.xcodeproj; path = "../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast.xcodeproj"; sourceTree = "<group>"; };
|
||||
7A6F0C1C198B4A6FB4AB907D /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = "<group>"; };
|
||||
7DD9301D866B4D52A7F83996 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
@@ -337,33 +351,10 @@
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
|
||||
E51DA6317685417F97A59475 /* libRNVectorIcons.a in Frameworks */,
|
||||
644044EA167D431D96D0E6C1 /* libLRDRCTSimpleToast.a in Frameworks */,
|
||||
076B30A1D09C6AEEAE912DEB /* libPods-ReactNativeFirebaseDemo.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */,
|
||||
2D02E4C21E0B4AEC006451C7 /* libRCTAnimation.a in Frameworks */,
|
||||
2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */,
|
||||
2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */,
|
||||
2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */,
|
||||
2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
|
||||
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
|
||||
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -449,6 +440,8 @@
|
||||
children = (
|
||||
139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
|
||||
3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
|
||||
8E7D4A511F83AF5200699FE4 /* libfishhook.a */,
|
||||
8E7D4A531F83AF5200699FE4 /* libfishhook-tvOS.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -479,6 +472,10 @@
|
||||
3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
|
||||
3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
|
||||
3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
|
||||
8EC7AC351F8397E50041B0FE /* libthird-party.a */,
|
||||
8EC7AC371F8397E50041B0FE /* libthird-party.a */,
|
||||
8EC7AC391F8397E50041B0FE /* libdouble-conversion.a */,
|
||||
8EC7AC3B1F8397E50041B0FE /* libdouble-conversion.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -526,7 +523,6 @@
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
|
||||
C7C48FEEC8E34DE4BB5DE211 /* RNFirebase.xcodeproj */,
|
||||
8BE028F5B04B4DC3BEF0305F /* RNVectorIcons.xcodeproj */,
|
||||
78C4D9D5FCAA43A384C23C35 /* LRDRCTSimpleToast.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -570,21 +566,10 @@
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* ReactNativeFirebaseDemo.app */,
|
||||
00E356EE1AD99517003FC87E /* ReactNativeFirebaseDemoTests.xctest */,
|
||||
2D02E47B1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS.app */,
|
||||
2D02E4901E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83F533111F76A95B0008C1A5 /* Recovered References */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C76E33ACF004369AEB318B1 /* libRNVectorIcons.a */,
|
||||
BBEE706291534F5F948A3805 /* libLRDRCTSimpleToast.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
99788FE61E69DE2900F6820C /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -601,14 +586,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
997890161E6D86E700F6820C /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9978901A1E6D86E700F6820C /* libLRDRCTSimpleToast.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F50F62EA16044AFF8BD7CF63 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -622,6 +599,7 @@
|
||||
CC24EB30F0484352BD65FFC1 /* Octicons.ttf */,
|
||||
FD3DFC8253C74B6298AFD3B7 /* SimpleLineIcons.ttf */,
|
||||
182271FFECD74C3B92960E1D /* Zocial.ttf */,
|
||||
528FC2DCD44F4567A3FE9F59 /* Feather.ttf */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -668,42 +646,6 @@
|
||||
productReference = 13B07F961A680F5B00A75B9A /* ReactNativeFirebaseDemo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
2D02E47A1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "ReactNativeFirebaseDemo-tvOS" */;
|
||||
buildPhases = (
|
||||
2D02E4771E0B4A5D006451C7 /* Sources */,
|
||||
2D02E4781E0B4A5D006451C7 /* Frameworks */,
|
||||
2D02E4791E0B4A5D006451C7 /* Resources */,
|
||||
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "ReactNativeFirebaseDemo-tvOS";
|
||||
productName = "ReactNativeFirebaseDemo-tvOS";
|
||||
productReference = 2D02E47B1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
2D02E48F1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOSTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "ReactNativeFirebaseDemo-tvOSTests" */;
|
||||
buildPhases = (
|
||||
2D02E48C1E0B4A5D006451C7 /* Sources */,
|
||||
2D02E48D1E0B4A5D006451C7 /* Frameworks */,
|
||||
2D02E48E1E0B4A5D006451C7 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "ReactNativeFirebaseDemo-tvOSTests";
|
||||
productName = "ReactNativeFirebaseDemo-tvOSTests";
|
||||
productReference = 2D02E4901E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOSTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -715,16 +657,11 @@
|
||||
TargetAttributes = {
|
||||
00E356ED1AD99517003FC87E = {
|
||||
CreatedOnToolsVersion = 6.2;
|
||||
DevelopmentTeam = YMA4Y8JWM2;
|
||||
TestTargetID = 13B07F861A680F5B00A75B9A;
|
||||
};
|
||||
2D02E47A1E0B4A5D006451C7 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
2D02E48F1E0B4A5D006451C7 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = 2D02E47A1E0B4A5D006451C7;
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
DevelopmentTeam = YMA4Y8JWM2;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -740,10 +677,6 @@
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 997890161E6D86E700F6820C /* Products */;
|
||||
ProjectRef = 78C4D9D5FCAA43A384C23C35 /* LRDRCTSimpleToast.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
|
||||
@@ -801,8 +734,6 @@
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* ReactNativeFirebaseDemo */,
|
||||
00E356ED1AD99517003FC87E /* ReactNativeFirebaseDemoTests */,
|
||||
2D02E47A1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS */,
|
||||
2D02E48F1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOSTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -983,6 +914,48 @@
|
||||
remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8E7D4A511F83AF5200699FE4 /* libfishhook.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libfishhook.a;
|
||||
remoteRef = 8E7D4A501F83AF5200699FE4 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8E7D4A531F83AF5200699FE4 /* libfishhook-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libfishhook-tvOS.a";
|
||||
remoteRef = 8E7D4A521F83AF5200699FE4 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8EC7AC351F8397E50041B0FE /* libthird-party.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libthird-party.a";
|
||||
remoteRef = 8EC7AC341F8397E50041B0FE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8EC7AC371F8397E50041B0FE /* libthird-party.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libthird-party.a";
|
||||
remoteRef = 8EC7AC361F8397E50041B0FE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8EC7AC391F8397E50041B0FE /* libdouble-conversion.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libdouble-conversion.a";
|
||||
remoteRef = 8EC7AC381F8397E50041B0FE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8EC7AC3B1F8397E50041B0FE /* libdouble-conversion.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libdouble-conversion.a";
|
||||
remoteRef = 8EC7AC3A1F8397E50041B0FE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
997890051E69DE2900F6820C /* RNFirebase.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
@@ -997,13 +970,6 @@
|
||||
remoteRef = 997890071E69DE2900F6820C /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
9978901A1E6D86E700F6820C /* libLRDRCTSimpleToast.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libLRDRCTSimpleToast.a;
|
||||
remoteRef = 997890191E6D86E700F6820C /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
@@ -1031,21 +997,7 @@
|
||||
885057F5D1FA461AAAE0B487 /* Octicons.ttf in Resources */,
|
||||
42A0E8F428A74B23B4C7D95A /* SimpleLineIcons.ttf in Resources */,
|
||||
D46EBD0604CE40EFB18F8A35 /* Zocial.ttf in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E4791E0B4A5D006451C7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E48E1E0B4A5D006451C7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
58EAF3FA628941C98A02BAE4 /* Feather.ttf in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1064,7 +1016,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
|
||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
|
||||
};
|
||||
26F9B43687A3EAE646F8970D /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -1084,20 +1036,6 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Bundle React Native Code And Images";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
|
||||
};
|
||||
6AE1012F46FF8A4D1D818A12 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1148,23 +1086,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E4771E0B4A5D006451C7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
|
||||
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
2D02E48C1E0B4A5D006451C7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2DCD954D1E0B4F2C00145EB5 /* ReactNativeFirebaseDemoTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -1173,11 +1094,6 @@
|
||||
target = 13B07F861A680F5B00A75B9A /* ReactNativeFirebaseDemo */;
|
||||
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
|
||||
};
|
||||
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 2D02E47A1E0B4A5D006451C7 /* ReactNativeFirebaseDemo-tvOS */;
|
||||
targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -1197,6 +1113,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
@@ -1205,7 +1122,6 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = ReactNativeFirebaseDemoTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1229,11 +1145,11 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = ReactNativeFirebaseDemoTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1259,11 +1175,11 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = ReactNativeFirebaseDemo/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1272,7 +1188,7 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.invertase.ReactNativeFirebaseDemo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.invertase.RNFirebaseTests;
|
||||
PRODUCT_NAME = ReactNativeFirebaseDemo;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
@@ -1284,11 +1200,11 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = ReactNativeFirebaseDemo/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1297,138 +1213,12 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.invertase.ReactNativeFirebaseDemo;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.invertase.RNFirebaseTests;
|
||||
PRODUCT_NAME = ReactNativeFirebaseDemo;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2D02E4971E0B4A5E006451C7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = "ReactNativeFirebaseDemo-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.ReactNativeFirebaseDemo-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2D02E4981E0B4A5E006451C7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-firebase/Firebase.framework/Headers/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
|
||||
"$(SRCROOT)/../node_modules/react-native-simple-toast/ios/LRDRCTSimpleToast",
|
||||
);
|
||||
INFOPLIST_FILE = "ReactNativeFirebaseDemo-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.ReactNativeFirebaseDemo-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2D02E4991E0B4A5E006451C7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = "ReactNativeFirebaseDemo-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.ReactNativeFirebaseDemo-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeFirebaseDemo-tvOS.app/ReactNativeFirebaseDemo-tvOS";
|
||||
TVOS_DEPLOYMENT_TARGET = 10.1;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2D02E49A1E0B4A5E006451C7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = "ReactNativeFirebaseDemo-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.ReactNativeFirebaseDemo-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeFirebaseDemo-tvOS.app/ReactNativeFirebaseDemo-tvOS";
|
||||
TVOS_DEPLOYMENT_TARGET = 10.1;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1448,6 +1238,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@@ -1489,6 +1280,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEVELOPMENT_TEAM = YMA4Y8JWM2;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
@@ -1526,24 +1318,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "ReactNativeFirebaseDemo-tvOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2D02E4971E0B4A5E006451C7 /* Debug */,
|
||||
2D02E4981E0B4A5E006451C7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "ReactNativeFirebaseDemo-tvOSTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2D02E4991E0B4A5E006451C7 /* Debug */,
|
||||
2D02E49A1E0B4A5E006451C7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeFirebaseDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
@@ -83,6 +84,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -65,6 +65,11 @@
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<string>Octicons.ttf</string>
|
||||
<string>SimpleLineIcons.ttf</string>
|
||||
<string>Zocial.ttf</string>
|
||||
<string>Feather.ttf</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
|
||||
2324
tests/package-lock.json
generated
2324
tests/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -32,13 +32,13 @@
|
||||
"js-beautify": "^1.6.11",
|
||||
"lodash.groupby": "^4.6.0",
|
||||
"lodash.some": "^4.6.0",
|
||||
"react": "16.0.0-alpha.12",
|
||||
"react-native": "^0.48.4",
|
||||
"react-test-renderer": "16.0.0-alpha.12",
|
||||
"react-native-simple-toast": "0.0.5",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.0.0",
|
||||
"react-native": "^0.49.1",
|
||||
"react-native-vector-icons": "^4.0.0",
|
||||
"react-navigation": "^1.0.0-beta.9",
|
||||
"react-redux": "^5.0.3",
|
||||
"react-test-renderer": "16.0.0-alpha.12",
|
||||
"redux": "^3.6.0",
|
||||
"redux-logger": "^2.8.2",
|
||||
"redux-persist": "^4.4.2",
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import some from 'lodash.some';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Toast from 'react-native-simple-toast';
|
||||
// import Toast from 'react-native-simple-toast';
|
||||
|
||||
import { runTests } from '../tests/index';
|
||||
import RunStatus from '../../lib/RunStatus';
|
||||
@@ -26,7 +26,7 @@ class OverviewControlButton extends Component {
|
||||
handleOnPress() {
|
||||
const { focusedTestIds, pendingTestIds, tests } = this.props;
|
||||
runTests(tests, { focusedTestIds, pendingTestIds });
|
||||
Toast.show('Running all suite tests.');
|
||||
// Toast.show('Running all suite tests.');
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import Toast from 'react-native-simple-toast';
|
||||
// import Toast from 'react-native-simple-toast';
|
||||
|
||||
import RunStatus from '../../lib/RunStatus';
|
||||
import { runTest } from '../tests/index';
|
||||
@@ -24,7 +24,7 @@ class TestControlButton extends Component {
|
||||
const { test: { id, description } } = this.props;
|
||||
|
||||
runTest(id);
|
||||
Toast.show(`Running ${description}.`);
|
||||
// Toast.show(`Running ${description}.`);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Toast from 'react-native-simple-toast';
|
||||
// import Toast from 'react-native-simple-toast';
|
||||
|
||||
import RunStatus from '../../lib/RunStatus';
|
||||
import { runTests } from '../tests/index';
|
||||
@@ -28,7 +28,7 @@ class TestSuiteControlButton extends Component {
|
||||
|
||||
runTests(testSuiteTests, { focusedTestIds, pendingTestIds });
|
||||
|
||||
Toast.show(`Running ${name} tests.`);
|
||||
// Toast.show(`Running ${name} tests.`);
|
||||
}
|
||||
|
||||
toggleOnlyShowFailingTests() {
|
||||
|
||||
@@ -31,7 +31,7 @@ class CoreContainer extends React.Component {
|
||||
NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
this.handleAppStateChange('active'); // Force connect (react debugger issue)
|
||||
this.props.dispatch(setNetworkState(isConnected));
|
||||
NetInfo.isConnected.addEventListener('change', this.handleNetworkChange);
|
||||
NetInfo.isConnected.addEventListener('connectionChange', this.handleNetworkChange);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class CoreContainer extends React.Component {
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this.handleAppStateChange);
|
||||
NetInfo.isConnected.removeEventListener('change', this.handleNetworkChange);
|
||||
NetInfo.isConnected.removeEventListener('connectionChange', this.handleNetworkChange);
|
||||
}
|
||||
|
||||
props: Props;
|
||||
|
||||
249
tests/src/phone-auth.js
Normal file
249
tests/src/phone-auth.js
Normal file
@@ -0,0 +1,249 @@
|
||||
import React, { Component } from 'react';
|
||||
import { View, Button, Text, TextInput, Image, ActivityIndicator, Platform } from 'react-native';
|
||||
import fb from './firebase';
|
||||
|
||||
const firebase = fb.native;
|
||||
|
||||
const imageUrl = 'https://www.shareicon.net/data/512x512/2016/07/19/798524_sms_512x512.png';
|
||||
|
||||
export default class PhoneAuth extends Component {
|
||||
static getDefaultState() {
|
||||
return {
|
||||
message: '',
|
||||
error: '',
|
||||
codeInput: '',
|
||||
phoneNumber: '+44',
|
||||
auto: Platform.OS === 'android',
|
||||
autoVerifyCountDown: 0,
|
||||
sent: false,
|
||||
started: false,
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.timeout = 20;
|
||||
this._autoVerifyInterval = null;
|
||||
this.state = PhoneAuth.getDefaultState();
|
||||
}
|
||||
|
||||
_tick() {
|
||||
this.setState({
|
||||
autoVerifyCountDown: this.state.autoVerifyCountDown - 1,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when confirm code is pressed - we should have the code and verificationId now in state.
|
||||
*/
|
||||
afterVerify = () => {
|
||||
const { codeInput, verificationId } = this.state;
|
||||
const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, codeInput);
|
||||
|
||||
// TODO do something with credential for example:
|
||||
firebase.auth()
|
||||
.signInWithCredential(credential)
|
||||
.then((user) => {
|
||||
console.log('PHONE AUTH USER ->>>>>', user.toJSON());
|
||||
this.setState({ user: user.toJSON() });
|
||||
}).catch(console.error);
|
||||
};
|
||||
|
||||
signIn = () => {
|
||||
const { phoneNumber } = this.state;
|
||||
this.setState({ message: 'Sending code ...', error: '', started: true, autoVerifyCountDown: this.timeout }, () => {
|
||||
firebase.auth()
|
||||
.verifyPhoneNumber(phoneNumber)
|
||||
.on('state_changed', (phoneAuthSnapshot) => {
|
||||
console.log(phoneAuthSnapshot);
|
||||
switch (phoneAuthSnapshot.state) {
|
||||
case firebase.auth.PhoneAuthState.CODE_SENT: // or 'sent'
|
||||
// update state with code sent and if android start a interval timer
|
||||
// for auto verify - to provide visual feedback
|
||||
this.setState({
|
||||
sent: true,
|
||||
message: 'Code Sent!',
|
||||
verificationId: phoneAuthSnapshot.verificationId,
|
||||
autoVerifyCountDown: this.timeout,
|
||||
}, () => {
|
||||
if (this.state.auto) {
|
||||
this._autoVerifyInterval = setInterval(this._tick.bind(this), 1000);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case firebase.auth.PhoneAuthState.ERROR: // or 'error'
|
||||
// restart the phone flow again on error
|
||||
clearInterval(this._autoVerifyInterval);
|
||||
this.setState({
|
||||
...PhoneAuth.getDefaultState(),
|
||||
error: phoneAuthSnapshot.error.message,
|
||||
});
|
||||
break;
|
||||
|
||||
// ---------------------
|
||||
// ANDROID ONLY EVENTS
|
||||
// ---------------------
|
||||
case firebase.auth.PhoneAuthState.AUTO_VERIFY_TIMEOUT: // or 'timeout'
|
||||
clearInterval(this._autoVerifyInterval);
|
||||
this.setState({
|
||||
sent: true,
|
||||
auto: false,
|
||||
verificationId: phoneAuthSnapshot.verificationId,
|
||||
});
|
||||
break;
|
||||
case firebase.auth.PhoneAuthState.AUTO_VERIFIED: // or 'verified'
|
||||
clearInterval(this._autoVerifyInterval);
|
||||
this.setState({
|
||||
sent: true,
|
||||
codeInput: phoneAuthSnapshot.code,
|
||||
verificationId: phoneAuthSnapshot.verificationId,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// will never get here - just for linting
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
renderInputPhoneNumber() {
|
||||
const { phoneNumber } = this.state;
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text>Enter phone number:</Text>
|
||||
<TextInput
|
||||
autoFocus
|
||||
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
|
||||
onChangeText={value => this.setState({ phoneNumber: value })}
|
||||
placeholder={'Phone number ... '}
|
||||
value={phoneNumber}
|
||||
/>
|
||||
<Button title="Begin Verification" color="green" onPress={this.signIn} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderSendingCode() {
|
||||
const { phoneNumber } = this.state;
|
||||
|
||||
return (
|
||||
<View style={{ paddingBottom: 15 }}>
|
||||
<Text
|
||||
style={{ paddingBottom: 25 }}
|
||||
>
|
||||
{`Sending verification code to '${phoneNumber}'.`}
|
||||
</Text>
|
||||
<ActivityIndicator animating style={{ padding: 50 }} size={'large'} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderAutoVerifyProgress() {
|
||||
const { autoVerifyCountDown, started, error, sent, phoneNumber } = this.state;
|
||||
if (!sent && started && !error.length) {
|
||||
return this.renderSendingCode();
|
||||
}
|
||||
return (
|
||||
<View style={{ padding: 0 }}>
|
||||
<Text
|
||||
style={{ paddingBottom: 25 }}
|
||||
>
|
||||
{`Verification code has been successfully sent to '${phoneNumber}'.`}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ marginBottom: 25 }}
|
||||
>
|
||||
{`We'll now attempt to automatically verify the code for you. This will timeout in ${autoVerifyCountDown} seconds.`}
|
||||
</Text>
|
||||
<Button
|
||||
style={{ paddingTop: 25 }} title="I have a code already" color="green"
|
||||
onPress={() => this.setState({ auto: false })}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderError() {
|
||||
const { error } = this.state;
|
||||
|
||||
return (
|
||||
<View style={{ padding: 10, borderRadius: 5, margin: 10, backgroundColor: 'rgb(255,0,0)' }}>
|
||||
<Text
|
||||
style={{ color: '#fff' }}
|
||||
>
|
||||
{error}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { started, error, codeInput, sent, auto, user } = this.state;
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: user ? 'rgb(0, 200, 0)' : '#fff' }}>
|
||||
<View
|
||||
style={{
|
||||
padding: 5,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<Image source={{ uri: imageUrl }} style={{ width: 128, height: 128, marginTop: 25, marginBottom: 15 }} />
|
||||
<Text style={{ fontSize: 25, marginBottom: 20 }}>Phone Auth Example</Text>
|
||||
{error && error.length ? this.renderError() : null}
|
||||
{!started && !sent ? this.renderInputPhoneNumber() : null}
|
||||
{started && auto && !codeInput.length ? this.renderAutoVerifyProgress() : null}
|
||||
{!user && started && sent && (codeInput.length || !auto) ? (
|
||||
<View style={{ marginTop: 15 }}>
|
||||
<Text>Enter verification code below:</Text>
|
||||
<TextInput
|
||||
autoFocus
|
||||
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
|
||||
onChangeText={value => this.setState({ codeInput: value })}
|
||||
placeholder={'Code ... '}
|
||||
value={codeInput}
|
||||
/>
|
||||
<Button title="Confirm Code" color="#841584" onPress={this.afterVerify} />
|
||||
</View>
|
||||
) : null}
|
||||
{user ? (
|
||||
<View style={{ marginTop: 15 }}>
|
||||
<Text>{`Signed in with new user id: '${user.uid}'`}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
{ user ? (
|
||||
<View
|
||||
style={{
|
||||
padding: 15,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#77dd77',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<Image source={{ uri: successImageUri }} style={{ width: 100, height: 100, marginBottom: 25 }} />
|
||||
<Text style={{ fontSize: 25 }}>Signed In!</Text>
|
||||
<Text>{JSON.stringify(user)}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
*/
|
||||
|
||||
|
||||
// Example usage if handling here and not in optionalCompleteCb:
|
||||
// const { verificationId, code } = phoneAuthSnapshot;
|
||||
// const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, code);
|
||||
|
||||
// Do something with your new credential, e.g.:
|
||||
// firebase.auth().signInWithCredential(credential);
|
||||
// firebase.auth().linkWithCredential(credential);
|
||||
// etc ...
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, View, Text, ListView, TouchableHighlight } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import some from 'lodash.some';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { StyleSheet, View, Text, ListView, TouchableHighlight } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { StyleSheet, View, Text, ScrollView } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { js_beautify as beautify } from 'js-beautify';
|
||||
|
||||
@@ -58,16 +58,17 @@ function coreTests({ describe, it }) {
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
it('it should initialize dynamic apps', () => {
|
||||
return RNFirebase
|
||||
.initializeApp(Platform.OS === 'ios' ? iosTestConfig : androidTestConfig, 'testsCoreApp')
|
||||
.onReady()
|
||||
.then((newApp) => {
|
||||
newApp.name.should.equal('TESTSCOREAPP');
|
||||
newApp.options.apiKey.should.equal((Platform.OS === 'ios' ? iosTestConfig : androidTestConfig).apiKey);
|
||||
return newApp.delete();
|
||||
});
|
||||
});
|
||||
// TODO add back in when android sdk support becomes available
|
||||
// it('it should initialize dynamic apps', () => {
|
||||
// return RNFirebase
|
||||
// .initializeApp(Platform.OS === 'ios' ? iosTestConfig : androidTestConfig, 'testsCoreApp')
|
||||
// .onReady()
|
||||
// .then((newApp) => {
|
||||
// newApp.name.should.equal('TESTSCOREAPP');
|
||||
// newApp.options.apiKey.should.equal((Platform.OS === 'ios' ? iosTestConfig : androidTestConfig).apiKey);
|
||||
// return newApp.delete();
|
||||
// });
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
385
tests/src/tests/firestore/collectionReferenceTests.js
Normal file
385
tests/src/tests/firestore/collectionReferenceTests.js
Normal file
@@ -0,0 +1,385 @@
|
||||
import sinon from 'sinon';
|
||||
import 'should-sinon';
|
||||
import should from 'should';
|
||||
|
||||
function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||
describe('CollectionReference', () => {
|
||||
context('class', () => {
|
||||
it('should return instance methods', () => {
|
||||
return new Promise((resolve) => {
|
||||
const collection = firebase.native.firestore().collection('collection-tests');
|
||||
collection.should.have.property('firestore');
|
||||
// TODO: Remaining checks
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('add()', () => {
|
||||
it('should create Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.add({ first: 'Ada', last: 'Lovelace', born: 1815 })
|
||||
.then(async (docRef) => {
|
||||
const doc = await firebase.native.firestore().doc(docRef.path).get();
|
||||
doc.data().first.should.equal('Ada');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('doc()', () => {
|
||||
it('should create DocumentReference with correct path', () => {
|
||||
return new Promise((resolve) => {
|
||||
const docRef = firebase.native.firestore().collection('collection-tests').doc('doc');
|
||||
should.equal(docRef.path, 'collection-tests/doc');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('get()', () => {
|
||||
it('should retrieve a single document', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().baz, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when document changes', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when document is added', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc2');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledThrice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('doesn\'t call callback when the ref is updated with the same value', async () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Where
|
||||
context('where()', () => {
|
||||
it('correctly handles == boolean values', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.where('baz', '==', true)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().baz, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly handles == string values', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.where('foo', '==', 'bar')
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().foo, 'bar');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly handles == null values', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.where('naz', '==', null)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().naz, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly handles >= number values', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.where('daz', '>=', 123)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().daz, 123);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly handles <= float values', () => {
|
||||
return firebase.native.firestore()
|
||||
.collection('collection-tests')
|
||||
.where('gaz', '<=', 12.1234666)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
should.equal(querySnapshot.size, 1);
|
||||
querySnapshot.forEach((documentSnapshot) => {
|
||||
should.equal(documentSnapshot.data().gaz, 12.1234567);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default collectionReferenceTests;
|
||||
299
tests/src/tests/firestore/documentReferenceTests.js
Normal file
299
tests/src/tests/firestore/documentReferenceTests.js
Normal file
@@ -0,0 +1,299 @@
|
||||
import sinon from 'sinon';
|
||||
import 'should-sinon';
|
||||
import should from 'should';
|
||||
|
||||
function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||
describe('DocumentReference', () => {
|
||||
context('class', () => {
|
||||
it('should return instance methods', () => {
|
||||
return new Promise((resolve) => {
|
||||
const document = firebase.native.firestore().doc('document-tests/doc1');
|
||||
document.should.have.property('firestore');
|
||||
// TODO: Remaining checks
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('delete()', () => {
|
||||
it('should delete Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.delete()
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
should.equal(doc.exists, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when value changes', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('doesn\'t call callback when the ref is updated with the same value', async () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('set()', () => {
|
||||
it('should create Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc2')
|
||||
.set({ name: 'doc2', testArray: [] })
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc2').get();
|
||||
doc.data().name.should.equal('doc2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('set()', () => {
|
||||
it('should merge Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.set({ merge: 'merge' }, { merge: true })
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('doc1');
|
||||
doc.data().merge.should.equal('merge');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('set()', () => {
|
||||
it('should overwrite Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.set({ name: 'overwritten' })
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('overwritten');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('update()', () => {
|
||||
it('should update Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.set({ name: 'updated' })
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default collectionReferenceTests;
|
||||
63
tests/src/tests/firestore/firestoreTests.js
Normal file
63
tests/src/tests/firestore/firestoreTests.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import should from 'should';
|
||||
|
||||
function firestoreTests({ describe, it, context, firebase }) {
|
||||
describe('firestore()', () => {
|
||||
context('collection()', () => {
|
||||
it('should create CollectionReference with the right id', () => {
|
||||
return new Promise((resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('collection1/doc1/collection2');
|
||||
should.equal(collectionRef.id, 'collection2');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('doc()', () => {
|
||||
it('should create DocumentReference with correct path', () => {
|
||||
return new Promise((resolve) => {
|
||||
const docRef = firebase.native.firestore().doc('collection1/doc1/collection2/doc2');
|
||||
should.equal(docRef.path, 'collection1/doc1/collection2/doc2');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('batch()', () => {
|
||||
it('should create / update / delete as expected', () => {
|
||||
const ayRef = firebase.native.firestore().collection('firestore-tests').doc('AY');
|
||||
const lRef = firebase.native.firestore().collection('firestore-tests').doc('LON');
|
||||
const nycRef = firebase.native.firestore().collection('firestore-tests').doc('NYC');
|
||||
const sfRef = firebase.native.firestore().collection('firestore-tests').doc('SF');
|
||||
|
||||
return firebase.native.firestore()
|
||||
.batch()
|
||||
.set(ayRef, { name: 'Aylesbury' })
|
||||
.set(lRef, { name: 'London' })
|
||||
.set(nycRef, { name: 'New York City' })
|
||||
.set(sfRef, { name: 'San Francisco' })
|
||||
.update(nycRef, { population: 1000000 })
|
||||
.update(sfRef, { name: 'San Fran' })
|
||||
.set(lRef, { population: 3000000 }, { merge: true })
|
||||
.delete(ayRef)
|
||||
.commit()
|
||||
.then(async () => {
|
||||
const ayDoc = await ayRef.get();
|
||||
should.equal(ayDoc.exists, false);
|
||||
|
||||
const lDoc = await lRef.get();
|
||||
lDoc.data().name.should.equal('London');
|
||||
lDoc.data().population.should.equal(3000000);
|
||||
|
||||
const nycDoc = await nycRef.get();
|
||||
nycDoc.data().name.should.equal('New York City');
|
||||
nycDoc.data().population.should.equal(1000000);
|
||||
|
||||
const sfDoc = await sfRef.get();
|
||||
sfDoc.data().name.should.equal('San Fran');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default firestoreTests;
|
||||
66
tests/src/tests/firestore/index.js
Normal file
66
tests/src/tests/firestore/index.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import firebase from '../../firebase';
|
||||
import TestSuite from '../../../lib/TestSuite';
|
||||
|
||||
/*
|
||||
Test suite files
|
||||
*/
|
||||
import collectionReferenceTests from './collectionReferenceTests';
|
||||
import documentReferenceTests from './documentReferenceTests';
|
||||
import firestoreTests from './firestoreTests';
|
||||
|
||||
const suite = new TestSuite('Firestore', 'firebase.firestore()', firebase);
|
||||
|
||||
const testGroups = [
|
||||
collectionReferenceTests,
|
||||
documentReferenceTests,
|
||||
firestoreTests,
|
||||
];
|
||||
|
||||
function firestoreTestSuite(testSuite) {
|
||||
testSuite.beforeEach(async () => {
|
||||
this.collectionTestsCollection = testSuite.firebase.native.firestore().collection('collection-tests');
|
||||
this.documentTestsCollection = testSuite.firebase.native.firestore().collection('document-tests');
|
||||
this.firestoreTestsCollection = testSuite.firebase.native.firestore().collection('firestore-tests');
|
||||
// Clean the collections in case the last run failed
|
||||
await cleanCollection(this.collectionTestsCollection);
|
||||
await cleanCollection(this.documentTestsCollection);
|
||||
await cleanCollection(this.firestoreTestsCollection);
|
||||
|
||||
await this.collectionTestsCollection.add({
|
||||
baz: true,
|
||||
daz: 123,
|
||||
foo: 'bar',
|
||||
gaz: 12.1234567,
|
||||
naz: null,
|
||||
});
|
||||
|
||||
await this.documentTestsCollection.doc('doc1').set({
|
||||
name: 'doc1',
|
||||
});
|
||||
});
|
||||
|
||||
testSuite.afterEach(async () => {
|
||||
await cleanCollection(this.collectionTestsCollection);
|
||||
await cleanCollection(this.documentTestsCollection);
|
||||
await cleanCollection(this.firestoreTestsCollection);
|
||||
});
|
||||
|
||||
testGroups.forEach((testGroup) => {
|
||||
testGroup(testSuite);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Register tests with test suite
|
||||
*/
|
||||
suite.addTests(firestoreTestSuite);
|
||||
|
||||
export default suite;
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
async function cleanCollection(collection) {
|
||||
const collectionTestsDocs = await collection.get();
|
||||
const tasks = [];
|
||||
collectionTestsDocs.forEach(doc => tasks.push(doc.ref.delete()));
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user