react-native-zip-archive

Native zip and unzip for React Native and Expo — password-protected archives, selective extraction, and cancellable operations on iOS and Android.

Library
npm
v9.5.1
484stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity84
Maintenance72
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture78
Code Quality84
Innovation83
Learning Curve75

react-native-zip-archive is a native module that gives React Native and Expo apps real zip and unzip capabilities on both iOS and Android, backed by native compression libraries rather than a pure-JavaScript implementation. It supports the New Architecture via TurboModules with a fallback path to the legacy NativeModules bridge, so the same JS API works whether or not the New Architecture is enabled, as long as the app is rebuilt against RN >= 0.70.

Beyond basic zip/unzip, the library handles password-protected archives with configurable encryption (ZipCrypto/AES-128/AES-256), selective extraction of specific entries or directories, listing archive contents without extracting, unzipping bundled app assets, and reporting progress through an event emitter. Long-running operations can be cancelled via a shared cancel() call or the standard AbortSignal pattern, and both platforms serialize zip/unzip work through a single queue to avoid concurrent native operations.

What You Get

  • Native zip/unzip on iOS and Android instead of a pure-JS implementation, avoiding the memory overhead of libraries like JSZip for large files.
  • Password-protected archive support with STANDARD (ZipCrypto), AES-128, and AES-256 encryption methods.
  • Selective extraction and listing — pull specific files or directories out of an archive, or list contents (path, size, compressed size, encryption flag) without extracting anything.
  • AbortSignal and cancel() support for stopping in-flight zip/unzip operations, plus a progress event emitter via subscribe().
  • TurboModule (New Architecture) support with automatic fallback to the legacy NativeModules bridge, plus an Expo config plugin for development builds/EAS.

Common Use Cases

  • Unpacking downloaded content bundles (assets, themes, offline data packs) into the app’s document directory after fetching them from a server.
  • Extracting bundled app assets shipped inside the APK or app bundle via unzipAssets, without needing an absolute filesystem path.
  • Building password-protected export/import flows, e.g. encrypting a user’s exported data before sharing it outside the app.
  • Previewing archive contents (file list, sizes) before committing to a full extraction, useful for large downloaded zip files.

Under The Hood

Architecture The JS layer (index.js) is a thin, functional wrapper: lazy-resolves the native module through TurboModuleRegistry with a NativeModules fallback (getRNZipArchive()), normalizes arguments across multiple overloaded call shapes (positional args vs options object) via small resolver functions (resolveZipOptions, resolvePasswordOptions, resolveUnzipArgs), and layers an AbortSignal wrapper (withAbort) around each native call using Promise.race against an abort gate. On Android, RNZipArchiveModule.java is a single large module class backed by zip4j, delegating path-safety concerns to ZipSecurity.java (a small, focused utility that disables symlink extraction and canonical-path-validates every entry to block Zip Slip) and StreamUtil.java for I/O helpers; codegen specs (specs/NativeZipArchive.ts, android/src/paper) generate the TurboModule interface consumed by both the old and new architecture code paths. iOS mirrors this via RNZipArchive.mm/h with RCT_EXPORT_MODULE and a conditionally compiled TurboModule getter. Because RNZipArchiveModule.java is the single choke point for both zip and unzip logic on Android, swapping the core native dependency would require re-verifying path validation, error codes, and progress events together.

Tech Stack package.json declares peer dependencies on react and react-native, with Jest for testing and a React Native community ESLint config for linting. Android build uses zip4j for the actual compression/encryption implementation, wired through Gradle with separate main and paper source sets to isolate New/old-architecture codegen output; codegen is driven by a codegenConfig block in package.json pointing at the TypeScript native spec. CI runs dedicated Android build, iOS build, old-architecture, end-to-end (Maestro), and zip-interoperability workflows, plus a separate publish workflow — a notably thorough matrix for a small utility library. Two full playground apps for plain React Native and Expo are checked into the repo as living smoke-test harnesses for development builds.

Code Quality The repo has real automated tests on both the JS and native side: multiple Jest test files cover the public API, module integration, package metadata, the Expo config plugin, and zip interoperability, and the Android module has JUnit tests for its security utility, error codes, entry-selection matching, and array conversion helpers — including a dedicated test validating the Zip Slip path-traversal fix. Errors are modeled explicitly through a ZipError factory with a fixed error-code enum rather than raw strings, and the JS layer consistently rejects with typed errors instead of swallowing failures. TypeScript types are hand-maintained as function overloads for every call shape rather than generated. ESLint is configured and CI enforces multiple build/test workflows before publish, with no signs of neglected lint or test failures in the sampled files.

API Design The public API is small and consistent — one verb-based function per operation (zip, unzip, zipWithPassword, unzipWithPassword, listContents, unzipAssets, getUncompressedSize, cancel, subscribe) with named constants for compression levels and encryption methods instead of magic numbers or strings. Backward compatibility is handled carefully: several functions accept either legacy positional arguments or a single options object, auto-detected at runtime, so adding AbortSignal support did not break existing call sites. Getting started requires one install plus an Expo config-plugin entry for Expo users, with no separate native-linking step documented for supported React Native versions. The README documents an explicit version-compatibility matrix and a comparison table against alternative approaches, which is unusually candid, developer-facing documentation for a small library.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search