Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0177a9f1c2
|
@ -19,6 +19,9 @@ xcuserdata/
|
|||
# Crashlytics configuations
|
||||
android/com_crashlytics_export_strings.xml
|
||||
|
||||
# Signing files
|
||||
android/.signing/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
**/android/local.properties
|
||||
|
||||
|
@ -54,12 +57,24 @@ ehthumbs.db
|
|||
Thumbs.dbandroid/gradle
|
||||
android/gradlew
|
||||
android/build
|
||||
android/.gradle
|
||||
android/gradlew.bat
|
||||
android/gradle/
|
||||
.idea
|
||||
android/gradle
|
||||
lib/.watchmanconfig
|
||||
.idea
|
||||
coverage
|
||||
yarn.lock
|
||||
|
||||
tests/build
|
||||
tests/ios/Podfile.lock
|
||||
tests/android/app/build
|
||||
tests/ios/Pods
|
||||
tests/ios/Podfile.lock
|
||||
tests/firebase
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
|
||||
**/ios/Pods/**
|
||||
**/ios/ReactNativeFirebaseDemo.xcworkspace/
|
||||
|
||||
|
|
|
@ -61,3 +61,5 @@ docs
|
|||
coverage
|
||||
yarn.lock
|
||||
tests
|
||||
lib/.watchmanconfig
|
||||
|
||||
|
|
51
README.md
51
README.md
|
@ -1,4 +1,4 @@
|
|||
# React Native Firebase<img align="left" src="http://i.imgur.com/01XQL0x.png">
|
||||
# React Native Firebase<a href="https://invertase.io/react-native-firebase"><img align="left" src="http://i.imgur.com/01XQL0x.png"></a>
|
||||
|
||||
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/t6bdqMs)
|
||||
[![Gitter](https://badges.gitter.im/invertase/react-native-firebase.svg)](https://gitter.im/invertase/react-native-firebase?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
@ -6,15 +6,19 @@
|
|||
[![License](https://img.shields.io/npm/l/react-native-firebase.svg)](/LICENSE)
|
||||
|
||||
**RNFirebase** makes using [Firebase](http://firebase.com) with React Native simple.
|
||||
|
||||
> [Documentation](https://invertase.io/react-native-firebase)
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
### Install
|
||||
```
|
||||
```bash
|
||||
npm i react-native-firebase --save
|
||||
```
|
||||
|
||||
#### Platform specific setup guides:
|
||||
[![ios](https://a.fsdn.com/sd/topics/ios_64.png)](docs/installation.ios.md) [![android](https://a.fsdn.com/sd/topics/android_64.png)](docs/installation.android.md)
|
||||
[![ios](https://a.fsdn.com/sd/topics/ios_64.png)](http://invertase.io/react-native-firebase/#/installation-ios) [![android](https://a.fsdn.com/sd/topics/android_64.png)](http://invertase.io/react-native-firebase/#/installation-android)
|
||||
|
||||
<hr>
|
||||
|
||||
|
@ -30,47 +34,6 @@ The native SDKs also allow us to hook into device sdk's which are not possible w
|
|||
|
||||
<hr>
|
||||
|
||||
### Test app
|
||||
|
||||
To help ensure changes and features work across both iOS & Android, we've developed an app specifically to test `react-native-firebase` against the [`firebase` web SDK](https://www.npmjs.com/package/firebase). Please see the [`tests`](tests/README.md) directory for more information.
|
||||
|
||||
<hr>
|
||||
|
||||
### Examples app
|
||||
|
||||
There's currently a work in progress [examples app](https://github.com/invertase/react-native-firebase-examples) which aims to demonstrate various real world use-case scenarios with React Native & Firebase. We welcome any new examples or updates to existing ones.
|
||||
|
||||
<hr>
|
||||
|
||||
### Documentation
|
||||
|
||||
RNFirebase aims to replicate the Firebase Web SDK as closely as possible. Because of this, the documentation focuses around the installation, differences & best practices of this library. Please see the [Firebase Web SDK](https://firebase.google.com/docs/reference/js/) documentation for Firebase functionality.
|
||||
|
||||
> If you find any discrepancies between the two libraries, please raise an issue or PR.
|
||||
|
||||
* [Firebase Setup](docs/firebase-setup.md)
|
||||
* API
|
||||
* [Authentication](docs/api/authentication.md)
|
||||
* [Realtime Database](docs/api/database.md)
|
||||
* [Analytics](docs/api/analytics.md)
|
||||
* [Storage](docs/api/storage.md)
|
||||
* [Messaging](docs/api/cloud-messaging.md)
|
||||
* [Crash](docs/api/crash.md)
|
||||
* [Transactions](docs/api/transactions.md)
|
||||
* [FAQs / Troubleshooting](docs/faqs.md)
|
||||
|
||||
<hr>
|
||||
|
||||
### Contributing
|
||||
|
||||
We welcome any contribution to the repository. Please ensure your changes to the JavaScript code follow the styling guides controlled by ESlint. Changes to native code should be kept clean and follow the standard of existing code.
|
||||
|
||||
Changes to existing code should ensure all relevant tests on the test app pass. Any new features should have new tests created and ensure all existing tests pass.
|
||||
|
||||
**Project board:** https://github.com/invertase/react-native-firebase/projects
|
||||
|
||||
<hr>
|
||||
|
||||
### License
|
||||
|
||||
- MIT
|
||||
|
|
|
@ -6,7 +6,7 @@ Pod::Spec.new do |s|
|
|||
s.version = package["version"]
|
||||
s.summary = package["description"]
|
||||
s.description = <<-DESC
|
||||
Wanna integrate firebase into your app using React Native?
|
||||
Integrate firebase into your app using the React Native SDKs.
|
||||
DESC
|
||||
s.homepage = "http://invertase.io"
|
||||
s.license = package['license']
|
||||
|
@ -16,11 +16,4 @@ Pod::Spec.new do |s|
|
|||
s.platform = :ios, "8.0"
|
||||
s.preserve_paths = 'README.md', 'package.json', '*.js'
|
||||
s.source_files = 'ios/RNFirebase/*.{h,m}'
|
||||
s.dependency 'React'
|
||||
s.dependency 'Firebase/Auth'
|
||||
s.dependency 'Firebase/Core'
|
||||
s.dependency 'Firebase/Database'
|
||||
s.dependency 'Firebase/Messaging'
|
||||
s.dependency 'Firebase/RemoteConfig'
|
||||
s.dependency 'Firebase/Storage'
|
||||
end
|
||||
|
|
|
@ -213,7 +213,7 @@ public class RNFirebaseDatabaseReference {
|
|||
query = query.orderByChild(key);
|
||||
}
|
||||
} else if ("limit".equals(type)) {
|
||||
int limit = (Integer) modifier.get("limit");
|
||||
int limit = ((Double)modifier.get("limit")).intValue();
|
||||
if ("limitToLast".equals(name)) {
|
||||
query = query.limitToLast(limit);
|
||||
} else if ("limitToFirst".equals(name)) {
|
||||
|
@ -249,46 +249,46 @@ public class RNFirebaseDatabaseReference {
|
|||
if ("number".equals(valueType)) {
|
||||
double value = (Double) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.endAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.endAt(value, key);
|
||||
}
|
||||
} else if ("boolean".equals(valueType)) {
|
||||
boolean value = (Boolean) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.endAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.endAt(value, key);
|
||||
}
|
||||
} else if ("string".equals(valueType)) {
|
||||
String value = (String) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.endAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.endAt(value, key);
|
||||
}
|
||||
}
|
||||
} else if ("startAt".equals(name)) {
|
||||
if ("number".equals(valueType)) {
|
||||
double value = (Double) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.startAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.startAt(value, key);
|
||||
}
|
||||
} else if ("boolean".equals(valueType)) {
|
||||
boolean value = (Boolean) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.startAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.startAt(value, key);
|
||||
}
|
||||
} else if ("string".equals(valueType)) {
|
||||
String value = (String) modifier.get("value");
|
||||
if (key == null) {
|
||||
query = query.equalTo(value);
|
||||
query = query.startAt(value);
|
||||
} else {
|
||||
query = query.equalTo(value, key);
|
||||
query = query.startAt(value, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
<h1 align="center">
|
||||
<img src="https://camo.githubusercontent.com/6c827e5a0bb91259f82a1f4923ab7efa4891b119/687474703a2f2f692e696d6775722e636f6d2f303158514c30782e706e67"/><br>
|
||||
|
||||
React Native Firebase
|
||||
</h1>
|
||||
|
||||
<div style="text-align: center;">
|
||||
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/t6bdqMs)
|
||||
[![Gitter](https://badges.gitter.im/invertase/react-native-firebase.svg)](https://gitter.im/invertase/react-native-firebase?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[![npm version](https://img.shields.io/npm/v/react-native-firebase.svg)](https://www.npmjs.com/package/react-native-firebase)
|
||||
[![License](https://img.shields.io/npm/l/react-native-firebase.svg)](/LICENSE)
|
||||
<br />
|
||||
A well tested Firebase implementation for React Native, supporting both iOS & Android apps.
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
RNFirebase is a _light-weight_ layer sitting on-top of the native Firebase libraries for both iOS and Android which mirrors the Firebase Web SDK as closely as possible.
|
||||
|
||||
Although the [Firebase Web SDK](https://www.npmjs.com/package/firebase) library will work with React Native, it is mainly built for the web.
|
||||
|
||||
RNFirebase provides a JavaScript bridge to the native Firebase SDKs for both iOS and Android. Firebase will run on the native thread, allowing the rest of your app to run on the [JS thread](https://facebook.github.io/react-native/docs/performance.html#javascript-frame-rate). The Firebase Web SDK also runs on the JS thread, therefore potentially affecting the frame rate causing jank with animations, touch events etc. All in all, RNFirebase provides much faster performance (~2x) over the web SDK.
|
||||
|
||||
The native SDKs also allow us to hook into device sdk's which are not possible with the web SDK, for example crash reporting, offline realtime database support, analyics and more!
|
|
@ -0,0 +1,25 @@
|
|||
- Getting started
|
||||
- [Installation - iOS](/installation-ios)
|
||||
- [Installation - Android](/installation-android)
|
||||
- [Firebase Setup](/firebase-setup.md)
|
||||
- [Usage](/usage)
|
||||
|
||||
- Contributing
|
||||
- [Guidelines](/contributing/guidelines)
|
||||
- [Testing](/contributing/testing)
|
||||
|
||||
- Modules
|
||||
- [Authentication](/modules/authentication)
|
||||
- [Realtime Database](/modules/database)
|
||||
- [Analytics](/modules/analytics)
|
||||
- [Storage](/modules/storage)
|
||||
- [Cloud Messaging](/modules/cloud-messaging)
|
||||
- [Crash Reporting](/modules/crash)
|
||||
- [Transactions](/modules/transactions)
|
||||
|
||||
- Other
|
||||
- [Project Board](https://github.com/invertase/react-native-firebase/projects)
|
||||
- [FAQs / Troubleshooting](/faqs)
|
||||
- [Examples](https://github.com/invertase/react-native-firebase-examples)
|
||||
- [Chat](https://discord.gg/t6bdqMs)
|
||||
- [Gitter](https://gitter.im/invertase/react-native-firebase)
|
|
@ -1 +0,0 @@
|
|||
# Remote Config
|
|
@ -1,23 +0,0 @@
|
|||
# Transactions
|
||||
|
||||
Transactions are currently an experimental feature as they can not be integrated as easily as the other Firebase features. Please see the [Firebase documentation](https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction) for full implemtation details.
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
const ref = firebase.database().ref('user/posts');
|
||||
|
||||
ref.transaction((posts) => {
|
||||
return (posts || 0) + 1;
|
||||
}, (error, committed, snapshot) => {
|
||||
if (error) {
|
||||
console.log('Something went wrong', error);
|
||||
} else if (!committed) {
|
||||
console.log('Aborted'); // Returning undefined will trigger this
|
||||
} else {
|
||||
console.log('User posts incremented by 1');
|
||||
}
|
||||
|
||||
console.log('User posts is now: ', snapshot.val());
|
||||
});
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
# Guidelines
|
||||
|
||||
We welcome any contribution to the repository. Please ensure your changes to the JavaScript code follow the styling guides controlled by ESlint. Changes to native code should be kept clean and follow the standard of existing code.
|
||||
|
||||
Changes to existing code should ensure all relevant tests on the test app pass. Any new features should have new tests created and ensure all existing tests pass.
|
|
@ -0,0 +1,3 @@
|
|||
# Testing
|
||||
|
||||
|
12
docs/faqs.md
12
docs/faqs.md
|
@ -1,6 +1,6 @@
|
|||
# FAQs / Troubleshooting
|
||||
|
||||
### Comparison to Firestack
|
||||
## Comparison to Firestack
|
||||
|
||||
Firestack was a great start to integrating Firebase and React Native, however has underlying issues which needed to be fixed.
|
||||
A V3 fork of Firestack was created to help address issues such as lack of standardisation with the Firebase Web SDK,
|
||||
|
@ -10,7 +10,7 @@ too large to manage on the existing repository, whilst trying to maintain backwa
|
|||
RNFirebase was re-written from the ground up, addressing these issues with core focus being around matching the Web SDK as
|
||||
closely as possible and fixing the major bugs/issues along the way.
|
||||
|
||||
### How do I integrate Redux with RNFirebase
|
||||
## How do I integrate Redux with RNFirebase
|
||||
|
||||
As every project has different requirements & structure, RNFirebase *currently* has no built in methods for Redux integration.
|
||||
As RNFirebase can be used outside of a Components context, you do have free reign to integrate it as you see fit. For example,
|
||||
|
@ -42,7 +42,7 @@ export function onAuthStateChanged() {
|
|||
}
|
||||
```
|
||||
|
||||
### [Android] Google Play Services related issues
|
||||
## [Android] Google Play Services related issues
|
||||
|
||||
The firebase SDK requires a certain version of Google Play Services installed on Android in order to function properly.
|
||||
|
||||
|
@ -68,7 +68,7 @@ party emulator such as GenyMotion.
|
|||
Using this kind of workaround with Google Play Services can be problematic, so we
|
||||
recommend using the native Android Studio emulators to reduce the chance of these complications.
|
||||
|
||||
### [Android] Turning off Google Play Services availability errors
|
||||
## [Android] Turning off Google Play Services availability errors
|
||||
|
||||
G.P.S errors can be turned off using a config option like so:
|
||||
|
||||
|
@ -79,7 +79,7 @@ const firebase = RNFirebase.initializeApp({
|
|||
```
|
||||
This will stop your app from immediately red-boxing or crashing, but won't solve the underlying issue of G.P.S not being available or of the correct version. This will mean certain functionalities won't work properly and your app may even crash.
|
||||
|
||||
### [Android] Checking for Google Play Services availability with React Native Firebase
|
||||
## [Android] Checking for Google Play Services availability with React Native Firebase
|
||||
|
||||
React Native Firebase actually has a useful helper object for checking G.P.S availability:
|
||||
|
||||
|
@ -109,7 +109,7 @@ This error will match the messages and error codes mentioned above, and can be f
|
|||
https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult#SERVICE_VERSION_UPDATE_REQUIRED
|
||||
|
||||
|
||||
### [Android] Duplicate Dex Files error (build time error)
|
||||
## [Android] Duplicate Dex Files error (build time error)
|
||||
|
||||
A common build time error when using libraries that require google play services is of the form:
|
||||
'Failed on android with com.android.dex.DexException: Multiple dex files... '
|
||||
|
|
|
@ -4,51 +4,17 @@ The RNFirebase library is intended on making it easy to work with [Firebase](htt
|
|||
|
||||
To add Firebase to your project, make sure to create a project in the [Firebase console](https://firebase.google.com/console)
|
||||
|
||||
![Create a new project](http://d.pr/i/17cJ2.png)
|
||||
![Create a new project](https://i.imgur.com/KbbamwD.png)
|
||||
|
||||
Each platform uses a different setup method after creating the project.
|
||||
|
||||
## iOS
|
||||
|
||||
See the [ios setup guide](./installation.ios.md).
|
||||
For iOS, ensure you've followed the instructions provided by Firebase; adding your [GoogleService-Info.plist](https://github.com/invertase/react-native-firebase/blob/master/tests/ios/GoogleService-Info.plist)
|
||||
file to the project, and [configuring your AppDelegate](https://github.com/invertase/react-native-firebase/blob/master/tests/ios/ReactNativeFirebaseDemo/AppDelegate.m#L20).
|
||||
|
||||
## Android
|
||||
|
||||
See the [android setup guide](./installation.android.md).
|
||||
|
||||
## Usage
|
||||
|
||||
After creating a Firebase project and installing the library, we can use it in our project by importing the library in our JavaScript:
|
||||
|
||||
```javascript
|
||||
import RNFirebase from 'react-native-firebase'
|
||||
```
|
||||
|
||||
We need to tell the Firebase library we want to _configure_ the project. RNFirebase provides a way to configure both the native and the JavaScript side of the project at the same time with a single command:
|
||||
|
||||
```javascript
|
||||
const firebase = RNFirebase.initializeApp({
|
||||
// config options
|
||||
});
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| option | type | Default Value | Description |
|
||||
|----------------|----------|-------------------------|----------------------------------------|
|
||||
| debug | bool | false | When set to true, RNFirebase will log messages to the console and fire `debug` events we can listen to in `js` |
|
||||
| persistence | bool | false | When set to true, database persistence will be enabled. |
|
||||
|
||||
For instance:
|
||||
|
||||
```javascript
|
||||
import RNFirebase from 'react-native-firebase';
|
||||
|
||||
const configurationOptions = {
|
||||
debug: true
|
||||
};
|
||||
|
||||
const firebase = RNFirebase.initializeApp(configurationOptions);
|
||||
|
||||
export default firebase;
|
||||
```
|
||||
For Android, ensure you've followed the instructions provided by Firebase; adding your [google-services.json](https://github.com/invertase/react-native-firebase/blob/master/tests/android/app/google-services.json)
|
||||
file to the project, installing the [google-services](https://github.com/invertase/react-native-firebase/blob/master/tests/android/build.gradle#L9)
|
||||
plugin and applying **at the end** of your [`build.gradle`](https://github.com/invertase/react-native-firebase/blob/master/tests/android/app/build.gradle#L144).
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>react-native-firebase - A react native firebase library supporting both android and ios native firebase SDK's</title>
|
||||
<meta name="description" content="A react native firebase library supporting both android and ios native firebase SDK's">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="shortcut icon" type="image/png" href="https://camo.githubusercontent.com/6c827e5a0bb91259f82a1f4923ab7efa4891b119/687474703a2f2f692e696d6775722e636f6d2f303158514c30782e706e67"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'react-native-firebase',
|
||||
repo: 'https://github.com/invertase/react-native-firebase',
|
||||
loadSidebar: true,
|
||||
search: 'auto',
|
||||
themeColor: '#f5820b',
|
||||
subMaxLevel: 2,
|
||||
maxLevel: 4,
|
||||
ga: 'UA-98196653-1',
|
||||
plugins: [
|
||||
function (hook) {
|
||||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer>',
|
||||
`<span>Caught a mistake or want to contribute to the documentation? <a href="https://github.com/invertase/react-native-firebase/tree/master/docs" target="_blank">Edit documentation on Github!</a>.</span>`,
|
||||
'</footer>'
|
||||
].join('');
|
||||
|
||||
hook.afterEach(function (html) {
|
||||
return html + footer
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-javascript.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-swift.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-objectivec.min.js"></script>
|
||||
</html>
|
|
@ -1,6 +1,6 @@
|
|||
# Android Installation
|
||||
|
||||
### 1 - Setup google-services.json
|
||||
## 1) Setup google-services.json
|
||||
Download the `google-services.json` file provided by Firebase in the _Add Firebase to Android_ platform menu in your Firebase configuration console. This file should be downloaded to `YOUR_PROJECT/android/app/google-services.json`.
|
||||
|
||||
Next you'll have to add the google-services gradle plugin in order to parse it.
|
||||
|
@ -23,7 +23,7 @@ In your app build.gradle file, add the gradle plugin at the VERY BOTTOM of the f
|
|||
apply plugin: 'com.google.gms.google-services'
|
||||
```
|
||||
|
||||
### 2 - Link RNFirebase
|
||||
## 2) Link RNFirebase
|
||||
|
||||
To install `react-native-firebase` in your project, you'll need to import the package from `io.invertase.firebase` in your project's `android/app/src/main/java/com/[app name]/MainApplication.java` and list it as a package for ReactNative in the `getPackages()` function:
|
||||
|
||||
|
@ -61,7 +61,7 @@ include ':react-native-firebase'
|
|||
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
|
||||
```
|
||||
|
||||
### 3 - Cloud Messaging (optional)
|
||||
## 3) Cloud Messaging (optional)
|
||||
|
||||
If you plan on using [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/), add the following to `android/app/src/main/AndroidManifest.xml`.
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
## iOS Installation
|
||||
# iOS Installation
|
||||
|
||||
### 1 - Setup google-services.plist and dependencies
|
||||
## 1) Setup google-services.plist and dependencies
|
||||
Setup the `google-services.plist` file and Firebase ios frameworks first; check out the relevant Firebase docs [here](https://firebase.google.com/docs/ios/setup#frameworks).
|
||||
|
||||
#### 1.1 - Initialisation
|
||||
### 1.1) Initialisation
|
||||
Make sure you've added the following to the top of your `ios/[YOUR APP NAME]]/AppDelegate.m` file:
|
||||
|
||||
`#import <Firebase.h>`
|
||||
|
@ -12,10 +12,11 @@ and this to the `didFinishLaunchingWithOptions:(NSDictionary *)launchOptions` me
|
|||
|
||||
`[FIRApp configure];`
|
||||
|
||||
### 2 - Link RNFirebase
|
||||
## 2) Link RNFirebase
|
||||
|
||||
There are multiple ways to install RNFirebase depending on how your project is currently setup:
|
||||
|
||||
#### 2.1 - Existing Cocoapods setup, including React Native as a pod
|
||||
### 2.1) You already use Cocoapods and have React Native installed as a pod
|
||||
Simply add the following to your `Podfile`:
|
||||
|
||||
```ruby
|
||||
|
@ -33,25 +34,27 @@ pod 'Firebase/Storage'
|
|||
pod 'RNFirebase', :path => '../node_modules/react-native-firebase'
|
||||
```
|
||||
|
||||
#### 2.2 - Via react-native-cli link
|
||||
### 2.2) You're not using Cocoapods or don't have React Native installed as a pod (Automatic install)
|
||||
|
||||
React native ships with a `link` command that can be used to link the projects together, which can help automate the process of linking our package environments.
|
||||
|
||||
```bash
|
||||
react-native link react-native-firebase
|
||||
```
|
||||
|
||||
#### cocoapods
|
||||
|
||||
We've automated the process of setting up with cocoapods. This will happen automatically upon linking the package with `react-native-cli`.
|
||||
|
||||
Update the newly installed pods once the linking is done:
|
||||
|
||||
```bash
|
||||
cd ios && pod update --verbose
|
||||
```
|
||||
|
||||
##### cocoapods
|
||||
We've automated the process of setting up with cocoapods. This will happen automatically upon linking the package with `react-native-cli`.
|
||||
**NOTE: You need to use the `ios/[YOUR APP NAME].xcworkspace` instead of the `ios/[YOUR APP NAME].xcproj` file from now on.**
|
||||
|
||||
**Remember to use the `ios/[YOUR APP NAME].xcworkspace` instead of the `ios/[YOUR APP NAME].xcproj` file from now on**.
|
||||
|
||||
#### 2.3 - Manually
|
||||
### 2.3) You're not using Cocoapods or don't have React Native installed as a pod (Manual install)
|
||||
|
||||
If you prefer not to use `react-native link`, we can manually link the package together with the following steps, after `npm install`:
|
||||
|
||||
|
@ -90,4 +93,70 @@ pod 'Firebase/RemoteConfig'
|
|||
pod 'Firebase/Storage'
|
||||
```
|
||||
|
||||
Then you can run `(cd ios && pod install)` to get the pods opened. If you do use this route, remember to use the `.xcworkspace` file.
|
||||
Then you can run `(cd ios && pod install)` to get the pods opened.
|
||||
|
||||
**NOTE: You need to use the `ios/[YOUR APP NAME].xcworkspace` instead of the `ios/[YOUR APP NAME].xcproj` file from now on.**
|
||||
|
||||
## 3) Cloud Messaging (optional)
|
||||
|
||||
If you plan on using [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) then, you need to:
|
||||
|
||||
**NOTE: FCM does not work on the iOS simulator, you must test is using a real device. This is a restriction enforced by Apple for some unknown reason.**
|
||||
|
||||
### 3.1) Set up certificates
|
||||
|
||||
Follow the instructions at https://firebase.google.com/docs/cloud-messaging/ios/certs
|
||||
|
||||
### 3.2) Enable capabilities
|
||||
|
||||
In Xcode, enable the following capabilities:
|
||||
|
||||
1) Push Notifications
|
||||
2) Background modes > Remove notifications
|
||||
|
||||
### 3.3) Update `AppDelegate.h`
|
||||
|
||||
Add the following import:
|
||||
|
||||
`@import UserNotifications;`
|
||||
|
||||
Change the interface descriptor to:
|
||||
|
||||
`@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>`
|
||||
|
||||
### 3.4) Update `AppDelegate.m`
|
||||
|
||||
Add the following import:
|
||||
|
||||
`#import "RNFirebaseMessaging.h"`
|
||||
|
||||
Add the following to the `didFinishLaunchingWithOptions:(NSDictionary *)launchOptions` method after `[FIRApp Configure]`:
|
||||
|
||||
`[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];`
|
||||
|
||||
Add the following methods:
|
||||
|
||||
```objectivec
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
||||
willPresentNotification:(UNNotification *)notification
|
||||
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
|
||||
{
|
||||
[RNFirebaseMessaging willPresentNotification:notification withCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
||||
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
||||
withCompletionHandler:(void (^)())completionHandler
|
||||
{
|
||||
[RNFirebaseMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
|
||||
[RNFirebaseMessaging didReceiveLocalNotification:notification];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
|
||||
[RNFirebaseMessaging didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
```
|
|
@ -1,6 +1,6 @@
|
|||
# Cloud Messaging
|
||||
|
||||
Firebase Cloud Messaging ([FCM](https://firebase.google.com/docs/cloud-messaging/)) allows you to send push messages at no
|
||||
Firebase Cloud Messaging ([FCM](https://firebase.google.com/docs/cloud-messaging/)) allows you to send push messages at no
|
||||
cost to both Android & iOS platforms. Assuming the installation instructions have been followed, FCM is ready to go.
|
||||
|
||||
As the Firebase Web SDK has limited messaging functionality, the following methods within `react-native-firebase` have been
|
||||
|
@ -26,7 +26,7 @@ firebase.messaging().unsubscribeFromTopic('foobar');
|
|||
|
||||
### getInitialNotification(): `Promise<Object>`
|
||||
|
||||
When the application has been opened from a notification `getInitialNotification` is called and the notification payload
|
||||
When the application has been opened from a notification `getInitialNotification` is called and the notification payload
|
||||
is returned. Use `onMessage` for notifications when the app is running.
|
||||
|
||||
```javascript
|
|
@ -4,7 +4,7 @@ RNFirebase provides crash reporting for your app out of the box. Please note cra
|
|||
|
||||
## Manual Crash Reporting
|
||||
|
||||
If you want to manually report a crash, such as a pre-caught exception this is possible by using the `report` method.
|
||||
If you want to manually report a crash, such as a pre-caught exception this is possible by using the `report` method.
|
||||
|
||||
```javascript
|
||||
try {
|
|
@ -72,7 +72,7 @@ class MyComponent extends Component {
|
|||
|
||||
### Reading data
|
||||
|
||||
Firstack allows the database instance to [persist on disk](https://firebase.google.com/docs/database/android/offline-capabilities) if enabled.
|
||||
Firebase allows the database instance to [persist on disk](https://firebase.google.com/docs/database/android/offline-capabilities) if enabled.
|
||||
To enable database persistence, pass the configuration option `persistence` before calls are made:
|
||||
|
||||
```javascript
|
||||
|
@ -181,7 +181,7 @@ class ToDos extends Component {
|
|||
#### Differences between `.on` & `.once`
|
||||
|
||||
With persistence enabled, any calls to a ref with `.once` will always read the data from disk and not contact the server.
|
||||
On behavious differently, by first checking for a connection and if none exists returns the persisted data. If it successfully connects
|
||||
On behaves differently, by first checking for a connection and if none exists returns the persisted data. If it successfully connects
|
||||
to the server, the new data will be returned and the disk data will be updated.
|
||||
|
||||
The database refs has a `keepSynced()` function to tell the RNFirebase library to keep the data at the `ref` in sync.
|
|
@ -3,8 +3,6 @@
|
|||
RNFirebase mimics the [Web Firebase SDK Storage](https://firebase.google.com/docs/storage/web/start), whilst
|
||||
providing some iOS and Android specific functionality.
|
||||
|
||||
All Storage operations are accessed via `storage()`.
|
||||
|
||||
## Uploading files
|
||||
|
||||
### Simple
|
|
@ -0,0 +1,38 @@
|
|||
# Transactions
|
||||
|
||||
!> Transactions is currently an experimental feature in RNFirebase. Whilst it does work there may still be some issues with it, especially around offline connectivity handling. Please report any issues in the usual manner.
|
||||
|
||||
|
||||
?> For help on how to use firebase transactions please see the [Firebase Transaction Documentation](https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction).
|
||||
|
||||
### Android Implementation
|
||||
|
||||
The [android implementation](https://github.com/invertase/react-native-firebase/blob/master/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java) makes use of [Condition](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html) and [ReentrantLock](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html) locks to handle transactions across the React Native Bridge.
|
||||
|
||||
|
||||
### iOS Implementation
|
||||
|
||||
The [iOS implementation](https://github.com/invertase/react-native-firebase/blob/master/ios/RNFirebase/RNFirebaseDatabase.m#L279) makes use of GCD (Grand Central Dispatch) to handle transactions across the React Native Bridge without blocking the application thread. Check out [this](https://mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html) post for some 'light' reading about it.
|
||||
|
||||
!> Transactions that receive no response from react native's JS thread within 30 seconds are automatically aborted - this value is currently not configurable - PR welcome.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
const ref = firebase.database().ref('user/posts');
|
||||
|
||||
ref.transaction((posts) => {
|
||||
return (posts || 0) + 1;
|
||||
}, (error, committed, snapshot) => {
|
||||
if (error) {
|
||||
console.log('Something went wrong', error);
|
||||
} else if (!committed) {
|
||||
console.log('Aborted'); // Returning undefined will trigger this
|
||||
} else {
|
||||
console.log('User posts incremented by 1');
|
||||
}
|
||||
|
||||
console.log('User posts is now: ', snapshot.val());
|
||||
});
|
||||
```
|
|
@ -0,0 +1,75 @@
|
|||
const RUNTIME = 'docsify'
|
||||
const HOSTNAME_WHITELIST = [
|
||||
self.location.hostname,
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'unpkg.com'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
const getFixedUrl = (req) => {
|
||||
var now = Date.now()
|
||||
var url = new URL(req.url)
|
||||
|
||||
// 1. fixed http URL
|
||||
// Just keep syncing with location.protocol
|
||||
// fetch(httpURL) belongs to active mixed content.
|
||||
// And fetch(httpRequest) is not supported yet.
|
||||
url.protocol = self.location.protocol
|
||||
|
||||
// 2. add query for caching-busting.
|
||||
// Github Pages served with Cache-Control: max-age=600
|
||||
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||
if (url.hostname === self.location.hostname) {
|
||||
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||
}
|
||||
return url.href
|
||||
}
|
||||
|
||||
/**
|
||||
* @Lifecycle Activate
|
||||
* New one activated when old isnt being used.
|
||||
*
|
||||
* waitUntil(): activating ====> activated
|
||||
*/
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
/**
|
||||
* @Functional Fetch
|
||||
* All network requests are being intercepted here.
|
||||
*
|
||||
* void respondWith(Promise<Response> r)
|
||||
*/
|
||||
self.addEventListener('fetch', event => {
|
||||
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||
// Stale-while-revalidate
|
||||
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||
const cached = caches.match(event.request)
|
||||
const fixedUrl = getFixedUrl(event.request)
|
||||
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||
|
||||
// Call respondWith() with whatever we get first.
|
||||
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||
// If there’s nothing in cache, wait for the fetch.
|
||||
// If neither yields a response, return offline pages.
|
||||
event.respondWith(
|
||||
Promise.race([fetched.catch(_ => cached), cached])
|
||||
.then(resp => resp || fetched)
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
|
||||
// Update the cache with the version we fetched (only for ok status)
|
||||
event.waitUntil(
|
||||
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
}
|
||||
})
|
|
@ -0,0 +1,36 @@
|
|||
# Usage
|
||||
|
||||
After creating a Firebase project and installing the library, we can use it in our project by importing the library in our JavaScript:
|
||||
|
||||
```javascript
|
||||
import RNFirebase from 'react-native-firebase'
|
||||
```
|
||||
|
||||
We need to tell the Firebase library we want to _configure_ the project. RNFirebase provides a way to configure both the native and the JavaScript side of the project at the same time with a single command:
|
||||
|
||||
```javascript
|
||||
const firebase = RNFirebase.initializeApp({
|
||||
// config options
|
||||
});
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| option | type | Default Value | Description |
|
||||
|----------------|----------|-------------------------|----------------------------------------|
|
||||
| debug | bool | false | When set to true, RNFirebase will log messages to the console and fire `debug` events we can listen to in `js` |
|
||||
| persistence | bool | false | When set to true, database persistence will be enabled. |
|
||||
|
||||
For instance:
|
||||
|
||||
```javascript
|
||||
import RNFirebase from 'react-native-firebase';
|
||||
|
||||
const configurationOptions = {
|
||||
debug: true
|
||||
};
|
||||
|
||||
const firebase = RNFirebase.initializeApp(configurationOptions);
|
||||
|
||||
export default firebase;
|
||||
```
|
71
ios/Podfile
71
ios/Podfile
|
@ -1,71 +0,0 @@
|
|||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
use_frameworks!
|
||||
platform :ios, '8.0'
|
||||
|
||||
def common_pods
|
||||
# pod 'RNFirebase', :path => '../'
|
||||
# pod 'React', :path => '../node_modules/react-native'
|
||||
[
|
||||
'Firebase',
|
||||
'Firebase/Core',
|
||||
'Firebase/Auth',
|
||||
'Firebase/Storage',
|
||||
'Firebase/Database',
|
||||
'Firebase/RemoteConfig',
|
||||
'Firebase/Messaging'
|
||||
].each do |lib|
|
||||
pod lib
|
||||
end
|
||||
end
|
||||
|
||||
def test_pods
|
||||
pod 'Quick', '~> 0.8.0'
|
||||
pod 'Nimble', '~> 3.0.0'
|
||||
end
|
||||
|
||||
def setup
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |configuration|
|
||||
# configuration.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
|
||||
# configuration.build_settings['CODE_SIGNING_REQUIRED'] = "YES"
|
||||
# configuration.build_settings['CODE_SIGNING_ALLOWED'] = "YES"
|
||||
|
||||
target.build_settings(configuration.name)['OTHER_LDFLAGS'] = '$(inherited)'
|
||||
target.build_settings(configuration.name)['USER_HEADER_SEARCH_PATHS'] = "$(BUILT_PRODUCTS_DIR)"
|
||||
target.build_settings(configuration.name)['LD_DYLIB_INSTALL_NAME'] = '@rpath/${EXECUTABLE_NAME}'
|
||||
target.build_settings(configuration.name)['LD_RUNPATH_SEARCH_PATHS'] = '$(inherited) @rpath @loader_path/../Frameworks @executable_path/Frameworks'
|
||||
|
||||
target.build_settings(configuration.name)['ONLY_ACTIVE_ARCH'] = 'NO'
|
||||
target.build_settings(configuration.name)['HEADER_SEARCH_PATHS'] = [
|
||||
"$(inherited)",
|
||||
"${PODS_ROOT}/Headers/**",
|
||||
"$(SRCROOT)/../../React/**",
|
||||
"$(SRCROOT)/../../react-native/React/**",
|
||||
'$(RN_ROOT)/React/**',
|
||||
'$(PODS_ROOT)/Headers'
|
||||
].join(' ')
|
||||
target.build_settings(configuration.name)['FRAMEWORK_SEARCH_PATHS'] = [
|
||||
"$(inherited)",
|
||||
'$(PODS_ROOT)/**',
|
||||
'$(PODS_CONFIGURATION_BUILD_DIR)/**'
|
||||
].join(' ')
|
||||
target.build_settings(configuration.name)['OTHER_LDFLAGS'] = "$(inherited)"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# target 'RNFirebase' do
|
||||
# common_pods
|
||||
# project "RNFirebase.xcodeproj"
|
||||
# setup
|
||||
# end
|
||||
|
||||
target 'RNFirebaseTests' do
|
||||
use_frameworks!
|
||||
common_pods
|
||||
test_pods
|
||||
pod 'React', :path => '../node_modules/react-native'
|
||||
setup
|
||||
end
|
|
@ -8,3 +8,4 @@ pod 'Firebase/DynamicLinks'
|
|||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
pod 'RNFirebase', :path => '../node_modules/react-native-firebase'
|
||||
|
|
|
@ -2,9 +2,21 @@
|
|||
#define RNFirebase_h
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RCTBridgeModule.h"
|
||||
#if __has_include(<React/RCTEventDispatcher.h>)
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventDispatcher.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTEventEmitter.h>)
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventEmitter.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebase : RCTEventEmitter <RCTBridgeModule> {
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#ifndef RNFirebaseAnalytics_h
|
||||
#define RNFirebaseAnalytics_h
|
||||
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseAnalytics : NSObject <RCTBridgeModule> {
|
||||
|
||||
|
|
|
@ -2,8 +2,16 @@
|
|||
#define RNFirebaseAuth_h
|
||||
|
||||
#import "Firebase.h"
|
||||
#if __has_include(<React/RCTEventEmitter.h>)
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventEmitter.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseAuth : RCTEventEmitter <RCTBridgeModule> {
|
||||
FIRAuthStateDidChangeListenerHandle authListenerHandle;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#ifndef RNFirebaseCrash_h
|
||||
#define RNFirebaseCrash_h
|
||||
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseCrash : NSObject <RCTBridgeModule> {
|
||||
|
||||
|
|
|
@ -2,8 +2,16 @@
|
|||
#define RNFirebaseDatabase_h
|
||||
|
||||
#import "Firebase.h"
|
||||
#if __has_include(<React/RCTEventEmitter.h>)
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventEmitter.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseDatabase : RCTEventEmitter <RCTBridgeModule> {
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#ifndef RNFirebaseErrors_h
|
||||
#define RNFirebaseErrors_h
|
||||
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
#import "Firebase.h"
|
||||
|
||||
@interface RNFirebaseErrors : NSObject <RCTBridgeModule> {
|
||||
|
|
|
@ -5,9 +5,22 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "Firebase.h"
|
||||
|
||||
#if __has_include(<React/RCTEventEmitter.h>)
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventEmitter.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTUtils.h>)
|
||||
#import <React/RCTUtils.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTUtils.h"
|
||||
#endif
|
||||
|
||||
@import UserNotifications;
|
||||
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
#import "RNFirebaseMessaging.h"
|
||||
|
||||
#import <React/RCTConvert.h>
|
||||
#if __has_include(<React/RCTEventDispatcher.h>)
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventDispatcher.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTConvert.h>)
|
||||
#import <React/RCTConvert.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTConvert.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTUtils.h>)
|
||||
#import <React/RCTUtils.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTUtils.h"
|
||||
#endif
|
||||
|
||||
@import UserNotifications;
|
||||
#import <FirebaseMessaging/FirebaseMessaging.h>
|
||||
|
@ -53,13 +65,13 @@ RCT_ENUM_CONVERTER(NSCalendarUnit,
|
|||
content.categoryIdentifier = [RCTConvert NSString:details[@"click_action"]];
|
||||
content.userInfo = details;
|
||||
content.badge = [RCTConvert NSNumber:details[@"badge"]];
|
||||
|
||||
|
||||
NSDate *fireDate = [RCTConvert NSDate:details[@"fire_date"]];
|
||||
|
||||
|
||||
if(fireDate == nil){
|
||||
return [UNNotificationRequest requestWithIdentifier:[RCTConvert NSString:details[@"id"]] content:content trigger:nil];
|
||||
}
|
||||
|
||||
|
||||
NSCalendarUnit interval = [RCTConvert NSCalendarUnit:details[@"repeat_interval"]];
|
||||
NSCalendarUnit unitFlags;
|
||||
switch (interval) {
|
||||
|
@ -177,12 +189,12 @@ RCT_EXPORT_MODULE()
|
|||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleNotificationReceived:)
|
||||
name:FCMNotificationReceived
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(disconnectFCM)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
|
@ -191,19 +203,19 @@ RCT_EXPORT_MODULE()
|
|||
selector:@selector(connectToFCM)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self selector:@selector(onTokenRefresh)
|
||||
name:kFIRInstanceIDTokenRefreshNotification object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self selector:@selector(sendDataMessageFailure:)
|
||||
name:FIRMessagingSendErrorNotification object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self selector:@selector(sendDataMessageSuccess:)
|
||||
name:FIRMessagingSendSuccessNotification object:nil];
|
||||
|
||||
|
||||
// For iOS 10 data message (sent via FCM)
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[FIRMessaging messaging] setRemoteMessageDelegate:self];
|
||||
|
@ -283,7 +295,7 @@ RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(R
|
|||
];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
}
|
||||
|
||||
|
@ -459,22 +471,22 @@ RCT_EXPORT_METHOD(finishNotificationResponse: (NSString *)completionHandlerId){
|
|||
self.notificationCallbacks[completionHandlerId] = completionHandler;
|
||||
data[@"_completionHandlerId"] = completionHandlerId;
|
||||
}
|
||||
|
||||
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:FCMNotificationReceived body:data];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)sendDataMessageFailure:(NSNotification *)notification
|
||||
{
|
||||
NSString *messageID = (NSString *)notification.userInfo[@"messageID"];
|
||||
|
||||
|
||||
NSLog(@"sendDataMessageFailure: %@", messageID);
|
||||
}
|
||||
|
||||
- (void)sendDataMessageSuccess:(NSNotification *)notification
|
||||
{
|
||||
NSString *messageID = (NSString *)notification.userInfo[@"messageID"];
|
||||
|
||||
|
||||
NSLog(@"sendDataMessageSuccess: %@", messageID);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,16 @@
|
|||
#define RNFirebaseStorage_h
|
||||
|
||||
#import "Firebase.h"
|
||||
#import "RCTBridgeModule.h"
|
||||
#if __has_include(<React/RCTEventEmitter.h>)
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTEventEmitter.h"
|
||||
#endif
|
||||
#if __has_include(<React/RCTBridgeModule.h>)
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#else // Compatibility for RN version < 0.40
|
||||
#import "RCTBridgeModule.h"
|
||||
#endif
|
||||
|
||||
@interface RNFirebaseStorage : RCTEventEmitter <RCTBridgeModule> {
|
||||
|
||||
|
|
|
@ -35,8 +35,10 @@ export default class Firebase {
|
|||
_crash: ?Object;
|
||||
|
||||
auth: Function;
|
||||
crash: Function;
|
||||
storage: Function;
|
||||
database: Function;
|
||||
analytics: Function;
|
||||
messaging: Function;
|
||||
|
||||
eventHandlers: Object;
|
||||
|
@ -79,6 +81,8 @@ export default class Firebase {
|
|||
this.storage = this._staticsOrInstance('storage', StorageStatics, Storage);
|
||||
this.database = this._staticsOrInstance('database', DatabaseStatics, Database);
|
||||
this.messaging = this._staticsOrInstance('messaging', MessagingStatics, Messaging);
|
||||
this.analytics = this._staticsOrInstance('analytics', {}, Analytics);
|
||||
this.crash = this._staticsOrInstance('crash', {}, Crash);
|
||||
|
||||
// init auth to start listeners
|
||||
this.auth();
|
||||
|
@ -107,20 +111,6 @@ export default class Firebase {
|
|||
return instances[name];
|
||||
}
|
||||
|
||||
analytics() {
|
||||
if (!this._analytics) {
|
||||
this._analytics = new Analytics(this);
|
||||
}
|
||||
return this._analytics;
|
||||
}
|
||||
|
||||
crash() {
|
||||
if (!this._crash) {
|
||||
this._crash = new Crash(this);
|
||||
}
|
||||
return this._crash;
|
||||
}
|
||||
|
||||
get apps(): Array<string> {
|
||||
return Object.keys(instances);
|
||||
}
|
||||
|
|
|
@ -83,7 +83,12 @@ export default class Database extends Base {
|
|||
* @param origCB
|
||||
* @returns {*}
|
||||
*/
|
||||
off(refId: number, listeners: Array<DatabaseListener>, remainingListenersCount: number) {
|
||||
off(
|
||||
refId: number,
|
||||
// $FlowFixMe
|
||||
listeners: Array<DatabaseListener>,
|
||||
remainingListenersCount: number
|
||||
) {
|
||||
this.log.debug('off() : ', refId, listeners);
|
||||
|
||||
// Delete the reference if there are no more listeners
|
||||
|
|
|
@ -151,23 +151,25 @@ export default class Reference extends ReferenceBase {
|
|||
*/
|
||||
off(eventName?: string = '', origCB?: () => any) {
|
||||
this.log.debug('ref.off(): ', this.refId, eventName);
|
||||
// $FlowFixMe
|
||||
const listeners: Array<DatabaseListener> = Object.values(this.listeners);
|
||||
let listenersToRemove;
|
||||
if (eventName && origCB) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
listenersToRemove = listeners.filter((listener) => {
|
||||
return listener.eventName === eventName && listener.successCallback === origCB;
|
||||
});
|
||||
// Only remove a single listener as per the web spec
|
||||
if (listenersToRemove.length > 1) listenersToRemove = [listenersToRemove[0]];
|
||||
} else if (eventName) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
listenersToRemove = listeners.filter((listener) => {
|
||||
return listener.eventName === eventName;
|
||||
});
|
||||
} else if (origCB) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
listenersToRemove = listeners.filter((listener) => {
|
||||
return listener.successCallback === origCB;
|
||||
});
|
||||
} else {
|
||||
listenersToRemove = Object.values(this.listeners);
|
||||
listenersToRemove = listeners;
|
||||
}
|
||||
// Remove the listeners from the reference to prevent memory leaks
|
||||
listenersToRemove.forEach((listener) => {
|
||||
|
@ -183,7 +185,7 @@ export default class Reference extends ReferenceBase {
|
|||
* @param onComplete
|
||||
* @param applyLocally
|
||||
*/
|
||||
transaction(transactionUpdate: Function, onComplete, applyLocally: boolean = false) {
|
||||
transaction(transactionUpdate: Function, onComplete: (?Error, boolean, ?Snapshot) => *, applyLocally: boolean = false) {
|
||||
if (!isFunction(transactionUpdate)) return Promise.reject(new Error('Missing transactionUpdate function argument.'));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
@ -80,7 +80,7 @@ export default class StorageReference extends ReferenceBase {
|
|||
* Alias to putFile
|
||||
* @returns {StorageReference.putFile}
|
||||
*/
|
||||
get put() {
|
||||
get put(): Function {
|
||||
return this.putFile;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ declare type UploadTaskSnapshotType = {
|
|||
downloadURL: string|null,
|
||||
metadata: Object, // TODO flow type def for https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata.html
|
||||
ref: StorageReference,
|
||||
state: StorageStatics.TaskState.RUNNING
|
||||
|StorageStatics.TaskState.PAUSED
|
||||
|StorageStatics.TaskState.SUCCESS
|
||||
|StorageStatics.TaskState.CANCELLED
|
||||
|StorageStatics.TaskState.ERROR,
|
||||
state: (
|
||||
typeof StorageStatics.TaskState.RUNNING
|
||||
| typeof StorageStatics.TaskState.PAUSED
|
||||
| typeof StorageStatics.TaskState.SUCCESS
|
||||
| typeof StorageStatics.TaskState.CANCELLED
|
||||
| typeof StorageStatics.TaskState.ERROR
|
||||
),
|
||||
task: StorageTask,
|
||||
totalBytes: number,
|
||||
};
|
||||
|
@ -24,15 +26,26 @@ declare type FuncSnapshotType = null|(snapshot: UploadTaskSnapshotType) => any;
|
|||
|
||||
declare type FuncErrorType = null|(error: Error) => any;
|
||||
|
||||
declare type NextOrObserverType = null
|
||||
|{ next?: FuncSnapshotType, error?: FuncErrorType, complete?:FuncSnapshotType }
|
||||
|FuncSnapshotType;
|
||||
declare type NextOrObserverType = null |
|
||||
{
|
||||
next?: FuncSnapshotType,
|
||||
error?: FuncErrorType,
|
||||
complete?:FuncSnapshotType
|
||||
} |
|
||||
FuncSnapshotType;
|
||||
|
||||
/**
|
||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask
|
||||
*/
|
||||
export default class StorageTask {
|
||||
constructor(type: UPLOAD_TASK|DOWNLOAD_TASK, promise: Promise, storageRef: StorageReference) {
|
||||
type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK
|
||||
ref: StorageReference
|
||||
storage: StorageReference.storage
|
||||
path: StorageReference.path
|
||||
then: Promise<*>
|
||||
catch: () => Promise<*>
|
||||
|
||||
constructor(type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK, promise: Promise<*>, storageRef: StorageReference) {
|
||||
this.type = type;
|
||||
this.ref = storageRef;
|
||||
this.storage = storageRef.storage;
|
||||
|
@ -49,13 +62,13 @@ export default class StorageTask {
|
|||
* @returns {Promise.<T>}
|
||||
* @private
|
||||
*/
|
||||
_interceptSnapshotEvent(f: Function|null|undefined): null|() => any {
|
||||
_interceptSnapshotEvent(f: ?Function): null | () => * {
|
||||
if (!isFunction(f)) return null;
|
||||
return (snapshot) => {
|
||||
const _snapshot = Object.assign({}, snapshot);
|
||||
_snapshot.task = this;
|
||||
_snapshot.ref = this.ref;
|
||||
return f(_snapshot);
|
||||
return f && f(_snapshot);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -65,12 +78,13 @@ export default class StorageTask {
|
|||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
_interceptErrorEvent(f: Function|null|undefined): null|() => any {
|
||||
_interceptErrorEvent(f: ?Function): null | (Error) => * {
|
||||
if (!isFunction(f)) return null;
|
||||
return (error) => {
|
||||
const _error = new Error(error.message);
|
||||
// $FlowFixMe
|
||||
_error.code = error.code;
|
||||
return f(_error);
|
||||
return f && f(_error);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -83,15 +97,41 @@ export default class StorageTask {
|
|||
* @private
|
||||
*/
|
||||
_subscribe(nextOrObserver: NextOrObserverType, error: FuncErrorType, complete: FuncSnapshotType): Function {
|
||||
const observer = isObject(nextOrObserver);
|
||||
let _error;
|
||||
let _next;
|
||||
let _complete;
|
||||
|
||||
const _error = this._interceptErrorEvent(observer ? nextOrObserver.error : error);
|
||||
const _next = this._interceptSnapshotEvent(observer ? nextOrObserver.next : nextOrObserver);
|
||||
const _complete = this._interceptSnapshotEvent(observer ? nextOrObserver.complete : complete);
|
||||
if (typeof nextOrObserver === 'function') {
|
||||
_error = this._interceptErrorEvent(error);
|
||||
_next = this._interceptSnapshotEvent(nextOrObserver);
|
||||
_complete = this._interceptSnapshotEvent(complete);
|
||||
} else if (nextOrObserver) {
|
||||
_error = this._interceptErrorEvent(nextOrObserver.error);
|
||||
_next = this._interceptSnapshotEvent(nextOrObserver.next);
|
||||
_complete = this._interceptSnapshotEvent(nextOrObserver.complete);
|
||||
}
|
||||
|
||||
if (_next) this.storage._addListener(this.path, StorageStatics.TaskEvent.STATE_CHANGED, _next);
|
||||
if (_error) this.storage._addListener(this.path, `${this.type}_failure`, _error);
|
||||
if (_complete) this.storage._addListener(this.path, `${this.type}_success`, _complete);
|
||||
if (_next) {
|
||||
this.storage._addListener(
|
||||
this.path,
|
||||
StorageStatics.TaskEvent.STATE_CHANGED,
|
||||
_next
|
||||
);
|
||||
}
|
||||
if (_error) {
|
||||
this.storage._addListener(
|
||||
this.path,
|
||||
`${this.type}_failure`,
|
||||
_error
|
||||
);
|
||||
}
|
||||
if (_complete) {
|
||||
this.storage._addListener(
|
||||
this.path,
|
||||
`${this.type}_success`,
|
||||
_complete
|
||||
);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (_next) this.storage._removeListener(this.path, StorageStatics.TaskEvent.STATE_CHANGED, _next);
|
||||
|
|
12
package.json
12
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-native-firebase",
|
||||
"version": "1.0.0-alpha12",
|
||||
"version": "1.0.2",
|
||||
"author": "Invertase <contact@invertase.io> (http://invertase.io)",
|
||||
"description": "A react native firebase library supporting both android and ios native firebase SDK's",
|
||||
"main": "index",
|
||||
|
@ -9,7 +9,12 @@
|
|||
"dev": "npm run compile -- --watch",
|
||||
"lint": "eslint ./src",
|
||||
"publish_pages": "gh-pages -d public/",
|
||||
"watchcpx": "echo 'See https://github.com/wix/wml for watching changes. \r\n'",
|
||||
"tests-npm-install": "cd tests && npm install",
|
||||
"tests-packager": "cd tests && npm run start",
|
||||
"tests-watch-init": "wml add $(node --eval \"console.log(require('path').resolve('./lib'));\") $(node --eval \"console.log(require('path').resolve('./tests/firebase'));\")",
|
||||
"tests-watch-start": "watchman watch $(node --eval \"console.log(require('path').resolve('./lib'));\") && wml start",
|
||||
"tests-watch-stop": "watchman watch-del $(node --eval \"console.log(require('path').resolve('./lib'));\") && wml stop",
|
||||
"tests-pod-install": "cd tests && npm run ios:pod:install",
|
||||
"flow": "flow"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -72,7 +77,8 @@
|
|||
"flow-bin": "^0.40.0",
|
||||
"react": "^15.3.0",
|
||||
"react-dom": "^15.3.0",
|
||||
"react-native": "^0.42.0"
|
||||
"react-native": "^0.42.0",
|
||||
"wml": "0.0.82"
|
||||
},
|
||||
"dependencies": {
|
||||
"bows": "^1.6.0",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__tests__/build/
|
|
@ -103,6 +103,84 @@ function pendingTestTests({ it: _it, describe: _describe }) {
|
|||
otherTest.should.be.called();
|
||||
});
|
||||
});
|
||||
|
||||
_describe('when an outer context is focused', () => {
|
||||
_it('a pending test will still not run', async () => {
|
||||
const pendingTest = sinon.spy();
|
||||
const otherTest = sinon.spy();
|
||||
const unfocusedTest = sinon.spy();
|
||||
|
||||
const testSuite = new TestSuite('', '', {});
|
||||
|
||||
testSuite.addTests(({ fdescribe, it, xit }) => {
|
||||
fdescribe('', () => {
|
||||
xit('', pendingTest);
|
||||
|
||||
it('', otherTest);
|
||||
});
|
||||
|
||||
it('', unfocusedTest);
|
||||
});
|
||||
|
||||
testSuite.setStore({
|
||||
getState: () => { return {}; },
|
||||
});
|
||||
|
||||
const testIdsToRun = Object.keys(testSuite.testDefinitions.focusedTestIds).reduce((memo, testId) => {
|
||||
if (!testSuite.testDefinitions.pendingTestIds[testId]) {
|
||||
memo.push(testId);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
await testSuite.run(testIdsToRun);
|
||||
|
||||
pendingTest.should.not.be.called();
|
||||
otherTest.should.be.called();
|
||||
unfocusedTest.should.not.be.called();
|
||||
});
|
||||
});
|
||||
|
||||
_describe('when an outer context is focused', () => {
|
||||
_it('a pending context will still not run', async () => {
|
||||
const pendingTest = sinon.spy();
|
||||
const otherTest = sinon.spy();
|
||||
const unfocusedTest = sinon.spy();
|
||||
|
||||
const testSuite = new TestSuite('', '', {});
|
||||
|
||||
testSuite.addTests(({ fdescribe, it, xdescribe }) => {
|
||||
fdescribe('', () => {
|
||||
xdescribe('', () => {
|
||||
it('', pendingTest);
|
||||
});
|
||||
|
||||
it('', otherTest);
|
||||
});
|
||||
|
||||
it('', unfocusedTest);
|
||||
});
|
||||
|
||||
testSuite.setStore({
|
||||
getState: () => { return {}; },
|
||||
});
|
||||
|
||||
const testIdsToRun = Object.keys(testSuite.testDefinitions.focusedTestIds).reduce((memo, testId) => {
|
||||
if (!testSuite.testDefinitions.pendingTestIds[testId]) {
|
||||
memo.push(testId);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
await testSuite.run(testIdsToRun);
|
||||
|
||||
pendingTest.should.not.be.called();
|
||||
otherTest.should.be.called();
|
||||
unfocusedTest.should.not.be.called();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default pendingTestTests;
|
||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||
classpath 'com.google.gms:google-services:3.0.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -18,3 +18,4 @@
|
|||
# org.gradle.parallel=true
|
||||
|
||||
android.useDeprecatedNdk=true
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
rootProject.name = 'ReactNativeFirebaseDemo'
|
||||
include ':react-native-firebase'
|
||||
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
|
||||
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, './../../android')
|
||||
include ':react-native-vector-icons'
|
||||
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
|
||||
|
||||
|
|
|
@ -36,5 +36,6 @@ target 'ReactNativeFirebaseDemo' do
|
|||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
|
||||
pod 'RNFirebase', :path => '../node_modules/react-native-firebase'
|
||||
|
||||
pod 'RNFirebase', :path => './../../'
|
||||
end
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
PODS:
|
||||
- Firebase/Analytics (3.15.0):
|
||||
- Firebase/Analytics (3.14.0):
|
||||
- Firebase/Core
|
||||
- Firebase/AppIndexing (3.15.0):
|
||||
- Firebase/AppIndexing (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAppIndexing (= 1.2.0)
|
||||
- Firebase/Auth (3.15.0):
|
||||
- Firebase/Auth (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAuth (= 3.1.1)
|
||||
- Firebase/Core (3.15.0):
|
||||
- Firebase/Core (3.14.0):
|
||||
- FirebaseAnalytics (= 3.7.0)
|
||||
- FirebaseCore (= 3.5.2)
|
||||
- Firebase/Crash (3.15.0):
|
||||
- FirebaseCore (= 3.5.1)
|
||||
- Firebase/Crash (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseCrash (= 1.1.6)
|
||||
- Firebase/Database (3.15.0):
|
||||
- Firebase/Database (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDatabase (= 3.1.2)
|
||||
- Firebase/DynamicLinks (3.15.0):
|
||||
- Firebase/DynamicLinks (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDynamicLinks (= 1.3.4)
|
||||
- Firebase/Messaging (3.15.0):
|
||||
- FirebaseDynamicLinks (= 1.3.3)
|
||||
- Firebase/Messaging (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseMessaging (= 1.2.2)
|
||||
- Firebase/RemoteConfig (3.15.0):
|
||||
- Firebase/RemoteConfig (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseRemoteConfig (= 1.3.4)
|
||||
- Firebase/Storage (3.15.0):
|
||||
- Firebase/Storage (3.14.0):
|
||||
- Firebase/Core
|
||||
- FirebaseStorage (= 1.1.0)
|
||||
- FirebaseAnalytics (3.7.0):
|
||||
|
@ -37,7 +37,7 @@ PODS:
|
|||
- FirebaseAnalytics (~> 3.7)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- FirebaseCore (3.5.2):
|
||||
- FirebaseCore (3.5.1):
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- FirebaseCrash (1.1.6):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
|
@ -47,7 +47,7 @@ PODS:
|
|||
- Protobuf (~> 3.1)
|
||||
- FirebaseDatabase (3.1.2):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseDynamicLinks (1.3.4):
|
||||
- FirebaseDynamicLinks (1.3.3):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseInstanceID (1.0.9)
|
||||
- FirebaseMessaging (1.2.2):
|
||||
|
@ -75,10 +75,8 @@ PODS:
|
|||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (2.1.1)
|
||||
- GTMSessionFetcher/Core (1.1.9)
|
||||
- GTMSessionFetcher/Core (1.1.8)
|
||||
- Protobuf (3.2.0)
|
||||
- React (0.40.0):
|
||||
- React/Core (= 0.40.0)
|
||||
- React/Core (0.40.0):
|
||||
- React/cxxreact
|
||||
- React/yoga
|
||||
|
@ -112,14 +110,7 @@ PODS:
|
|||
- React/RCTWebSocket (0.40.0):
|
||||
- React/Core
|
||||
- React/yoga (0.40.0)
|
||||
- RNFirebase (1.0.0-alpha12):
|
||||
- Firebase/Auth
|
||||
- Firebase/Core
|
||||
- Firebase/Database
|
||||
- Firebase/Messaging
|
||||
- Firebase/RemoteConfig
|
||||
- Firebase/Storage
|
||||
- React
|
||||
- RNFirebase (1.0.0-alpha13)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Firebase/Analytics
|
||||
|
@ -145,33 +136,33 @@ DEPENDENCIES:
|
|||
- React/RCTText (from `../node_modules/react-native`)
|
||||
- React/RCTVibration (from `../node_modules/react-native`)
|
||||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNFirebase (from `../node_modules/react-native-firebase`)
|
||||
- RNFirebase (from `./../../`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
React:
|
||||
:path: "../node_modules/react-native"
|
||||
:path: ../node_modules/react-native
|
||||
RNFirebase:
|
||||
:path: "../node_modules/react-native-firebase"
|
||||
:path: ./../../
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Firebase: 2b1cdfba1cda8589f32904a697cc753322bff9d8
|
||||
Firebase: 85a581fb04e44f63ae9f4fbc8d6dabf4a4c18653
|
||||
FirebaseAnalytics: 0d1b7d81d5021155be37702a94ba1ec16d45365d
|
||||
FirebaseAppIndexing: d0fa52ce0ad13f4b5b2f09e4b47fb0dc2213f4e9
|
||||
FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6
|
||||
FirebaseCore: a024587e43778508700af8c6b1209f7c4516ba02
|
||||
FirebaseCore: 225d40532489835a034b8f4e2c9c87fbf4f615a2
|
||||
FirebaseCrash: db4c05d9c75baa050744d31b36357c8f1efba481
|
||||
FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1
|
||||
FirebaseDynamicLinks: 30fb0856dd9ae6d8ba4da00972141a5c293a27b2
|
||||
FirebaseDynamicLinks: f0d025dd29a1d70418c003344813b67ab748ffb9
|
||||
FirebaseInstanceID: 2d0518b1378fe9d685ef40cbdd63d2fdc1125339
|
||||
FirebaseMessaging: df8267f378580a24174ce7861233aa11d5c90109
|
||||
FirebaseRemoteConfig: af3003f4e8daa2bd1d5cf90d3cccc1fe224f8ed9
|
||||
FirebaseStorage: a5c55b23741a49a72af8f30f95b3bb5ddbeda12d
|
||||
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
|
||||
GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e
|
||||
GTMSessionFetcher: 6f8d8b28b7e345549ac471071608170b31cb4977
|
||||
Protobuf: 745f59e122e5de98d4d7ef291e264a0eef80f58e
|
||||
React: 6dfb2f72edb1d74a800127ae157af038646673ce
|
||||
RNFirebase: 228c16667a3ed1ba3b9ff0702449dca3be1c3618
|
||||
RNFirebase: 46bfe1099349ac6fac8c5e57cf4f0b0f4b7938ac
|
||||
|
||||
PODFILE CHECKSUM: 23445e2727726988c7338fa2f396980d6fd3906f
|
||||
PODFILE CHECKSUM: f8bc5de55afd159ec2faf523f1b8e0d861d0832b
|
||||
|
||||
COCOAPODS: 1.2.0
|
||||
|
|
|
@ -286,8 +286,7 @@ class TestRun {
|
|||
suiteId: this.testSuite.id,
|
||||
status: RunStatus.ERR,
|
||||
time: Date.now() - this.runStartTime,
|
||||
message: `Test suite failed: ${error.message}`,
|
||||
stackTrace: error.stack,
|
||||
message: `Test suite failed: ${error.message}`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -306,7 +305,7 @@ class TestRun {
|
|||
}
|
||||
|
||||
async _safelyRunFunction(func, timeOutDuration, description) {
|
||||
const syncResultOrPromise = tryCatcher(func);
|
||||
const syncResultOrPromise = captureThrownErrors(func);
|
||||
|
||||
if (syncResultOrPromise.error) {
|
||||
// Synchronous Error
|
||||
|
@ -314,49 +313,59 @@ class TestRun {
|
|||
}
|
||||
|
||||
// Asynchronous Error
|
||||
return promiseToCallBack(syncResultOrPromise.value, timeOutDuration, description);
|
||||
return capturePromiseErrors(syncResultOrPromise.result, timeOutDuration, description);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Try catch to object
|
||||
* @returns {{}}
|
||||
* Call a function and capture any errors that are immediately thrown.
|
||||
* @returns {Object} Object containing result of executing the function, or the error
|
||||
* message that was captured
|
||||
* @private
|
||||
*/
|
||||
|
||||
function tryCatcher(func) {
|
||||
function captureThrownErrors(func) {
|
||||
const result = {};
|
||||
|
||||
try {
|
||||
result.value = func();
|
||||
} catch (e) {
|
||||
result.error = e;
|
||||
result.result = func();
|
||||
} catch (error) {
|
||||
result.error = error;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a promise callback-able to trap errors
|
||||
* @param promise
|
||||
* Wraps a promise so that if it's rejected or an error is thrown while it's being
|
||||
* evaluated, it's captured and thrown no further
|
||||
* @param {*} target - Target to wrap. If a thenable object, it's wrapped so if it's
|
||||
* rejected or an error is thrown, it will be captured. If a non-thenable object,
|
||||
* wrapped in resolved promise and returned.
|
||||
* @param {Number} timeoutDuration - Number of milliseconds the promise is allowed
|
||||
* to pend before it's considered timed out
|
||||
* @param {String} description - Description of the context the promises is defined
|
||||
* in, used for reporting where a timeout occurred in the resulting error message.
|
||||
* @private
|
||||
*/
|
||||
|
||||
function promiseToCallBack(promise, timeoutDuration, description) {
|
||||
function capturePromiseErrors(target, timeoutDuration, description) {
|
||||
let returnValue = null;
|
||||
|
||||
try {
|
||||
returnValue = Promise.resolve(promise)
|
||||
returnValue = Promise.resolve(target)
|
||||
.then(() => {
|
||||
return null;
|
||||
}, (error) => {
|
||||
return Promise.resolve(error);
|
||||
})
|
||||
.timeout(timeoutDuration, `${description} took longer than ${timeoutDuration}ms. This can be extended with the timeout option.`)
|
||||
.catch((error) => {
|
||||
return Promise.resolve(error);
|
||||
});
|
||||
})
|
||||
.timeout(timeoutDuration,
|
||||
`${description} took longer than ${timeoutDuration}ms. This can be extended with the timeout option.`
|
||||
);
|
||||
} catch (error) {
|
||||
returnValue = Promise.resolve(error);
|
||||
}
|
||||
|
|
|
@ -111,19 +111,19 @@ class TestSuite {
|
|||
*/
|
||||
async run(testIds = undefined) {
|
||||
const testsToRun = (() => {
|
||||
if (testIds) {
|
||||
return testIds.map((id) => {
|
||||
const test = this.testDefinitions.tests[id];
|
||||
return (testIds || Object.keys(this.testDefinitions.tests)).reduce((memo, id) => {
|
||||
const test = this.testDefinitions.tests[id];
|
||||
|
||||
if (!test) {
|
||||
throw new RangeError(`ReactNativeFirebaseTests.TestRunError: Test with id ${id} not found in test suite ${this.name}`);
|
||||
}
|
||||
if (!test) {
|
||||
throw new RangeError(`ReactNativeFirebaseTests.TestRunError: Test with id ${id} not found in test suite ${this.name}`);
|
||||
}
|
||||
|
||||
return test;
|
||||
});
|
||||
}
|
||||
if (!this.testDefinitions.pendingTestIds[id]) {
|
||||
memo.push(test);
|
||||
}
|
||||
|
||||
return Object.values(this.testDefinitions.tests);
|
||||
return memo;
|
||||
}, []);
|
||||
})();
|
||||
|
||||
const testRun = new TestRun(this, testsToRun.reverse(), this.testDefinitions);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
"react-native-firebase": "file:..",
|
||||
"react-native-simple-toast": "0.0.5",
|
||||
"react-native-vector-icons": "^4.0.0",
|
||||
"react-navigation": "^1.0.0-beta.7",
|
||||
"react-navigation": "^1.0.0-beta.9",
|
||||
"react-redux": "^5.0.3",
|
||||
"redux": "^3.6.0",
|
||||
"redux-logger": "^2.8.2",
|
||||
|
|
|
@ -14,13 +14,14 @@ export function setSuiteStatus({ suiteId, status, time, message, progress }) {
|
|||
};
|
||||
}
|
||||
|
||||
export function setTestStatus({ testId, status, time = 0, message = null }) {
|
||||
export function setTestStatus({ testId, status, stackTrace, time = 0, message = null }) {
|
||||
return {
|
||||
type: TEST_SET_STATUS,
|
||||
testId,
|
||||
|
||||
status,
|
||||
message,
|
||||
stackTrace,
|
||||
time,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class CoreContainer extends React.Component {
|
|||
StatusBar.setBackgroundColor('#0279ba');
|
||||
}
|
||||
if (Platform.OS === 'ios') {
|
||||
StatusBar.setBarStyle('light-content')
|
||||
StatusBar.setBarStyle('light-content');
|
||||
}
|
||||
AppState.addEventListener('change', this.handleAppStateChange);
|
||||
NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
|
@ -44,6 +44,7 @@ class CoreContainer extends React.Component {
|
|||
}
|
||||
|
||||
props: Props;
|
||||
_isConnected: boolean;
|
||||
|
||||
/**
|
||||
* Handle app state changes
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import firebase from 'firebase';
|
||||
import RNfirebase from 'react-native-firebase';
|
||||
import RNfirebase from './../firebase/firebase';
|
||||
|
||||
import DatabaseContents from './tests/support/DatabaseContents';
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ function testsReducers(state = initState.tests, action: Object): State {
|
|||
flattened[`${action.testId}.status`] = action.status;
|
||||
flattened[`${action.testId}.message`] = action.message;
|
||||
flattened[`${action.testId}.time`] = action.time;
|
||||
flattened[`${action.testId}.stackTrace`] = action.stackTrace;
|
||||
|
||||
return unflatten(flattened);
|
||||
}
|
||||
|
|
|
@ -13,17 +13,11 @@ class Overview extends React.Component {
|
|||
// noinspection JSUnusedGlobalSymbols
|
||||
static navigationOptions = {
|
||||
title: 'Test Suites',
|
||||
header: () => {
|
||||
return {
|
||||
style: { backgroundColor: '#0288d1' },
|
||||
tintColor: '#ffffff',
|
||||
right: (
|
||||
<View style={{ marginRight: 8 }}>
|
||||
<OverviewControlButton />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
},
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ marginRight: 8 }}>
|
||||
<OverviewControlButton />
|
||||
</View>
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,25 +11,19 @@ import TestSuiteControlButton from '../components/TestSuiteControlButton';
|
|||
|
||||
class Suite extends React.Component {
|
||||
|
||||
static navigationOptions = {
|
||||
title: ({ state: { params: { title } } }) => {
|
||||
return title;
|
||||
},
|
||||
header: ({ state: { params: { testSuiteId, onlyShowFailingTests } }, setParams }) => {
|
||||
return {
|
||||
style: { backgroundColor: '#0288d1' },
|
||||
tintColor: '#ffffff',
|
||||
right: (
|
||||
<View style={{ flexDirection: 'row', marginRight: 8 }}>
|
||||
<TestSuiteControlButton
|
||||
testSuiteId={testSuiteId}
|
||||
onlyShowFailingTests={onlyShowFailingTests}
|
||||
onFilterChange={setParams}
|
||||
/>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
},
|
||||
static navigationOptions = ({ navigation: { state: { params: { title, testSuiteId, onlyShowFailingTests } }, setParams } }) => {
|
||||
return {
|
||||
title,
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ flexDirection: 'row', marginRight: 8 }}>
|
||||
<TestSuiteControlButton
|
||||
testSuiteId={testSuiteId}
|
||||
onlyShowFailingTests={onlyShowFailingTests}
|
||||
onFilterChange={setParams}
|
||||
/>
|
||||
</View>,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,21 +9,15 @@ import TestControlButton from '../components/TestControlButton';
|
|||
|
||||
class Test extends React.Component {
|
||||
|
||||
static navigationOptions = {
|
||||
title: ({ state: { params: { title } } }) => {
|
||||
return title;
|
||||
},
|
||||
header: ({ state: { params: { testId } } }) => {
|
||||
return {
|
||||
style: { backgroundColor: '#0288d1' },
|
||||
tintColor: '#ffffff',
|
||||
right: (
|
||||
<View style={{ marginRight: 8 }}>
|
||||
<TestControlButton testId={testId} />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
},
|
||||
static navigationOptions = ({ navigation: { state: { params: { title, testId } } } }) => {
|
||||
return {
|
||||
title,
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ marginRight: 8 }}>
|
||||
<TestControlButton testId={testId} />
|
||||
</View>,
|
||||
};
|
||||
};
|
||||
|
||||
static renderBanner({ status, time }) {
|
||||
|
@ -57,35 +51,28 @@ class Test extends React.Component {
|
|||
setParams({ test });
|
||||
}
|
||||
|
||||
renderError() {
|
||||
const { test: { message } } = this.props;
|
||||
|
||||
if (message) {
|
||||
return (
|
||||
<ScrollView>
|
||||
<Text style={styles.codeHeader}>Test Error</Text>
|
||||
<Text style={styles.code}>
|
||||
<Text>{message}</Text>
|
||||
</Text>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { test: { func, status, time } } = this.props;
|
||||
const { test: { stackTrace, description, func, status, time }, testContextName } = this.props;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{Test.renderBanner({ status, time })}
|
||||
<View style={styles.content}>
|
||||
{this.renderError()}
|
||||
<Text style={styles.codeHeader}>Test Code Preview</Text>
|
||||
<ScrollView>
|
||||
<Text style={styles.code}>
|
||||
<View >
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<Text style={styles.heading}>{testContextName}</Text>
|
||||
<Text style={styles.description}>{description}</Text>
|
||||
</ScrollView>
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<Text style={styles.heading}>Test Error</Text>
|
||||
<Text style={styles.description}>
|
||||
<Text>{stackTrace || 'None.'}</Text>
|
||||
</Text>
|
||||
</ScrollView>
|
||||
<Text style={styles.heading}>
|
||||
Test Code Preview
|
||||
</Text>
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<Text style={styles.description}>
|
||||
{beautify(removeLastLine(removeFirstLine(func.toString())), { indent_size: 4, break_chained_methods: true })}
|
||||
</Text>
|
||||
</ScrollView>
|
||||
|
@ -99,10 +86,13 @@ Test.propTypes = {
|
|||
test: PropTypes.shape({
|
||||
status: PropTypes.string,
|
||||
time: PropTypes.number,
|
||||
message: PropTypes.string,
|
||||
func: PropTypes.function,
|
||||
stackTrace: PropTypes.function,
|
||||
description: PropTypes.string,
|
||||
}).isRequired,
|
||||
|
||||
testContextName: PropTypes.string,
|
||||
|
||||
navigation: PropTypes.shape({
|
||||
setParams: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
|
@ -113,27 +103,32 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
content: {},
|
||||
code: {
|
||||
backgroundColor: '#3F373A',
|
||||
color: '#c3c3c3',
|
||||
padding: 5,
|
||||
fontSize: 12,
|
||||
sectionContainer: {
|
||||
minHeight: 100,
|
||||
},
|
||||
codeHeader: {
|
||||
fontWeight: '600',
|
||||
fontSize: 18,
|
||||
backgroundColor: '#000',
|
||||
color: '#fff',
|
||||
heading: {
|
||||
padding: 5,
|
||||
backgroundColor: '#0288d1',
|
||||
fontWeight: '600',
|
||||
color: '#ffffff',
|
||||
fontSize: 16,
|
||||
},
|
||||
description: {
|
||||
padding: 5,
|
||||
fontSize: 14,
|
||||
},
|
||||
});
|
||||
|
||||
function select({ tests }, { navigation: { state: { params: { testId } } } }) {
|
||||
function select({ tests, testContexts }, { navigation: { state: { params: { testId } } } }) {
|
||||
const test = tests[testId];
|
||||
let testContext = testContexts[test.testContextId];
|
||||
|
||||
while(testContext.parentContextId && testContexts[testContext.parentContextId].parentContextId) {
|
||||
testContext = testContexts[testContext.parentContextId];
|
||||
}
|
||||
return {
|
||||
test,
|
||||
testContextName: testContext.name,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue