Skip to content

feat: React Native New Architecture (Bridgeless) support#343

Open
plrthink wants to merge 18 commits intomasterfrom
feat/new-architecture
Open

feat: React Native New Architecture (Bridgeless) support#343
plrthink wants to merge 18 commits intomasterfrom
feat/new-architecture

Conversation

@plrthink
Copy link
Copy Markdown
Collaborator

@plrthink plrthink commented May 4, 2026

Summary

Closes #330

This PR migrates react-native-zip-archive to support React Native 0.76 New Architecture (Fabric + TurboModules) with Bridgeless mode enabled.

Library Changes

iOS:

  • Add RCTTurboModuleRegistry and getTurboModule: returning NativeZipArchiveSpecJSI for Bridgeless registration
  • Fix podspec install_modules_dependencies check and flatten header_search_paths
  • Fix encryption default inconsistency: empty encryptionType now defaults to standard ZipCrypto (matching Android)
  • Add old-arch fallback via #ifdef RCT_NEW_ARCH_ENABLED guards in header and implementation
  • Cache methodQueue dispatch queue instead of creating a new one on every call

Android:

  • Add conditional com.facebook.react plugin and codegen sourceSets when newArchEnabled=true
  • Add Paper (Old Architecture) fallback spec at android/src/oldarch/NativeZipArchiveSpec.java
  • Fix illegal SSZipArchive symbol in build.gradle
  • Fix unzipAssets for compressed assets: AssetManager.openFd() fails for .zip files stored compressed in the APK; now falls back to InputStream.available()
  • Add null check for f.listFiles() in processZip to prevent NPE

JS:

  • Implement lazy TurboModule loading to avoid Bridgeless init crash
  • Update unit tests for lazy loading behavior

Playground (New Expo 52 App)

  • Create Expo dev-client playground with expo-router
  • Enable newArchEnabled=true in app.json
  • Demo screens: zip, unzip, password, progress, benchmarks, assets
  • Fix nested file creation (ensureDir before write)
  • Add listFilesRecursive utility for displaying extracted nested files
  • Add expo-document-picker explicitly (pnpm transitive dep fix)

E2E Testing

  • Add Maestro flows for iOS and Android
  • Handle iOS dev-client launcher (tap Metro URL)
  • Handle Android cold-start with 45s timeout
  • Add assets.yaml flow for Android unzipAssets demo
  • Add npm scripts: e2e:ios, e2e:android, e2e
  • Add shell scripts for sequential test execution

Test Results

Platform Flow Result
iOS home
iOS zip-and-unzip
iOS password
iOS progress
Android home
Android zip-and-unzip
Android password
Android progress
Android assets
Unit tests 27/27

Breaking Changes

Requires React Native >= 0.70.0. New Architecture is opt-in (enabled via newArchEnabled=true in consuming app).


Open in Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

plrthink

This comment was marked as duplicate.

plrthink

This comment was marked as duplicate.

devin-ai-integration[bot]

This comment was marked as resolved.

@plrthink plrthink force-pushed the feat/new-architecture branch from 156c118 to 96f8f02 Compare May 6, 2026 04:49
plrthink added 10 commits May 6, 2026 13:14
- Update version to 8.0.0-rc.1
- Update peer dependencies: RN >= 0.70.0, React >= 18.0.0
- Add playground/ to .npmignore
- Update description for New Architecture
- Add TypeScript spec for Codegen (specs/NativeZipArchive.ts)
- Migrate iOS from RCTBridgeModule to TurboModule protocol
- Migrate Android from ReactContextBaseJavaModule to NativeZipArchiveSpec
- Update JS entry point to use TurboModuleRegistry with Legacy fallback
- Update podspec to include .mm files
- Add complete Expo playground with expo-dev-client
- Include 7 demo screens for all library features
- Add Jest test suite with 27 passing tests
- Add TurboModule integration tests
- Configure Metro for local module linking
- Rewrite README with New Architecture focus
- Add MIGRATION.md with step-by-step guide
- Add CHANGELOG.md with v8.0.0 release notes
- Document Expo Development Build requirements
- Preserve all existing API documentation
- Explain why Expo Go is not supported
- Add step-by-step Development Build setup
- Include comparison table for clarity
- Link to playground example
- iOS: Extend RCTEventEmitter to support progress events (critical fix)
- Podspec: Add install_modules_dependencies for modern RN support
- index.d.ts: Fix unzipWithPassword parameter name
- Android: Remove outdated AGP buildscript block
- CHANGELOG: Update release date
- .npmignore: Exclude dev files from npm package
- Mock: Remove non-existent native method from mock
…layground

This commit migrates react-native-zip-archive to support React Native 0.76
New Architecture (Fabric + TurboModules) with Bridgeless mode enabled.

Library changes:
- iOS: add RCT_EXPORT_MODULE() and getTurboModule: returning
  NativeZipArchiveSpecJSI for Bridgeless registration
- iOS: fix podspec install_modules_dependencies check and flatten subspec
- Android: add conditional com.facebook.react plugin and codegen sourceSets
  when newArchEnabled=true
- Android: add Paper (Old Architecture) fallback spec
- Android: fix illegal switch-on-double in getCompressionLevel()
- JS: implement lazy TurboModule loading to avoid Bridgeless init crash
- JS: update unit tests for lazy loading behavior

Playground (new Expo 52 app):
- Create Expo dev-client playground with expo-router
- Enable newArchEnabled in app.json
- Add demo screens: zip, unzip, password, progress, benchmarks, assets
- Fix nested file creation (ensureDir before writeAsStringAsync)
- Add expo-linking explicitly (pnpm transitive dep fix)
- Add accessibilityLabel for E2E automation

E2E testing:
- Add Maestro flows for iOS and Android
- Handle iOS dev-client launcher (tap Metro URL)
- Handle Android cold-start with 45s timeout
- Add npm scripts: test:e2e, test:e2e:android, test:e2e:ios
- Add shell scripts for sequential test execution

Documentation:
- Add e2e/README.md with Maestro setup instructions
- iOS: call [super addListener:] / [super removeListeners:] to preserve
  RCTEventEmitter lifecycle (startObserving/stopObserving) for progress events
- Android: add missing return after promise.reject in unzipWithPassword
  and zipWithPassword to prevent double-resolve / NullPointerException
- Android: use TurboReactPackage instead of BaseReactPackage for RN 0.70+
  backward compatibility
- README: fix broken Buy Me A Coffee markdown link
- Android unzipWithPassword: resolve with destDirectory string instead of
  WritableArray to match TurboModule spec (Promise<string>) and iOS behavior
- Android processZip: add missing return after promise.reject when file
  doesn't exist, preventing double promise settlement
- Android processZip: move updateProgress(100%) outside the for loop so
  it fires once after all entries are processed, not on every iteration
Devin review noted that early RN 0.70.x releases require a 7-arg
ReactModuleInfo constructor including hasConstants. Adding the 7th
arg maintains backward compatibility with >= 0.70.0 peer dep.
@plrthink plrthink force-pushed the feat/new-architecture branch from 96f8f02 to 283bb74 Compare May 6, 2026 05:14
devin-ai-integration[bot]

This comment was marked as resolved.

plrthink added 3 commits May 6, 2026 14:52
- Fix encryption method default inconsistency: empty string now defaults
  to non-AES (ZIP_STANDARD) on iOS, matching Android behavior.
- Add RCT_NEW_ARCH_ENABLED guards for old architecture compatibility:
  conditionally import NativeZipArchiveSpec header and conform to the
  protocol only when New Architecture is enabled, matching the Android
  paper shim pattern.

Refs: Devin review comments #3193190132, #3193190251
Add Maestro E2E test for the Android Assets demo screen.
The test navigates to Assets (Android), taps Unzip Assets,
and asserts the sample.zip contents are extracted correctly.

Also includes the new flow in the Android E2E test script.
devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator Author

@plrthink plrthink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit d08ce66. Added a null check before Arrays.asList(f.listFiles()) — if listFiles() returns null (e.g., directory unreadable due to permissions), we now fall back to an empty ArrayList instead of throwing NPE.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator Author

@plrthink plrthink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit ef43fc5. Added a methodQueue property to RNZipArchive.h and changed the getter in RNZipArchive.mm to lazily initialize and cache the serial dispatch queue, preventing a new queue from being created on every call.

@plrthink plrthink changed the title feat: React Native New Architecture (Bridgeless) support v8.0.0-rc.1 feat: React Native New Architecture (Bridgeless) support v8.0.0-rc.2 May 10, 2026
@plrthink plrthink changed the title feat: React Native New Architecture (Bridgeless) support v8.0.0-rc.2 feat: React Native New Architecture (Bridgeless) support May 10, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator Author

@plrthink plrthink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 71d099d. Changed the private helper to catch Exception instead of IOException (covers ZipException which extends Exception), and wrapped the public method in try-catch so it rejects the promise with a proper error message instead of crashing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

React Native Zip Archive - Migration to New Architecture

1 participant