iOS Shared UserDefaults for App Extensions With RCTBridgeModule

2 min read

Get/Set key-value from both React Native and Swift/Obj-C

In this blog post, I will share the code for a simple RCTBridgeModule that can write/read key-value from React Native.

The use case for this is to access the data in iOS Share Extension using value set from React Native.

So that the Share Extension can perform API call with sufficient data that was set in React Native, and thus giving user a much better experience similar to other natively built apps. This is a much more complicated implementation and there are much simpler ways to get it done without writing too many native code and that will be for another blog post.

Let's get back and focus on this topic, get and set value in UserDefaults that are accesible in Share Extension. In order to achieve that, we need to use UserDefaults with suiteName that starts with group..

Before you proceed, please make sure that you have already created Share Extension and updated App Groups in the Signing & Capabilities. This is not covered in this post and there are alot of online resources for this topic.



1. First, create a header file in xcode.

I'll name it SharedUserDefaults.h

#ifndef SharedUserDefaults_h #define SharedUserDefaults_h #endif #import <Foundation/Foundation.h> #if __has_include(<React/RCTAssert.h>) #import <React/RCTBridgeModule.h> #else #import "RCTBridgeModule.h" #endif @interface SharedUserDefaults : NSObject <RCTBridgeModule> @end

2. Then, create the implementation file.

SharedUserDefaults.m

#import <Foundation/Foundation.h> #import "SharedUserDefaults.h" @implementation SharedUserDefaults RCT_EXPORT_MODULE() + (BOOL)requiresMainQueueSetup { return YES; } RCT_EXPORT_METHOD(set:(NSString *)suiteName key:(NSString *)keyName value:(NSString *)value) { NSUserDefaults *shareExtensionDefaults = [[NSUserDefaults alloc] initWithSuiteName: suiteName]; [shareExtensionDefaults setObject:value forKey:keyName]; NSLog(@"val written %@", value); } RCT_EXPORT_METHOD(get:(NSString *)suiteName key:(NSString *)keyName resolver: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSUserDefaults *shareExtensionDefaults = [[NSUserDefaults alloc] initWithSuiteName: suiteName]; NSString *val = [shareExtensionDefaults stringForKey:keyName]; if (val == nil) { NSError *error = [NSError errorWithDomain:@"org.reactjs.native.example.Bill" code:0 userInfo:@{ @"message": @"Empty" }]; reject(@"error", @"error description", error); } else { resolve(val); } } @end

3. Next, build and run your app.

And you can use the methods from the native module you've just written.

In your React Native project, you can now get and set key-value pair to UserDefaults via the native module.

import { NativeModules } from 'react-native'; const SharedUserDefaults = NativeModules.SharedUserDefaults; // Usage // Set SharedUserDefaults.set("group.org.reactjs.native.example.YourProject", "yourKey", "some string to be stored"); // Get let val = await SharedUserDefaults.get("group.org.reactjs.native.example.YourProject", "yourKey");

In iOS, the value can be retrieved in ShareViewController.swift or AppDelegate.m.

Swift

var userDefaults = UserDefaults(suiteName: "group.org.reactjs.native.example.YourProject") // Get value stored earlier let storedValue = userDefaults?.object(forKey: "yourKey") as? String // Set new value userDefaults?.set("some string to be stored", forKey: "yourKey")

Obj-C

NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName: @"group.org.reactjs.native.example.YourProject"]; // Get value stored earlier NSString *val = [userDefaults stringForKey:@"yourKey"]; // Set new value [userDefaults setObject:@"some string to be stored" forKey:@"yourKey"];

End

You are now all set!

Now you can set value from React Native and retrieve it in your ShareViewController.swift.

That's it! Hope it helps.

Cheers.