All articles
Article 4 min read

A Polyfill, Shims, and Native Module Journey: Building a Crypto Wallet

This article explores challenges faced while developing a React Native crypto wallet, including the use of polyfills, shims, and native modules to ensure cross-platform functionality.

Introduction

In 2021, I embarked on an ambitious project that combined my interest in cryptocurrency with my expertise in React Native. My objective was to build a mobile crypto wallet for iOS and Android using JavaScript, leveraging React Native's flexibility for rapid development across platforms. This journey involved navigating the complexities of cross-platform development, especially when dealing with non-standard features or libraries unavailable on certain platforms. Two critical aspects of this process were the use of polyfills, shims, and native modules to ensure compatibility and performance. In this article, I'll delve into these techniques and share lessons learned from my experience building a crypto wallet using React Native.

Polyfills

Polyfills are scripts that fill in gaps or provide fallbacks for features supported natively by modern browsers but not available through the JavaScript environment of older browsers. When working on a cross-platform project like mine, polyfills became essential to ensure consistent behavior across both iOS and Android devices.

Common Challenges with ES6 Features

One significant challenge was dealing with newer ECMAScript 2015+ features that were not natively supported by either platform's JavaScript runtime environment. For example, I needed to handle Promises, which are fundamental for asynchronous operations such as API calls in a crypto wallet application.

Implementing Polyfills

I addressed these challenges using polyfill libraries such as babel-polyfill or whatwg-fetch. These tools dynamically add the necessary functionality at runtime if required features are not available natively. For instance, to support Promises on older browsers that lack native Promise objects, I used whatwg-fetch for making HTTP requests instead of relying solely on fetch(), which only works with modern JavaScript environments.

Shims

Shims act as a bridge between APIs expected by code and the actual API implementation provided by underlying systems. In my crypto wallet project, shims were necessary to ensure compatibility with specific features that might not be natively implemented in all platforms or environments.

Cross-Platform Functionality

One particular example involved creating a shim for iOS’s UIDevice class, which doesn’t exist on Android. I needed functionality such as getting the device’s model and manufacturer through this API. By creating a shims to emulate these functionalities, I ensured that my application worked seamlessly across both platforms without requiring platform-specific code.

Shimming the UIDevice Class

To achieve this, I wrote an adapter for the UIDevice class in JavaScript. This adapter would provide the necessary device information when accessed through the native class and fallback gracefully if no such object is found. This approach allowed me to maintain a clean, unified API across all platforms without sacrificing functionality.

Native Modules

Native modules are compiled binaries that integrate directly with the platform’s native code and runtime environment. They offer superior performance over JavaScript interop mechanisms like polyfills and shims due to their direct interaction with hardware and system libraries.

Integrating Crypto Functions

A critical component of a crypto wallet involves handling high-performance cryptographic functions such as hashing, signing, and encryption/decryption. These operations are typically faster when implemented natively rather than through JavaScript or other interop mechanisms.

Implementing Native Modules for Crypto Operations

To achieve this in my project, I used React Native’s native module system to create a C++ extension that interacts with the underlying platform’s cryptographic libraries. This allowed me to leverage hardware acceleration and optimized code paths provided by native modules, resulting in significant performance improvements for key operations within the crypto wallet.

Cross-Platform Usage

Despite starting from a JavaScript-native environment, I still needed to ensure cross-platform compatibility using a combination of polyfills, shims, and native modules. Each approach had its own use cases: polyfills covered gaps in standard library support, shims bridged missing platform APIs, while native modules optimized performance-critical operations.

Conclusion

My experience building a crypto wallet with React Native underscored the importance of understanding cross-platform development challenges and leveraging appropriate techniques such as polyfills, shims, and native modules. These tools helped me build a robust, performant, and feature-complete application that could be deployed across multiple platforms without sacrificing functionality or performance.

By adopting these strategies, developers can overcome many of the common hurdles associated with cross-platform mobile app development using frameworks like React Native and ensure their applications provide an excellent user experience on all target devices.