This article is translated and the original address is:

Adding a native iOS “Share” button to a React Native app

I was working on my React Native app and came across a small feature point to add a local third-party sharing button. This is a very detailed feature point and therefore is not incorporated into the default framework. However, the framework provides a list of native Objective-C interfaces that interact with the upper layer, making it easy to do the following:

How it works in iOS

The local end of iOS uses the control UIActivityViewController, which provides the function of a simple modal dialog box, which can be displayed at the bottom of the screen to carry out some predefined operations. UIActivityViewController is relatively simple to use. A simple sharing popup can be constructed with the following code:

- (IBAction)shareButton:(UIBarButtonItem *)sender { NSString *textToShare = @"Look at this awesome website for aspiring iOS Developers!" ; NSURL *myWebsite = [NSURL URLWithString:@"http://www.codingexplorer.com/"]; NSArray *objectsToShare = @[textToShare, myWebsite]; UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil]; NSArray *excludeActivities = @[UIActivityTypeAirDrop, UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll, UIActivityTypeAddToReadingList, UIActivityTypePostToFlickr, UIActivityTypePostToVimeo]; activityVC.excludedActivityTypes = excludeActivities; [self presentViewController:activityVC animated:YES completion:nil]; }

I won’t go into detail here on how to construct and pop up a shared modal window on the local side, but it’s important to discuss whether the window should pop up as a UIView or as a toggling UIViewController. My first reaction was to check the React documentation where they explained how to encapsulate a native control in the React form. My approach is also to display the UIView that the shared form is in and render it the way we want it to be. But as I mentioned earlier, there’s a UIView controller that you’re calling instead of a UIView.

How to call the Share dialog from a native module

So creating a native module by switching UIViewController instead of embedding a shared page in the React element is very simple, as shown in the figure below:

The template for the initialization code looks like this:

//
//  RCTShareManager.h
//
 
#import <RCTBridgeModule.h>
 
@interface RCTShareManager : NSObject <RCTBridgeModule>
@end

 

//
//
//  RCTShareManager.m
//
 
#import "RCTShareManager.h"
 
@implementation RCTShareManager
 
RCT_EXPORT_MODULE();
 
RCT_EXPORT_METHOD(shareURL:(NSString *)URLString)
{
    // Some native code
}
 
@end

Finally, the interface to the shareURL method is exposed to JavaScript in the following way:

var React = require('react-native');
var ShareManager = React.NativeModules.ShareManager;
 
// Somewhere in your component...
 
function onPress(){
    ShareManager.shareURL(someURL);
};

In the native code, you can combine the UIActivityViewController as follows:

//
//  RCTShareManager.m
//
 
#import "RCTShareManager.h"
@import UIKit;
 
@implementation RCTShareManager
 
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(shareURL:(NSString *)URLString)
{
    NSArray *objectsToShare = @[[NSURL URLWithString:URLString]];
    UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
 
    UIViewController *rootController = UIApplication.sharedApplication.delegate.window.rootViewController;
 
    [rootController presentViewController:activityVC animated:YES completion:nil];
}
 
@end

However, if you do this, Xcode will report the following error:

This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes.  This will cause an exception in a future release.

And after a long time, the screen should look like this:

This is because React Native executes the code in the background thread, while IOS allows only the main thread to render the front-end interface by default. Therefore, we need to place the page rendering part in the main thread:

RCT_EXPORT_METHOD(shareURL:(NSString *)URLString)
{
    NSArray *objectsToShare = @[[NSURL URLWithString:URLString]];
    UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
 
    UIViewController *rootController = UIApplication.sharedApplication.delegate.window.rootViewController;
 
    dispatch_async(dispatch_get_main_queue(), ^{
        [rootController presentViewController:activityVC animated:YES completion:nil];
    });
}