Skip to content

feat: React Native New Architecture (Bridgeless) support v8.0.0-rc.1#343

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

feat: React Native New Architecture (Bridgeless) support v8.0.0-rc.1#343
plrthink wants to merge 14 commits intomasterfrom
feat/new-architecture

Conversation

@plrthink
Copy link
Copy Markdown
Collaborator

@plrthink plrthink commented May 4, 2026

Summary

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

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()

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).

Version

6.1.0


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.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 14 additional findings in Devin Review.

Open in Devin Review

Comment thread ios/RNZipArchive.mm
Comment on lines 252 to 254
- (dispatch_queue_t)methodQueue {
return dispatch_queue_create("com.mockingbot.ReactNative.ZipArchiveQueue", DISPATCH_QUEUE_SERIAL);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 iOS methodQueue creates a new dispatch queue on every call

The methodQueue method at RNZipArchive.mm:252-254 calls dispatch_queue_create every time it's invoked, rather than caching the queue. This means each method invocation may get a different serial queue (depending on how React Native caches the result). This is a pre-existing pattern unchanged by this PR. In practice, React Native caches the result of methodQueue internally, but this implementation is unusual compared to the typical pattern of storing the queue in an ivar.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

1 participant