Skip to content

feat: support react-native-check-biometric-auth-changed#2

Merged
huhuanming merged 79 commits into
mainfrom
react-native-check-biometric-auth-changed
Dec 13, 2025
Merged

feat: support react-native-check-biometric-auth-changed#2
huhuanming merged 79 commits into
mainfrom
react-native-check-biometric-auth-changed

Conversation

@huhuanming
Copy link
Copy Markdown
Contributor

@huhuanming huhuanming commented Dec 12, 2025

Summary by CodeRabbit

  • New Features

    • Added a biometric-auth change detection API and a runnable example app.
  • Documentation

    • Added a "Create Nitro Module" guide plus contributing, code of conduct, and example README content.
  • Chores

    • CI publish workflow updated to enable Corepack before installing dependencies.
  • Infrastructure

    • Added full iOS/Android example scaffolding, build configs, and publishing metadata.

✏️ Tip: You can customize this high-level summary in your review settings.

Updated LiteCardInfo to use explicit properties in both Swift and TypeScript, replacing the generic object type. Modified getLiteInfo to return LiteCardInfo or null for better type safety and clarity.
Introduces a new OnekeyLite class for managing NFC card operations, including methods for card info retrieval, permission checks, mnemonic management, PIN changes, and event handling. Adds comprehensive type definitions for callback and promise results, card info, and error codes to improve type safety and maintainability.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 45

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e2600f0 and d58282e.

⛔ Files ignored due to path filters (13)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (71)
  • .github/workflows/package-publish.yml (1 hunks)
  • README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.editorconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.gitattributes (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.gitignore (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.nvmrc (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.watchmanconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/CODE_OF_CONDUCT.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/LICENSE (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/ReactNativeCheckBiometricAuthChanged.podspec (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/CMakeLists.txt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/gradle.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/AndroidManifest.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChanged.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChangedPackage.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/babel.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/.bundle/config (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/.watchmanconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/Gemfile (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/proguard-rules.pro (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/AndroidManifest.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainActivity.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainApplication.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/drawable/rn_edit_text_material.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/strings.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/styles.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradlew (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradlew.bat (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/settings.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/app.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/index.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/.xcode.env (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/project.pbxproj (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/xcshareddata/xcschemes/ReactNativeCheckBiometricAuthChangedExample.xcscheme (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcworkspace/contents.xcworkspacedata (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/AppDelegate.swift (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/AppIcon.appiconset/Contents.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/Contents.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Info.plist (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/LaunchScreen.storyboard (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/PrivacyInfo.xcprivacy (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/jest.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/package.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/ios/ReactNativeCheckBiometricAuthChanged.swift (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/lefthook.yml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/nitro.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/package.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/__tests__/index.test.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/tsconfig.build.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/tsconfig.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/turbo.json (1 hunks)
  • native-modules/react-native-lite-card/example/react-native.config.js (1 hunks)
  • native-modules/react-native-lite-card/package.json (1 hunks)
  • react-native.base.config.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1)
native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1)
  • checkBiometricAuthChanged (9-11)
native-modules/react-native-check-biometric-auth-changed/example/index.js (1)
native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1)
  • App (6-20)
native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (3)
native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (3)
  • path (1-1)
  • require (2-2)
  • root (5-5)
native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (1)
  • path (1-1)
native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1)
  • __dirname (10-10)
native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1)
native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1)
  • ReactNativeCheckBiometricAuthChanged (3-6)
native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (3)
native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (3)
  • path (1-1)
  • require (2-2)
  • pkg (3-3)
native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (3)
  • path (1-1)
  • require (2-2)
  • require (3-3)
native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1)
  • __dirname (10-10)
🪛 Clang (14.0.6)
native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp

[error] 1-1: 'jni.h' file not found

(clang-diagnostic-error)


[warning] 4-4: variable 'jint' is non-const and globally accessible, consider making it const

(cppcoreguidelines-avoid-non-const-global-variables)

🪛 Cppcheck (2.18.0)
native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp

[information] 1-1: Include file

(missingIncludeSystem)


[information] 2-2: Include file

(missingInclude)


[style] 4-4: The function 'JNI_OnLoad' is never used.

(unusedFunction)

🪛 LanguageTool
README.md

[uncategorized] ~102-~102: “React” is a proper noun and needs to be capitalized.
Context: ...e following variables at the top of the react block in `new-library/example/android/a...

(A_GOOGLE)

native-modules/react-native-check-biometric-auth-changed/CODE_OF_CONDUCT.md

[style] ~33-~33: Try using a synonym here to strengthen your wording.
Context: ...ind * Trolling, insulting or derogatory comments, and personal or political attacks * Pu...

(COMMENT_REMARK)

native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md

[style] ~30-~30: Consider shortening or rephrasing this to strengthen your wording.
Context: ...rogen** in following cases: - When you make changes to any *.nitro.ts files. - When running ...

(MAKE_CHANGES)


[uncategorized] ~139-~139: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...free series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead....

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
README.md

37-37: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


38-38: Ordered list item prefix
Expected: 1; Actual: 5; Style: 1/2/3

(MD029, ol-prefix)


40-40: Ordered list item prefix
Expected: 2; Actual: 6; Style: 1/2/3

(MD029, ol-prefix)


42-42: Ordered list item prefix
Expected: 3; Actual: 7; Style: 1/2/3

(MD029, ol-prefix)


44-44: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


74-74: Ordered list item prefix
Expected: 1; Actual: 8; Style: 1/2/3

(MD029, ol-prefix)


76-76: Ordered list item prefix
Expected: 2; Actual: 9; Style: 1/2/3

(MD029, ol-prefix)


78-78: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


102-102: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


102-102: Ordered list item prefix
Expected: 1; Actual: 10; Style: 1/1/1

(MD029, ol-prefix)


104-104: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


117-117: Ordered list item prefix
Expected: 1; Actual: 11; Style: 1/2/3

(MD029, ol-prefix)


119-119: Ordered list item prefix
Expected: 2; Actual: 12; Style: 1/2/3

(MD029, ol-prefix)

native-modules/react-native-check-biometric-auth-changed/example/README.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🪛 RuboCop (1.81.7)
native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile

[convention] 8-8: Put a comma after the last item of a multiline array.

(Style/TrailingCommaInArrayLiteral)


[convention] 32-32: Avoid comma after the last parameter of a method call.

(Style/TrailingCommaInArguments)

native-modules/react-native-check-biometric-auth-changed/example/Gemfile

[convention] 8-8: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem activesupport should appear before cocoapods.

(Bundler/OrderedGems)


[convention] 10-10: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem concurrent-ruby should appear before xcodeproj.

(Bundler/OrderedGems)


[convention] 15-15: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem benchmark should appear before logger.

(Bundler/OrderedGems)

native-modules/react-native-check-biometric-auth-changed/ReactNativeCheckBiometricAuthChanged.podspec

[convention] 14-14: Prefer to_s over string interpolation.

(Style/RedundantInterpolation)

🔇 Additional comments (56)
native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/Contents.json (1)

1-6: LGTM: standard Xcode asset catalog metadata.

Looks like the default Contents.json schema Xcode expects. No changes needed.

native-modules/react-native-check-biometric-auth-changed/example/.watchmanconfig (1)

1-1: LGTM — valid empty Watchman config.
An empty {} is fine and keeps tooling happy.

native-modules/react-native-check-biometric-auth-changed/.watchmanconfig (1)

1-1: LGTM — harmless boilerplate.
Empty {} is valid JSON and a common Watchman setup.

native-modules/react-native-check-biometric-auth-changed/.editorconfig (1)

1-15: Configuration is solid and follows best practices.

This .editorconfig enforces consistent formatting across the module—2-space indentation, LF line endings, UTF-8, and clean trailing whitespace. Standard and sensible for a JavaScript project.

native-modules/react-native-check-biometric-auth-changed/CODE_OF_CONDUCT.md (2)

31-36: Keep wording as-is; don’t over-edit the template.

The “insulting or derogatory comments” phrasing (Line 33) is clear and standard. I wouldn’t chase the style suggestion here.


118-133: Attribution/links look correct.

References and link labels are consistent and readable.

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/xcshareddata/xcschemes/ReactNativeCheckBiometricAuthChangedExample.xcscheme (3)

1-24: Looks like a standard shared scheme; app BuildAction is wired correctly.


43-80: Launch/Profile actions look clean and consistent (Debug for run, Release for profile).


81-88: Analyze/Archive actions are fine as-is.

native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md (1)

1-146: Overall: Document is comprehensive and well-structured.

The guide clearly covers setup, testing, conventions, and publishing for this Nitro module project. Sections flow logically and commands are easy to copy/paste. A few minor wording tweaks above would improve clarity and grammatical accuracy.

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/AppDelegate.swift (2)

24-33: Verify window visibility (makeKeyAndVisible) behavior.

You never call window?.makeKeyAndVisible() (Line 24-33). If factory.startReactNative(...) doesn’t do it, the app can launch to a blank screen. Consider making it explicit, or add a comment that the factory handles it.


36-47: Confirm RN API compatibility for bundleURL() and jsBundleURL(forBundleRoot:).

The delegate overrides and the RCTBundleURLProvider call are RN-version sensitive. Please confirm these signatures match the React Native version used by this repo (and that release builds embed main.jsbundle as expected).

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/AppIcon.appiconset/Contents.json (1)

1-53: LGTM—standard asset catalog scaffold.

The file structure is correct. No actual icon images are defined yet, so the app will use default placeholders. That's typical for example projects.

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Info.plist (1)

38-39: RCTNewArchEnabled is intentional and supported.

React Native 0.83.0 has stable new architecture support. The project explicitly depends on react-native-nitro-modules (v0.31.10), which is a native module framework built for the new architecture. This configuration is correct for the module's design.

native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1)

5-5: No action needed. The import is correct for ESLint 9.x.

ESLint 9.x explicitly exports defineConfig from 'eslint/config' as a helper for flat config. The import statement is valid and follows the official ESLint 9.x pattern.

Likely an incorrect or invalid review comment.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainApplication.kt (1)

10-26: Code follows the modern React Native template correctly.

The APIs you're using—ReactHost, getDefaultReactHost(), and ReactNativeApplicationEntryPoint.loadReactNative()—are standard in React Native 0.83.0 (your project's version). These APIs became the default with RN 0.76's new architecture, so they're stable and well-documented. Your implementation matches the official RN template.

native-modules/react-native-check-biometric-auth-changed/example/app.json (1)

1-4: Looks good; naming is consistent.

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcworkspace/contents.xcworkspacedata (1)

1-10: Workspace file looks standard and correct.

native-modules/react-native-check-biometric-auth-changed/example/jest.config.js (1)

1-3: Clean and minimal Jest setup.

native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp (1)

1-6: Ensure initialize(vm) returns a valid JNI_VERSION_* constant.

Per JNI specification, JNI_OnLoad must return a recognized JNI_VERSION_* value (e.g., JNI_VERSION_1_6). If initialize(vm) returns anything else, the VM will reject the library load.

Also name the unused second parameter to avoid compiler warnings:

-JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+  (void)reserved;
   return margelo::nitro::onekeyfe_reactnativecheckbiometricauthchanged::initialize(vm);
 }
native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (1)

1-12: Standard Babel config looks good.

This is the correct setup for a React Native example app in a monorepo using builder-bob.

native-modules/react-native-check-biometric-auth-changed/tsconfig.json (1)

1-30: Solid TypeScript config with strict settings.

The strict compiler options and path mapping are appropriate for a React Native native module.

native-modules/react-native-check-biometric-auth-changed/tsconfig.build.json (1)

1-4: Standard build config.

Correctly extends base config and excludes example/build directories.

native-modules/react-native-check-biometric-auth-changed/example/android/app/proguard-rules.pro (1)

1-10: Standard ProGuard placeholder.

This template is appropriate for initial scaffolding. Add project-specific rules as needed.

.github/workflows/package-publish.yml (1)

15-15: Good addition of corepack enable.

This ensures the correct Yarn version is used before install. Aligns with modern Yarn workflows.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/strings.xml (1)

1-3: Standard Android string resource.

App name is correctly defined for the example app.

native-modules/react-native-check-biometric-auth-changed/example/index.js (1)

1-5: Standard React Native entry point.

Correctly registers the root component using AppRegistry. Clean setup.

native-modules/react-native-check-biometric-auth-changed/example/android/app/build.gradle (1)

1-123: No issue here. hermesEnabled is properly defined in gradle.properties at the same level as build.gradle, making it accessible throughout the Gradle build. Standard Gradle behavior.

native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1)

1-11: LGTM! Clean Nitro module bridge.

The implementation correctly wires the hybrid object and exposes the public API. The promise-based interface aligns with the Nitro interface definition.

native-modules/react-native-check-biometric-auth-changed/android/CMakeLists.txt (1)

1-24: LGTM! Standard CMake setup for Nitro module.

The configuration correctly sets up the native library with proper includes, autolinking, and library dependencies for Android.

native-modules/react-native-check-biometric-auth-changed/android/src/main/AndroidManifest.xml (1)

1-2: LGTM! Minimal manifest is appropriate.

Native module libraries don't need permissions declared here. The consuming app handles that.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/styles.xml (1)

1-9: LGTM! Standard React Native theme.

The AppTheme configuration with DayNight support and custom edit text styling is appropriate for the example app.

native-modules/react-native-lite-card/package.json (1)

41-41: Verify versioning and changelog generation are handled by separate scripts.

The release script now only publishes. The CI/CD workflow calls this via yarn version:publish, which chains through the root workspace scripts. Confirm that version:bump, version:apply, and version:commit in the root package.json handle versioning, git tagging, and changelog generation before the release script runs. Also remove the unused release-it config from this package.json since it's no longer called.

native-modules/react-native-check-biometric-auth-changed/example/android/gradle.properties (1)

1-44: LGTM!

Standard Android/React Native configuration. The settings align with React Native 0.83 best practices.

native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (1)

1-26: LGTM!

Monorepo Metro configuration is correct. Path resolution and watch folders are set up properly.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/AndroidManifest.xml (1)

1-27: LGTM!

Standard React Native Android manifest. Permissions and activity configuration are appropriate for an example app.

react-native.base.config.js (1)

1-10: LGTM!

Clean base configuration for React Native projects in the monorepo. Path resolution and iOS settings are correct.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/drawable/rn_edit_text_material.xml (1)

1-37: LGTM!

Standard React Native workaround for the Android NullPointerException issue. The comments clearly explain the fix.

native-modules/react-native-check-biometric-auth-changed/turbo.json (1)

20-20: Verify empty outputs for build tasks.

Both build:android and build:ios have empty outputs arrays. Turborepo caching works best when outputs are specified. Is this intentional?

If builds produce artifacts, specify them:

-      "outputs": []
+      "outputs": ["android/build/**"]

Similarly for iOS:

-      "outputs": []
+      "outputs": ["example/ios/build/**"]
native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile (1)

1-1: Don’t hard-force New Architecture. Let env override.
Use ||= so callers can disable it.

-ENV['RCT_NEW_ARCH_ENABLED'] = '1'
+ENV['RCT_NEW_ARCH_ENABLED'] ||= '1'
native-modules/react-native-lite-card/example/react-native.config.js (1)

3-6: Verify the require path resolves correctly.

The relative path ../../../react-native.base.config needs confirmation that react-native.base.config.js (or .cjs/.mjs) exists at the repository root and is accessible from the example folder. Run the verification commands to ensure the require statement works.

native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1)

1-6: Add doc comment and complete Kotlin implementation for checkChanged.

The method name doesn't explain what "changed" means—it detects if biometric authentication state changed on the device. Add JSDoc to clarify this.

More critically: the Kotlin implementation is a stub that just returns false. It needs to match the Swift implementation's logic (comparing current vs. stored biometric auth state).

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainActivity.kt (1)

8-22: LGTM!

Standard React Native MainActivity with new architecture support. Implementation is correct.

native-modules/react-native-check-biometric-auth-changed/example/android/gradlew (1)

1-251: LGTM!

Standard Gradle wrapper script. This is generated boilerplate.

native-modules/react-native-check-biometric-auth-changed/android/gradle.properties (1)

1-5: LGTM!

Android build properties are well-defined and use reasonable versions.

native-modules/react-native-check-biometric-auth-changed/example/android/build.gradle (1)

1-21: LGTM!

Standard React Native example app build configuration with appropriate versions.

native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (2)

5-18: LGTM!

Config correctly spreads the base config and adds the module dependency with proper path resolution. The explicit platform entries work around the Codegen issue as documented.


1-3: The base config path is correct.

The file react-native.base.config.js exists at the repository root. The import in line 3 correctly resolves to this file.

native-modules/react-native-check-biometric-auth-changed/android/build.gradle (6)

18-21: LGTM!

Standard ABI filter helper with sensible defaults covering all common architectures.


23-28: LGTM!

Plugin applications follow the correct order for React Native native modules with Nitro integration.


33-64: LGTM!

CMake config includes proper security hardening flags (-fstack-protector-all) and appropriate optimization levels per build type.


66-85: LGTM!

Standard packaging exclusions prevent duplicate native libraries and conflicts with React Native's bundled libraries.


87-115: LGTM!

Build configuration is appropriate for a React Native native module. Prefab support and generated source directories align with Nitro framework requirements.


117-128: LGTM!

Dependencies are minimal and appropriate. The Nitro modules dependency correctly references the monorepo project.

native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChangedPackage.kt (2)

1-15: LGTM!

Package structure correctly implements BaseReactPackage for a Nitro-only module with no traditional React Native modules.


17-21: Library name matches CMakeLists.txt. The init block correctly loads "onekeyfe_reactnativecheckbiometricauthchanged", which matches the PACKAGE_NAME in CMakeLists.txt. No issues here.

Comment thread native-modules/react-native-check-biometric-auth-changed/.gitignore
Comment thread native-modules/react-native-check-biometric-auth-changed/.gitignore
Comment thread native-modules/react-native-check-biometric-auth-changed/.gitignore
Comment thread native-modules/react-native-check-biometric-auth-changed/.nvmrc
Comment thread native-modules/react-native-check-biometric-auth-changed/nitro.json
Comment thread native-modules/react-native-check-biometric-auth-changed/README.md
Comment thread README.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 21

♻️ Duplicate comments (39)
native-modules/react-native-check-biometric-auth-changed/example/.bundle/config (1)

1-2: Document why these Bundler settings exist (in the example README).

These entries can confuse contributors and change install behavior across machines/CI. Add a short note in native-modules/react-native-check-biometric-auth-changed/example/README.md explaining BUNDLE_PATH and BUNDLE_FORCE_RUBY_PLATFORM, and when to keep/remove them.

native-modules/react-native-check-biometric-auth-changed/LICENSE (1)

3-3: Fix the copyright holder string.

@onekeyfeonekeyfe looks duplicated/malformed. Use the real legal holder (company name) or the correct org/user name.

-Copyright (c) 2025 @onekeyfeonekeyfe
+Copyright (c) 2025 OneKey
native-modules/react-native-check-biometric-auth-changed/.gitignore (3)

5-6: Remove duplicate .expo/ and rename “XDE” to “Expo”.
.expo/ is listed twice. Also, “XDE” is outdated and unclear now.

-# XDE
-.expo/
+# Expo
+.expo/
@@
-# Expo
-.expo/

Also applies to: 72-73


30-31: Use trailing slash for project.xcworkspace/.
This is a directory. Make it explicit.

-project.xcworkspace
+project.xcworkspace/

42-42: Ignore all .iml files, not just android.iml.
Android Studio can generate multiple module files.

-android.iml
+*.iml
native-modules/react-native-check-biometric-auth-changed/.nvmrc (1)

1-1: Node version conflict already flagged.

A previous reviewer identified a mismatch: this pins v22.20.0 locally, but CI runs Node 20.x. See the detailed analysis above for alignment options.

native-modules/react-native-check-biometric-auth-changed/.gitattributes (1)

1-3: Use binary instead of -text for .pbxproj, and clarify the comment wording.

The -text flag only disables line-ending normalization; it doesn't prevent Git diffs or merges on .pbxproj files. Since these files are fragile and prone to corruption during merges, mark them as binary to block automatic text processing. Also sharpen the comment for clarity.

Apply this diff:

-*.pbxproj -text
-# specific for windows script files
+*.pbxproj binary
+# Windows batch script files
native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (2)

17-25: Fix: extends is invalid in flat config; spread the compat configs instead.
Right now, extends: fixupConfigRules(...) won’t work as intended because flat config expects config objects in the top-level array, not an extends key.

 export default defineConfig([
-  {
-    extends: fixupConfigRules(compat.extends('@react-native', 'prettier')),
-    plugins: { prettier },
-    rules: {
-      'react/react-in-jsx-scope': 'off',
-      'prettier/prettier': 'error',
-    },
-  },
+  ...fixupConfigRules(compat.extends('@react-native', 'prettier')),
+  {
+    plugins: { prettier },
+    rules: {
+      'react/react-in-jsx-scope': 'off',
+      'prettier/prettier': 'error',
+    },
+  },
   {
     ignores: ['node_modules/', 'lib/'],
   },
 ]);

18-25: Optional: add settings.react.version = 'detect' to avoid React-version warnings.
If you see “React version not specified” warnings, add settings next to plugins.

   {
     plugins: { prettier },
+    settings: {
+      react: {
+        version: 'detect',
+      },
+    },
     rules: {
       'react/react-in-jsx-scope': 'off',
       'prettier/prettier': 'error',
     },
   },
native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile (1)

4-8: RuboCop trailing-comma issues already flagged.

A previous review caught these style violations. Fix line 8 (missing comma) and line 32 (extra comma) as suggested in the earlier comment.

Also applies to: 32-32

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/PrivacyInfo.xcprivacy (1)

7-30: Remove undeclared API types—Apple rejects inaccurate manifests.

Past review confirmed only UserDefaults has matching code. FileTimestamp and SystemBootTime declarations have no implementation. Drop them to pass App Store review.

Apply this diff:

 	<key>NSPrivacyAccessedAPITypes</key>
 	<array>
-		<dict>
-			<key>NSPrivacyAccessedAPIType</key>
-			<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
-			<key>NSPrivacyAccessedAPITypeReasons</key>
-			<array>
-				<string>C617.1</string>
-			</array>
-		</dict>
 		<dict>
 			<key>NSPrivacyAccessedAPIType</key>
 			<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
 			<key>NSPrivacyAccessedAPITypeReasons</key>
 			<array>
 				<string>CA92.1</string>
 			</array>
 		</dict>
-		<dict>
-			<key>NSPrivacyAccessedAPIType</key>
-			<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
-			<key>NSPrivacyAccessedAPITypeReasons</key>
-			<array>
-				<string>35F9.1</string>
-			</array>
-		</dict>
 	</array>
native-modules/react-native-check-biometric-auth-changed/example/ios/.xcode.env (1)

11-11: Past review concern still unaddressed: fail fast when Node is missing.

The previous review correctly flagged this: command -v node returns an empty string if Node isn't found, leading to cryptic Xcode errors. Add a check to fail immediately with a clear message.

Apply the suggested diff from the past review:

-export NODE_BINARY=$(command -v node)
+export NODE_BINARY="$(command -v node)"
+: "${NODE_BINARY:?Node not found. Set NODE_BINARY in .xcode.env.local (or fix PATH).}"
native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md (3)

28-28: Add the article "the" for grammatical correctness.

This issue was flagged in a previous review. The phrase needs the definite article.

-Run **Nitrogen** in following cases:
+Run **Nitrogen** in the following cases:

67-67: Use "verify" instead of "confirm" for stronger language.

This concern was raised in a previous review. Replace the weaker verb to make the instruction more direct.

-To confirm that the app is running with the new architecture, you can check the Metro logs for a message like this:
+To verify the app is running with the new architecture, check the Metro logs for this message:

111-111: Clarify when pre-commit hooks become active.

A previous review flagged this ambiguity. Explain that hooks are auto-installed with dependencies to help new contributors understand the setup flow.

-Our pre-commit hooks verify that your commit message matches this format when committing.
+Pre-commit hooks (installed automatically when you run `yarn`) verify that your commit message matches this format when committing.
native-modules/react-native-check-biometric-auth-changed/lefthook.yml (2)

10-10: Fix inconsistent glob pattern spacing.

Line 10's glob has a space after ts, but line 6 doesn't. Keep spacing consistent.

-      glob: "*.{js,ts, jsx, tsx}"
+      glob: "*.{js,ts,jsx,tsx}"

11-11: Limit TypeScript checks to staged files.

Running npx tsc without arguments checks your entire project, which slows commits. Pass staged files to speed it up.

-      run: npx tsc
+      run: npx tsc --noEmit {staged_files}
README.md (1)

38-124: Fix markdown formatting issues.

The previously flagged markdown issues remain:

  • List numbering starts at 5 instead of 1
  • Code blocks lack language identifiers
  • Line 102: "react" should be "React"
native-modules/react-native-check-biometric-auth-changed/example/android/gradle/wrapper/gradle-wrapper.properties (1)

3-3: Downgrade Gradle to 8.9.

Gradle 9.0.0 remains incompatible with React Native 0.83.0 and Android Gradle Plugin 8.7.2. This will cause build failures.

native-modules/react-native-check-biometric-auth-changed/example/Gemfile (1)

6-16: Sort gems alphabetically within each section.

RuboCop still flags gem ordering violations:

  • activesupport before cocoapods
  • concurrent-ruby before xcodeproj
  • benchmark before logger
native-modules/react-native-check-biometric-auth-changed/example/android/gradlew.bat (1)

61-66: Use backslashes for Windows paths.

Line 63 still uses forward slashes. Windows batch scripts should use backslashes consistently.

native-modules/react-native-check-biometric-auth-changed/babel.config.js (1)

1-12: Fix node_modules regex to match Windows paths too.
Your regex only matches /, not \.

 module.exports = {
   overrides: [
     {
-      exclude: /\/node_modules\//,
+      exclude: /[\\/]node_modules[\\/]/,
       presets: ['module:react-native-builder-bob/babel-preset'],
     },
     {
-      include: /\/node_modules\//,
+      include: /[\\/]node_modules[\\/]/,
       presets: ['module:@react-native/babel-preset'],
     },
   ],
 };
native-modules/react-native-check-biometric-auth-changed/package.json (1)

54-63: Fix malformed GitHub URLs (repository/bugs/homepage).
These paths look wrong and will break links on npm.

   "repository": {
     "type": "git",
-    "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed.git"
+    "url": "git+https://github.com/OneKeyHQ/app-modules.git"
   },
   "author": "@onekeyfeonekeyfe <huanming@onekey.so> (https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed)",
   "license": "MIT",
   "bugs": {
-    "url": "https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed/issues"
+    "url": "https://github.com/OneKeyHQ/app-modules/issues"
   },
-  "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed#readme",
+  "homepage": "https://github.com/OneKeyHQ/app-modules#readme",
native-modules/react-native-check-biometric-auth-changed/src/__tests__/index.test.tsx (1)

1-1: Replace it.todo() with a real unit test (current file adds zero coverage).

A minimal mock-based test will also flush out early-init issues in src/index.tsx.

-it.todo('write a test');
+import { checkBiometricAuthChanged } from '..';
+
+jest.mock('react-native-nitro-modules', () => ({
+  NitroModules: {
+    createHybridObject: jest.fn(() => ({
+      checkChanged: jest.fn(async () => true),
+    })),
+  },
+}));
+
+it('resolves boolean from native bridge', async () => {
+  await expect(checkBiometricAuthChanged()).resolves.toBe(true);
+});
native-modules/react-native-check-biometric-auth-changed/README.md (1)

18-24: Fix README usage snippet: multiply() is wrong; show checkBiometricAuthChanged() instead.

-import { multiply } from '@onekeyfe/react-native-check-biometric-auth-changed';
+import { checkBiometricAuthChanged } from '@onekeyfe/react-native-check-biometric-auth-changed';
 
 // ...
 
-const result = multiply(3, 7);
+const hasChanged = await checkBiometricAuthChanged();
+console.log('Biometric auth changed:', hasChanged);
native-modules/react-native-check-biometric-auth-changed/example/README.md (1)

1-5: Add a top-level H1 on Line 1 to satisfy MD041.

+#
+# ReactNativeCheckBiometricAuthChangedExample
+
 This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli).
native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/xcshareddata/xcschemes/ReactNativeCheckBiometricAuthChangedExample.xcscheme (1)

25-42: Consider setting MacroExpansion for more predictable xcodebuild test

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/LaunchScreen.storyboard (2)

2-2: Outdated storyboard toolsVersion may cause Xcode warnings


19-23: Launch screen title will truncate/wrap on smaller devices

-                            <label ... text="ReactNativeCheckBiometricAuthChangedExample" ...>
+                            <label ... text="RN Biometric Example" ...>
native-modules/react-native-check-biometric-auth-changed/nitro.json (1)

1-17: Fix Nitro config schema: split cxxNamespace segments + add missing autolinking.*.cpp

 {
-  "cxxNamespace": ["onekeyfe_reactnativecheckbiometricauthchanged"],
+  "cxxNamespace": ["onekeyfe", "reactnativecheckbiometricauthchanged"],
   "ios": {
     "iosModuleName": "ReactNativeCheckBiometricAuthChanged"
   },
   "android": {
     "androidNamespace": ["onekeyfe","reactnativecheckbiometricauthchanged"],
     "androidCxxLibName": "onekeyfe_reactnativecheckbiometricauthchanged"
   },
   "autolinking": {
     "ReactNativeCheckBiometricAuthChanged": {
+      "cpp": "ReactNativeCheckBiometricAuthChanged",
       "swift": "ReactNativeCheckBiometricAuthChanged",
       "kotlin": "ReactNativeCheckBiometricAuthChanged"
     }
   },
   "ignorePaths": ["node_modules"]
 }
native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1)

9-13: Add error handling for the promise.

The checkBiometricAuthChanged() call has no .catch(). If it rejects, you'll get an unhandled promise rejection.

Apply this fix:

   useEffect(() => {
     checkBiometricAuthChanged().then((result) => {
       setResult(result);
-    });
+    }).catch((error) => {
+      console.error('Failed to check biometric auth:', error);
+    });
   }, []);
native-modules/react-native-check-biometric-auth-changed/example/android/settings.gradle (1)

15-21: Remove duplicate plugin resolution logic.

Lines 15-21 duplicate the reactNativeGradlePlugin resolution from the pluginManagement block above (lines 2-8). This runs the expensive Node exec twice.

Delete lines 15-21 entirely:

 extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
 rootProject.name = 'onekeyfe.reactnativecheckbiometricauthchanged.example'
 include ':app'
-
-def reactNativeGradlePlugin = new File(
-providers.exec {
-    workingDir(rootDir)
-    commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
-}.standardOutput.asText.get().trim()
-).getParentFile().absolutePath
-includeBuild(reactNativeGradlePlugin)
native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Info.plist (1)

36-37: Remove or populate the location usage description.

The NSLocationWhenInUseUsageDescription key has an empty string. If your app requests location access, iOS requires a user-facing explanation—otherwise the App Store rejects it. If you don't need location, delete this key.

Apply this diff to remove the unused key:

-	<key>NSLocationWhenInUseUsageDescription</key>
-	<string></string>
native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/project.pbxproj (2)

380-380: REACT_NATIVE_PATH uses fragile relative paths that break on repo layout changes.

Define it via .xcode.env or derive it from SRCROOT to keep the example portable.

Also applies to: 449-449


339-339: Avoid pinning code signing identity in an example project.

Let Xcode manage signing, or set this via local developer settings. Hard-coding causes "signing requires a development team" friction.

Also applies to: 416-416

native-modules/react-native-check-biometric-auth-changed/example/package.json (1)

5-11: Remove workspaces here; fix build:* scripts (they likely don’t exist).
This package is not a workspace root, and "workspaces": ["example"] is almost certainly wrong. Also, react-native build-android is not a standard RN CLI command; build-ios support varies by CLI version.

@@
   "scripts": {
     "android": "react-native run-android",
     "ios": "react-native run-ios",
     "start": "react-native start",
-    "build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
-    "build:ios": "react-native build-ios --mode Debug"
+    "build:android": "react-native run-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
+    "build:ios": "react-native run-ios --mode Debug"
   },
@@
-  "workspaces": [
-    "example"
-  ],
For @react-native-community/cli 20.0.0 (RN 0.83), what are the supported commands? Specifically: do `react-native build-android` and `react-native build-ios` exist, and what are the correct equivalents?

Also applies to: 17-19

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/AppDelegate.swift (2)

13-23: Set dependencyProvider before you create RCTReactNativeFactory (init-order risk).
If the factory reads the delegate during init, it can miss the provider.

@@
-    let delegate = ReactNativeDelegate()
-    let factory = RCTReactNativeFactory(delegate: delegate)
-    delegate.dependencyProvider = RCTAppDependencyProvider()
+    let delegate = ReactNativeDelegate()
+    delegate.dependencyProvider = RCTAppDependencyProvider()
+    let factory = RCTReactNativeFactory(delegate: delegate)

6-12: Tighten sample code: final + narrower visibility.
Prevents accidental subclassing/mutation and reads cleaner.

@@
 @main
-class AppDelegate: UIResponder, UIApplicationDelegate {
+final class AppDelegate: UIResponder, UIApplicationDelegate {
@@
-  var reactNativeDelegate: ReactNativeDelegate?
-  var reactNativeFactory: RCTReactNativeFactory?
+  private var reactNativeDelegate: ReactNativeDelegate?
+  private var reactNativeFactory: RCTReactNativeFactory?
@@
-class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
+private final class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {

Also applies to: 36-48

native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChanged.kt (1)

6-11: Android implementation is still a stub (false), so the feature doesn’t work on Android.
This creates a platform mismatch and will break callers that rely on parity with iOS.

What is the recommended Android approach (API 23+) to detect biometric enrollment changes reliably (e.g., Android Keystore key invalidated via setInvalidatedByBiometricEnrollment(true), and which exceptions signal enrollment change on modern Android)?

If you want, I can draft a concrete implementation using Android Keystore + KeyPermanentlyInvalidatedException and SharedPreferences baseline storage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e2600f0 and 66c0985.

⛔ Files ignored due to path filters (13)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (71)
  • .github/workflows/package-publish.yml (1 hunks)
  • README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.editorconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.gitattributes (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.gitignore (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.nvmrc (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/.watchmanconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/CODE_OF_CONDUCT.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/LICENSE (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/ReactNativeCheckBiometricAuthChanged.podspec (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/CMakeLists.txt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/gradle.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/AndroidManifest.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChanged.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChangedPackage.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/babel.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/.bundle/config (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/.watchmanconfig (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/Gemfile (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/README.md (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/proguard-rules.pro (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/AndroidManifest.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainActivity.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainApplication.kt (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/drawable/rn_edit_text_material.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/strings.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/styles.xml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/build.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradlew (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/gradlew.bat (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/android/settings.gradle (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/app.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/index.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/.xcode.env (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/project.pbxproj (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcodeproj/xcshareddata/xcschemes/ReactNativeCheckBiometricAuthChangedExample.xcscheme (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcworkspace/contents.xcworkspacedata (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/AppDelegate.swift (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/AppIcon.appiconset/Contents.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Images.xcassets/Contents.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/Info.plist (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/LaunchScreen.storyboard (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample/PrivacyInfo.xcprivacy (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/jest.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/package.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/ios/ReactNativeCheckBiometricAuthChanged.swift (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/lefthook.yml (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/nitro.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/package.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/__tests__/index.test.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/tsconfig.build.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/tsconfig.json (1 hunks)
  • native-modules/react-native-check-biometric-auth-changed/turbo.json (1 hunks)
  • native-modules/react-native-lite-card/example/react-native.config.js (1 hunks)
  • native-modules/react-native-lite-card/package.json (1 hunks)
  • react-native.base.config.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1)
native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1)
  • ReactNativeCheckBiometricAuthChanged (3-6)
native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (3)
native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (4)
  • path (1-1)
  • require (2-2)
  • require (3-3)
  • root (5-5)
native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (2)
  • path (1-1)
  • pkg (2-2)
native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1)
  • __dirname (10-10)
native-modules/react-native-check-biometric-auth-changed/example/index.js (1)
native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1)
  • App (6-20)
native-modules/react-native-check-biometric-auth-changed/example/src/App.tsx (1)
native-modules/react-native-check-biometric-auth-changed/src/index.tsx (1)
  • checkBiometricAuthChanged (9-11)
native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (3)
native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (3)
  • path (1-1)
  • require (2-2)
  • pkg (3-3)
native-modules/react-native-check-biometric-auth-changed/example/metro.config.js (3)
  • path (1-1)
  • require (2-2)
  • require (3-3)
native-modules/react-native-check-biometric-auth-changed/eslint.config.mjs (1)
  • __dirname (10-10)
🪛 Clang (14.0.6)
native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp

[error] 1-1: 'jni.h' file not found

(clang-diagnostic-error)


[warning] 4-4: variable 'jint' is non-const and globally accessible, consider making it const

(cppcoreguidelines-avoid-non-const-global-variables)

🪛 Cppcheck (2.18.0)
native-modules/react-native-check-biometric-auth-changed/android/src/main/cpp/cpp-adapter.cpp

[information] 1-1: Include file

(missingIncludeSystem)


[information] 2-2: Include file

(missingInclude)


[style] 4-4: The function 'JNI_OnLoad' is never used.

(unusedFunction)

🪛 LanguageTool
native-modules/react-native-check-biometric-auth-changed/CODE_OF_CONDUCT.md

[style] ~33-~33: Try using a synonym here to strengthen your wording.
Context: ...ind * Trolling, insulting or derogatory comments, and personal or political attacks * Pu...

(COMMENT_REMARK)

README.md

[uncategorized] ~102-~102: “React” is a proper noun and needs to be capitalized.
Context: ...e following variables at the top of the react block in `new-library/example/android/a...

(A_GOOGLE)

native-modules/react-native-check-biometric-auth-changed/CONTRIBUTING.md

[style] ~30-~30: Consider shortening or rephrasing this to strengthen your wording.
Context: ...rogen** in following cases: - When you make changes to any *.nitro.ts files. - When running ...

(MAKE_CHANGES)


[uncategorized] ~139-~139: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...free series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead....

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
native-modules/react-native-check-biometric-auth-changed/example/README.md

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🪛 RuboCop (1.81.7)
native-modules/react-native-check-biometric-auth-changed/example/Gemfile

[convention] 8-8: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem activesupport should appear before cocoapods.

(Bundler/OrderedGems)


[convention] 10-10: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem concurrent-ruby should appear before xcodeproj.

(Bundler/OrderedGems)


[convention] 15-15: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem benchmark should appear before logger.

(Bundler/OrderedGems)

native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile

[convention] 8-8: Put a comma after the last item of a multiline array.

(Style/TrailingCommaInArrayLiteral)


[convention] 32-32: Avoid comma after the last parameter of a method call.

(Style/TrailingCommaInArguments)

native-modules/react-native-check-biometric-auth-changed/ReactNativeCheckBiometricAuthChanged.podspec

[convention] 14-14: Prefer to_s over string interpolation.

(Style/RedundantInterpolation)

🔇 Additional comments (27)
native-modules/react-native-check-biometric-auth-changed/.editorconfig (1)

1-15: EditorConfig looks solid.

Standard formatting rules in place. Settings align well with a JavaScript/TypeScript project. Syntax is clean and correct.

native-modules/react-native-check-biometric-auth-changed/example/.watchmanconfig (1)

1-1: Configuration looks good.

The empty JSON object tells Watchman to use default settings. This is standard for React Native modules.

native-modules/react-native-check-biometric-auth-changed/.watchmanconfig (1)

1-1: Standard Watchman configuration.

The empty JSON object is valid and appropriate. Consistent with the example directory setup.

native-modules/react-native-check-biometric-auth-changed/example/jest.config.js (1)

1-3: LGTM! Standard React Native Jest setup.

This minimal config is appropriate for an example app. The 'react-native' preset handles common transformations and test environment setup.

native-modules/react-native-check-biometric-auth-changed/example/ios/Podfile (1)

1-36: Podfile structure looks solid.

The configuration is standard for React Native. New architecture enablement, dynamic pod resolution, and post-install hooks are all correct.

.github/workflows/package-publish.yml (1)

15-15: Good: Enable Corepack before Yarn install.

Corepack ensures the correct package manager version is used, improving reproducibility in CI. The change is safe and aligns with Node 20.x best practices.

native-modules/react-native-check-biometric-auth-changed/example/ios/ReactNativeCheckBiometricAuthChangedExample.xcworkspace/contents.xcworkspacedata (1)

1-10: LGTM! Standard Xcode workspace configuration.

The workspace structure correctly references the main project and Pods integration.

native-modules/react-native-check-biometric-auth-changed/example/app.json (1)

1-4: LGTM! Standard React Native app configuration.

The app name and display name are properly configured for the example app.

react-native.base.config.js (1)

1-10: LGTM! Clean base configuration.

The React Native path resolution and automatic Pods installation settings are properly configured for the monorepo.

native-modules/react-native-check-biometric-auth-changed/turbo.json (1)

6-41: Verify empty outputs for build tasks.

Both build:android and build:ios have empty output arrays. Build tasks typically track output artifacts for caching. Confirm this is intentional if native build outputs are managed outside Turbo's cache.

native-modules/react-native-lite-card/example/react-native.config.js (1)

3-6: Base config import + spread looks clean and keeps the example config DRY.
Just make sure the ../../../react-native.base.config relative path is stable in this repo layout.

native-modules/react-native-check-biometric-auth-changed/example/react-native.config.js (1)

1-18: Clear, consistent RN config for local linking + codegen workaround.
The base config spread keeps it simple.

native-modules/react-native-check-biometric-auth-changed/android/src/main/AndroidManifest.xml (1)

1-2: Minimal library manifest is fine—just verify the Gradle namespace is set.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/strings.xml (1)

1-3: LGTM: app_name resource looks correct.

native-modules/react-native-check-biometric-auth-changed/example/index.js (1)

1-5: LGTM: standard React Native entry point.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/res/values/styles.xml (1)

1-9: Verify the manifest uses AppTheme and @drawable/rn_edit_text_material exists in all variants.

Theme/resource mismatches will crash at runtime on startup.

native-modules/react-native-check-biometric-auth-changed/example/android/gradle.properties (1)

28-40: Confirm you really want New Architecture hard-enabled in the example
If consumers run the example with New Arch off, this can surprise them. Consider documenting this requirement in the example README.

native-modules/react-native-check-biometric-auth-changed/example/babel.config.js (1)

1-12: Verify the Babel config is pointing at the right package.json (module vs example app)
Right now it reads ../package.json and sets root to the module root. If this is meant for the example app, you may want ./package.json and __dirname.

-const pkg = require('../package.json');
+const pkg = require('./package.json');

-const root = path.resolve(__dirname, '..');
+const root = path.resolve(__dirname);
native-modules/react-native-check-biometric-auth-changed/src/ReactNativeCheckBiometricAuthChanged.nitro.ts (1)

1-6: LGTM!

Clean Nitro module interface with proper platform types and promise-based method signature.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/AndroidManifest.xml (1)

1-27: LGTM!

Standard React Native manifest. The android:exported="true" is required for launcher activities on Android 12+.

native-modules/react-native-check-biometric-auth-changed/tsconfig.json (1)

1-30: LGTM!

Solid TypeScript config with strict mode enabled and modern module resolution.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainActivity.kt (1)

1-22: LGTM!

Standard React Native MainActivity implementation. Correctly uses DefaultReactActivityDelegate with Fabric support.

native-modules/react-native-check-biometric-auth-changed/android/src/main/java/com/margelo/nitro/onekeyfe/reactnativecheckbiometricauthchanged/ReactNativeCheckBiometricAuthChangedPackage.kt (1)

8-21: LGTM! Nitro autolinking pattern confirmed.

This package loads the native library but delegates module registration to the autolinking layer. This pattern aligns with the Nitro module integration mentioned in the summary.

native-modules/react-native-check-biometric-auth-changed/example/android/app/src/main/java/onekeyfe/reactnativecheckbiometricauthchanged/example/MainApplication.kt (1)

10-26: LGTM! Standard React Native new architecture setup.

Clean implementation with lazy initialization and proper lifecycle management.

native-modules/react-native-check-biometric-auth-changed/android/gradle.properties (1)

1-5: Properties defined correctly for dynamic resolution.

These properties are properly consumed by android/build.gradle. Note: Version mismatches with the example app were flagged in example/android/build.gradle.

native-modules/react-native-check-biometric-auth-changed/example/android/app/build.gradle (1)

118-122: Verify hermesEnabled property definition.

The hermesEnabled property is referenced on line 119 but isn't defined in this file. Confirm it exists in gradle.properties or a parent configuration.

native-modules/react-native-check-biometric-auth-changed/android/build.gradle (1)

25-25: The autolinking gradle file reference is correct. Nitrogen/Nitro generates this file at build time—it's not a missing static file. The apply from: statement properly integrates the generated autolinking artifact per Nitro documentation.

Comment thread native-modules/react-native-lite-card/package.json
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
native-modules/react-native-check-biometric-auth-changed/package.json (2)

54-63: Fix repository URLs—this blocks publishing. ⚠️ Still not resolved from previous review.

The URLs contain incorrect module-specific paths and don't match the actual GitHub repo. Update to canonical paths pointing to the repository root.

Apply this diff:

  "repository": {
    "type": "git",
-   "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed.git"
+   "url": "git+https://github.com/OneKeyHQ/app-modules.git"
  },
  ...
  "bugs": {
-   "url": "https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed/issues"
+   "url": "https://github.com/OneKeyHQ/app-modules/issues"
  },
-"homepage": "https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed/onekeyfe-react-native-check-biometric-auth-changed#readme",
+"homepage": "https://github.com/OneKeyHQ/app-modules#readme",

58-58: Remove the personal email from author before publishing.

The email address will be publicly visible on npm. Replace with just the name or a project contact.

Apply this diff:

- "author": "@onekeyfeonekeyfe <huanming@onekey.so> (https://github.com/OneKeyHQ/app-modules/react-native-check-biometric-auth-changed)",
+ "author": "OneKey <https://github.com/OneKeyHQ>",
native-modules/react-native-lite-card/package.json (1)

42-42: Duplicate: Remove unused release-it config and dependencies.

This issue was already flagged in a previous review. The release script no longer uses release-it, but the config (lines 139-157) and dependencies (lines 69, 83) remain.

Also applies to: 69-69, 83-83, 139-157

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 64b9420 and 02b6527.

📒 Files selected for processing (4)
  • native-modules/react-native-check-biometric-auth-changed/package.json (1 hunks)
  • native-modules/react-native-lite-card/ReactNativeLiteCard.podspec (1 hunks)
  • native-modules/react-native-lite-card/package.json (3 hunks)
  • native-modules/react-native-lite-card/src/index.tsx (1 hunks)
🔇 Additional comments (4)
native-modules/react-native-check-biometric-auth-changed/package.json (3)

1-48: Config structure and scripts look solid.

Entry points, workspace setup, and build scripts follow React Native conventions. The clean task properly excludes build artifacts. No issues here.


67-98: Dependencies and peer requirements are well-configured.

React 19.2.0, React Native 0.83.0, and modern tooling versions are appropriate. ESLint flat config is set up correctly for v9.x. Nitro module dependencies are pinned consistently.


99-172: Build config and tool setup are correct.

Builder Bob targets (custom nitrogen, module, typescript) are properly chained. All tool configs (Prettier, Jest, Commitlint, release-it) are sensible for a native module monorepo. The create-react-native-library metadata correctly identifies this as a Kotlin+Swift Nitro module.

native-modules/react-native-lite-card/package.json (1)

3-3: Verify the version jump is intentional.

Jumping from 0.1.2 to 1.1.3 skips several minor versions. Confirm this follows your versioning policy and isn't a mistake.

Comment thread native-modules/react-native-lite-card/package.json
Comment thread native-modules/react-native-lite-card/ReactNativeLiteCard.podspec Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/Exceptions.kt (1)

1-6: toJson() can generate invalid JSON; escape or use a JSON encoder.
If message contains quotes/newlines, the output breaks JSON.

 sealed class NFCExceptions(val code: Int, override val message: String? = null) : Exception(message) {
     fun toJson(): String {
-        return """{"code":$code,"message":"$message"}"""
+        val safeMsg = message
+            ?.replace("\\", "\\\\")
+            ?.replace("\"", "\\\"")
+            ?.replace("\n", "\\n")
+            ?.replace("\r", "\\r")
+            ?: ""
+        return """{"code":$code,"message":"$safeMsg"}"""
     }
 }
native-modules/react-native-lite-card/package.json (2)

15-35: Remove keys from the files array (or document its purpose if needed).

The keys/ directory contains only source files (keys.c/keys.h) that reference an external secrets file (keys.secret, which is properly excluded). While publishing source code headers isn't a leak, the directory name is misleading and risks future misconfiguration. Consider renaming it to crypto/ or validation/ for clarity, or add a comment in package.json explaining why it's included. The framework/ directory is fine—it's a legitimate iOS binary SDK required for iOS builds.


36-44: Use npm publish --dry-run instead of npm pack --dry-run for proper release validation.

The suggested dry-run command should test the actual publish flow, not just tarball creation. Use npm publish --dry-run to validate the full publishing process without uploading to npm. Also note that lint and typecheck already run in pre-commit hooks (via lefthook), so those checks in the release script add redundancy but harmless defense-in-depth. The --provenance flag isn't applicable unless your npm org has enabled it.

   "scripts": {
-    "release": "yarn prepare && npm whoami && npm publish --access public"
+    "release:dry": "yarn clean && yarn prepare && npm publish --dry-run",
+    "release": "yarn release:dry && npm whoami && npm publish --access public"
   },
♻️ Duplicate comments (3)
native-modules/react-native-lite-card/package.json (1)

63-87: Remove release-it config/deps or use it again.

The scripts no longer call release-it, but config and devDependencies remain. Pick one: delete them, or switch release back to release-it so you keep tagging/changelog automation.

Also applies to: 140-158

native-modules/react-native-check-biometric-auth-changed/package.json (2)

54-63: Fix the malformed GitHub metadata URLs (repository/bugs/homepage).
They include duplicated path segments and won’t resolve cleanly on npm.


58-58: Don’t publish a personal email in author.
That email will be public on npm. Use a team alias or omit it.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9281c53 and f5521a6.

📒 Files selected for processing (28)
  • native-modules/react-native-check-biometric-auth-changed/package.json (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/AndroidManifest.xml (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/LoggerManager.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/keys/KeysNativeProvider.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/Exceptions.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/NfcUtils.kt (2 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/broadcast/NfcStatusChangeBroadcastReceiver.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/NfcConstant.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/OnekeyLiteCard.kt (2 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/APDUParam.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardInfo.java (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardResponse.java (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardState.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/ParsedCertInfo.java (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SecureChanelParam.java (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SendResponse.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/Connection.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/EventUtils.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/GpsUtil.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/HexUtils.java (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/LogUtil.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/MiUtil.kt (2 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/NfcPermissionUtils.kt (1 hunks)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/Utils.java (1 hunks)
  • native-modules/react-native-lite-card/package.json (3 hunks)
🔇 Additional comments (29)
native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/OnekeyLiteCard.kt (1)

1-18: Namespace change is clean and consistent.

The package rename to com.onekeyfe.reactnativelitecard.onekeyLite is already applied consistently across the codebase. No old namespace references remain, and all imports and package declarations use the new namespace. No reflection strings, JNI code, or hardcoded FQCNs reference the old package. This file is safe to merge.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SecureChanelParam.java (2)

1-1: PR scope mismatch detected.

This file belongs to react-native-lite-card module, but the PR title indicates work on react-native-check-biometric-auth-changed. Confirm whether this package rename is intentionally included in this PR or if it was added by mistake.


1-1: Package rename verified—no stale references found.

The namespace refactor from so.onekey.app.wallet.lite to com.onekeyfe.reactnativelitecard is complete. No old package references remain in the codebase.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardState.kt (2)

5-10: LGTM!

Data class structure is clean. Default values are sensible.


1-1: No action needed—imports already updated.

The old package references have been fully migrated. All imports of CardState correctly reference the new namespace com.onekeyfe.reactnativelitecard.onekeyLite.entitys. The package name "entitys" is the established naming convention for this module, so no changes are required.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/LoggerManager.kt (1)

1-7: Namespace update is fine.
Import path matches the new module namespace.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardInfo.java (1)

1-1: Package rename is straightforward and safe.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/HexUtils.java (1)

1-1: Package rename looks correct.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt (1)

15-20: Import rewiring matches the new package layout.

Also applies to: 26-26

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/Connection.kt (1)

1-17: Namespace refactor is consistent here.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt (1)

1-6: Package and imports are clean—no old namespace references found.
The migration is complete. Package declaration aligns with the file path, and no stray references to the old so.onekey.app.wallet.lite namespace exist in the codebase. The refactor is solid.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/GpsUtil.kt (1)

1-1: Package rename looks good.

This namespace consolidation aligns with the broader refactor across the module.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/broadcast/NfcStatusChangeBroadcastReceiver.kt (1)

1-1: Package rename looks good.

Namespace change only; all NFC state handling logic remains intact.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/Utils.java (1)

1-1: Package rename looks good.

Namespace updated; all utility logic unchanged.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/keys/KeysNativeProvider.kt (1)

1-1: Package rename looks good.

Namespace change only; native library integration unchanged.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/APDUParam.kt (1)

1-1: Package rename looks good.

Data class remains functionally identical.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardResponse.java (1)

1-1: Package rename looks good.

Entity structure and serialization unchanged.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/ParsedCertInfo.java (1)

1-1: Package rename looks good.

Certificate entity structure unchanged.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt (4)

1-1: Package rename looks good.

Namespace consolidation aligns with the broader refactor.


7-11: Import paths updated correctly.

All imports now reference the new package namespace.


1-178: Old package references have been removed. No instances of so.onekey.app.wallet.lite remain in the codebase.


13-16: Configuration verified: V2 card type is properly configured.

The config/command.json file contains v2 entries for all 15 command types (verify_certificate, verify_auth_data, select_primary_safety, select_backup_applet, get_backup_status, get_pin_status, get_serial_number, get_pin_retry_count, reset_card, verify_pin, setup_new_pin, change_pin, backup_data, export_data). The generalCommand() method can safely access these v2 configurations without runtime exceptions.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/NfcConstant.kt (1)

1-4: Namespace refactor looks good.

Package and import paths correctly updated to the new namespace.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SendResponse.kt (1)

1-3: Package and import updated correctly.

Namespace changes align with the module refactor.

native-modules/react-native-lite-card/android/src/main/AndroidManifest.xml (1)

1-2: Manifest package attribute added correctly.

Aligns with the new module namespace.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/NfcUtils.kt (1)

1-12: Namespace refactor completed correctly.

Package and MiUtil import path updated to match the new namespace.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/EventUtils.kt (1)

1-1: Package declaration updated correctly.

Namespace change aligns with the module refactor.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/NfcPermissionUtils.kt (1)

1-1: Package updated to new namespace.

Refactor is consistent with other utility classes.

native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/LogUtil.kt (1)

1-4: Namespace refactor is complete.

The codebase contains no remaining references to the old package namespace. Package and imports in LogUtil.kt correctly use the new namespace com.onekeyfe.reactnativelitecard.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between f5521a6 and 0a0a1cc.

📒 Files selected for processing (1)
  • native-modules/react-native-lite-card/android/build.gradle (1 hunks)

Comment thread native-modules/react-native-lite-card/android/build.gradle
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt (3)

377-384: Unsafe cast to FragmentActivity.

Same issue as initialize(). Use safe cast to avoid runtime crash.

       override fun onNfcOn() {
         super.onNfcOn()
-        Utils.getTopActivity()?.let {
+        (Utils.getTopActivity() as? FragmentActivity)?.let { activity ->
           launch(Dispatchers.IO) {
-            OneKeyLiteCard.startNfc(it as FragmentActivity) {}
+            OneKeyLiteCard.startNfc(activity) {}
           }
         }
       }

413-425: Unsafe cast to FragmentActivity.

Same pattern again. Be consistent with safe casts throughout.

   override fun onHostPause() {
-    Utils.getTopActivity()?.let {
+    (Utils.getTopActivity() as? FragmentActivity)?.let { activity ->
       launch(Dispatchers.IO) {
         try {
-          OneKeyLiteCard.stopNfc(it as FragmentActivity)
+          OneKeyLiteCard.stopNfc(activity)
           mNFCState.set(NFCState.Dead)
           Log.d(TAG, "NFC 已关闭")
         } catch (e: Exception) {
           Log.e(TAG, "stopNfc failed", e)
         }
       }
     }
   }

427-432: Consider logging the exception.

Swallowing exceptions silently makes debugging harder. Add a log statement.

   override fun onHostDestroy() {
     try {
       Utils.getTopActivity()?.unregisterReceiver(mNfcStateBroadcastReceiver)
-    } catch (ignore: Exception) {
+    } catch (e: Exception) {
+      Log.w(TAG, "Failed to unregister NFC receiver", e)
     }
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 0a0a1cc and d6ead8c.

📒 Files selected for processing (1)
  • native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt (9 hunks)
🔇 Additional comments (3)
native-modules/react-native-lite-card/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt (3)

15-26: LGTM!

Import reorganization to consolidated package path looks clean.


33-34: LGTM!

Adding val promotes the constructor parameter to a property. Good Kotlin idiom.


397-411: Good pattern here.

This method correctly checks if (it !is FragmentActivity) before use. Apply this pattern to the other locations.

@huhuanming huhuanming merged commit 5512d9d into main Dec 13, 2025
3 checks passed
huhuanming added a commit that referenced this pull request Apr 23, 2026
#1 Align Android `metadataRequiresCommonBundle` with iOS OR semantics.
Previously the helper returned the explicit `requiresCommonBundle` value
when present (so `requiresCommonBundle=false` would suppress the
`bundleFormat=three-bundle` signal), which iOS doesn't do. The helper
is also used by `validateBundleDescriptor` and `validateEntryBundlesSha256`
on Android, so the divergence let Android accept three-bundle manifests
that iOS rejects (missing `common.bundle` allowed through, common.bundle
sha256 not enforced on startup hot path). Switch the helper itself to
OR semantics; `currentBundleRequiresPerSegmentHash` now just calls it.

#2 `validateWebEmbedRecursive` now fails closed on `listFiles() == null`.
Java's `File.listFiles()` returns null on I/O error or unreadable dir.
Treating that as "nothing to verify" silently allowed a tampered
web-embed asset whose containing directory was unlistable. Log the path
and return false instead.

#3 iOS background-thread refuses IPA fallback when OTA main is active.
If the OTA main bundle is loaded but the OTA common/background lookup
fails (typical cause: package skew where bundle-update is older than
split-bundle-loader/background-thread and doesn't expose the new
`currentBundleCommonJSBundle` selector), falling back to the IPA built-in
common.jsbundle / background.bundle would moduleId-mismatch the OTA main
and crash on first require() — the very crash this patch was added to
prevent. Detect "OTA main is active" via the existing reflective lookup
and return nil from bundleURL / resolveBackgroundEntryBundlePath in that
case. The background runtime aborts loudly instead of crashing silently.
huhuanming added a commit that referenced this pull request Apr 23, 2026
…n abort

Two follow-ups from the fourth-pass review of 22036ec.

#1 Rename `_bundleURLUsedOtaCommon` -> `_otaActiveAtBundleResolve` and set
it in BOTH OTA branches of `bundleURL`: when OTA common resolves AND when
OTA main is active but OTA common is unresolvable (the refused-fallback
path that returns nil). The flag now captures the invariant "this delegate
is locked to OTA territory" rather than the narrower "OTA common was
loaded". Under normal RCTHost lifecycle hostDidStart won't fire after
bundleURL returns nil, but the broader semantic closes the theoretical
hole where a future lifecycle change or host retry could reach
`resolveBackgroundEntryBundlePath` with the old flag still NO and silently
fall back to IPA built-in background.bundle.

#2 Clear `_rctInstance = nil` before the early return in `hostDidStart`'s
fatal branch. `_rctInstance` was set on lines 287-288 before the abort,
and `registerSegmentWithId` only gates on `_rctInstance != nil` — so any
downstream segment registration after the abort would happily call into
a runtime where SharedStore / SharedRPC / error handler /
`__setupBackgroundRPCHandler` were all skipped. Nilling the ivar makes
the half-initialized state visible to those guards.
huhuanming added a commit that referenced this pull request Apr 23, 2026
Two real issues caught by Devin review on PR #49.

#1 Android `validateEntryBundlesSha256` was the only sha256 comparison in
the file using `String.equals(..., ignoreCase = true)` instead of the
constant-time `secureCompare` helper used everywhere else
(validateFilesRecursive, validateWebEmbedRecursive, iOS counterpart).
Switch to `secureCompare(expected.lowercase(), actual.lowercase())` —
preserves the case-insensitive semantic against uppercase-hex manifests
while restoring constant-time comparison for the timing-attack guarantee.

#2 iOS `bundleFormat == "three-bundle"` was case-sensitive at three
sites (currentBundleRequiresPerSegmentHash, validateBundlePairCompatibility,
validateEntryBundlesSha256), while Android's `metadataRequiresCommonBundle`
already calls `.lowercase()` before comparing. A manifest with
`bundleFormat: "Three-Bundle"` would activate three-bundle gating on
Android (common bundle required, per-segment hash enforced) but not on
iOS, leaving iOS silently in two-bundle mode. Lowercase the comparand on
all three iOS sites to match Android's case-insensitive semantic.
limichange pushed a commit that referenced this pull request Apr 24, 2026
* feat(background-thread): prefer OTA-installed common/background bundles

The background runtime previously loaded the IPA-bundled common.jsbundle
and background.bundle even when an OTA update had installed newer copies
to disk, which could crash on moduleId mismatch with the OTA-loaded
main bundle. Now reflectively query BundleUpdateStore for the OTA paths
(mirroring the SplitBundleLoader cross-framework reflection pattern, since
the Swift umbrella header pulls in C++/Nitro headers that break the Clang
dependency scanner) and fall back to the built-in resources when no OTA
is active.

Migrated from app-monorepo patches/@onekeyfe+react-native-background-thread+3.0.20.patch.

* feat(bundle-update): three-bundle metadata, validated-bundle cache, fast-path entry sha256

Three changes that ship together because they share the same metadata
parsing path on both platforms:

1. Three-bundle metadata: parse and reserve requiresCommonBundle and
   bundleFormat keys. When set, validateBundleDescriptor requires a
   common.bundle alongside main.jsbundle.hbc, so OTA installs of the
   union/split-thread layout fail closed instead of silently shipping a
   broken main bundle that references moduleIds living in common. The
   Android metadata parser also now accepts boolean/numeric scalars
   (skipping nested objects) so manifests can carry future descriptors
   without breaking sha verification.

2. validatedCurrentBundleInfo cache: every bundleURL / common / main /
   background path getter on startup re-ran the full signature + sha256
   pipeline. Memoize by currentBundleVersion, invalidate on every
   mutation (clearBundle, resetToBuiltInBundle, clearAllJSBundleData,
   setCurrentUpdateBundleData) and on the no-version path.

3. Fast-path entry sha256: replace the full-tree validateAllFilesInDir
   sweep on the startup hot path with validateEntryBundlesSha256, which
   only hashes main + common + background (gated by metadata flags).
   Full-tree validation already runs at install time, sandboxed app data
   plus signed metadata bind every file's expected hash, and per-segment
   integrity is now enforced at loadSegment time by SplitBundleLoader.

Also exposes BundleUpdateStore.currentBundleCommonJSBundle() on iOS so
the background runtime can look up the OTA common bundle path.

Migrated from app-monorepo patches/@onekeyfe+react-native-bundle-update+3.0.20.patch.

* feat(split-bundle-loader): verify segment SHA-256 at load time

Pairs with the bundle-update fast-path startup change: BundleUpdate no
longer re-hashes the whole bundle directory on every launch, so segment
integrity is now enforced lazily here at resolveSegmentPath / loadSegment
time instead of trusting install-time validation.

Empty expected hash is treated as skip for back-compat with manifests
that omit per-segment hashes. Hashes are streamed in 64KB chunks so a
large segment doesn't pull the whole file into memory just to verify it.

Migrated from app-monorepo patches/@onekeyfe+react-native-split-bundle-loader+3.0.20.patch.

* fix(bundle-update,split-bundle-loader): address codex audit findings

Three fixes from the audit of the patch migration on this branch.

#1 Lazy web-embed sha256 verification + cache.
The startup hot path (validateEntryBundlesSha256) only verifies the JS
entry bundles, so a tampered web-embed asset (HTML/JS/CSS) would slip
through and execute inside the WebView. WebKit/Chromium SRI isn't
enforced because the build pipeline doesn't yet inject integrity
attributes; until that lands, native must verify. Walk web-embed/** at
getWebEmbedPath time, gate against metadata sha256 entries (rejecting
files-on-disk-not-in-metadata and metadata-entries-missing-on-disk),
and cache the verified bundleVersion so the cost is paid once per
(re)install. Cache is invalidated alongside cachedValidatedBundleInfo
on every bundle mutation. Both platforms.

#2 Per-segment sha256 fail-closed for three-bundle format.
SplitBundleLoader's verifySha256 previously treated empty expected hash
as a back-compat skip — combined with the startup fast path that only
checks entry bundles, a tampered segment with an empty manifest hash
would pass both gates. Add a new public API,
BundleUpdateStore.currentBundleRequiresPerSegmentHash(), that returns
true when the current bundle's metadata declares the three-bundle /
split-thread layout (or sets requiresCommonBundle). SplitBundleLoader
queries this reflectively (matching the existing OTA-path lookup
pattern) and treats empty expected as a hard fail when true. Older
formats keep the back-compat skip.

#3 installBundle invalidates the validated-bundle cache.
Symmetry with the other mutators (clearBundle / resetToBuiltInBundle /
clearAllJSBundleData / setCurrentUpdateBundleData). Currently safe in
practice because installBundle always writes a new appVersion-bundleVersion
folder, so the cache key changes. But signature/native-version writes
inside installBundle could otherwise leave callers reading stale
validated info if anyone ever adds a same-version reinstall path. One
line at the top of each platform's installBundle.

* fix(bundle-update): align Android per-segment-hash predicate; close install race

Two follow-up fixes from the second-pass review of 88f641a.

#1 Android `currentBundleRequiresPerSegmentHash` was reusing
`metadataRequiresCommonBundle`, which has explicit-false-overrides-bundleFormat
semantics: an explicit `requiresCommonBundle=false` would suppress the
`bundleFormat=three-bundle` signal and let SplitBundleLoader allow empty
per-segment hashes. iOS's same-named API uses OR semantics (true if either
opts in). Inline the OR semantics in Android's API to match iOS, leaving
`metadataRequiresCommonBundle` alone so existing `validateBundleDescriptor`
behavior is preserved.

#2 `installBundle` invalidated the validated-bundle cache *before* the
async install body. A reader calling `validatedCurrentBundleInfo()` in
the window between the synchronous invalidate and the async
`currentBundleVersion` write could re-cache pre-install state, leaving
it stale after the install commits. Add a second invalidate at the end
of the async body. (Different-version installs are already safe via the
version-keyed cache; this closes the same-version reinstall window and
any reader race in general.) Both platforms.

* chore(split-bundle-loader,background-thread): peer-depend on bundle-update >=3.0.21

Both packages reflectively call BundleUpdateStore APIs that are only
available starting in this branch's release:
- split-bundle-loader: `currentBundleRequiresPerSegmentHash` (decides
  whether empty per-segment sha256 is fail-closed or back-compat skip).
- background-thread: `currentBundleCommonJSBundle` (OTA-installed
  common bundle path; the equivalent main/background paths existed in
  prior versions).

Without this peer dep, an app that bumps either package without bumping
bundle-update will silently fall through to the back-compat code paths
(reflection returns nil, fail-open per-segment, IPA built-in common
bundle). Surface that as an install-time peer-dependency warning so the
mismatch is caught before runtime.

Range is `>=3.0.21` because 3.0.20 was the most recent published
release before these APIs were added.

* fix: address third-pass codex audit findings

#1 Align Android `metadataRequiresCommonBundle` with iOS OR semantics.
Previously the helper returned the explicit `requiresCommonBundle` value
when present (so `requiresCommonBundle=false` would suppress the
`bundleFormat=three-bundle` signal), which iOS doesn't do. The helper
is also used by `validateBundleDescriptor` and `validateEntryBundlesSha256`
on Android, so the divergence let Android accept three-bundle manifests
that iOS rejects (missing `common.bundle` allowed through, common.bundle
sha256 not enforced on startup hot path). Switch the helper itself to
OR semantics; `currentBundleRequiresPerSegmentHash` now just calls it.

#2 `validateWebEmbedRecursive` now fails closed on `listFiles() == null`.
Java's `File.listFiles()` returns null on I/O error or unreadable dir.
Treating that as "nothing to verify" silently allowed a tampered
web-embed asset whose containing directory was unlistable. Log the path
and return false instead.

#3 iOS background-thread refuses IPA fallback when OTA main is active.
If the OTA main bundle is loaded but the OTA common/background lookup
fails (typical cause: package skew where bundle-update is older than
split-bundle-loader/background-thread and doesn't expose the new
`currentBundleCommonJSBundle` selector), falling back to the IPA built-in
common.jsbundle / background.bundle would moduleId-mismatch the OTA main
and crash on first require() — the very crash this patch was added to
prevent. Detect "OTA main is active" via the existing reflective lookup
and return nil from bundleURL / resolveBackgroundEntryBundlePath in that
case. The background runtime aborts loudly instead of crashing silently.

* fix(background-thread): abort hostDidStart when OTA common loaded but OTA background missing

The previous fix had `resolveBackgroundEntryBundlePath` return nil when
OTA main was active and OTA background couldn't be resolved, but
`hostDidStart` treated nil identically to the legitimate "no background
bundle" case (warn and continue). It would still install SharedStore /
SharedRPC and call `__setupBackgroundRPCHandler` against a runtime with
no entry bundle — RPC would be silently broken instead of loudly fatal.

Track whether `bundleURL` actually loaded an OTA common bundle on a new
instance ivar `_bundleURLUsedOtaCommon`, reset on every `bundleURL` call.
`resolveBackgroundEntryBundlePath` consults the same flag (replacing the
duplicated `isOtaMainBundleActive()` reflective check) and `hostDidStart`
returns early when bgBundlePath is nil AND the flag is set, distinguishing
the fatal case from the legitimate "this bundle was never split" case.

* fix(background-thread): broaden OTA-active flag; clear _rctInstance on abort

Two follow-ups from the fourth-pass review of 22036ec.

#1 Rename `_bundleURLUsedOtaCommon` -> `_otaActiveAtBundleResolve` and set
it in BOTH OTA branches of `bundleURL`: when OTA common resolves AND when
OTA main is active but OTA common is unresolvable (the refused-fallback
path that returns nil). The flag now captures the invariant "this delegate
is locked to OTA territory" rather than the narrower "OTA common was
loaded". Under normal RCTHost lifecycle hostDidStart won't fire after
bundleURL returns nil, but the broader semantic closes the theoretical
hole where a future lifecycle change or host retry could reach
`resolveBackgroundEntryBundlePath` with the old flag still NO and silently
fall back to IPA built-in background.bundle.

#2 Clear `_rctInstance = nil` before the early return in `hostDidStart`'s
fatal branch. `_rctInstance` was set on lines 287-288 before the abort,
and `registerSegmentWithId` only gates on `_rctInstance != nil` — so any
downstream segment registration after the abort would happily call into
a runtime where SharedStore / SharedRPC / error handler /
`__setupBackgroundRPCHandler` were all skipped. Nilling the ivar makes
the half-initialized state visible to those guards.

* fix(bundle-update): address Devin PR review findings

Two real issues caught by Devin review on PR #49.

#1 Android `validateEntryBundlesSha256` was the only sha256 comparison in
the file using `String.equals(..., ignoreCase = true)` instead of the
constant-time `secureCompare` helper used everywhere else
(validateFilesRecursive, validateWebEmbedRecursive, iOS counterpart).
Switch to `secureCompare(expected.lowercase(), actual.lowercase())` —
preserves the case-insensitive semantic against uppercase-hex manifests
while restoring constant-time comparison for the timing-attack guarantee.

#2 iOS `bundleFormat == "three-bundle"` was case-sensitive at three
sites (currentBundleRequiresPerSegmentHash, validateBundlePairCompatibility,
validateEntryBundlesSha256), while Android's `metadataRequiresCommonBundle`
already calls `.lowercase()` before comparing. A manifest with
`bundleFormat: "Three-Bundle"` would activate three-bundle gating on
Android (common bundle required, per-segment hash enforced) but not on
iOS, leaving iOS silently in two-bundle mode. Lowercase the comparand on
all three iOS sites to match Android's case-insensitive semantic.

* refactor(bundle-update): extract "three-bundle" literal into a named constant

Add `bundleFormatThreeBundle` (Swift) / `BUNDLE_FORMAT_THREE_BUNDLE`
(Kotlin) alongside the existing metadata-key constants and replace the
four call sites that previously inlined the string. Keeps the iOS and
Android sides in lockstep and prevents the prior class of bug where
one platform got updated to a new format token (or a typo) while the
other silently kept comparing against the old literal.

* 3.0.21

* docs(background-thread,split-bundle-loader): correct jsbundle→bundle in comments

Comment references were out of sync with the actual resource name used
in code (common.bundle). No runtime change.

* 3.0.22

* docs(changelog): document 3.0.21 and 3.0.22 releases

- 3.0.21: three-bundle OTA metadata + validated-bundle cache, segment
  SHA-256 verification at load time, background-thread prefers
  OTA-installed common/background bundles, lazy web-embed verification,
  and a cluster of audit-driven fixes (Android/iOS parity, constant-time
  hash compare, install-race cache invalidation, OTA-active abort path).
- 3.0.22: comment-only correction (jsbundle → bundle) and version bump.
huhuanming added a commit that referenced this pull request May 12, 2026
Reviewer flagged a mix of integration-contract gaps, an Android error-
propagation bug, and a couple of C++ housekeeping items. Fixes:

iOS — host-integration contract (#1, high)
- Document the post-reload contract explicitly on
  `installSharedBridgeInMainRuntime:` and `restartWithMode:` headers. The
  host AppDelegate's `hostDidStart:` must re-invoke both the SharedBridge
  install (every reload) and `startBackgroundRunner` (mode='all' only).
- `restartWithMode:` now arms a one-shot `RCTJavaScriptDidLoadNotification`
  observer that fires ~1.5s after the new main bridge loads:
  * mode='all': self-respawns the bg runtime if the host AppDelegate
    didn't (idempotent via the existing `isStarted` guard, so a correctly-
    wired host pays nothing).
  * Both modes: logs `[BTLogger error:]` if the host failed to re-call
    `installSharedBridgeInMainRuntime:`. Tracked via a new atomic flag
    `mainSharedBridgeInstalled` flipped in the install lambda. Surfaces
    integration omissions in production logs instead of silent RPC drop.

JS spec — cross-platform asymmetry (#2, high)
- `NativeBackgroundThread.ts` JSDoc now spells out: iOS preserves the
  process across `mode='all'` (soft reload); Android kills it via
  `Runtime.exit(0)`. Callers depending on native process-level state
  (timers, singletons, in-memory caches, foreground services) must not
  assume cross-platform survival.

Android — false-success promise resolution (#3, medium)
- `triggerProcessRestart` returns `Boolean` so failure (intent not
  resolvable, `startActivity` `SecurityException`) propagates instead of
  being swallowed; caller rejects the Promise with `BG_RESTART_ERROR`.
- `mode='ui'` soft-reload moves `promise.resolve(null)` inside the
  `Handler.post` success branch — a synchronous `ReactHost.reload()`
  throw now routes through the same fallback-then-reject path instead of
  reporting false success because resolve already happened.

SharedRPC — clean up dead listener entries (#6, low)
- `invalidate(runtimeId)` now erases the listener entry from `listeners_`
  instead of leaving it with `alive=false`. Already-dispatched executor
  lambdas hold their own `shared_ptr<alive>` snapshot so erasing is
  race-safe; it only prevents NEW `notifyOtherRuntime()` snapshots from
  picking up the dead entry. Stops a permanently-dead listener from
  hanging around when a `mode='all'` restart never gets its post-reload
  re-install.
- `install()`'s defensive dedup loop is now documented as the legacy /
  no-prior-invalidate fallback path (#7, low).

Reviewer #4 (no tests) and #2's Android-side TODO (soft-reload both
runtimes via `ReactHost.reload`) remain follow-ups — flagged in PR
description, not in scope here.
huhuanming added a commit that referenced this pull request May 12, 2026
Round-1 self-heal observer hinged on RCTJavaScriptDidLoadNotification,
which reviewer flagged as unreliable in bridgeless / NewArch. The fix
also surfaced two secondary hazards (observer leak when notification
never fires; cross-generation flag misreporting on concurrent restarts).
All three close together by dropping the notification entirely.

iOS — replace notification observer with plain dispatch_after (#1, #2, high)
- The two signals the post-reload check needs (mainSharedBridgeInstalled,
  isStarted) are this module's own state. No external timing anchor is
  required; the notification was only ever an attempt at one. A direct
  dispatch_after on the main queue at kRestartHealthCheckDelaySeconds
  (3s, constant — empirical 6× margin over baseline hostDidStart chain
  on low-end devices) eliminates the bridgeless-fire-or-not gamble AND
  the observer-leak/cross-generation misfire that the observer pattern
  introduced.

iOS — generation counter for concurrent restart() safety (#3, medium)
- Adds `restartGeneration` (nonatomic; main-thread-only by construction).
  Each restartWithMode: bumps it and the health-check captures its own
  `myGen`; on fire, it bails if `restartGeneration != myGen` so a later
  restart's flag reset can't make an earlier restart's check misreport.

iOS — self-respawn loses custom OTA entry URL (#6, low)
- The bg self-respawn path falls through `startBackgroundRunner` →
  default URL (`background.bundle` / DEBUG URL), losing any custom
  entry URL the host set via startBackgroundRunnerWithEntryURL:
  (typically an OTA-resolved bundle path) because
  reactNativeFactoryDelegate is released for mode='all'. Added an
  explicit `[BTLogger warn:]` so this trade-off is visible in logs
  when the host's AppDelegate wiring is broken AND OTA paths matter.

Android — soften over-confident resolve-delivery comment (#4, medium)
- Round-1 comment claimed "the JS thread is still live and can deliver
  the success callback before being destroyed". Closer to truth: the
  CallInvoker is bound to the outgoing ReactInstance which reload
  invalidates very quickly, and `await restart(...)` callers' continu-
  ations are typically superseded by the reload. Position-of-resolve
  only matters for the synchronous-throw path. Updated the comment.

Not changed:
- 1.5s → 3s on the health-check delay is the right call but isn't
  itself a magic-number fix — `kRestartHealthCheckDelaySeconds` is a
  named constant with rationale comment. Polling-until-flag-flips was
  considered and skipped: extra complexity for a one-line log output.

Still pending end-to-end verification on the OneKey host app:
- mode='ui' / mode='all' on iOS bridgeless: confirm health-check logs
  fire only when integration is actually broken (deliberate
  AppDelegate.hostDidStart: omission test).
- Android: confirm BG_RESTART_ERROR Promise rejection on synthetic
  startActivity failure (e.g. invalid intent).
huhuanming added a commit that referenced this pull request May 12, 2026
Round-2 left three open concerns reviewer flagged as merge-blockers for
the OTA path plus a memory-ordering nit. Fixes:

iOS — cache lastEntryURL for OTA-safe self-respawn (#1, medium)
- Round-2's self-respawn fell through to `startBackgroundRunner` →
  default `background.bundle`. On OTA-equipped hosts that's a moduleId-
  mismatch crash waiting to happen: main runs the OTA-updated bundle,
  bg loads the IPA's bundled bg bundle, next cross-runtime RPC crashes.
- Add `lastEntryURL` (nonatomic, copy) cached unconditionally inside
  `startBackgroundRunnerWithEntryURL:`. Self-respawn now replays the
  cached URL via `startBackgroundRunnerWithEntryURL:` instead of the
  default, keeping the bg moduleId table aligned with main.
- Falls back to the default-URL path only when no URL was ever cached
  (host never called start before triggering restart('all') — implausible
  in practice), with the original warn log preserved.

iOS — two-stage health-check tolerates slow devices (#2, medium)
- The 3s `dispatch_after` was measured from restart() dispatch time, not
  new-host ready. On low-end devices an OTA-multi-bundle reload chain
  can eat most of that budget, leaving the host's hostDidStart no time
  to flip the flags — false self-respawn / false error log.
- Extract the health-check into `scheduleHealthCheckForRestart:isAll:
  generation:retried:`. Stage 1 at +3s decides:
    * Both halves healthy → log OK, done.
    * Main ready but bg not (mode='all') → STABLE signal that the host
      didn't re-call startBackgroundRunner; self-respawn now.
    * Main NOT ready → could be a slow device; reschedule stage 2.
  Stage 2 at +6s total is the final verdict; whatever's still missing
  is logged as integration failure (and bg self-healed if it can be).
  Generation check at each stage entry bails on supersession.
- Added detailed stage1/stage2 diagnostic logs so production logs
  distinguish "host omitted the call" from "host was just slow".

iOS — isStarted nonatomic + cross-thread reads (#3, medium)
- Pre-existing nonatomic property is now read on main thread by the
  health-check while writes happen on caller's thread (the module's
  public surface does not pin start... to main). One-line change to
  (atomic, assign, readwrite); inline comment documents the TOCTOU race
  on concurrent first-time starts as a separate pre-existing concern.

Not changed:
- TOCTOU race in start... (concurrent first-time call → double init)
  is real but pre-existing and out of scope here; flagged in the new
  property comment so the next maintainer sees it.
- kRestartHealthCheckDelaySeconds stays at 3.0s — total budget is now
  6s via stage 2, which the reviewer's worst-case "1.5–2s reload + slow
  hostDidStart" easily fits inside.

Health-check method declared in the class extension as a forward
declaration so call-site readability is preserved (definition lives
after restartWithMode: where the restart flow naturally starts).
huhuanming added a commit that referenced this pull request May 12, 2026
…lish)

Round-3 left four low-risk items reviewer recommended resolving for
consistency / debuggability. All four close cleanly:

#1 — lastEntryURL → atomic
- Same rationale as the round-3 isStarted change: written from caller's
  thread (public API doesn't pin start... to main), read on main by
  the health-check. NSString* assignment isn't atomic under ObjC ARC,
  so cross-thread readers could observe a torn pointer or stale value.
  One-line change to (atomic, copy); pre-existing nonatomic was an
  inconsistency with the round-3 fix.

#2 — race-debug warn on startBackgroundRunnerWithEntryURL: early return
- The early-return short-circuit (`if (self.isStarted) return;`) is
  the natural collision point for the self-respawn-vs-host-async-start
  race: self-respawn at stage 2 boots with the cached URL, then the
  host's late async start call comes in with a different URL and gets
  silently dropped. Added a `[BTLogger warn:]` that fires when the
  requested URL differs from the active one — production traces now
  show "bg is on URL X but Y was requested" instead of a mystery.

#3 — stage 1 always defers bg self-respawn to stage 2
- Round-3 stage 1 had a fast-path that self-respawned immediately when
  it saw mainReady=YES but bgReady=NO, on the assumption that mainReady
  was a stable signal the host wasn't going to call start. That's true
  for hosts whose hostDidStart: synchronously calls both install AND
  start, but hosts that gate startBackgroundRunner on async work
  (feature flag fetch, login, network) can be mainReady=YES while the
  real start is still inflight — the fast-path would race them and
  the host's late start would be dropped silently (#2 makes that case
  loud now, but losing the URL is still wrong). Stage 1 now always
  reschedules stage 2 if anything is missing; stage 2 (+~3s) is sized
  to give async host paths time to land. Cost is +3s on the actual
  self-respawn moment, only on broken-integration paths.

#4 — treat bundled default "background.bundle" as no-real-cache
- startBackgroundRunnerWithEntryURL: caches unconditionally, including
  the bundled default when host calls the no-arg startBackgroundRunner
  in release builds. Round-3 self-respawn's "cachedURL.length > 0"
  branch was treating that as a real cache and skipping the OTA-
  mismatch warn — but a host that bootstrapped with the default and
  never swapped to an OTA URL still has the same crash risk. Now
  filters: `cachedURL.length > 0 && ![cachedURL isEqualTo
  String:@"background.bundle"]`. Hosts that immediately call
  startBackgroundRunnerWithEntryURL:OTAUrl overwrite the cache so
  this filter only triggers in the genuinely-no-custom-URL case.

#5 (cosmetic explicit ivar init) is deliberately skipped — reviewer
flagged it as not necessary.
huhuanming added a commit that referenced this pull request May 13, 2026
… crash (#54)

* feat(background-thread): add restart(mode, reason) and fix iOS reload crash

- New TurboModule method `restart(mode, reason)` to replace `react-native-restart`:
  `mode='ui'` reloads the main JS runtime only (bg stays hot — language/devSettings),
  `mode='all'` reloads both runtimes (OTA install/switch, resetData).
- iOS: sequence SharedRPC quiesce → optional bg host release → `RCTTriggerReloadCommandListeners`
  on the main thread; AppDelegate.hostDidStart re-arms the main SharedRPC listener and
  re-spawns the bg host for `mode='all'`.
- Android: invalidate SharedRPC listeners via new JNI `nativeInvalidateSharedRpc` then
  process-restart (parity with react-native-restart-newarch).
- Fix iOS EXC_BAD_ACCESS on main runtime reload: SharedRPC carries a per-listener
  `alive` atomic flipped synchronously in `invalidate(runtimeId)`, and executor lambdas
  on both iOS sites now capture `RCTInstance` `__weak` so a torn-down instance no-ops
  cleanly instead of dispatching into invalidated memory.
- Bump `@onekeyfe/react-native-background-thread` to 3.0.32.

* feat(background-thread Android): soft-reload main runtime for restart('ui')

Replaces the v1 placeholder where Android did a full-process restart for
both modes. Now matches iOS semantics: `mode='ui'` keeps the bg runtime
hot, only the main JS runtime reloads.

- Capture `mainReactHost` lazily in `installSharedBridgeInMainRuntime` via
  `(applicationContext as ReactApplication).reactHost`. Stays null on
  non-bridgeless hosts.
- `restart()` with `mode='ui'`: after SharedRPC invalidate('main'),
  resolve the promise, then post to UI thread and call
  `ReactHost.reload(reason)`. JS bootstrap re-invokes `installSharedBridge`
  which refreshes `mainRuntimePtr` and re-arms the "main" SharedRPC
  listener — symmetric with iOS where AppDelegate.hostDidStart does the
  same job.
- Fallback to process restart when `mainReactHost` is null or
  `reload()` throws — keeps semantics consistent across host setups.
- `mode='all'` unchanged: process restart via `Runtime.exit +
  makeRestartActivityTask`. OTA install/switch wants a clean re-read of
  both bundles from disk, and Android has a clean self-relaunch path that
  iOS lacks, so we don't pay the sequencing complexity of soft-reloading
  both runtimes.
- Clear `mainReactHost` in `destroy()` to match other lifecycle fields.

Not yet verified end-to-end — needs a build against the host app to
exercise: bridgeless detection, listener re-arm timing, bg-to-main RPC
during the reload window. Filed for follow-up testing.

* fix(background-thread): address PR #54 audit findings

Reviewer flagged a mix of integration-contract gaps, an Android error-
propagation bug, and a couple of C++ housekeeping items. Fixes:

iOS — host-integration contract (#1, high)
- Document the post-reload contract explicitly on
  `installSharedBridgeInMainRuntime:` and `restartWithMode:` headers. The
  host AppDelegate's `hostDidStart:` must re-invoke both the SharedBridge
  install (every reload) and `startBackgroundRunner` (mode='all' only).
- `restartWithMode:` now arms a one-shot `RCTJavaScriptDidLoadNotification`
  observer that fires ~1.5s after the new main bridge loads:
  * mode='all': self-respawns the bg runtime if the host AppDelegate
    didn't (idempotent via the existing `isStarted` guard, so a correctly-
    wired host pays nothing).
  * Both modes: logs `[BTLogger error:]` if the host failed to re-call
    `installSharedBridgeInMainRuntime:`. Tracked via a new atomic flag
    `mainSharedBridgeInstalled` flipped in the install lambda. Surfaces
    integration omissions in production logs instead of silent RPC drop.

JS spec — cross-platform asymmetry (#2, high)
- `NativeBackgroundThread.ts` JSDoc now spells out: iOS preserves the
  process across `mode='all'` (soft reload); Android kills it via
  `Runtime.exit(0)`. Callers depending on native process-level state
  (timers, singletons, in-memory caches, foreground services) must not
  assume cross-platform survival.

Android — false-success promise resolution (#3, medium)
- `triggerProcessRestart` returns `Boolean` so failure (intent not
  resolvable, `startActivity` `SecurityException`) propagates instead of
  being swallowed; caller rejects the Promise with `BG_RESTART_ERROR`.
- `mode='ui'` soft-reload moves `promise.resolve(null)` inside the
  `Handler.post` success branch — a synchronous `ReactHost.reload()`
  throw now routes through the same fallback-then-reject path instead of
  reporting false success because resolve already happened.

SharedRPC — clean up dead listener entries (#6, low)
- `invalidate(runtimeId)` now erases the listener entry from `listeners_`
  instead of leaving it with `alive=false`. Already-dispatched executor
  lambdas hold their own `shared_ptr<alive>` snapshot so erasing is
  race-safe; it only prevents NEW `notifyOtherRuntime()` snapshots from
  picking up the dead entry. Stops a permanently-dead listener from
  hanging around when a `mode='all'` restart never gets its post-reload
  re-install.
- `install()`'s defensive dedup loop is now documented as the legacy /
  no-prior-invalidate fallback path (#7, low).

Reviewer #4 (no tests) and #2's Android-side TODO (soft-reload both
runtimes via `ReactHost.reload`) remain follow-ups — flagged in PR
description, not in scope here.

* fix(background-thread): address PR #54 audit round 2

Round-1 self-heal observer hinged on RCTJavaScriptDidLoadNotification,
which reviewer flagged as unreliable in bridgeless / NewArch. The fix
also surfaced two secondary hazards (observer leak when notification
never fires; cross-generation flag misreporting on concurrent restarts).
All three close together by dropping the notification entirely.

iOS — replace notification observer with plain dispatch_after (#1, #2, high)
- The two signals the post-reload check needs (mainSharedBridgeInstalled,
  isStarted) are this module's own state. No external timing anchor is
  required; the notification was only ever an attempt at one. A direct
  dispatch_after on the main queue at kRestartHealthCheckDelaySeconds
  (3s, constant — empirical 6× margin over baseline hostDidStart chain
  on low-end devices) eliminates the bridgeless-fire-or-not gamble AND
  the observer-leak/cross-generation misfire that the observer pattern
  introduced.

iOS — generation counter for concurrent restart() safety (#3, medium)
- Adds `restartGeneration` (nonatomic; main-thread-only by construction).
  Each restartWithMode: bumps it and the health-check captures its own
  `myGen`; on fire, it bails if `restartGeneration != myGen` so a later
  restart's flag reset can't make an earlier restart's check misreport.

iOS — self-respawn loses custom OTA entry URL (#6, low)
- The bg self-respawn path falls through `startBackgroundRunner` →
  default URL (`background.bundle` / DEBUG URL), losing any custom
  entry URL the host set via startBackgroundRunnerWithEntryURL:
  (typically an OTA-resolved bundle path) because
  reactNativeFactoryDelegate is released for mode='all'. Added an
  explicit `[BTLogger warn:]` so this trade-off is visible in logs
  when the host's AppDelegate wiring is broken AND OTA paths matter.

Android — soften over-confident resolve-delivery comment (#4, medium)
- Round-1 comment claimed "the JS thread is still live and can deliver
  the success callback before being destroyed". Closer to truth: the
  CallInvoker is bound to the outgoing ReactInstance which reload
  invalidates very quickly, and `await restart(...)` callers' continu-
  ations are typically superseded by the reload. Position-of-resolve
  only matters for the synchronous-throw path. Updated the comment.

Not changed:
- 1.5s → 3s on the health-check delay is the right call but isn't
  itself a magic-number fix — `kRestartHealthCheckDelaySeconds` is a
  named constant with rationale comment. Polling-until-flag-flips was
  considered and skipped: extra complexity for a one-line log output.

Still pending end-to-end verification on the OneKey host app:
- mode='ui' / mode='all' on iOS bridgeless: confirm health-check logs
  fire only when integration is actually broken (deliberate
  AppDelegate.hostDidStart: omission test).
- Android: confirm BG_RESTART_ERROR Promise rejection on synthetic
  startActivity failure (e.g. invalid intent).

* fix(background-thread): address PR #54 audit round 3 (iOS hardening)

Round-2 left three open concerns reviewer flagged as merge-blockers for
the OTA path plus a memory-ordering nit. Fixes:

iOS — cache lastEntryURL for OTA-safe self-respawn (#1, medium)
- Round-2's self-respawn fell through to `startBackgroundRunner` →
  default `background.bundle`. On OTA-equipped hosts that's a moduleId-
  mismatch crash waiting to happen: main runs the OTA-updated bundle,
  bg loads the IPA's bundled bg bundle, next cross-runtime RPC crashes.
- Add `lastEntryURL` (nonatomic, copy) cached unconditionally inside
  `startBackgroundRunnerWithEntryURL:`. Self-respawn now replays the
  cached URL via `startBackgroundRunnerWithEntryURL:` instead of the
  default, keeping the bg moduleId table aligned with main.
- Falls back to the default-URL path only when no URL was ever cached
  (host never called start before triggering restart('all') — implausible
  in practice), with the original warn log preserved.

iOS — two-stage health-check tolerates slow devices (#2, medium)
- The 3s `dispatch_after` was measured from restart() dispatch time, not
  new-host ready. On low-end devices an OTA-multi-bundle reload chain
  can eat most of that budget, leaving the host's hostDidStart no time
  to flip the flags — false self-respawn / false error log.
- Extract the health-check into `scheduleHealthCheckForRestart:isAll:
  generation:retried:`. Stage 1 at +3s decides:
    * Both halves healthy → log OK, done.
    * Main ready but bg not (mode='all') → STABLE signal that the host
      didn't re-call startBackgroundRunner; self-respawn now.
    * Main NOT ready → could be a slow device; reschedule stage 2.
  Stage 2 at +6s total is the final verdict; whatever's still missing
  is logged as integration failure (and bg self-healed if it can be).
  Generation check at each stage entry bails on supersession.
- Added detailed stage1/stage2 diagnostic logs so production logs
  distinguish "host omitted the call" from "host was just slow".

iOS — isStarted nonatomic + cross-thread reads (#3, medium)
- Pre-existing nonatomic property is now read on main thread by the
  health-check while writes happen on caller's thread (the module's
  public surface does not pin start... to main). One-line change to
  (atomic, assign, readwrite); inline comment documents the TOCTOU race
  on concurrent first-time starts as a separate pre-existing concern.

Not changed:
- TOCTOU race in start... (concurrent first-time call → double init)
  is real but pre-existing and out of scope here; flagged in the new
  property comment so the next maintainer sees it.
- kRestartHealthCheckDelaySeconds stays at 3.0s — total budget is now
  6s via stage 2, which the reviewer's worst-case "1.5–2s reload + slow
  hostDidStart" easily fits inside.

Health-check method declared in the class extension as a forward
declaration so call-site readability is preserved (definition lives
after restartWithMode: where the restart flow naturally starts).

* fix(background-thread iOS): address PR #54 audit round 4 (low-risk polish)

Round-3 left four low-risk items reviewer recommended resolving for
consistency / debuggability. All four close cleanly:

#1 — lastEntryURL → atomic
- Same rationale as the round-3 isStarted change: written from caller's
  thread (public API doesn't pin start... to main), read on main by
  the health-check. NSString* assignment isn't atomic under ObjC ARC,
  so cross-thread readers could observe a torn pointer or stale value.
  One-line change to (atomic, copy); pre-existing nonatomic was an
  inconsistency with the round-3 fix.

#2 — race-debug warn on startBackgroundRunnerWithEntryURL: early return
- The early-return short-circuit (`if (self.isStarted) return;`) is
  the natural collision point for the self-respawn-vs-host-async-start
  race: self-respawn at stage 2 boots with the cached URL, then the
  host's late async start call comes in with a different URL and gets
  silently dropped. Added a `[BTLogger warn:]` that fires when the
  requested URL differs from the active one — production traces now
  show "bg is on URL X but Y was requested" instead of a mystery.

#3 — stage 1 always defers bg self-respawn to stage 2
- Round-3 stage 1 had a fast-path that self-respawned immediately when
  it saw mainReady=YES but bgReady=NO, on the assumption that mainReady
  was a stable signal the host wasn't going to call start. That's true
  for hosts whose hostDidStart: synchronously calls both install AND
  start, but hosts that gate startBackgroundRunner on async work
  (feature flag fetch, login, network) can be mainReady=YES while the
  real start is still inflight — the fast-path would race them and
  the host's late start would be dropped silently (#2 makes that case
  loud now, but losing the URL is still wrong). Stage 1 now always
  reschedules stage 2 if anything is missing; stage 2 (+~3s) is sized
  to give async host paths time to land. Cost is +3s on the actual
  self-respawn moment, only on broken-integration paths.

#4 — treat bundled default "background.bundle" as no-real-cache
- startBackgroundRunnerWithEntryURL: caches unconditionally, including
  the bundled default when host calls the no-arg startBackgroundRunner
  in release builds. Round-3 self-respawn's "cachedURL.length > 0"
  branch was treating that as a real cache and skipping the OTA-
  mismatch warn — but a host that bootstrapped with the default and
  never swapped to an OTA URL still has the same crash risk. Now
  filters: `cachedURL.length > 0 && ![cachedURL isEqualTo
  String:@"background.bundle"]`. Hosts that immediately call
  startBackgroundRunnerWithEntryURL:OTAUrl overwrite the cache so
  this filter only triggers in the genuinely-no-custom-URL case.

#5 (cosmetic explicit ivar init) is deliberately skipped — reviewer
flagged it as not necessary.

* refactor(background-thread): type restart() mode as string-literal union

Replace the bare `mode: string` parameter on the TurboModule spec with a
typed `RestartMode = 'ui' | 'all'` string-literal union exported from
NativeBackgroundThread.ts.

Why a literal union (not a TS enum):
- Zero runtime cost — a regular `enum` compiles to a JS object that
  ships with the bundle; a literal union erases to nothing.
- RN TurboModule codegen's supported-type whitelist is primitives,
  Object/Array, Promise, and string-literal unions. Plain TS `enum` is
  not on that list; behaviour across RN versions is unstable and best
  avoided in spec files.
- Consumers can `import type { RestartMode } from '...'` and pass a
  plain string; no runtime import dependency.

Migration note: if a downstream consumer was using
`EAppRestartMode` (TS string enum from `@onekeyhq/shared`) as the value,
its members aren't assignable to a string-literal union by default.
Two options at the call site:
  1. `restart(EAppRestartMode.UI as RestartMode, reason)`.
  2. Migrate `EAppRestartMode` to a string-literal union / `as const`
     object so the two stay aligned.

JSDoc updated to reference {@link RestartMode}; the native code still
validates at runtime (it's the source of truth for which strings the
platforms accept), so any cast that smuggles in an unknown mode is
caught and rejects the Promise.

* fix(background-thread cpp): explicit #include <algorithm> in SharedRPC.cpp

std::remove_if is used in both install() and invalidate(); the symbol was
only resolved transitively via SharedRPC.h's STL chain, which is fragile
across toolchain/header changes. Make the dependency explicit so a future
header diet on SharedRPC.h cannot break the build.

* fix(background-thread): address PR #54 audit round 5

- iOS: align isStarted public-header declaration with .mm redeclaration
  (atomic, readonly). The previous nonatomic/atomic mismatch trips
  Clang -Wproperty-attribute-mismatch and fails CI under -Werror.
- src: re-export RestartMode from the package entry so the JSDoc-promised
  `import type { RestartMode } from '@onekeyfe/react-native-background-thread'`
  actually resolves; consumers were getting a TS2305 against the prepared
  index.d.ts.
- iOS: refresh the scheduleHealthCheckForRestart: docblock — earlier rounds
  removed the stage-1 self-respawn-on-bg-not-ready short-circuit, but the
  function-level comment still described it. Comment now matches the
  unconditional-reschedule behaviour the body actually implements.

* fix(background-thread): address PR #54 audit round 6

- Android restart('ui'): handle async reload-task fault, not just the
  synchronous throw. ReactHost.reload(reason) returns TaskInterface<Void>
  in RN 0.83 and the public TaskInterface surface only exposes
  waitForCompletion + isFaulted/isCancelled/getError (no continueWith).
  Watch the task on a short-lived daemon thread; on fault, cancellation,
  or 15s timeout, post back to the main thread and trigger the existing
  process-restart fallback. Without this, an async reload fault leaves
  SharedRPC main listener invalidated and main runtime torn down with no
  rebuild path — app would be permanently broken until manual relaunch.
- src/NativeBackgroundThread.ts: fix the Prettier error that was the
  only true exit-1 lint failure (loadSegmentInBackground signature
  collapsed onto one line). Also drop the two stale eslint-disable
  directives in SharedRPC.ts / SharedStore.ts now that the underlying
  no-var hits no longer fire (warning-level but flagged in the audit).
- src/NativeBackgroundThread.ts JSDoc: replace the stale 'post-reload
  observer' wording with 'host hostDidStart: + dispatch_after health-
  check fallback' so the public docs match the implementation (which
  explicitly avoids RCTJavaScriptDidLoadNotification because of its
  unreliable timing in bridgeless / NewArch).

* 3.0.32

* fix(background-thread): loosen bundle-update peerDep to "*"

The 3.0.32 release-it commit (0247ebf) updated the yarn.lock entry
for background-thread's bundle-update peerDep but missed updating the
package.json itself, breaking CI's `yarn install --immutable`. Past
releases have hit the same shape — the peerDep version is bumped on
every bundle-update release, and any miss in either file desyncs the
lockfile.

The version floor wasn't load-bearing in practice (bundle-update
hasn't shipped a breaking API change for background-thread integration
since the floor was first introduced), so drop the floor and use `*`.
This eliminates the release-it sync hazard going forward and keeps
the runtime contract (consumer must have bundle-update installed)
intact via the peerDep entry.

* test(background-thread example): add restart(mode, reason) test buttons

Three buttons on BackgroundThreadTestPage:
- restart('ui'): exercises the main-runtime soft reload path. iOS goes
  through RCTTriggerReloadCommandListeners; Android goes through
  ReactHost.reload (bridgeless) with the new TaskInterface watcher
  falling back to process restart on async fault.
- restart('all'): on iOS, soft-reloads main and re-spawns bg; on
  Android, process-restarts via Runtime.exit + makeRestartActivityTask.
- bogus mode: drives the synchronous validation reject path so the
  log shows a visible BG_RESTART_ERROR rejection.

Imports RestartMode from the package entry to verify the new re-export
is reachable from a real consumer (the previously-broken JSDoc claim).

* Update Podfile.lock

* chore(example): pin cocoapods to ~> 1.16.2 (Ruby 3.4-compatible)

cocoapods 1.15.x (which the old Gemfile constraint
`>= 1.13, != 1.15.0, != 1.15.1` resolves to) crashes on Ruby 3.4 with
`cannot load such file -- kconv` — kconv was removed from the Ruby
3.4 stdlib. 1.16.2 dropped the direct kconv dependency, but xcodeproj
still caps CFPropertyList to `< 4.0`, and CFPropertyList 3.x has a
leftover `require 'kconv'` at file head (no actual Kconv calls).

Pin cocoapods to ~> 1.16.2, relax xcodeproj to >= 1.27.0 (1.16.x
requires it), and add a tiny local `kconv-shim` gem with an empty
`kconv.rb` so the orphan require in CFPropertyList resolves.
`bundle exec pod install` is now reproducible across machines and
locks the toolchain to a known-good version.

* chore(example ios): disable code signing for simulator builds

The example target had no DEVELOPMENT_TEAM set (intentionally — it's
per-developer and never committed). With Automatic signing, xcodebuild
errored "Signing for 'example' requires a development team" even on
simulator runs (`yarn ios`, fresh-clone build, CI), because Xcode 14+
asks for a team regardless of SDK when CODE_SIGN_STYLE is Automatic.

Add `CODE_SIGNING_ALLOWED[sdk=iphonesimulator*] = NO` on both Debug
and Release configs of the example target. Simulator builds now skip
signing entirely (the binary doesn't need it to run in the sim);
device builds (iphoneos SDK) still require a team, which devs can
configure locally in Xcode without committing personal identifiers.

* fix(example ios): ad-hoc sign simulator builds instead of disabling signing

Previous attempt (cfee72c) set CODE_SIGNING_ALLOWED=NO for the
iphonesimulator SDK to bypass the 'requires a development team'
error. That worked for the example target's main binary but it also
cleared signing on the embedded frameworks Copy-Frameworks step —
GPChannelSDKCore.framework (vendored by react-native-lite-card) and
hermesvm.framework ended up unsigned. iOS 26 simulator dyld refuses
to load unsigned frameworks at startup, so the app SIGABRT'd at
launch with 'Library not loaded: GPChannelSDKCore'.

Replace the all-off switch with ad-hoc signing on simulator:
- CODE_SIGN_STYLE = Manual   (skip automatic team resolution)
- CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = '-'  (Sign to Run Locally)

Simulator builds still get a valid (ad-hoc) signature on the main
binary and every embedded framework, so dyld accepts them. No team
is required because Manual style doesn't try to provision. Device
(iphoneos) builds remain untouched — devs configure their own team
in Xcode locally as before.

* fix(auto-size-input): dispatch focus/blur to UI thread

Nitro hybrid view methods can be invoked off the UI thread (JS thread on
iOS, arbitrary thread on Android). UIKit's becomeFirstResponder /
resignFirstResponder and Android's requestFocus / clearFocus / IMM calls
must run on the main thread.

On iOS the previous implementation crashed with SIGTRAP via
FrontBoardServices' assertBarrierOnQueue. Android would raise
CalledFromWrongThreadException.

Wrap both focus() and blur() with a main-thread dispatch (Thread.isMainThread
short-circuit on iOS, Looper.getMainLooper() + View.post on Android). The
isDisposed check is re-run inside the posted block on Android to avoid
touching a recycled view.

* 3.0.33

* Update CHANGELOG.md
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.

2 participants