firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.86k stars 891 forks source link

Firestore offline persistence not working on react native #436

Closed santiarias closed 6 years ago

santiarias commented 6 years ago

when enabling persistence I get an error on react native:


import * as firebase from 'firebase';
require("firebase/firestore");
firebase.firestore().enablePersistence();

Error enabling offline storage. Falling back to storage disabled: FirebaseError: [code=unimplemented]: This platform is either missing IndexedDB or is known to have an incomplete implementation. Offline persistence has been disabled.

When reading https://firebase.google.com/docs/firestore/manage-data/enable-offline I see:

Note: Offline persistence is supported only in Android, iOS, and web apps. and Important: For the web, offline persistence is an experimental feature that is supported only by the Chrome, Safari, and Firefox web browsers. Also, if a user opens multiple browser tabs that point to the same Cloud Firestore database, and offline persistence is enabled, Cloud Firestore will work correctly only in the first tab.

I assume that is the reason why that is not working on react native, if so, could you confirm. Is this in the pipeline?

google-oss-bot commented 6 years ago

Hey there! I couldn't figure out what this issue is about, so I've labeled it for a human to triage. Hang tight.

google-oss-bot commented 6 years ago

Hmmm this issue does not seem to follow the issue template. Make sure you provide all the required information.

merlinnot commented 6 years ago

You might want to use https://rnfirebase.io instead. It works really well.

santiarias commented 6 years ago

Hi,

Thanks, sadly that library requires manual linking to native code for ios / android, which I think it goes against the "write once, run everywhere" mentality that react native is trying to achieve. Furthermore that library does not work with Expo which is bundled and used by default by react native (ie https://facebook.github.io/react-native/docs/getting-started.html)

cloudprogrammer commented 6 years ago

You can just eject from expo and still use the expo sdk if you wanna use its tools. And the manual linking is required, its a small caveat to the react native process. You link then you write JS code once that runs on Android or iOS.

philohelp commented 6 years ago

The best solution would be to enable offline persistance within react-native. Are there any structural problems to achieve this or should we consider that it's only a matter of time ?

matthiaw commented 6 years ago

Hi All, i try to use firestore wirth react-native, redux and expo. It works fine in the online version. See https://github.com/matthiaw/react-native-redux-example/tree/d91d38adb2f376dc3a22825482668de3ad8ccf63.

But it throws an exception when i want to enable offline-persistence. See the given code in my repo to test it.

Can anyone name a working offline-persistence for firestore with react-native and expo?

dfreire commented 6 years ago

According to the docs:

  • For Android and iOS, offline persistence is enabled by default. To disable persistence, set the PersistenceEnabled option to false.
  • For the web, offline persistence is disabled by default. To enable persistence, call the enablePersistence method. Cloud Firestore's cache isn't automatically cleared between sessions. Consequently, if your web app handles sensitive information, make sure to ask the user if they're on a trusted device before enabling persistence.

https://firebase.google.com/docs/firestore/manage-data/enable-offline

Can you try not calling enablePersistence()and check if offline persistence works? (I mean, using https://rnfirebase.io)

samtstern commented 6 years ago

It's been a while since there has been any activity on this issue, so I am going to close it.

While we want to support using Firestore everywhere in a flexible manner, right now our only recommended usage method for React Native is through react-native-firebase, as some commenters have already said.

Please give that library a try, and raise issues on that repository if persistence does not work.

jurosh commented 6 years ago

😢 @samtstern react-native-firebase isn't for everyone. Current and probably the only proper way how to use Firebase in Expo is through web SDK - all other options would need app to be ejected what is something what most Expo devs doesn't want to do as it's it leads to loosing many benefits and simplicity of expo package.

Would be really great if there would be way, or at least some workaround how to make persistence work without need to use native modules.

santiarias commented 6 years ago

Thanks @jurosh @samtstern The reason why there was no activity no this thread, is because there was never an official response from the team for this issue.

I only got responses that did not address the issue.

I think @jurosh explained my point really well.
Using react-native-firebase makes Expo, the most used open source toolchain built around React Native, unusable. Which is recommended in the official documentation of react native

wilhuff commented 6 years ago

I'm no expert in react-native, but you're welcome to try making changes here:

https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/local/simple_db.ts#L96

This is the logic that determines whether or we allow offline persistence on the platform. Just as a test you could force that method to return true. If it works try to come up with some narrower test that allows persistence to proceed in this environment.

As I understand it though with a brief search, react-native does not support IndexedDB, which is why that function returns false today. From what I can find they expect you to use their own AsyncStorage API. This is no small undertaking and not anything we can take on. We'd welcome a community contribution that implemented it and would be happy to help integrate it, but we're stretched thin already and can't do this work ourselves.

You might also try to find something to polyfill IndexedDB, similar to IndexedDBShim though that makes no mention of AsyncStorage support so I'm not hopeful for that particular one.

So unless react-native actually supports IndexedDB and our test is just wrong, our advice stands: if you want offline persistence you have to use react-native-firebase.

mohshraim commented 6 years ago

not expert with react native..

On iOS if react-native using webview where IndexedDB not implemented so firestore persistence will not work. if they use WKWebview then should presiste successfully...

again don't know much about react native but i think you should give a try using this; https://github.com/CRAlpha/react-native-wkwebview

share with us the result :)

SourceCipher commented 6 years ago

I tried multiple times to enable persistence on react native but failing each time.. I tried doing it via settings like firebase.firestore().settings({ persistence: true }) but that wont work as well.

The weirdest thing about this is if I run my app offline, all works well, images loading instantly, everything is kept as it was from the last launch, but as soon as I relaunch with the wifi on, all the data is being loaded from the back end and it takes sometimes 5s for the image to appear.. Its a very big issue for me and I have no idea how to solve

philohelp commented 6 years ago

it works with invertase / react-native-firebase - unfortunately incompatible with expo

Le mar. 26 juin 2018 à 20:35, Gvidas M. notifications@github.com a écrit :

I tried multiple times to enable persistence on react native but failing each time.. I tried doing it via settings like firebase.firestore().settings({ persistence: true }) but that wont work as well. The weirdest thing about this is if I run my app offline, all works well, images loading instantly, everything is kept as it was from the last launch, but as soon as I relaunch with the wifi on, all the data is being loaded from the back end and it takes sometimes 5s for the image to appear.. Its a very big issue for me and I have no idea how to solve

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/firebase/firebase-js-sdk/issues/436#issuecomment-400418930, or mute the thread https://github.com/notifications/unsubscribe-auth/AMCgW5GgiqHY0fdN7_FFebAvcL3bO2hAks5uAn7pgaJpZM4RdzV4 .

SourceCipher commented 6 years ago

@philohelp I am not using expo

agates4 commented 6 years ago

https://github.com/sunnylqm/react-native-storage

can't this be used to plug into the local storage that firebase is using? shouldn't be hard to implement that library to create a solution that works for expo..

nandorojo commented 5 years ago

Is there any plan to add offline persistence for Expo?

mikelehen commented 5 years ago

@nandorojo We don't currently have plans to invest in making our Web SDK offline support work in React Native. Would it be possible to use the native (Android / iOS) Firestore SDKs instead? I believe Expo supports that to some degree now. https://blog.expo.io/using-firebase-in-expo-e13844061832

nandorojo commented 5 years ago

Hey @mikelehen, thanks for getting back to me. The article you attached is for detached Expo projects only unfortunately, so it doesn't work with managed Expo projects.

I understand there's no plan for this now, but I think it would be amazing if you decided to add support for RN offline. Many apps are moving towards RN (above all, Expo) and offline support is a central draw of using Firestore.

I believe JS libraries like redux-persist use localStorage on web and AsyncStorage on RN out of the box. I assume the same could be done for Firestore using pure JS without much trouble.

From the article you sent:

We started building expo-firebase based off of react-native-firebase in order to attempt to get it to work well within the Expo client. It turned out that there wasn’t a good way to do this — the SDK fully expects that there is one binary per app, and the Expo client has multiple apps inside of it. We weren’t able to work around this. If you’d like to use Firebase in the Expo client with the managed workflow, we’d recommend using the Firebase JS SDK.

Really hoping this gets added to plans for support. Thanks again for your help!

wilhuff commented 5 years ago

My previous response on this topic still stands.

React Native's AsyncStorage and react-native-async-storage are simple key-value stores with just get/put operations. These are insufficient for implementing Firestore: we rely on being able to scan keys in order using range scans to implement queries.

Essentially, until it's possible to polyfill IndexedDB on top of React Native, there's no way we can support offline persistence there.

nandorojo commented 5 years ago

Thanks for clarifying. While I'm not familiar with how IndexedDB works, if I could come up with an implementation for React Native, would offline persistence then be supported?

mikelehen commented 5 years ago

@nandorojo Yes! It should just automatically work if IndexedDB was available (https://github.com/firebase/firebase-js-sdk/blob/462047e2b664efd4612d670d73bec93caeace7f0/packages/firestore/src/local/simple_db.ts#L134).

zwily commented 5 years ago

I hesitate to share this because of how hacky it all seems, but I did manage to get Firestore persistence working in an Expo app with the firebase web SDK:

https://gist.github.com/zwily/e9e97e0f9f523a72c24c7df01d889482

I wouldn't ship anything with that without a ton of testing (I've only done about an hour's worth). It does appear to be feasible though!

SourceCipher commented 5 years ago

I actually disabled firebase persistance and doing it all myself using realm local db. Its super fast and it acts like a bridge between your user and firebase db

nandorojo commented 5 years ago

@SourceCipher Do you have an example of how to implement that? Do all firestore persistence features work?

So far I've been storing all of my firestore data in redux, and using redux-persist to have it cache. I'm not sure if this is optimal, though. Would be great to be able to actually use the offline persistence as intended instead of adding a whole new step for redux.

@zwily Thank you for passing along the gist, I'll give it a try tonight!

zwily commented 5 years ago

@nandorojo Let me know how it goes. I haven't run into any problems while testing my app today, and it's nice having everything loading so quickly...

nandorojo commented 5 years ago

@zwily Seems to work (with a slight lag). Will do more tests throughout the night to figure out if the lag is in my render code or not and if there are any bugs. This is great work. I’ll do what I can to make sure it’s ready for production.

Also, is it worth adding a check for the react native platform in case the user is on expo web?

smontlouis commented 5 years ago

@zwily Thank you SO much ! Working like a charm !

smontlouis commented 5 years ago

@zwily haha I was too quick to talk :

On Android

Uncaught Error: console.error: "Firestore (6.3.5) INTERNAL UNHANDLED ERROR: Could not evaluate a key from keyPath and there is no key generator"
nandorojo commented 5 years ago

@zwily haha I was too quick to talk :

On Android

Uncaught Error: console.error: "Firestore (6.3.5) INTERNAL UNHANDLED ERROR: Could not evaluate a key from keyPath and there is no key generator"

I've had no issues on iOS and have been testing for about a week so far. I'll try it out on Android too.

@bulby97 Would you mind describing the error a bit more?

Did this happen immediately on app load? Does it keep the app from working? Is your firebase.firestore().enablePersistence() wrapped in a try/catch and this is the error it gives? Does it happen both with and without connection?

nandorojo commented 5 years ago

I've tested @zwily's solution on Android and get the same error as @bulby97. It keeps the app from working at all. For now I'm trying if (Platform.OS === 'ios') instead.

schmidt-sebastian commented 5 years ago

@nandorojo @bulby97 @zwily We are actually using IndexedDbShim as our testing layer during development. While I certainly don't recommend that anyone should ship an actual app using this, it has been relatively reliable (other than the fact that is is a little on the slow side). See https://github.com/firebase/firebase-js-sdk/blob/3c8f85d0185e3305f0ba7790d46eebb8e9e78e62/packages/firestore/test/util/node_persistence.ts

nandorojo commented 5 years ago

@schmidt-sebastian Thanks for the heads up! I'll test it out.

For now, @zwily's solution seems to work on iOS, though I'm still testing speeds for it.

Given the high levels of investment in react native/expo from the community, I hope that at some point the firebase team considers a similar pure-JS workaround for persistence on react native.

nandorojo commented 5 years ago

@zwily Perhaps there is a better place to put these errors, but I got this randomly on iOS:

Screen Shot 2019-09-19 at 10 37 18 AM

Seems to be a SQLite error of sorts, not sure what the cause is.

JCBsystem commented 5 years ago

setting the autoIncrement to true in the './node_modules/indexeddbshim/dist/indexeddbshim-noninvasive' makes Uncaught Error: console.error: "Firestore (6.3.5) INTERNAL UNHANDLED ERROR: Could not evaluate a key from keyPath and there is no key generator" go away

but i can not figure out how to set it by override can only do it by hard code it to true in the code base.

agates4 commented 5 years ago

been following this thread for a year..

would love to see android implementation

zaptrem commented 5 years ago

Same here. Does that hack support Android @zwily ?