Skip to content

[FIX] Move the storage location on iOS to Application Support #274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

HeyImChris
Copy link
Contributor

@HeyImChris HeyImChris commented Jan 4, 2020

Summary:

Right now on iOS, the data is stored in the Documents directory (NSDocumentDirectory) on iOS and the caches directory (NSCachesDirectory) on tvOS.

These are not the best locations for the following reasons:

  • NSDocumentDirectory- this folder is visible on iOS in scenarios where you can view the Files structure. For instance, in Word/PPT/Excel, a user can tap through to this and see a folder titled "RCTAsyncLocalStorage_V1".
  • NSCachesDirectory- Apple documents this as a location that can get purged in low memory scenarios "the system may delete the Caches directory on rare occasions when the system is very low on disk space."

This fix moves the location to the Application Support directory (NSApplicationSupportDirectory). This directory is documented by Apple as "[containing] all app-specific data and support files" and it can safely contain user data. There is not risk of this purging in low memory situations and this isn't visible to iOS users.

This is not a breaking change as we are able to maintain fidelity with the one-time data migration code to our new location.

The general fix is this:

  • Maintain our existing deprecation/removal of the old Documents/.../RNCAsyncLocalStorage_V1/manifest.json
  • Maintain our existing migration from Documents/.../RNCCreateStorageDirectoryPath to Documents/.../RCTAsyncLocalStorage_V1/manifest.json
  • Add an additional migration from Documents/.../RCTAsyncLocalStorage_V1/manifest.json to Application Support/[bundleID]/RCTAsyncLocalStorage_V1/manifest.json, but do not delete the Document version
  • In the rewrite of RCTCreateStorageDirectoryPath, use NSApplicationSupportDirectory instead of caches or documents
  • Refactor our migration methods to take in a from and a to directory path parameter so we can run the migration twice- once with the old caches/documents location paired with RCTOldStorageDirectory and again with the old caches/documents location paired with RCTStorageDirectory. We also added a shouldCleanupOldDirectory parameter so we can optionally delete the "from" path when we're migrating from Documents/RNC* but retain the "from" path when migrating from Documents/RCT*
  • Cache some duplicate method calls in a couple places to save on performance

Please see https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html#//apple_ref/doc/uid/TP40010672-CH10-SW1 and https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1 for more documentation on this.

Test Plan:

  • Ran the example test app on iOS and incremented the counter. Verified this saves by hitting the Restart button and the content persisted.
  • Verified that the migration is correct on iOS by stashing this fix, incrementing the counter, popping back this change, and in the debugger I stepped through it copying the data over to the Application Support/[bundleID]/ location. I also verified that it correctly cleared out the old data. Finally, I checked that in the aforementioned migration scenario, there was no data loss in the test app.
  • Tested updating the manifest when there was no existing manifest in Documents/RCT*
  • Tested updating the manifest when there was no existing manifest in ApplicationSupport/RCT*
  • Tested updating the manifest when there was no existing manifest in Documents/RNC*
  • Tested updating the manifest when there was an existing manifest in Documents/RCT*
  • Tested updating the manifest when there was an existing manifest in ApplicationSupport/RCT*

@tido64 tido64 requested review from tido64 and krizzu January 6, 2020 08:47
Copy link
Member

@tido64 tido64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@krizzu, do you want to take a look?

@tido64 tido64 added the platform: iOS This is iOS specific label Jan 7, 2020
@krizzu
Copy link
Member

krizzu commented Jan 7, 2020

Looks okay to me to.
@tido64 @HeyImChris WDYT about dropping the support for RNC* manifest file? I know that would be somehow a breaking change, but we could release this feature in 1.8.

@tido64
Copy link
Member

tido64 commented Jan 7, 2020

@krizzu, should that be a separate PR?

@tido64
Copy link
Member

tido64 commented Jan 7, 2020

@krizzu, I also just remembered that I had already done this, but it seems it was in a different file? Will we have to repeat this PR for v2? Seems to me v2 should just use this new directory right away.

@HeyImChris
Copy link
Contributor Author

@krizzu, I also just remembered that I had already done this, but it seems it was in a different file? Will we have to repeat this PR for v2? Seems to me v2 should just use this new directory right away.

Haven't taken a look at V2, but agree that we should drop storage support in the caches and documents directories.

@krizzu
Copy link
Member

krizzu commented Jan 8, 2020

@krizzu, should that be a separate PR?

Yes, I'd do that.

@krizzu, I also just remembered that I had already done this, but it seems it was in a different file? Will we have to repeat this PR for v2? Seems to me v2 should just use this new directory right away.

Haven't taken a look at V2, but agree that we should drop storage support in the caches and documents directories.

Yes please - v2 to have Application Support directory as default location.

@Rotemy
Copy link

Rotemy commented Jan 30, 2020

When is this scheduled to be merged?

@HeyImChris
Copy link
Contributor Author

When is this scheduled to be merged?

Thanks for your patience, been busy with other work recently. As we discussed on discord, I'll have to make another update where we don't delete the RCT* files. Will try and get that out today and can hopefully merge thereafter.

@Palid
Copy link

Palid commented Feb 4, 2020

Hey, do you need any help with reviewing/merging this thing? I'd love to start working on adding app storage support for iOS, but it looks like this merge would immensly help me with this.

@HeyImChris
Copy link
Contributor Author

Hey, do you need any help with reviewing/merging this thing? I'd love to start working on adding app storage support for iOS, but it looks like this merge would immensly help me with this.

@Palid - A review would be great. @krizzu had some great feedback that I added in the latest iteration. Once no one's waiting on it then I'd love for someone with permissions to merge it in.

RCTStorageDirectoryMigrationCheck(RCTCreateStorageDirectoryPath_deprecated(RCTOldStorageDirectory), RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), YES, YES);

// Then migrate what's in "Documents/.../RCTAsyncLocalStorage_V1" to "Application Support/[bundleID]/RCTAsyncLocalStorage_V1"
RCTStorageDirectoryMigrationCheck(RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), RCTCreateStorageDirectoryPath(RCTStorageDirectory), NO, NO);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're passing YES, YES to first migration, then NO, NO to the second one, you can actually use one parameter for that, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but they represent pretty different actions. Also it sounds like we're going to drop RNC* migration support soon anyway so this leads us to a pretty easy plan there (drop the last parameter and keep the other one)

Copy link
Member

@krizzu krizzu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tido64 Do you mind giving a second look on this?

@HeyImChris
Copy link
Contributor Author

@tido64 Do you mind giving a second look on this?

Thanks for the reviews. If it looks good, does one of you have permissions to merge? Doesn't look like I can.

Kudo added a commit to expo/expo that referenced this pull request Jan 11, 2023
# Why

react-native 0.71 removed the builtin async storage, to keep the backward compatibility, we should now vendor the *@react-native-async-storage/async-storage*
close ENG-7190

# How

- [tools] add @react-native-async-storage/async-storage to vendoring config
- to support expo-go's scoped async storage, we should further patch react-native-async-storage. they are now in the vendoring patch.
  - previously on ios, we had the patch [in our fork](expo/react-native@c7d3f6d)
  - previously on android, we did this from [the transform tool for our fork](https://github.com/expo/expo/blob/9047ecfbe233924e4848722b518d8ce1fa8b7173/android/tools/src/main/java/host/exp/exponent/tools/ReactAndroidCodeTransformer.java#L215-L216)
- the new react-native-async-storage saves data in a different storage, so they have the migration steps. to keep backward compatibility for existing expo-go. i skip the migrations and read the storage data from previous expo-go paths.
  - the new react-native-async-storage saves ios data in [*Application Support* rather than *Documents*](react-native-async-storage/async-storage#274). i don't want to follow the design. the reason is, besides backward compatibility, expo-go as a developer tool, it's good for developers to view the storage in *Documents*.
- [ios] migrate the AsyncStorage native module from `RCTAsyncLocalStorage` to `RNCAsyncStorage`
- [android] migrate `ExponentAsyncStorageModule` parent class to the new `AsyncStorageModule`
  - the new react-native-async-storage doesn't support turbo module, we have to move our integration from *ExpoTurboPackage* to *ExponentPackage*
  - the classic native module system respects the `@ReactMethod` annotation, we should add all of them in the `ExponentAsyncStorageModule`.

# Test Plan

- [ncl] AsyncStorage test case before this pr and after. makes sure the AsyncStorage value is kept after the changes.
turnipdabeets pushed a commit to turnipdabeets/expo that referenced this pull request Jan 11, 2023
# Why

react-native 0.71 removed the builtin async storage, to keep the backward compatibility, we should now vendor the *@react-native-async-storage/async-storage*
close ENG-7190

# How

- [tools] add @react-native-async-storage/async-storage to vendoring config
- to support expo-go's scoped async storage, we should further patch react-native-async-storage. they are now in the vendoring patch.
  - previously on ios, we had the patch [in our fork](expo/react-native@c7d3f6d)
  - previously on android, we did this from [the transform tool for our fork](https://github.com/expo/expo/blob/9047ecfbe233924e4848722b518d8ce1fa8b7173/android/tools/src/main/java/host/exp/exponent/tools/ReactAndroidCodeTransformer.java#L215-L216)
- the new react-native-async-storage saves data in a different storage, so they have the migration steps. to keep backward compatibility for existing expo-go. i skip the migrations and read the storage data from previous expo-go paths.
  - the new react-native-async-storage saves ios data in [*Application Support* rather than *Documents*](react-native-async-storage/async-storage#274). i don't want to follow the design. the reason is, besides backward compatibility, expo-go as a developer tool, it's good for developers to view the storage in *Documents*.
- [ios] migrate the AsyncStorage native module from `RCTAsyncLocalStorage` to `RNCAsyncStorage`
- [android] migrate `ExponentAsyncStorageModule` parent class to the new `AsyncStorageModule`
  - the new react-native-async-storage doesn't support turbo module, we have to move our integration from *ExpoTurboPackage* to *ExponentPackage*
  - the classic native module system respects the `@ReactMethod` annotation, we should add all of them in the `ExponentAsyncStorageModule`.

# Test Plan

- [ncl] AsyncStorage test case before this pr and after. makes sure the AsyncStorage value is kept after the changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform: iOS This is iOS specific
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants