-
Notifications
You must be signed in to change notification settings - Fork 400
Description
Really appreciate the work that @jvandenaardweg went to over in issue #182 to try and help everybody out, but I thought I'd open this here to share a solution that doesn't need to modify build settings or fork any repos. I would suggest just writing your own share extension and using some skeleton code from this issue. You can still follow most of the install steps, but without importing this lib, and a few additional steps.
- Create your iOS share extension (in current install steps)
In X-Code, having opened up your project
File > New > Target -> ShareExtension
- In your podfile, set your target to use all of the react-native libs
# right below use_native_modules!
# for share extension
target 'name_of_your_share' do
use_native_modules!
inherit! :complete
end- Replace the default code with an extension of
UIViewControllerand implementviewDidLoadto load react native
MyShareExtension.h
#import <UIKit/UIKit.h>
#import <React/RCTBridgeModule.h>
@interface MyShareExtension : UIViewController<RCTBridgeModule>
@end
MyShareExtension.m
#import "MyShareExtension.h"
#import <React/RCTRootView.h>
#import <React/RCTBundleURLProvider.h>
NSExtensionContext* extensionContext;
@implementation MyShareExtension {
}
RCT_EXPORT_MODULE();
- (void) viewDidLoad {
[super viewDidLoad];
extensionContext = self.extensionContext; // global for later call to async promise
// set up react native instance
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
moduleName: @"your_target_react_native_app" // AppRegistry.registerComponent("your_target_react_native_app", App)
initialProperties: nil
launchOptions: nil];
UIViewController *rootViewController = [UIViewController alloc];
rootViewController.view = rootView;
[self addChildViewController: rootViewController];
rootViewController.view.frame = self.view.bounds;
rootViewController.view.translatesAutoresizingMaskIntoConstraints = false;
[[self view] addSubview:rootViewController.view];
NSArray* constraints = [NSArray arrayWithObjects:
[rootViewController.view.leftAnchor constraintEqualToAnchor: self.view.leftAnchor],
[rootViewController.view.rightAnchor constraintEqualToAnchor: self.view.rightAnchor],
[rootViewController.view.topAnchor constraintEqualToAnchor: self.view.topAnchor],
[rootViewController.view.bottomAnchor constraintEqualToAnchor: self.view.bottomAnchor], nil
];
[NSLayoutConstraint activateConstraints:constraints];
[self didMoveToParentViewController: self];
}
- Pretty much copy the content from this lib and expose methods to react native to fetch the parameters capturing from the share extension
// top of file
#import <MobileCoreServices/MobileCoreServices.h>
#define URL_IDENTIFIER (NSString *)kUTTypeURL
#define IMAGE_IDENTIFIER (NSString *)kUTTypeImage
// ... more code
RCT_REMAP_METHOD(getParameters,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[self extractData: extensionContext withCallback:^(NSDictionary* result, NSException* err) {
if(err) {
reject(@"error", err.description, nil);
} else {
resolve(result);
}
}];
}
- (void) extractData: (NSExtensionContext *)context withCallback:(void(^)(NSDictionary* result, NSException *exception))callback {
@try {
// get items shared
NSExtensionItem *item = [context.inputItems firstObject];
__block NSItemProvider *provider = item.attachments.firstObject;
if ([provider hasItemConformingToTypeIdentifier:IMAGE_IDENTIFIER]){
[provider loadItemForTypeIdentifier:IMAGE_IDENTIFIER options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSURL *url = (NSURL *)item;
NSDictionary *result = @{@"data": [url absoluteString], @"extension": [[[url absoluteString] pathExtension] lowercaseString], @"type": @"image"};
if(callback) {
callback(result, nil);
}
}];
return;
}
if([provider hasItemConformingToTypeIdentifier:URL_IDENTIFIER]) {
[provider loadItemForTypeIdentifier:URL_IDENTIFIER options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSURL *url = (NSURL *)item;
NSDictionary *result = @{@"data": [url absoluteString], @"type": @"url"};
if(callback) {
callback(result, nil);
}
}];
return;
}
if(callback) {
callback(nil, [NSException exceptionWithName:@"Error" reason:@"couldn't find provider" userInfo:nil]);
}
}
@catch (NSException *exception) {
}
}
Conclusion
You still need to follow the install steps to restrict the types that your app can receive (The plist) and ensure the transport settings let you connect to the react native bundler server, but these were the most critical steps to getting my share extension working.