Async-storage: Accessing stored data from native code?

Created on 15 Apr 2019  ·  16Comments  ·  Source: react-native-async-storage/async-storage

You want to:

From my iOS extension be able to access the data stored by my JavaScript code within the react native app.

Is it possible to call read/write functions from native code?

Exmaple:
From javascript

import AsyncStorage from '@react-native-community/async-storage';
await AsyncStorage.setItem('count', 999);

and then, from my native code I want to call what would be equivalent to getItem('count') to access the stored data. In my case, from the iOS share extension which needs to access this data. Are there any working example of how to do this? Is it even possible?

Details:

Sorry for asking questions that are a bit outside the scope of this module. I know it is supposed to be react native context, but some documentation about how this work behind the scene would be fantastic.

iOS question

Most helpful comment

This is possible but requires some knowledge of how native modules work in general. I'm not sure how future-proof this is with regards to the upcoming refactoring work in React Native but this is how you could access it today:

// First, get the RNCAsyncStorage instance from the bridge
RNCAsyncStorage *asyncStorage = [bridge moduleForClass:[RNCAsyncStorage class]];

// Then call the getter:
[asyncStorage multiGet:@[@"count"]] callback:^(NSArray *response){
    NSObject *count = response[0];
    if ([count isKindOfClass:[NSError class]]) {
        // Failed to get count
        return;
    }

    // Use count here
}];

Another (arguably better) way to do this is to implement RNCAsyncStorageDelegate as described in this guide. You would have to handle storage yourself but this will allow your extensions to access data directly without knowledge of the bridge or even React Native. We will also strive to have this API stable in the future.

All 16 comments

This is possible but requires some knowledge of how native modules work in general. I'm not sure how future-proof this is with regards to the upcoming refactoring work in React Native but this is how you could access it today:

// First, get the RNCAsyncStorage instance from the bridge
RNCAsyncStorage *asyncStorage = [bridge moduleForClass:[RNCAsyncStorage class]];

// Then call the getter:
[asyncStorage multiGet:@[@"count"]] callback:^(NSArray *response){
    NSObject *count = response[0];
    if ([count isKindOfClass:[NSError class]]) {
        // Failed to get count
        return;
    }

    // Use count here
}];

Another (arguably better) way to do this is to implement RNCAsyncStorageDelegate as described in this guide. You would have to handle storage yourself but this will allow your extensions to access data directly without knowledge of the bridge or even React Native. We will also strive to have this API stable in the future.

@tido64 Do you know if it also exists a similar way for the Android native access?

@kodeusz: Unfortunately, I'm not as well-versed on the Android side as I'd like to be. From looking at the code, it seems the Android equivalent is ReactContext.getNativeModule(). There's an example of it being used in UIManagerHelper. Hope that helps 😄

@tido64 I'm just wondering, does that solution also work if you want to also subscribe to future updates of any var? If I'm not wrong, with the snippet you posted, we will only check one time the var's value but I'd like to keep my native side up to date whenever a var is updated from js. Is there a way to do that?

Edit.
I know I could do that with the delegate but I don't want to implement all those methods my self if there's an easy way to do that.

It would be really good if there was a way to just hook into one function but keeping the same underlying storage.

There is currently no way to subscribe, neither in JS or in native. That's pretty much outside the scope of AsyncStorage.

@tido64 hello. How do I use that for swift code? I already have access on RNCAsyncStorage in swift but don't know how to get value from RNCAsyncStorage in swift code.

@albilaga You can get values from RNCAsyncStorage the same way you would in Objective-C. You just need to translate the code to Swift:

asyncStorage.multiGet(["count"]) { response in
  // Use `response` here
};

I already tried that code but I got exception must be executed on storage thread. Any idea @tido64 ?

Never mind. I need to access with

asyncStorage.methodQueueu.async {
   asyncStorage.multiGet(["count"]) { response in
   // Use response here
}

This is possible but requires some knowledge of how native modules work in general. I'm not sure how future-proof this is with regards to the upcoming refactoring work in React Native but this is how you could access it today:

// First, get the RNCAsyncStorage instance from the bridge
RNCAsyncStorage *asyncStorage = [bridge moduleForClass:[RNCAsyncStorage class]];

// Then call the getter:
[asyncStorage multiGet:@[@"count"]] callback:^(NSArray *response){
    NSObject *count = response[0];
    if ([count isKindOfClass:[NSError class]]) {
        // Failed to get count
        return;
    }

    // Use count here
}];

Another (arguably better) way to do this is to implement RNCAsyncStorageDelegate as described in this guide. You would have to handle storage yourself but this will allow your extensions to access data directly without knowledge of the bridge or even React Native. We will also strive to have this API stable in the future.

Is there an update to that delegate guide? I think the link is broken

Is there an update to that delegate guide? I think the link is broken

You can find the guide here: https://react-native-community.github.io/async-storage/docs/advanced/brownfield

Is there an update to that delegate guide? I think the link is broken

You can find the guide here: https://react-native-community.github.io/async-storage/docs/advanced/brownfield

Thanks for the update, from that guide I'm assuming this would still go through the bridge even on the native side?

from that guide I'm assuming this would still go through the bridge even on the native side?

If you're calling your delegate directly from native code, you're not going through the bridge. The delegate object is owned by you in this scenario.

from that guide I'm assuming this would still go through the bridge even on the native side?

If you're calling your delegate directly from native code, you're not going through the bridge. The delegate object is owned by you in this scenario.

With delegates I just need to implements the required methods correct? I think the data file creation, store, etc. is still managed by AsyncStorage

@tido64 I tried using this https://github.com/react-native-community/async-storage/issues/80#issuecomment-685004407 but I can't get the value. The response I got is NSArray with 2 items with response[0] is NSNull and response[1] is Any with no value that I expected even though I already check in react native app and it get the correct value. Any idea?

Sorry, without knowing what your code looks like, that's hard for me to tell. It sounds like you didn't get the correct instance or there is a race condition.

I'm going to lock this issue as it has turned into a support channel. If you're hitting issues that you think are bugs in AsyncStorage, please file a new issue.

Was this page helpful?
0 / 5 - 0 ratings