React Native share PDF
TL;DR: Use react-native-share-pdf library to share base64 PDF on Android/iOS.
Disclaimer: Intended for React developers.
Context
At ING Investments we use React Native to deliver the Mobile Investments App on two platforms. The mobile application is a trading App which allows to buy and sell different financial instruments for the Dutch market. Without a registered account you can try the public environment which gives a sneak peak of the available features. If you’re interested, you can find this playground here: (iOS — Android).
As full stack developer within a small multi disciplinary team on ING Investments, we worked on costs transparency for all financial transactions. As part of this critical feature, we came across the time sensitive challenge to share a PDF file (encoded as base64
) so that the user could save a local copy in his preferred destination, which can be useful for tax reasons among others.
Sharing the document did work on iOS but not on Android. Let’s examine why and how we solved it.
Why React Native?
React Native is a valuable framework that borrows React’s paradigm and design principles to enable lightning fast, cross-platform development of snappy UIs. Facebook, Uber, Instagram, Tesla, Skype and many others already have their latest apps built with React Native delivering for both iOS & Android customers. As one of the first dutch teams using React Native, our experience with this technology and other native modules has been optimal.
Sharing in React Native
Our goal is to open the native Share action sheet (or activity), so the system can propose the apps that supports the PDF format. After that the user can choose which app will be used to store the file.
On iOS, React Native allow us to easily share base64 encoded files using the <url> property. The following snippet opens the native Share action sheet:
The system interprets the url
type and data and gives the option to create a PDF. The system interprets the type and data and gives the option to create a PDF.
Unfortunately, on Android the property is not supported.
ING Investments solution
React Native is designed in a way that enables you to perform cross-language function calls. You can execute custom native code from JavaScript and vice versa.
➡️ Let’s describe our native solution in order to share the PDF file to the customer’s device.
After retrieving the base64 data the native Java solution for Android consists of the following steps:
- Clean up previously shared PDF files.
We don’t want to accumulate too many files on the device so we clean up the previously shared PDF files:
2. Write the PDF file to the device system.
We can do this by decoding the base64
string as a byte array
:
3. Start a share activity.
In Android we have to construct an Intent by specifying the PDF mime type with ACTION_SEND
in order to send the PDF file data from one activity to another one. EXTRA_STREAM
is used to specify the actual binary data that is going to be shared.
Uri outputFileUri = FileProvider.getUriForFile(reactContext, "com.maximegerbe.reactnative.sharefile.provider", file);Intent intentShareFile = new Intent(Intent.ACTION_SEND);
intentShareFile.setType(TYPE_PDF);
intentShareFile.putExtra(Intent.EXTRA_STREAM, outputFileUri);reactContext.startActivity(Intent.createChooser(intentShareFile, ""));
In order to write/read the PDF file to the device system we need to create a FileProvider component in AndroidManifest.xml
. To specify the directory of available files we are using child elements of the <paths>
element. For example, the following paths
element tells FileProvider
that you intend to request content URIs for the pdf_documents_for_sharing/
subdirectory of your private file area.
ShareFile
will handles the 3 fore-mentioned steps. The complete implementation of the Java class can be found here.
From the native module we export the RNShareFile
object and expose the following share()
method that can be called from the JavaScript layer. You can read more about the well documented native module setup here.
Share method signature:
Usage in App.js
:
Which opens the native share activity (more demo)
In this example we share the PDF file to GMail.
Unit Testing
The goal is to validate that the sharePDF()
method does 1 thing for each platform:
- Invoke the platform API for iOS.
- Invoke the
share()
method of our native module on Android.
We can achieve this with Jest by mocking the React Native libraries: Platform.select
and Share.share
:
Coverage result:
Conclusion
The PDF use case shows that sometimes an app needs to access the platform API and if React Native doesn’t provide the corresponding module we can always write native code and have access to the full power of the platform. Other examples could include: reusing existing native code, multi-threaded code, etc.
Currently we can share only files with the mime type application/pdf
. We can improve that by providing the mime type as a parameter. Since React Native is an open source project, in the future we can contribute by integrating this library to the project.
This library is distributed as a NPM package: NPM (4.2 kB) and the source code is available on GitHub: https://github.com/MadeinFrance/react-native-share-pdf
If this post got your attention, you can find a demo project here.
For any questions or feedback, feel free to let me know in the comments down below. If this was useful, please click the clap 👏 button to the side a few times to show your support.
Thanks for reading,
Maxime Gerbe.