Closed TheHeumanModean closed 1 year ago
Seems like there's the old AsyncStorage (from RN) creeping in. iOS has a migration process where it would copy over the old manifest file, if exists, and use it as a current storage destination. This happens on every app launch.
Make sure there's no other AsyncStorage used except for one from react-native-async-storage org
Seems like there's the old AsyncStorage (from RN) creeping in. iOS has a migration process where it would copy over the old manifest file, if exists, and use it as a current storage destination. This happens on every app launch.
Make sure there's no other AsyncStorage used except for one from react-native-async-storage org
This is the only file in my project that imports AsyncStorage, so thats probably not it.
I do have some native modules that use persistent storage (not sure how, code is pretty obfuscated), could this be causing conflicts?
Edit: After asking another team using the same native modules as me, the native modules do not seem to be the problem as they are not experiencing this issue.
I am not fluent at all in objective-c so I can't tell why Manifest does not exist - creating a new one.
gets logged but that definitely seems to be the culprit. Can someone provide me more info on how that manifest gets loaded?
Hi, I am experiencing the same issue, though I am using Expo.
"dependencies": { "expo": "~48.0.15", "@react-native-async-storage/async-storage": "1.17.11", "expo-secure-store": "~12.1.1", "react-native": "0.71.7" },
As @TheHeumanModean described, it works when app resumes (from background), but when it is freshly started (that is when it is really need for persisting users to be logged in), data in storage are alwaysnull
. I tried to use different package Expo's SecureStore to work around this, but it behaves the same way. I am experiencing this on iOS app installed from Testflight. Not sure if those two can be connected somehow. It worked for me before updating my project to Expo SDK 48.
@TheHeumanModean are you able to reproduce this on a new project? If not, I'd assume it has to be something related to your project. Can you spot the issue on android too?
@TheHeumanModean are you able to reproduce this on a new project? If not, I'd assume it has to be something related to your project. Can you spot the issue on android too?
@krizzu I was mistaken when I first made this, it seems android is fine and this is just an iOS problem for my project. And no I can't reproduce it in a new project, I know it has something to do with mine, just need to figure out what it is.
I need help understanding why the "manifest" gets recreated with no data on app start so that I can resolve the issue
@TheHeumanModean The "manifest" is a file (JSON) where all key-value values below 5MB are being saved on iOS. When AsyncStorage was extracted from React Native, the location of the manifest file is located has changed. Now we needed the migration code to move files to the new location so that users could work undisturbed. The migration code removes the old manifest file, once migration is successful, so that we know AsyncStorage operates on latest version of it.
We spotted the issue you have where two versions of AsyncStorage and AsyncStorage from RN are used. Old AsyncStorage creates a manifest on app launch and the new one removes it, after migration.
@krizzu Looking at the comments in that method I don't think it really applies to our project. I've never used react-native/async-storage nor have I used this plugin pre 1.17.3. I put in some logs to confirm my suspicions and sure enough no migration happens
init
// Get the path to any old storage directory that needs to be migrated. If multiple exist,
// the oldest are removed and the most recently modified is returned.
NSString *oldStoragePath = RCTGetStoragePathForMigration();
if (oldStoragePath != nil) {
printf("ASYNC STORAGE, old storage path is NOT nil");
// Migrate our deprecated path "Documents/.../RNCAsyncLocalStorage_V1" or
// "Documents/.../RCTAsyncLocalStorage" to "Documents/.../RCTAsyncLocalStorage_V1"
RCTStorageDirectoryMigrationCheck(
oldStoragePath, RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), YES);
}
else {
printf("ASYNC STORAGE, old storage path is nil\n");
}
// Migrate what's in "Documents/.../RCTAsyncLocalStorage_V1" to
// "Application Support/[bundleID]/RCTAsyncLocalStorage_V1"
RCTStorageDirectoryMigrationCheck(RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory),
RCTCreateStorageDirectoryPath(RCTStorageDirectory),
NO);
RCTStorageDirectoryMigrationCheck
if ([fileManager fileExistsAtPath:fromStorageDirectory isDirectory:&isDir] && isDir) {
printf("ASYNC STORAGE, old storage path does exist and we need to migrate\n");
...
else {
printf("ASYNC STORAGE, old storage path does not exist\n");
}
Logs on startup:
ASYNC STORAGE, old storage path is nil ASYNC STORAGE, old storage path does not exist
I think the problem is here on line 528 where data is not serialized because it does not read the file
static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
printf("Storage file does exist\n");
...
return entryString;
}
printf("Storage file does NOT exist\n");
return nil;
}
Storage file does NOT exist
hit reload
Storage file does exist
force close and cold start
Storage file does NOT exist
I don't know why but it looks like the file you write to and the file you read from differ on cold start, so I logged the file written to and the file read from on the next cold start. And on the simulator they differ!
write
/Users/my.username/Library/Developer/CoreSimulator/Devices/0148E0A0-9A01-471F-A676-AD5E08693911/data/Containers/Data/Application/6B2E78F2-865E-450E-A8E8-E55FF7069539/Library/Application Support/redacted.bundle.id/RCTAsyncLocalStorage_V1/manifest.json
read
/Users/my.username/Library/Developer/CoreSimulator/Devices/0148E0A0-9A01-471F-A676-AD5E08693911/data/Containers/Data/Application/8F1C5550-6E39-45C0-A8BE-CBCD2458E5E9/Library/Application Support/redacted.bundle.id/RCTAsyncLocalStorage_V1/manifest.json
They differ in the application id, (6B2E78F2-865E-450E-A8E8-E55FF7069539 vs 8F1C5550-6E39-45C0-A8BE-CBCD2458E5E9)
The same thing happens on an actual device
write
/var/mobile/Containers/Data/Application/CAA95996-C39C-408A-9228-C68D8F19E00F/Library/Application Support/redacted.bundle.id/RCTAsyncLocalStorage_V1/manifest.json
read
/var/mobile/Containers/Data/Application/B9966AEA-6A28-4760-A3B6-85C4A9450CB0/Library/Application Support/redacted.bundle.id/RCTAsyncLocalStorage_V1/manifest.json
so it seems for simulators the reason the data isn't persisting is because you're storing data under a specific application directory that changes from run to run.
Is there a way for me to correct this app side? Or is it a bug on the package side that would need to be fixed? Storage directory name is constructed here
It seems very weird that this would only happen to my project
Edit: after reviewing a different project using this package, the changing of the application id does not happen after force close. So definitely project specific
@TheHeumanModean This behavior (different paths for Dodcuments/Library data) exists since iOS 8, here's the technical note on that. AsyncStorage uses system APIs to retrieve the application data location so that the manifest file can be stored there.
I've never used react-native/async-storage nor have I used this plugin pre 1.17.3.
My bet would be that one of your dependencies is using AsyncStorage and causing this - I can suggest scanning node_modules
to see if any library is using AsyncStorage.
@krizzu
grep -R --exclude-dir=@react-native-async-storage --include \*.ts --include \*.js "AsyncStorage" node_modules/
returns only results from react native, react native types, metro and the actual react-native async storage library
node_modules//@types/react-native/index.d.ts: * AsyncStorage is a simple, unencrypted, asynchronous, persistent, key-value storage
... More results from same file
node_modules//react-native/Libraries/Storage/AsyncStorage.js:const RCTAsyncStorage = NativeAsyncSQLiteDBStorage || NativeAsyncLocalStorage;
... More results from same file
node_modules//react-native/index.js: get AsyncStorage(): AsyncStorage {
... More results from same file
node_modules//metro/node_modules/metro-react-native-babel-preset/src/configs/lazy-imports.js: "AsyncStorage",
node_modules//metro-react-native-babel-preset/src/configs/lazy-imports.js: "AsyncStorage",
So looks like thats not the issue unless you have a better way to find references to that library?
Do you use .clear
method by any chance somewhere?
Otherwise, I'd try the divide-and-conquer approach, starting with commenting out all imports in index.js
, so that App would run and test if storage is removed on restart. Then bring back import by import, checking where the issue is reproducible.
@krizzu issue is with one of our native modules, a minor release from them caused the problem. Of course its a highly obfuscated one so I don't know what caused it. May report back later with info but closing it for now as its not an issue with the async storage package.
i am using redux toolkit with redux-persist value save on android but on ios persist not working properly sometimes gives undefined or sometimes gives me value
Here is my observation and fix. Hope this helps someone
My problem: Data stored is not persisted after reboot of the device. My OS: Android 13
AsyncStorage can be exported using the following two ways,
import AsyncStorage from '@react-native-async-storage/async-storage';
import {AsyncStorage} from 'react-native';
With 1 above, my data is lost after re-boot of the device. WIth 2, the data is persisted and it works as expected. However, with 2 above, I get a warning that "AsyncStorage would removed from react-native..", Basically the console warning is suggesting to import using method 1 above and instead of 2.
I've decided to go ahead with 2 above for now and keep watching for fixes using 1.
This is still an issue on ```@react-native-async-storage/async-storage@^1.23.1```` after much troubleshooting, much nothing new has come out of the issue aside what has already been mentioned above
What happened?
Storage does not persist when app force closed on iOS.
This issue was closed but is not resolved for me, nor is it resolved for others in that thread.
I am not using expo
Expected
Actual
I've also tried delaying the loading of the storage with a setTimeout in case it was trying to load value before it could access storage, but there was no behavioral difference.
This is logged in xcode
So it seems on iOS at least a new manifest is created (and therefore not loading previously saved data) on start of app every time and that is what causes the value to be null
I do not have time to investigate android as deeply as I did iOS but there could be a similar problem there
Version
Have tried various between 1.17.3 and 1.18.1
What platforms are you seeing this issue on?
System Information
Steps to Reproduce
Code
Logs
app is refreshed
app is forcce closed