From e9ae1738d27f2b749efba3de51e87567fb0c3795 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Sat, 21 Mar 2026 12:01:26 +0800 Subject: [PATCH 01/74] feat(background-thread): add SharedBridge JSI HostObject for cross-runtime data transfer Add a shared C++ HostObject that is installed in both the main and background JSI runtimes, enabling direct memory-level communication without ObjC dispatch overhead. Provides both push (existing postHostMessage/onHostMessage) and pull (SharedBridge send/drain) communication models. - cpp/SharedBridge.{h,cpp}: Cross-platform HostObject with thread-safe queues - iOS: Install in background runtime via hostDidStart, main runtime via class method - TypeScript: ISharedBridge type and getSharedBridge() helper - Example: Updated test page with ping/pong demo and drain loop --- example/react-native/background.js | 25 ++++ .../ios/example/AppDelegate.swift | 7 + .../pages/BackgroundThreadTestPage.tsx | 132 ++++++++++++++++-- .../BackgroundThread.podspec | 3 +- .../cpp/SharedBridge.cpp | 104 ++++++++++++++ .../cpp/SharedBridge.h | 36 +++++ .../BackgroundRunnerReactNativeDelegate.mm | 6 + .../ios/BackgroundThreadManager.h | 6 + .../ios/BackgroundThreadManager.mm | 26 ++++ .../src/SharedBridge.ts | 34 +++++ .../src/index.tsx | 2 + 11 files changed, 369 insertions(+), 12 deletions(-) create mode 100644 native-modules/react-native-background-thread/cpp/SharedBridge.cpp create mode 100644 native-modules/react-native-background-thread/cpp/SharedBridge.h create mode 100644 native-modules/react-native-background-thread/src/SharedBridge.ts diff --git a/example/react-native/background.js b/example/react-native/background.js index e711a188..df5121fd 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -70,3 +70,28 @@ nativeBGBridge.onHostMessage((message) => { }, 3000); } }); + +// SharedBridge pull-model: drain messages from the main runtime +function drainSharedBridge() { + if (globalThis.sharedBridge) { + if (globalThis.sharedBridge.hasMessages) { + const messages = globalThis.sharedBridge.drain(); + messages.forEach((raw) => { + try { + const msg = JSON.parse(raw); + console.log('[SharedBridge BG] received:', msg); + if (msg.type === 'ping') { + // Echo back with pong via SharedBridge + globalThis.sharedBridge.send( + JSON.stringify({ type: 'pong', ts: Date.now() }), + ); + } + } catch (e) { + console.warn('[SharedBridge BG] parse error:', e); + } + }); + } + } + setTimeout(drainSharedBridge, 16); // ~60fps check cadence +} +drainSharedBridge(); diff --git a/example/react-native/ios/example/AppDelegate.swift b/example/react-native/ios/example/AppDelegate.swift index 5ff0433c..cb9889a6 100644 --- a/example/react-native/ios/example/AppDelegate.swift +++ b/example/react-native/ios/example/AppDelegate.swift @@ -2,6 +2,7 @@ import UIKit import React import React_RCTAppDelegate import ReactAppDependencyProvider +import BackgroundThread @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -50,4 +51,10 @@ class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { Bundle.main.url(forResource: "main", withExtension: "jsbundle") #endif } + + override func hostDidStart(_ host: RCTHost) { + super.hostDidStart(host) + // Install SharedBridge HostObject into the main runtime + BackgroundThreadManager.installSharedBridge(inMainRuntime: host) + } } diff --git a/example/react-native/pages/BackgroundThreadTestPage.tsx b/example/react-native/pages/BackgroundThreadTestPage.tsx index 6b840335..6635cdee 100644 --- a/example/react-native/pages/BackgroundThreadTestPage.tsx +++ b/example/react-native/pages/BackgroundThreadTestPage.tsx @@ -1,32 +1,142 @@ -import React, { useState } from 'react'; -import { View, Text } from 'react-native'; -import { TestPageBase, TestButton } from './TestPageBase'; +import React, { useState, useEffect, useRef } from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import { TestPageBase, TestButton, TestResult } from './TestPageBase'; import { BackgroundThread } from '@onekeyfe/react-native-background-thread'; BackgroundThread.initBackgroundThread(); export function BackgroundThreadTestPage() { - const [result, setResult] = useState(''); + const [pushResult, setPushResult] = useState(''); + const [bridgeResult, setBridgeResult] = useState(''); + const [bridgeAvailable, setBridgeAvailable] = useState(false); + const drainTimer = useRef | null>(null); + // Check SharedBridge availability and start draining + useEffect(() => { + const check = setInterval(() => { + if (globalThis.sharedBridge) { + setBridgeAvailable(true); + clearInterval(check); + } + }, 100); - const handlePostMessage = () => { + // Drain loop: pull messages from background via SharedBridge + drainTimer.current = setInterval(() => { + if (globalThis.sharedBridge?.hasMessages) { + const messages = globalThis.sharedBridge.drain(); + messages.forEach((raw) => { + try { + const msg = JSON.parse(raw); + setBridgeResult( + (prev) => + `${prev}\n[${new Date().toLocaleTimeString()}] Received: ${JSON.stringify(msg)}`, + ); + } catch { + setBridgeResult((prev) => `${prev}\nParse error: ${raw}`); + } + }); + } + }, 16); + + return () => { + clearInterval(check); + if (drainTimer.current) clearInterval(drainTimer.current); + }; + }, []); + + // Push model: existing postBackgroundMessage / onBackgroundMessage + const handlePushMessage = () => { const message = { type: 'test1' }; BackgroundThread.onBackgroundMessage((event) => { - setResult(`Message received from background thread: ${event}`); + setPushResult(`Received from background: ${event}`); }); BackgroundThread.postBackgroundMessage(JSON.stringify(message)); - setResult(`Message sent to background thread: ${JSON.stringify(message)}`); + setPushResult(`Sent: ${JSON.stringify(message)}`); + }; + + // Pull model: SharedBridge send + drain + const handleSharedBridgePing = () => { + if (!globalThis.sharedBridge) { + setBridgeResult('SharedBridge not available yet'); + return; + } + const msg = { type: 'ping', ts: Date.now() }; + globalThis.sharedBridge.send(JSON.stringify(msg)); + setBridgeResult( + (prev) => + `${prev}\n[${new Date().toLocaleTimeString()}] Sent: ${JSON.stringify(msg)}`, + ); + }; + + const handleClearBridgeLog = () => { + setBridgeResult(''); }; return ( - - Result: {result} + {/* Push Model (existing) */} + + Push Model (postBackgroundMessage) + + + + + {/* Pull Model (SharedBridge) */} + + Pull Model (SharedBridge HostObject) + + SharedBridge: {bridgeAvailable ? 'Available' : 'Waiting...'} + {bridgeAvailable && + ` | isMain: ${globalThis.sharedBridge?.isMain}`} + + + {bridgeResult ? ( + + {bridgeResult.trim()} + + ) : null} ); } + +const styles = StyleSheet.create({ + section: { + marginBottom: 20, + gap: 10, + }, + sectionTitle: { + fontSize: 16, + fontWeight: '700', + color: '#333', + }, + statusText: { + fontSize: 13, + color: '#666', + fontFamily: 'Courier New', + }, + clearButton: { + backgroundColor: '#8E8E93', + }, + logContainer: { + backgroundColor: '#1a1a2e', + padding: 12, + borderRadius: 8, + maxHeight: 300, + }, + logText: { + fontSize: 12, + color: '#00ff88', + fontFamily: 'Courier New', + lineHeight: 18, + }, +}); diff --git a/native-modules/react-native-background-thread/BackgroundThread.podspec b/native-modules/react-native-background-thread/BackgroundThread.podspec index c3cf0a71..15dc8e1b 100644 --- a/native-modules/react-native-background-thread/BackgroundThread.podspec +++ b/native-modules/react-native-background-thread/BackgroundThread.podspec @@ -13,8 +13,9 @@ Pod::Spec.new do |s| s.platforms = { :ios => min_ios_version_supported } s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-background-thread.git", :tag => "#{s.version}" } - s.source_files = "ios/**/*.{h,m,mm,swift,cpp}" + s.source_files = "ios/**/*.{h,m,mm,swift,cpp}", "cpp/**/*.{h,cpp}" s.public_header_files = "ios/**/*.h" + s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp"' } s.dependency 'ReactNativeNativeLogger' diff --git a/native-modules/react-native-background-thread/cpp/SharedBridge.cpp b/native-modules/react-native-background-thread/cpp/SharedBridge.cpp new file mode 100644 index 00000000..a3ffcba6 --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedBridge.cpp @@ -0,0 +1,104 @@ +#include "SharedBridge.h" + +// Static member definitions +std::mutex SharedBridge::mutex_; +std::queue SharedBridge::mainQueue_; +std::queue SharedBridge::bgQueue_; +std::atomic SharedBridge::hasMainMsg_{false}; +std::atomic SharedBridge::hasBgMsg_{false}; + +void SharedBridge::install(jsi::Runtime &rt, bool isMain) { + auto bridge = std::make_shared(isMain); + auto obj = jsi::Object::createFromHostObject(rt, bridge); + rt.global().setProperty(rt, "sharedBridge", std::move(obj)); +} + +void SharedBridge::reset() { + std::lock_guard lock(mutex_); + std::queue().swap(mainQueue_); + std::queue().swap(bgQueue_); + hasMainMsg_.store(false); + hasBgMsg_.store(false); +} + +jsi::Value SharedBridge::get(jsi::Runtime &rt, const jsi::PropNameID &name) { + auto prop = name.utf8(rt); + + // send(message: string): void + // Pushes a string message into the OTHER runtime's queue. + if (prop == "send") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [this](jsi::Runtime &rt, const jsi::Value &, + const jsi::Value *args, size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError(rt, + "SharedBridge.send expects a string argument"); + } + auto msg = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + if (isMain_) { + bgQueue_.push(std::move(msg)); + hasBgMsg_.store(true); + } else { + mainQueue_.push(std::move(msg)); + hasMainMsg_.store(true); + } + } + return jsi::Value::undefined(); + }); + } + + // drain(): string[] + // Pulls all pending messages from this runtime's queue. + if (prop == "drain") { + return jsi::Function::createFromHostFunction( + rt, name, 0, + [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, + size_t) -> jsi::Value { + std::vector msgs; + { + std::lock_guard lock(mutex_); + auto &q = isMain_ ? mainQueue_ : bgQueue_; + auto &flag = isMain_ ? hasMainMsg_ : hasBgMsg_; + while (!q.empty()) { + msgs.push_back(std::move(q.front())); + q.pop(); + } + flag.store(false); + } + auto arr = jsi::Array(rt, msgs.size()); + for (size_t i = 0; i < msgs.size(); i++) { + arr.setValueAtIndex( + rt, i, jsi::String::createFromUtf8(rt, msgs[i])); + } + return arr; + }); + } + + // hasMessages: boolean (getter) + // Returns true if there are pending messages for this runtime. + // Uses atomic load — essentially zero overhead. + if (prop == "hasMessages") { + bool has = isMain_ ? hasMainMsg_.load(std::memory_order_relaxed) + : hasBgMsg_.load(std::memory_order_relaxed); + return jsi::Value(has); + } + + // isMain: boolean (getter) + if (prop == "isMain") { + return jsi::Value(isMain_); + } + + return jsi::Value::undefined(); +} + +std::vector SharedBridge::getPropertyNames(jsi::Runtime &rt) { + std::vector props; + props.push_back(jsi::PropNameID::forUtf8(rt, "send")); + props.push_back(jsi::PropNameID::forUtf8(rt, "drain")); + props.push_back(jsi::PropNameID::forUtf8(rt, "hasMessages")); + props.push_back(jsi::PropNameID::forUtf8(rt, "isMain")); + return props; +} diff --git a/native-modules/react-native-background-thread/cpp/SharedBridge.h b/native-modules/react-native-background-thread/cpp/SharedBridge.h new file mode 100644 index 00000000..fc3c6ec2 --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedBridge.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace jsi = facebook::jsi; + +class SharedBridge : public jsi::HostObject { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override; + std::vector getPropertyNames(jsi::Runtime &rt) override; + + /// Install a SharedBridge instance into the given runtime. + /// @param rt The JSI runtime to install into. + /// @param isMain true for the main (UI) runtime, false for background. + static void install(jsi::Runtime &rt, bool isMain); + + /// Reset all queues and flags. Call when tearing down. + static void reset(); + +private: + explicit SharedBridge(bool isMain) : isMain_(isMain) {} + + bool isMain_; + + // Shared state across both runtimes (static, process-wide) + static std::mutex mutex_; + static std::queue mainQueue_; // messages destined for main + static std::queue bgQueue_; // messages destined for background + static std::atomic hasMainMsg_; + static std::atomic hasBgMsg_; +}; diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 503c712a..ff69194e 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -8,6 +8,8 @@ #include #include +#include "SharedBridge.h" + #import #import @@ -198,6 +200,10 @@ - (void)hostDidStart:(RCTHost *)host facebook::react::defineReadOnlyGlobal(runtime, "postHostMessage", [self createPostMessageFunction:runtime]); facebook::react::defineReadOnlyGlobal(runtime, "onHostMessage", [self createSetOnMessageFunction:runtime]); [self setupErrorHandler:runtime]; + + // Install SharedBridge HostObject into background runtime + SharedBridge::install(runtime, /* isMain */ false); + [BTLogger info:@"SharedBridge installed in background runtime"]; }]; } diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h index fa0cf969..5d73432f 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h @@ -4,12 +4,18 @@ NS_ASSUME_NONNULL_BEGIN @class BackgroundReactNativeDelegate; @class RCTReactNativeFactory; +@class RCTHost; @interface BackgroundThreadManager : NSObject /// Shared instance for singleton pattern + (instancetype)sharedInstance; +/// Install SharedBridge HostObject into the main (UI) runtime. +/// Call this from your AppDelegate's ReactNativeDelegate hostDidStart: callback. +/// @param host The RCTHost for the main runtime ++ (void)installSharedBridgeInMainRuntime:(RCTHost *)host; + /// Start background runner with default entry URL - (void)startBackgroundRunner; diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 16a19630..ba451a12 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -15,6 +15,10 @@ #import "BackgroundRunnerReactNativeDelegate.h" #import "BTLogger.h" +#include "SharedBridge.h" +#import +#import + @interface BackgroundThreadManager () @property (nonatomic, strong) BackgroundReactNativeDelegate *reactNativeFactoryDelegate; @property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory; @@ -48,6 +52,28 @@ - (instancetype)init { return self; } +#pragma mark - SharedBridge + ++ (void)installSharedBridgeInMainRuntime:(RCTHost *)host { + if (!host) { + [BTLogger error:@"Cannot install SharedBridge: RCTHost is nil"]; + return; + } + + Ivar ivar = class_getInstanceVariable([host class], "_instance"); + id instance = object_getIvar(host, ivar); + + if (!instance) { + [BTLogger error:@"Cannot install SharedBridge: RCTInstance is nil"]; + return; + } + + [instance callFunctionOnBufferedRuntimeExecutor:^(facebook::jsi::Runtime &runtime) { + SharedBridge::install(runtime, /* isMain */ true); + [BTLogger info:@"SharedBridge installed in main runtime"]; + }]; +} + #pragma mark - Public Methods - (void)startBackgroundRunner { diff --git a/native-modules/react-native-background-thread/src/SharedBridge.ts b/native-modules/react-native-background-thread/src/SharedBridge.ts new file mode 100644 index 00000000..39a1db79 --- /dev/null +++ b/native-modules/react-native-background-thread/src/SharedBridge.ts @@ -0,0 +1,34 @@ +/** + * SharedBridge — a JSI HostObject installed in both the main and background + * runtimes, backed by the same C++ queues. Available as `globalThis.sharedBridge` + * once installed on the native side. + * + * Main runtime: send() pushes to background queue, drain() pulls from main queue. + * Background: send() pushes to main queue, drain() pulls from background queue. + */ +export interface ISharedBridge { + /** Push a string message into the OTHER runtime's queue. */ + send(message: string): void; + + /** Pull all pending messages from THIS runtime's queue. */ + drain(): string[]; + + /** True if there are pending messages for THIS runtime. Atomic read, ~0 cost. */ + readonly hasMessages: boolean; + + /** True if this instance is installed in the main (UI) runtime. */ + readonly isMain: boolean; +} + +declare global { + // eslint-disable-next-line no-var + var sharedBridge: ISharedBridge | undefined; +} + +/** + * Get the SharedBridge instance from globalThis. + * Returns undefined if native side hasn't installed it yet. + */ +export function getSharedBridge(): ISharedBridge | undefined { + return globalThis.sharedBridge; +} diff --git a/native-modules/react-native-background-thread/src/index.tsx b/native-modules/react-native-background-thread/src/index.tsx index 9eb79b52..f8226d88 100644 --- a/native-modules/react-native-background-thread/src/index.tsx +++ b/native-modules/react-native-background-thread/src/index.tsx @@ -1,3 +1,5 @@ import NativeBackgroundThread from './NativeBackgroundThread'; export const BackgroundThread = NativeBackgroundThread; +export { getSharedBridge } from './SharedBridge'; +export type { ISharedBridge } from './SharedBridge'; From 9747116795844af9f1e57d1fa5158b61e35846a7 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Sat, 21 Mar 2026 14:15:35 +0800 Subject: [PATCH 02/74] feat(background-thread): implement Android with second ReactHost and SharedBridge - CMakeLists.txt + cpp-adapter.cpp: JNI bridge for SharedBridge install, postHostMessage/onHostMessage JSI globals, and message passing - BackgroundThreadModule.kt: Full implementation with ReactHostImpl for background JS runtime, JSI bindings install via ReactInstanceEventListener, SharedBridge in both main and background runtimes - build.gradle: Add externalNativeBuild with CMake, prefab for fbjni/jsi - SharedBridge.h: Make constructor public for std::make_shared compatibility --- .../android/CMakeLists.txt | 28 +++ .../android/build.gradle | 42 +++++ .../android/src/main/cpp/cpp-adapter.cpp | 139 +++++++++++++++ .../BackgroundThreadModule.kt | 160 +++++++++++++++++- .../cpp/SharedBridge.h | 3 +- .../android/src/main/AndroidManifest.xml | 2 +- 6 files changed, 363 insertions(+), 11 deletions(-) create mode 100644 native-modules/react-native-background-thread/android/CMakeLists.txt create mode 100644 native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp diff --git a/native-modules/react-native-background-thread/android/CMakeLists.txt b/native-modules/react-native-background-thread/android/CMakeLists.txt new file mode 100644 index 00000000..1cd284b8 --- /dev/null +++ b/native-modules/react-native-background-thread/android/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.13) +project(background_thread) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_VERBOSE_MAKEFILE ON) + +find_package(fbjni REQUIRED CONFIG) +find_package(ReactAndroid REQUIRED CONFIG) + +add_library(${PROJECT_NAME} SHARED + src/main/cpp/cpp-adapter.cpp + ../cpp/SharedBridge.cpp +) + +target_include_directories(${PROJECT_NAME} PRIVATE + src/main/cpp + ../cpp +) + +find_library(LOG_LIB log) + +target_link_libraries(${PROJECT_NAME} + ${LOG_LIB} + fbjni::fbjni + ReactAndroid::jsi + ReactAndroid::reactnative + android +) diff --git a/native-modules/react-native-background-thread/android/build.gradle b/native-modules/react-native-background-thread/android/build.gradle index 62bad2b3..62541acd 100644 --- a/native-modules/react-native-background-thread/android/build.gradle +++ b/native-modules/react-native-background-thread/android/build.gradle @@ -25,6 +25,11 @@ def getExtOrIntegerDefault(name) { return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["BackgroundThread_" + name]).toInteger() } +def reactNativeArchitectures() { + def value = rootProject.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + android { namespace "com.backgroundthread" @@ -33,10 +38,47 @@ android { defaultConfig { minSdkVersion getExtOrIntegerDefault("minSdkVersion") targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + + externalNativeBuild { + cmake { + cppFlags "-frtti -fexceptions -Wall -fstack-protector-all" + arguments "-DANDROID_STL=c++_shared", + "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" + abiFilters(*reactNativeArchitectures()) + } + } + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } } buildFeatures { buildConfig true + prefab true + } + + packagingOptions { + excludes = [ + "META-INF", + "META-INF/**", + "**/libc++_shared.so", + "**/libfbjni.so", + "**/libjsi.so", + "**/libfolly_json.so", + "**/libfolly_runtime.so", + "**/libglog.so", + "**/libhermes.so", + "**/libhermes-executor-debug.so", + "**/libhermes_executor.so", + "**/libreactnative.so", + "**/libreactnativejni.so", + "**/libturbomodulejsijni.so", + "**/libreact_nativemodule_core.so", + "**/libjscexecutor.so" + ] } buildTypes { diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp new file mode 100644 index 00000000..a5d71a7f --- /dev/null +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +#include "SharedBridge.h" + +#define LOG_TAG "BackgroundThread" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) + +namespace jsi = facebook::jsi; + +static JavaVM *gJavaVM = nullptr; +static jobject gModuleRef = nullptr; +static std::shared_ptr gBgOnMessageCallback; + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + gJavaVM = vm; + return JNI_VERSION_1_6; +} + +static JNIEnv *getJNIEnv() { + JNIEnv *env = nullptr; + if (gJavaVM) { + gJavaVM->AttachCurrentThread(&env, nullptr); + } + return env; +} + +// Install postHostMessage / onHostMessage JSI globals into the background runtime. +// Also stores a global ref to the Java module for callbacks. +extern "C" JNIEXPORT void JNICALL +Java_com_backgroundthread_BackgroundThreadModule_nativeInstallBgBindings( + JNIEnv *env, jobject thiz, jlong runtimePtr) { + + auto *runtime = reinterpret_cast(runtimePtr); + if (!runtime) return; + + // Store global ref to module for JNI callbacks + if (gModuleRef) { + env->DeleteGlobalRef(gModuleRef); + } + gModuleRef = env->NewGlobalRef(thiz); + + // Reset previous callback + gBgOnMessageCallback.reset(); + + // postHostMessage(message: string) — background JS calls this to send to main + auto postHostMessage = jsi::Function::createFromHostFunction( + *runtime, + jsi::PropNameID::forAscii(*runtime, "postHostMessage"), + 1, + [](jsi::Runtime &rt, const jsi::Value &, + const jsi::Value *args, size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError(rt, "postHostMessage expects a string argument"); + } + std::string msg = args[0].getString(rt).utf8(rt); + + JNIEnv *env = getJNIEnv(); + if (env && gModuleRef) { + jclass cls = env->GetObjectClass(gModuleRef); + jmethodID mid = env->GetMethodID( + cls, "onBgMessage", "(Ljava/lang/String;)V"); + if (mid) { + jstring jmsg = env->NewStringUTF(msg.c_str()); + env->CallVoidMethod(gModuleRef, mid, jmsg); + env->DeleteLocalRef(jmsg); + } + env->DeleteLocalRef(cls); + } + return jsi::Value::undefined(); + }); + + runtime->global().setProperty( + *runtime, "postHostMessage", std::move(postHostMessage)); + + // onHostMessage(callback: function) — background JS registers a message handler + auto onHostMessage = jsi::Function::createFromHostFunction( + *runtime, + jsi::PropNameID::forAscii(*runtime, "onHostMessage"), + 1, + [](jsi::Runtime &rt, const jsi::Value &, + const jsi::Value *args, size_t count) -> jsi::Value { + if (count < 1 || !args[0].isObject() || + !args[0].asObject(rt).isFunction(rt)) { + throw jsi::JSError(rt, "onHostMessage expects a function"); + } + gBgOnMessageCallback = std::make_shared( + args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); + }); + + runtime->global().setProperty( + *runtime, "onHostMessage", std::move(onHostMessage)); + + LOGI("JSI bindings (postHostMessage/onHostMessage) installed in background runtime"); +} + +// Post a message from main to background JS. +// Must be called on the background JS thread. +extern "C" JNIEXPORT void JNICALL +Java_com_backgroundthread_BackgroundThreadModule_nativePostToBackground( + JNIEnv *env, jobject thiz, jlong runtimePtr, jstring message) { + + if (!gBgOnMessageCallback || runtimePtr == 0) return; + + auto *runtime = reinterpret_cast(runtimePtr); + const char *msgChars = env->GetStringUTFChars(message, nullptr); + std::string msg(msgChars); + env->ReleaseStringUTFChars(message, msgChars); + + try { + auto parsedValue = runtime->global() + .getPropertyAsObject(*runtime, "JSON") + .getPropertyAsFunction(*runtime, "parse") + .call(*runtime, jsi::String::createFromUtf8(*runtime, msg)); + + gBgOnMessageCallback->call(*runtime, {std::move(parsedValue)}); + } catch (const jsi::JSError &e) { + LOGE("JSError in postToBackground: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("Error in postToBackground: %s", e.what()); + } +} + +// Install SharedBridge HostObject into a runtime. +extern "C" JNIEXPORT void JNICALL +Java_com_backgroundthread_BackgroundThreadModule_nativeInstallSharedBridge( + JNIEnv *env, jobject thiz, jlong runtimePtr, jboolean isMain) { + + auto *rt = reinterpret_cast(runtimePtr); + if (!rt) return; + + SharedBridge::install(*rt, static_cast(isMain)); + LOGI("SharedBridge installed (isMain=%d)", static_cast(isMain)); +} diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt index d9572e6e..db8f4f19 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt @@ -1,29 +1,171 @@ package com.backgroundthread +import android.util.Log +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.ReactApplication +import com.facebook.react.ReactInstanceEventListener +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.UiThreadUtil +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.defaults.DefaultComponentsRegistry +import com.facebook.react.defaults.DefaultReactHostDelegate +import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate +import com.facebook.react.fabric.ComponentFactory import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.runtime.ReactHostImpl +import com.facebook.react.runtime.hermes.HermesInstance @ReactModule(name = BackgroundThreadModule.NAME) class BackgroundThreadModule(reactContext: ReactApplicationContext) : NativeBackgroundThreadSpec(reactContext) { - override fun getName(): String { - return NAME + private var bgReactHost: ReactHostImpl? = null + @Volatile + private var bgRuntimePtr: Long = 0 + private var isStarted = false + + companion object { + const val NAME = "BackgroundThread" + private const val TAG = "BackgroundThread" + + init { + System.loadLibrary("background_thread") + } } - override fun initBackgroundThread() { - // TODO: Implement initBackgroundThread + // JNI declarations + private external fun nativeInstallBgBindings(runtimePtr: Long) + private external fun nativePostToBackground(runtimePtr: Long, message: String) + private external fun nativeInstallSharedBridge(runtimePtr: Long, isMain: Boolean) + + override fun getName(): String = NAME + + /** + * Called from C++ (via JNI) when background JS calls postHostMessage(message). + * Emits the message to the main JS runtime via TurboModule event emitter. + */ + @DoNotStrip + fun onBgMessage(message: String) { + UiThreadUtil.runOnUiThread { + try { + emitOnBackgroundMessage(message) + } catch (e: Exception) { + Log.e(TAG, "Error emitting background message", e) + } + } } - override fun postBackgroundMessage(message: String) { - // TODO: Implement postBackgroundMessage + override fun initBackgroundThread() { + // Install SharedBridge in the main runtime + val context = reactApplicationContext + context.runOnJSQueueThread { + try { + val ptr = context.javaScriptContextHolder?.get() ?: 0L + if (ptr != 0L) { + nativeInstallSharedBridge(ptr, true) + Log.i(TAG, "SharedBridge installed in main runtime") + } else { + Log.w(TAG, "Main runtime pointer is 0, cannot install SharedBridge") + } + } catch (e: Exception) { + Log.e(TAG, "Error installing SharedBridge in main runtime", e) + } + } } + @OptIn(UnstableReactNativeAPI::class) override fun startBackgroundRunnerWithEntryURL(entryURL: String) { - // TODO: Implement startBackgroundRunnerWithEntryURL + if (isStarted) { + Log.w(TAG, "Background runner already started") + return + } + isStarted = true + Log.i(TAG, "Starting background runner with entryURL: $entryURL") + + val appContext = reactApplicationContext.applicationContext + + val bundleLoader = if (entryURL.startsWith("http")) { + // For dev server: load bundle directly from URL + object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + delegate.loadScriptFromFile(entryURL, entryURL, false) + return entryURL + } + } + } else { + JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) + } + + val delegate = DefaultReactHostDelegate( + jsMainModulePath = "background", + jsBundleLoader = bundleLoader, + reactPackages = emptyList(), + jsRuntimeFactory = HermesInstance(), + turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder(), + ) + + val componentFactory = ComponentFactory() + DefaultComponentsRegistry.register(componentFactory) + + val host = ReactHostImpl( + appContext, + delegate, + componentFactory, + true, /* allowPackagerServerAccess */ + false, /* useDevSupport */ + ) + bgReactHost = host + + host.addReactInstanceEventListener(object : ReactInstanceEventListener { + override fun onReactContextInitialized(context: ReactContext) { + Log.i(TAG, "Background ReactContext initialized") + context.runOnJSQueueThread { + try { + val ptr = context.javaScriptContextHolder?.get() ?: 0L + if (ptr != 0L) { + bgRuntimePtr = ptr + nativeInstallBgBindings(ptr) + nativeInstallSharedBridge(ptr, false) + Log.i(TAG, "JSI bindings and SharedBridge installed in background runtime") + } else { + Log.e(TAG, "Background runtime pointer is 0") + } + } catch (e: Exception) { + Log.e(TAG, "Error installing bindings in background runtime", e) + } + } + } + }) + + host.start() } - companion object { - const val NAME = "BackgroundThread" + override fun postBackgroundMessage(message: String) { + val ptr = bgRuntimePtr + if (ptr == 0L) { + Log.w(TAG, "Cannot post message: background runtime not ready") + return + } + + bgReactHost?.currentReactContext?.runOnJSQueueThread { + try { + if (bgRuntimePtr != 0L) { + nativePostToBackground(bgRuntimePtr, message) + } + } catch (e: Exception) { + Log.e(TAG, "Error posting message to background", e) + } + } + } + + override fun invalidate() { + super.invalidate() + bgRuntimePtr = 0 + bgReactHost?.destroy("BackgroundThreadModule invalidated", null) + bgReactHost = null + isStarted = false } } diff --git a/native-modules/react-native-background-thread/cpp/SharedBridge.h b/native-modules/react-native-background-thread/cpp/SharedBridge.h index fc3c6ec2..311b6c84 100644 --- a/native-modules/react-native-background-thread/cpp/SharedBridge.h +++ b/native-modules/react-native-background-thread/cpp/SharedBridge.h @@ -22,9 +22,10 @@ class SharedBridge : public jsi::HostObject { /// Reset all queues and flags. Call when tearing down. static void reset(); -private: explicit SharedBridge(bool isMain) : isMain_(isMain) {} +private: + bool isMain_; // Shared state across both runtimes (static, process-wide) diff --git a/native-views/react-native-pager-view/android/src/main/AndroidManifest.xml b/native-views/react-native-pager-view/android/src/main/AndroidManifest.xml index cfe65132..ed8b453c 100644 --- a/native-views/react-native-pager-view/android/src/main/AndroidManifest.xml +++ b/native-views/react-native-pager-view/android/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ + > From 5c27e6f481f58a9d3ae5a75d549b8ee9455910c3 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Sun, 22 Mar 2026 22:11:51 +0800 Subject: [PATCH 03/74] refactor(background-thread): restructure Android to match iOS architecture Extract BackgroundThreadManager singleton from BackgroundThreadModule, add BTLogger with dynamic OneKeyLog dispatch, add error handler setup and JNI cleanup in cpp-adapter, and protect callback with mutex. --- .../android/src/main/cpp/cpp-adapter.cpp | 146 +++++++++++-- .../java/com/backgroundthread/BTLogger.kt | 55 +++++ .../BackgroundThreadManager.kt | 198 ++++++++++++++++++ .../BackgroundThreadModule.kt | 181 ++++------------ 4 files changed, 417 insertions(+), 163 deletions(-) create mode 100644 native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BTLogger.kt create mode 100644 native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index a5d71a7f..f435f4c2 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "SharedBridge.h" @@ -13,7 +14,8 @@ namespace jsi = facebook::jsi; static JavaVM *gJavaVM = nullptr; -static jobject gModuleRef = nullptr; +static jobject gManagerRef = nullptr; +static std::mutex gCallbackMutex; static std::shared_ptr gBgOnMessageCallback; extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { @@ -29,23 +31,39 @@ static JNIEnv *getJNIEnv() { return env; } +// Stub a JSI function on an object (replaces it with a no-op). +static void stubJsiFunction(jsi::Runtime &runtime, jsi::Object &object, const char *name) { + object.setProperty( + runtime, + name, + jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, name), 1, + [](auto &, const auto &, const auto *, size_t) { + return jsi::Value::undefined(); + })); +} + +// ── nativeInstallBgBindings ───────────────────────────────────────────── // Install postHostMessage / onHostMessage JSI globals into the background runtime. -// Also stores a global ref to the Java module for callbacks. +// Also stores a global ref to the Java manager for callbacks. extern "C" JNIEXPORT void JNICALL -Java_com_backgroundthread_BackgroundThreadModule_nativeInstallBgBindings( +Java_com_backgroundthread_BackgroundThreadManager_nativeInstallBgBindings( JNIEnv *env, jobject thiz, jlong runtimePtr) { auto *runtime = reinterpret_cast(runtimePtr); if (!runtime) return; - // Store global ref to module for JNI callbacks - if (gModuleRef) { - env->DeleteGlobalRef(gModuleRef); + // Store global ref to manager for JNI callbacks + if (gManagerRef) { + env->DeleteGlobalRef(gManagerRef); } - gModuleRef = env->NewGlobalRef(thiz); + gManagerRef = env->NewGlobalRef(thiz); // Reset previous callback - gBgOnMessageCallback.reset(); + { + std::lock_guard lock(gCallbackMutex); + gBgOnMessageCallback.reset(); + } // postHostMessage(message: string) — background JS calls this to send to main auto postHostMessage = jsi::Function::createFromHostFunction( @@ -60,13 +78,13 @@ Java_com_backgroundthread_BackgroundThreadModule_nativeInstallBgBindings( std::string msg = args[0].getString(rt).utf8(rt); JNIEnv *env = getJNIEnv(); - if (env && gModuleRef) { - jclass cls = env->GetObjectClass(gModuleRef); + if (env && gManagerRef) { + jclass cls = env->GetObjectClass(gManagerRef); jmethodID mid = env->GetMethodID( cls, "onBgMessage", "(Ljava/lang/String;)V"); if (mid) { jstring jmsg = env->NewStringUTF(msg.c_str()); - env->CallVoidMethod(gModuleRef, mid, jmsg); + env->CallVoidMethod(gManagerRef, mid, jmsg); env->DeleteLocalRef(jmsg); } env->DeleteLocalRef(cls); @@ -88,8 +106,11 @@ Java_com_backgroundthread_BackgroundThreadModule_nativeInstallBgBindings( !args[0].asObject(rt).isFunction(rt)) { throw jsi::JSError(rt, "onHostMessage expects a function"); } - gBgOnMessageCallback = std::make_shared( - args[0].asObject(rt).asFunction(rt)); + { + std::lock_guard lock(gCallbackMutex); + gBgOnMessageCallback = std::make_shared( + args[0].asObject(rt).asFunction(rt)); + } return jsi::Value::undefined(); }); @@ -99,13 +120,19 @@ Java_com_backgroundthread_BackgroundThreadModule_nativeInstallBgBindings( LOGI("JSI bindings (postHostMessage/onHostMessage) installed in background runtime"); } +// ── nativePostToBackground ────────────────────────────────────────────── // Post a message from main to background JS. // Must be called on the background JS thread. extern "C" JNIEXPORT void JNICALL -Java_com_backgroundthread_BackgroundThreadModule_nativePostToBackground( +Java_com_backgroundthread_BackgroundThreadManager_nativePostToBackground( JNIEnv *env, jobject thiz, jlong runtimePtr, jstring message) { - if (!gBgOnMessageCallback || runtimePtr == 0) return; + std::shared_ptr callback; + { + std::lock_guard lock(gCallbackMutex); + callback = gBgOnMessageCallback; + } + if (!callback || runtimePtr == 0) return; auto *runtime = reinterpret_cast(runtimePtr); const char *msgChars = env->GetStringUTFChars(message, nullptr); @@ -118,7 +145,7 @@ Java_com_backgroundthread_BackgroundThreadModule_nativePostToBackground( .getPropertyAsFunction(*runtime, "parse") .call(*runtime, jsi::String::createFromUtf8(*runtime, msg)); - gBgOnMessageCallback->call(*runtime, {std::move(parsedValue)}); + callback->call(*runtime, {std::move(parsedValue)}); } catch (const jsi::JSError &e) { LOGE("JSError in postToBackground: %s", e.getMessage().c_str()); } catch (const std::exception &e) { @@ -126,9 +153,10 @@ Java_com_backgroundthread_BackgroundThreadModule_nativePostToBackground( } } +// ── nativeInstallSharedBridge ─────────────────────────────────────────── // Install SharedBridge HostObject into a runtime. extern "C" JNIEXPORT void JNICALL -Java_com_backgroundthread_BackgroundThreadModule_nativeInstallSharedBridge( +Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( JNIEnv *env, jobject thiz, jlong runtimePtr, jboolean isMain) { auto *rt = reinterpret_cast(runtimePtr); @@ -137,3 +165,87 @@ Java_com_backgroundthread_BackgroundThreadModule_nativeInstallSharedBridge( SharedBridge::install(*rt, static_cast(isMain)); LOGI("SharedBridge installed (isMain=%d)", static_cast(isMain)); } + +// ── nativeSetupErrorHandler ───────────────────────────────────────────── +// Wrap the global error handler in the background runtime. +// Mirrors iOS BackgroundRunnerReactNativeDelegate.setupErrorHandler:. +extern "C" JNIEXPORT void JNICALL +Java_com_backgroundthread_BackgroundThreadManager_nativeSetupErrorHandler( + JNIEnv *env, jobject thiz, jlong runtimePtr) { + + auto *runtime = reinterpret_cast(runtimePtr); + if (!runtime) return; + + try { + jsi::Object global = runtime->global(); + jsi::Value errorUtilsVal = global.getProperty(*runtime, "ErrorUtils"); + if (!errorUtilsVal.isObject()) { + LOGE("ErrorUtils is not available on global object"); + return; + } + + jsi::Object errorUtils = errorUtilsVal.asObject(*runtime); + + // Capture the current global error handler + auto originalHandler = std::make_shared( + errorUtils.getProperty(*runtime, "getGlobalHandler") + .asObject(*runtime).asFunction(*runtime).call(*runtime)); + + // Create a custom handler that delegates to the original + auto handlerFunc = jsi::Function::createFromHostFunction( + *runtime, + jsi::PropNameID::forAscii(*runtime, "customGlobalErrorHandler"), + 2, + [originalHandler]( + jsi::Runtime &rt, const jsi::Value &, + const jsi::Value *args, size_t count) -> jsi::Value { + if (count < 2) { + return jsi::Value::undefined(); + } + + if (originalHandler->isObject() && + originalHandler->asObject(rt).isFunction(rt)) { + jsi::Function original = + originalHandler->asObject(rt).asFunction(rt); + original.call(rt, args, count); + } + + return jsi::Value::undefined(); + }); + + // Set the new global error handler + jsi::Function setHandler = + errorUtils.getProperty(*runtime, "setGlobalHandler") + .asObject(*runtime).asFunction(*runtime); + setHandler.call(*runtime, {std::move(handlerFunc)}); + + // Disable further setGlobalHandler from background JS + stubJsiFunction(*runtime, errorUtils, "setGlobalHandler"); + + LOGI("Error handler installed in background runtime"); + } catch (const jsi::JSError &e) { + LOGE("JSError setting up error handler: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("Error setting up error handler: %s", e.what()); + } +} + +// ── nativeDestroy ─────────────────────────────────────────────────────── +// Clean up JNI global references and callbacks. +// Called from BackgroundThreadManager.destroy(). +extern "C" JNIEXPORT void JNICALL +Java_com_backgroundthread_BackgroundThreadManager_nativeDestroy( + JNIEnv *env, jobject thiz) { + + { + std::lock_guard lock(gCallbackMutex); + gBgOnMessageCallback.reset(); + } + + if (gManagerRef) { + env->DeleteGlobalRef(gManagerRef); + gManagerRef = nullptr; + } + + LOGI("Native resources cleaned up"); +} diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BTLogger.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BTLogger.kt new file mode 100644 index 00000000..e8bc71e4 --- /dev/null +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BTLogger.kt @@ -0,0 +1,55 @@ +package com.backgroundthread + +/** + * Lightweight logging wrapper that dynamically dispatches to OneKeyLog. + * Uses reflection to avoid a hard dependency on the native-logger module. + * Falls back to android.util.Log when OneKeyLog is not available. + * + * Mirrors iOS BTLogger. + */ +object BTLogger { + private const val TAG = "BackgroundThread" + + private val logClass: Class<*>? by lazy { + try { + Class.forName("com.margelo.nitro.nativelogger.OneKeyLog") + } catch (_: ClassNotFoundException) { + null + } + } + + private val methods by lazy { + val cls = logClass ?: return@lazy null + mapOf( + "debug" to cls.getMethod("debug", String::class.java, String::class.java), + "info" to cls.getMethod("info", String::class.java, String::class.java), + "warn" to cls.getMethod("warn", String::class.java, String::class.java), + "error" to cls.getMethod("error", String::class.java, String::class.java), + ) + } + + @JvmStatic + fun debug(message: String) = log("debug", message, android.util.Log.DEBUG) + + @JvmStatic + fun info(message: String) = log("info", message, android.util.Log.INFO) + + @JvmStatic + fun warn(message: String) = log("warn", message, android.util.Log.WARN) + + @JvmStatic + fun error(message: String) = log("error", message, android.util.Log.ERROR) + + private fun log(level: String, message: String, androidLogLevel: Int) { + val method = methods?.get(level) + if (method != null) { + try { + method.invoke(null, TAG, message) + return + } catch (_: Exception) { + // Fall through to android.util.Log + } + } + android.util.Log.println(androidLogLevel, TAG, message) + } +} diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt new file mode 100644 index 00000000..259658c6 --- /dev/null +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -0,0 +1,198 @@ +package com.backgroundthread + +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.ReactInstanceEventListener +import com.facebook.react.bridge.JSBundleLoader +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContext +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.defaults.DefaultComponentsRegistry +import com.facebook.react.defaults.DefaultReactHostDelegate +import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate +import com.facebook.react.fabric.ComponentFactory +import com.facebook.react.runtime.ReactHostImpl +import com.facebook.react.runtime.hermes.HermesInstance + +/** + * Singleton manager for the background React Native runtime. + * Mirrors iOS BackgroundThreadManager. + * + * Responsibilities: + * - Manages background ReactHostImpl lifecycle + * - Installs SharedBridge into main and background runtimes + * - Routes messages between runtimes via JNI/JSI + */ +class BackgroundThreadManager private constructor() { + + private var bgReactHost: ReactHostImpl? = null + + @Volatile + private var bgRuntimePtr: Long = 0 + private var isStarted = false + private var onMessageCallback: ((String) -> Unit)? = null + + companion object { + private const val MODULE_NAME = "background" + + init { + System.loadLibrary("background_thread") + } + + @Volatile + private var instance: BackgroundThreadManager? = null + + @JvmStatic + fun getInstance(): BackgroundThreadManager { + return instance ?: synchronized(this) { + instance ?: BackgroundThreadManager().also { instance = it } + } + } + } + + // ── JNI declarations ──────────────────────────────────────────────────── + + private external fun nativeInstallBgBindings(runtimePtr: Long) + private external fun nativePostToBackground(runtimePtr: Long, message: String) + private external fun nativeInstallSharedBridge(runtimePtr: Long, isMain: Boolean) + private external fun nativeSetupErrorHandler(runtimePtr: Long) + private external fun nativeDestroy() + + // ── SharedBridge ──────────────────────────────────────────────────────── + + /** + * Install SharedBridge HostObject into the main (UI) runtime. + * Call this from initBackgroundThread(). + */ + fun installSharedBridgeInMainRuntime(context: ReactApplicationContext) { + context.runOnJSQueueThread { + try { + val ptr = context.javaScriptContextHolder?.get() ?: 0L + if (ptr != 0L) { + nativeInstallSharedBridge(ptr, true) + BTLogger.info("SharedBridge installed in main runtime") + } else { + BTLogger.warn("Main runtime pointer is 0, cannot install SharedBridge") + } + } catch (e: Exception) { + BTLogger.error("Error installing SharedBridge in main runtime: ${e.message}") + } + } + } + + // ── Background runner lifecycle ───────────────────────────────────────── + + @OptIn(UnstableReactNativeAPI::class) + fun startBackgroundRunnerWithEntryURL(context: ReactApplicationContext, entryURL: String) { + if (isStarted) { + BTLogger.warn("Background runner already started") + return + } + isStarted = true + BTLogger.info("Starting background runner with entryURL: $entryURL") + + val appContext = context.applicationContext + + val bundleLoader = if (entryURL.startsWith("http")) { + object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + delegate.loadScriptFromFile(entryURL, entryURL, false) + return entryURL + } + } + } else { + JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) + } + + val delegate = DefaultReactHostDelegate( + jsMainModulePath = MODULE_NAME, + jsBundleLoader = bundleLoader, + reactPackages = emptyList(), + jsRuntimeFactory = HermesInstance(), + turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder(), + ) + + val componentFactory = ComponentFactory() + DefaultComponentsRegistry.register(componentFactory) + + val host = ReactHostImpl( + appContext, + delegate, + componentFactory, + true, /* allowPackagerServerAccess */ + false, /* useDevSupport */ + ) + bgReactHost = host + + host.addReactInstanceEventListener(object : ReactInstanceEventListener { + override fun onReactContextInitialized(context: ReactContext) { + BTLogger.info("Background ReactContext initialized") + context.runOnJSQueueThread { + try { + val ptr = context.javaScriptContextHolder?.get() ?: 0L + if (ptr != 0L) { + bgRuntimePtr = ptr + nativeInstallBgBindings(ptr) + nativeInstallSharedBridge(ptr, false) + nativeSetupErrorHandler(ptr) + BTLogger.info("JSI bindings, SharedBridge, and error handler installed in background runtime") + } else { + BTLogger.error("Background runtime pointer is 0") + } + } catch (e: Exception) { + BTLogger.error("Error installing bindings in background runtime: ${e.message}") + } + } + } + }) + + host.start() + } + + // ── Messaging ─────────────────────────────────────────────────────────── + + fun postBackgroundMessage(message: String) { + val ptr = bgRuntimePtr + if (ptr == 0L) { + BTLogger.warn("Cannot post message: background runtime not ready") + return + } + + bgReactHost?.currentReactContext?.runOnJSQueueThread { + try { + if (bgRuntimePtr != 0L) { + nativePostToBackground(bgRuntimePtr, message) + } + } catch (e: Exception) { + BTLogger.error("Error posting message to background: ${e.message}") + } + } + } + + fun setOnMessageCallback(callback: (String) -> Unit) { + onMessageCallback = callback + } + + fun checkMessageCallback(): Boolean = onMessageCallback != null + + /** + * Called from C++ (via JNI) when background JS calls postHostMessage(message). + * Routes the message to the registered callback (which emits to the main JS runtime). + */ + @DoNotStrip + fun onBgMessage(message: String) { + onMessageCallback?.invoke(message) + } + + // ── Lifecycle ─────────────────────────────────────────────────────────── + + val isBackgroundStarted: Boolean get() = isStarted + + fun destroy() { + nativeDestroy() + bgRuntimePtr = 0 + bgReactHost?.destroy("BackgroundThreadManager destroyed", null) + bgReactHost = null + isStarted = false + onMessageCallback = null + } +} diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt index db8f4f19..e02d3564 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt @@ -1,171 +1,60 @@ package com.backgroundthread -import android.util.Log -import com.facebook.proguard.annotations.DoNotStrip -import com.facebook.react.ReactApplication -import com.facebook.react.ReactInstanceEventListener -import com.facebook.react.ReactPackage -import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.UiThreadUtil -import com.facebook.react.common.annotations.UnstableReactNativeAPI -import com.facebook.react.defaults.DefaultComponentsRegistry -import com.facebook.react.defaults.DefaultReactHostDelegate -import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate -import com.facebook.react.fabric.ComponentFactory import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.runtime.ReactHostImpl -import com.facebook.react.runtime.hermes.HermesInstance +/** + * TurboModule entry point for BackgroundThread. + * Delegates all heavy lifting to [BackgroundThreadManager] singleton. + * + * Mirrors iOS BackgroundThread.mm. + */ @ReactModule(name = BackgroundThreadModule.NAME) class BackgroundThreadModule(reactContext: ReactApplicationContext) : - NativeBackgroundThreadSpec(reactContext) { + NativeBackgroundThreadSpec(reactContext) { - private var bgReactHost: ReactHostImpl? = null - @Volatile - private var bgRuntimePtr: Long = 0 - private var isStarted = false - - companion object { - const val NAME = "BackgroundThread" - private const val TAG = "BackgroundThread" - - init { - System.loadLibrary("background_thread") + companion object { + const val NAME = "BackgroundThread" } - } - // JNI declarations - private external fun nativeInstallBgBindings(runtimePtr: Long) - private external fun nativePostToBackground(runtimePtr: Long, message: String) - private external fun nativeInstallSharedBridge(runtimePtr: Long, isMain: Boolean) + override fun getName(): String = NAME - override fun getName(): String = NAME - - /** - * Called from C++ (via JNI) when background JS calls postHostMessage(message). - * Emits the message to the main JS runtime via TurboModule event emitter. - */ - @DoNotStrip - fun onBgMessage(message: String) { - UiThreadUtil.runOnUiThread { - try { - emitOnBackgroundMessage(message) - } catch (e: Exception) { - Log.e(TAG, "Error emitting background message", e) - } + /** + * Force register event callback during initialization. + * This is mainly to handle the scenario of restarting in development environment. + */ + override fun initBackgroundThread() { + bindMessageCallback() + BackgroundThreadManager.getInstance().installSharedBridgeInMainRuntime(reactApplicationContext) } - } - override fun initBackgroundThread() { - // Install SharedBridge in the main runtime - val context = reactApplicationContext - context.runOnJSQueueThread { - try { - val ptr = context.javaScriptContextHolder?.get() ?: 0L - if (ptr != 0L) { - nativeInstallSharedBridge(ptr, true) - Log.i(TAG, "SharedBridge installed in main runtime") - } else { - Log.w(TAG, "Main runtime pointer is 0, cannot install SharedBridge") + override fun startBackgroundRunnerWithEntryURL(entryURL: String) { + val manager = BackgroundThreadManager.getInstance() + if (!manager.checkMessageCallback()) { + bindMessageCallback() } - } catch (e: Exception) { - Log.e(TAG, "Error installing SharedBridge in main runtime", e) - } + manager.startBackgroundRunnerWithEntryURL(reactApplicationContext, entryURL) } - } - @OptIn(UnstableReactNativeAPI::class) - override fun startBackgroundRunnerWithEntryURL(entryURL: String) { - if (isStarted) { - Log.w(TAG, "Background runner already started") - return - } - isStarted = true - Log.i(TAG, "Starting background runner with entryURL: $entryURL") - - val appContext = reactApplicationContext.applicationContext - - val bundleLoader = if (entryURL.startsWith("http")) { - // For dev server: load bundle directly from URL - object : JSBundleLoader() { - override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { - delegate.loadScriptFromFile(entryURL, entryURL, false) - return entryURL + override fun postBackgroundMessage(message: String) { + val manager = BackgroundThreadManager.getInstance() + if (!manager.checkMessageCallback()) { + bindMessageCallback() } - } - } else { - JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) + manager.postBackgroundMessage(message) } - val delegate = DefaultReactHostDelegate( - jsMainModulePath = "background", - jsBundleLoader = bundleLoader, - reactPackages = emptyList(), - jsRuntimeFactory = HermesInstance(), - turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder(), - ) - - val componentFactory = ComponentFactory() - DefaultComponentsRegistry.register(componentFactory) - - val host = ReactHostImpl( - appContext, - delegate, - componentFactory, - true, /* allowPackagerServerAccess */ - false, /* useDevSupport */ - ) - bgReactHost = host - - host.addReactInstanceEventListener(object : ReactInstanceEventListener { - override fun onReactContextInitialized(context: ReactContext) { - Log.i(TAG, "Background ReactContext initialized") - context.runOnJSQueueThread { - try { - val ptr = context.javaScriptContextHolder?.get() ?: 0L - if (ptr != 0L) { - bgRuntimePtr = ptr - nativeInstallBgBindings(ptr) - nativeInstallSharedBridge(ptr, false) - Log.i(TAG, "JSI bindings and SharedBridge installed in background runtime") - } else { - Log.e(TAG, "Background runtime pointer is 0") + private fun bindMessageCallback() { + BackgroundThreadManager.getInstance().setOnMessageCallback { message -> + UiThreadUtil.runOnUiThread { + try { + emitOnBackgroundMessage(message) + } catch (e: Exception) { + BTLogger.error("Error emitting background message: ${e.message}") + } } - } catch (e: Exception) { - Log.e(TAG, "Error installing bindings in background runtime", e) - } - } - } - }) - - host.start() - } - - override fun postBackgroundMessage(message: String) { - val ptr = bgRuntimePtr - if (ptr == 0L) { - Log.w(TAG, "Cannot post message: background runtime not ready") - return - } - - bgReactHost?.currentReactContext?.runOnJSQueueThread { - try { - if (bgRuntimePtr != 0L) { - nativePostToBackground(bgRuntimePtr, message) } - } catch (e: Exception) { - Log.e(TAG, "Error posting message to background", e) - } } - } - override fun invalidate() { - super.invalidate() - bgRuntimePtr = 0 - bgReactHost?.destroy("BackgroundThreadModule invalidated", null) - bgReactHost = null - isStarted = false - } } From ca50a26b278fe4aba5e7d8fcfb922df7b4e8789d Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 23 Mar 2026 00:57:05 +0800 Subject: [PATCH 04/74] feat(background-thread): replace SharedBridge with SharedStore + SharedRPC SharedStore: persistent key-value HostObject for cross-runtime config/state sharing. Supports bool/number/string. Both runtimes read/write freely. SharedRPC: temporary slot HostObject for RPC data passing. Write puts data in a slot keyed by callId; read retrieves and deletes it. Notification handled by existing postHostMessage/postBackgroundMessage channels. Both use C++ static memory with mutex protection, zero serialization for primitive types. --- example/react-native/background.js | 42 ++-- .../pages/BackgroundThreadTestPage.tsx | 134 +++++++------ .../android/CMakeLists.txt | 3 +- .../android/src/main/cpp/cpp-adapter.cpp | 10 +- .../cpp/SharedBridge.cpp | 104 ---------- .../cpp/SharedBridge.h | 37 ---- .../cpp/SharedRPC.cpp | 126 ++++++++++++ .../cpp/SharedRPC.h | 28 +++ .../cpp/SharedStore.cpp | 184 ++++++++++++++++++ .../cpp/SharedStore.h | 28 +++ .../BackgroundRunnerReactNativeDelegate.mm | 10 +- .../ios/BackgroundThreadManager.mm | 8 +- .../src/SharedBridge.ts | 34 ---- .../src/SharedRPC.ts | 15 ++ .../src/SharedStore.ts | 18 ++ .../src/index.tsx | 6 +- 16 files changed, 521 insertions(+), 266 deletions(-) delete mode 100644 native-modules/react-native-background-thread/cpp/SharedBridge.cpp delete mode 100644 native-modules/react-native-background-thread/cpp/SharedBridge.h create mode 100644 native-modules/react-native-background-thread/cpp/SharedRPC.cpp create mode 100644 native-modules/react-native-background-thread/cpp/SharedRPC.h create mode 100644 native-modules/react-native-background-thread/cpp/SharedStore.cpp create mode 100644 native-modules/react-native-background-thread/cpp/SharedStore.h delete mode 100644 native-modules/react-native-background-thread/src/SharedBridge.ts create mode 100644 native-modules/react-native-background-thread/src/SharedRPC.ts create mode 100644 native-modules/react-native-background-thread/src/SharedStore.ts diff --git a/example/react-native/background.js b/example/react-native/background.js index df5121fd..0c9be38d 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -71,27 +71,27 @@ nativeBGBridge.onHostMessage((message) => { } }); -// SharedBridge pull-model: drain messages from the main runtime -function drainSharedBridge() { - if (globalThis.sharedBridge) { - if (globalThis.sharedBridge.hasMessages) { - const messages = globalThis.sharedBridge.drain(); - messages.forEach((raw) => { - try { - const msg = JSON.parse(raw); - console.log('[SharedBridge BG] received:', msg); - if (msg.type === 'ping') { - // Echo back with pong via SharedBridge - globalThis.sharedBridge.send( - JSON.stringify({ type: 'pong', ts: Date.now() }), - ); - } - } catch (e) { - console.warn('[SharedBridge BG] parse error:', e); - } - }); +// SharedStore: read config values set by main runtime +function checkSharedStore() { + if (globalThis.sharedStore) { + const locale = globalThis.sharedStore.get('locale'); + if (locale) { + console.log('[SharedStore BG] locale =', locale); } } - setTimeout(drainSharedBridge, 16); // ~60fps check cadence + setTimeout(checkSharedStore, 1000); } -drainSharedBridge(); +checkSharedStore(); + +// SharedRPC: handle RPC calls from main runtime via onHostMessage +nativeBGBridge.onHostMessage((message) => { + if (message.type === 'rpc' && message.callId) { + const params = globalThis.sharedRPC?.read(message.callId); + if (params !== undefined) { + console.log('[SharedRPC BG] received call:', message.callId, params); + // Echo back the params as the result + globalThis.sharedRPC?.write(message.callId, 'echo: ' + params); + nativeBGBridge.postHostMessage({ type: 'rpc_response', callId: message.callId }); + } + } +}); diff --git a/example/react-native/pages/BackgroundThreadTestPage.tsx b/example/react-native/pages/BackgroundThreadTestPage.tsx index 6635cdee..b14ab597 100644 --- a/example/react-native/pages/BackgroundThreadTestPage.tsx +++ b/example/react-native/pages/BackgroundThreadTestPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { TestPageBase, TestButton, TestResult } from './TestPageBase'; import { BackgroundThread } from '@onekeyfe/react-native-background-thread'; @@ -7,101 +7,123 @@ BackgroundThread.initBackgroundThread(); export function BackgroundThreadTestPage() { const [pushResult, setPushResult] = useState(''); - const [bridgeResult, setBridgeResult] = useState(''); - const [bridgeAvailable, setBridgeAvailable] = useState(false); - const drainTimer = useRef | null>(null); + const [storeResult, setStoreResult] = useState(''); + const [rpcResult, setRpcResult] = useState(''); + const [storeAvailable, setStoreAvailable] = useState(false); - // Check SharedBridge availability and start draining useEffect(() => { const check = setInterval(() => { - if (globalThis.sharedBridge) { - setBridgeAvailable(true); + if (globalThis.sharedStore && globalThis.sharedRPC) { + setStoreAvailable(true); clearInterval(check); } }, 100); + return () => clearInterval(check); + }, []); - // Drain loop: pull messages from background via SharedBridge - drainTimer.current = setInterval(() => { - if (globalThis.sharedBridge?.hasMessages) { - const messages = globalThis.sharedBridge.drain(); - messages.forEach((raw) => { - try { - const msg = JSON.parse(raw); - setBridgeResult( - (prev) => - `${prev}\n[${new Date().toLocaleTimeString()}] Received: ${JSON.stringify(msg)}`, - ); - } catch { - setBridgeResult((prev) => `${prev}\nParse error: ${raw}`); - } - }); + // Listen for RPC responses from background + useEffect(() => { + const sub = BackgroundThread.onBackgroundMessage((msg) => { + try { + const parsed = JSON.parse(msg); + if (parsed.type === 'rpc_response' && parsed.callId) { + const result = globalThis.sharedRPC?.read(parsed.callId); + setRpcResult( + (prev) => + `${prev}\n[${new Date().toLocaleTimeString()}] Response: ${result}`, + ); + } else { + setPushResult(`Received: ${msg}`); + } + } catch { + setPushResult(`Received: ${msg}`); } - }, 16); - - return () => { - clearInterval(check); - if (drainTimer.current) clearInterval(drainTimer.current); - }; + }); + return sub; }, []); - // Push model: existing postBackgroundMessage / onBackgroundMessage + // Push model const handlePushMessage = () => { const message = { type: 'test1' }; - BackgroundThread.onBackgroundMessage((event) => { - setPushResult(`Received from background: ${event}`); - }); BackgroundThread.postBackgroundMessage(JSON.stringify(message)); setPushResult(`Sent: ${JSON.stringify(message)}`); }; - // Pull model: SharedBridge send + drain - const handleSharedBridgePing = () => { - if (!globalThis.sharedBridge) { - setBridgeResult('SharedBridge not available yet'); + // SharedStore test + const handleStoreTest = () => { + if (!globalThis.sharedStore) { + setStoreResult('SharedStore not available'); return; } - const msg = { type: 'ping', ts: Date.now() }; - globalThis.sharedBridge.send(JSON.stringify(msg)); - setBridgeResult( - (prev) => - `${prev}\n[${new Date().toLocaleTimeString()}] Sent: ${JSON.stringify(msg)}`, - ); + globalThis.sharedStore.set('locale', 'zh-CN'); + globalThis.sharedStore.set('networkId', 42); + globalThis.sharedStore.set('devMode', true); + const keys = globalThis.sharedStore.keys(); + const values = keys + .map((k) => `${k}=${globalThis.sharedStore?.get(k)}`) + .join(', '); + setStoreResult(`Set 3 values. Current: ${values} | size=${globalThis.sharedStore.size}`); }; - const handleClearBridgeLog = () => { - setBridgeResult(''); + // SharedRPC test + const handleRpcTest = () => { + if (!globalThis.sharedRPC) { + setRpcResult('SharedRPC not available'); + return; + } + const callId = `rpc_${Date.now()}`; + globalThis.sharedRPC.write( + callId, + JSON.stringify({ method: 'echo', params: { ts: Date.now() } }), + ); + BackgroundThread.postBackgroundMessage( + JSON.stringify({ type: 'rpc', callId }), + ); + setRpcResult( + (prev) => + `${prev}\n[${new Date().toLocaleTimeString()}] Sent RPC: ${callId}`, + ); }; return ( - {/* Push Model (existing) */} + {/* Push Model */} Push Model (postBackgroundMessage) - {/* Pull Model (SharedBridge) */} + {/* SharedStore */} - Pull Model (SharedBridge HostObject) + SharedStore (persistent key-value) - SharedBridge: {bridgeAvailable ? 'Available' : 'Waiting...'} - {bridgeAvailable && - ` | isMain: ${globalThis.sharedBridge?.isMain}`} + Available: {storeAvailable ? 'Yes' : 'Waiting...'} + + + + {/* SharedRPC */} + + SharedRPC (temporary read-and-delete) + setRpcResult('')} style={styles.clearButton} /> - {bridgeResult ? ( + {rpcResult ? ( - {bridgeResult.trim()} + {rpcResult.trim()} ) : null} diff --git a/native-modules/react-native-background-thread/android/CMakeLists.txt b/native-modules/react-native-background-thread/android/CMakeLists.txt index 1cd284b8..fe5212ea 100644 --- a/native-modules/react-native-background-thread/android/CMakeLists.txt +++ b/native-modules/react-native-background-thread/android/CMakeLists.txt @@ -9,7 +9,8 @@ find_package(ReactAndroid REQUIRED CONFIG) add_library(${PROJECT_NAME} SHARED src/main/cpp/cpp-adapter.cpp - ../cpp/SharedBridge.cpp + ../cpp/SharedStore.cpp + ../cpp/SharedRPC.cpp ) target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index f435f4c2..5c966ed6 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -5,7 +5,8 @@ #include #include -#include "SharedBridge.h" +#include "SharedStore.h" +#include "SharedRPC.h" #define LOG_TAG "BackgroundThread" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) @@ -154,7 +155,7 @@ Java_com_backgroundthread_BackgroundThreadManager_nativePostToBackground( } // ── nativeInstallSharedBridge ─────────────────────────────────────────── -// Install SharedBridge HostObject into a runtime. +// Install SharedStore and SharedRPC into a runtime. extern "C" JNIEXPORT void JNICALL Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( JNIEnv *env, jobject thiz, jlong runtimePtr, jboolean isMain) { @@ -162,8 +163,9 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( auto *rt = reinterpret_cast(runtimePtr); if (!rt) return; - SharedBridge::install(*rt, static_cast(isMain)); - LOGI("SharedBridge installed (isMain=%d)", static_cast(isMain)); + SharedStore::install(*rt); + SharedRPC::install(*rt); + LOGI("SharedStore and SharedRPC installed (isMain=%d)", static_cast(isMain)); } // ── nativeSetupErrorHandler ───────────────────────────────────────────── diff --git a/native-modules/react-native-background-thread/cpp/SharedBridge.cpp b/native-modules/react-native-background-thread/cpp/SharedBridge.cpp deleted file mode 100644 index a3ffcba6..00000000 --- a/native-modules/react-native-background-thread/cpp/SharedBridge.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "SharedBridge.h" - -// Static member definitions -std::mutex SharedBridge::mutex_; -std::queue SharedBridge::mainQueue_; -std::queue SharedBridge::bgQueue_; -std::atomic SharedBridge::hasMainMsg_{false}; -std::atomic SharedBridge::hasBgMsg_{false}; - -void SharedBridge::install(jsi::Runtime &rt, bool isMain) { - auto bridge = std::make_shared(isMain); - auto obj = jsi::Object::createFromHostObject(rt, bridge); - rt.global().setProperty(rt, "sharedBridge", std::move(obj)); -} - -void SharedBridge::reset() { - std::lock_guard lock(mutex_); - std::queue().swap(mainQueue_); - std::queue().swap(bgQueue_); - hasMainMsg_.store(false); - hasBgMsg_.store(false); -} - -jsi::Value SharedBridge::get(jsi::Runtime &rt, const jsi::PropNameID &name) { - auto prop = name.utf8(rt); - - // send(message: string): void - // Pushes a string message into the OTHER runtime's queue. - if (prop == "send") { - return jsi::Function::createFromHostFunction( - rt, name, 1, - [this](jsi::Runtime &rt, const jsi::Value &, - const jsi::Value *args, size_t count) -> jsi::Value { - if (count < 1 || !args[0].isString()) { - throw jsi::JSError(rt, - "SharedBridge.send expects a string argument"); - } - auto msg = args[0].getString(rt).utf8(rt); - { - std::lock_guard lock(mutex_); - if (isMain_) { - bgQueue_.push(std::move(msg)); - hasBgMsg_.store(true); - } else { - mainQueue_.push(std::move(msg)); - hasMainMsg_.store(true); - } - } - return jsi::Value::undefined(); - }); - } - - // drain(): string[] - // Pulls all pending messages from this runtime's queue. - if (prop == "drain") { - return jsi::Function::createFromHostFunction( - rt, name, 0, - [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, - size_t) -> jsi::Value { - std::vector msgs; - { - std::lock_guard lock(mutex_); - auto &q = isMain_ ? mainQueue_ : bgQueue_; - auto &flag = isMain_ ? hasMainMsg_ : hasBgMsg_; - while (!q.empty()) { - msgs.push_back(std::move(q.front())); - q.pop(); - } - flag.store(false); - } - auto arr = jsi::Array(rt, msgs.size()); - for (size_t i = 0; i < msgs.size(); i++) { - arr.setValueAtIndex( - rt, i, jsi::String::createFromUtf8(rt, msgs[i])); - } - return arr; - }); - } - - // hasMessages: boolean (getter) - // Returns true if there are pending messages for this runtime. - // Uses atomic load — essentially zero overhead. - if (prop == "hasMessages") { - bool has = isMain_ ? hasMainMsg_.load(std::memory_order_relaxed) - : hasBgMsg_.load(std::memory_order_relaxed); - return jsi::Value(has); - } - - // isMain: boolean (getter) - if (prop == "isMain") { - return jsi::Value(isMain_); - } - - return jsi::Value::undefined(); -} - -std::vector SharedBridge::getPropertyNames(jsi::Runtime &rt) { - std::vector props; - props.push_back(jsi::PropNameID::forUtf8(rt, "send")); - props.push_back(jsi::PropNameID::forUtf8(rt, "drain")); - props.push_back(jsi::PropNameID::forUtf8(rt, "hasMessages")); - props.push_back(jsi::PropNameID::forUtf8(rt, "isMain")); - return props; -} diff --git a/native-modules/react-native-background-thread/cpp/SharedBridge.h b/native-modules/react-native-background-thread/cpp/SharedBridge.h deleted file mode 100644 index 311b6c84..00000000 --- a/native-modules/react-native-background-thread/cpp/SharedBridge.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace jsi = facebook::jsi; - -class SharedBridge : public jsi::HostObject { -public: - jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override; - std::vector getPropertyNames(jsi::Runtime &rt) override; - - /// Install a SharedBridge instance into the given runtime. - /// @param rt The JSI runtime to install into. - /// @param isMain true for the main (UI) runtime, false for background. - static void install(jsi::Runtime &rt, bool isMain); - - /// Reset all queues and flags. Call when tearing down. - static void reset(); - - explicit SharedBridge(bool isMain) : isMain_(isMain) {} - -private: - - bool isMain_; - - // Shared state across both runtimes (static, process-wide) - static std::mutex mutex_; - static std::queue mainQueue_; // messages destined for main - static std::queue bgQueue_; // messages destined for background - static std::atomic hasMainMsg_; - static std::atomic hasBgMsg_; -}; diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp new file mode 100644 index 00000000..bdcb3047 --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -0,0 +1,126 @@ +#include "SharedRPC.h" + +// Static member definitions +std::mutex SharedRPC::mutex_; +std::unordered_map SharedRPC::slots_; + +void SharedRPC::install(jsi::Runtime &rt) { + auto rpc = std::make_shared(); + auto obj = jsi::Object::createFromHostObject(rt, rpc); + rt.global().setProperty(rt, "sharedRPC", std::move(obj)); +} + +void SharedRPC::reset() { + std::lock_guard lock(mutex_); + slots_.clear(); +} + +RPCValue SharedRPC::extractValue(jsi::Runtime &rt, const jsi::Value &val) { + if (val.isBool()) { + return val.getBool(); + } + if (val.isNumber()) { + return val.getNumber(); + } + if (val.isString()) { + return val.getString(rt).utf8(rt); + } + throw jsi::JSError(rt, + "SharedRPC: unsupported value type. " + "Only bool, number, and string are supported."); +} + +jsi::Value SharedRPC::toJSI(jsi::Runtime &rt, const RPCValue &val) { + if (std::holds_alternative(val)) { + return jsi::Value(std::get(val)); + } + if (std::holds_alternative(val)) { + return jsi::Value(std::get(val)); + } + // std::string + return jsi::String::createFromUtf8(rt, std::get(val)); +} + +jsi::Value SharedRPC::get(jsi::Runtime &rt, const jsi::PropNameID &name) { + auto prop = name.utf8(rt); + + // write(callId: string, value: bool | number | string): void + if (prop == "write") { + return jsi::Function::createFromHostFunction( + rt, name, 2, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 2 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedRPC.write expects (callId: string, value)"); + } + auto callId = args[0].getString(rt).utf8(rt); + auto value = extractValue(rt, args[1]); + { + std::lock_guard lock(mutex_); + slots_.insert_or_assign(std::move(callId), std::move(value)); + } + return jsi::Value::undefined(); + }); + } + + // read(callId: string): bool | number | string | undefined + // Deletes the entry after reading (read-and-delete semantics). + if (prop == "read") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedRPC.read expects (callId: string)"); + } + auto callId = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + auto it = slots_.find(callId); + if (it == slots_.end()) { + return jsi::Value::undefined(); + } + auto value = std::move(it->second); + slots_.erase(it); + return toJSI(rt, value); + } + }); + } + + // has(callId: string): boolean + if (prop == "has") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedRPC.has expects (callId: string)"); + } + auto callId = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + return jsi::Value(slots_.count(callId) > 0); + } + }); + } + + // pendingCount: number (getter, not a function) + if (prop == "pendingCount") { + std::lock_guard lock(mutex_); + return jsi::Value(static_cast(slots_.size())); + } + + return jsi::Value::undefined(); +} + +std::vector SharedRPC::getPropertyNames(jsi::Runtime &rt) { + std::vector props; + props.push_back(jsi::PropNameID::forUtf8(rt, "write")); + props.push_back(jsi::PropNameID::forUtf8(rt, "read")); + props.push_back(jsi::PropNameID::forUtf8(rt, "has")); + props.push_back(jsi::PropNameID::forUtf8(rt, "pendingCount")); + return props; +} diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.h b/native-modules/react-native-background-thread/cpp/SharedRPC.h new file mode 100644 index 00000000..adec32ab --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace jsi = facebook::jsi; + +using RPCValue = std::variant; + +class SharedRPC : public jsi::HostObject { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override; + std::vector getPropertyNames(jsi::Runtime &rt) override; + + static void install(jsi::Runtime &rt); + static void reset(); + +private: + static RPCValue extractValue(jsi::Runtime &rt, const jsi::Value &val); + static jsi::Value toJSI(jsi::Runtime &rt, const RPCValue &val); + + static std::mutex mutex_; + static std::unordered_map slots_; +}; diff --git a/native-modules/react-native-background-thread/cpp/SharedStore.cpp b/native-modules/react-native-background-thread/cpp/SharedStore.cpp new file mode 100644 index 00000000..4c1be8ad --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedStore.cpp @@ -0,0 +1,184 @@ +#include "SharedStore.h" + +// Static member definitions +std::mutex SharedStore::mutex_; +std::unordered_map SharedStore::data_; + +void SharedStore::install(jsi::Runtime &rt) { + auto store = std::make_shared(); + auto obj = jsi::Object::createFromHostObject(rt, store); + rt.global().setProperty(rt, "sharedStore", std::move(obj)); +} + +void SharedStore::reset() { + std::lock_guard lock(mutex_); + data_.clear(); +} + +StoreValue SharedStore::extractValue(jsi::Runtime &rt, + const jsi::Value &val) { + if (val.isBool()) { + return val.getBool(); + } + if (val.isNumber()) { + return val.getNumber(); + } + if (val.isString()) { + return val.getString(rt).utf8(rt); + } + throw jsi::JSError(rt, + "SharedStore: unsupported value type. " + "Only bool, number, and string are supported."); +} + +jsi::Value SharedStore::toJSI(jsi::Runtime &rt, const StoreValue &val) { + if (std::holds_alternative(val)) { + return jsi::Value(std::get(val)); + } + if (std::holds_alternative(val)) { + return jsi::Value(std::get(val)); + } + if (std::holds_alternative(val)) { + return jsi::String::createFromUtf8(rt, std::get(val)); + } + return jsi::Value::undefined(); +} + +jsi::Value SharedStore::get(jsi::Runtime &rt, const jsi::PropNameID &name) { + auto prop = name.utf8(rt); + + // set(key: string, value: bool | number | string): void + if (prop == "set") { + return jsi::Function::createFromHostFunction( + rt, name, 2, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 2 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedStore.set expects (string key, value)"); + } + auto key = args[0].getString(rt).utf8(rt); + auto val = extractValue(rt, args[1]); + { + std::lock_guard lock(mutex_); + data_[std::move(key)] = std::move(val); + } + return jsi::Value::undefined(); + }); + } + + // get(key: string): bool | number | string | undefined + if (prop == "get") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedStore.get expects a string key"); + } + auto key = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + auto it = data_.find(key); + if (it == data_.end()) { + return jsi::Value::undefined(); + } + return toJSI(rt, it->second); + } + }); + } + + // has(key: string): boolean + if (prop == "has") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedStore.has expects a string key"); + } + auto key = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + return jsi::Value(data_.count(key) > 0); + } + }); + } + + // delete(key: string): boolean + if (prop == "delete") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isString()) { + throw jsi::JSError( + rt, "SharedStore.delete expects a string key"); + } + auto key = args[0].getString(rt).utf8(rt); + { + std::lock_guard lock(mutex_); + return jsi::Value(data_.erase(key) > 0); + } + }); + } + + // keys(): string[] + if (prop == "keys") { + return jsi::Function::createFromHostFunction( + rt, name, 0, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, + size_t) -> jsi::Value { + std::vector allKeys; + { + std::lock_guard lock(mutex_); + allKeys.reserve(data_.size()); + for (const auto &pair : data_) { + allKeys.push_back(pair.first); + } + } + auto arr = jsi::Array(rt, allKeys.size()); + for (size_t i = 0; i < allKeys.size(); i++) { + arr.setValueAtIndex( + rt, i, jsi::String::createFromUtf8(rt, allKeys[i])); + } + return arr; + }); + } + + // clear(): void + if (prop == "clear") { + return jsi::Function::createFromHostFunction( + rt, name, 0, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, + size_t) -> jsi::Value { + { + std::lock_guard lock(mutex_); + data_.clear(); + } + return jsi::Value::undefined(); + }); + } + + // size: number (getter, not a function) + if (prop == "size") { + std::lock_guard lock(mutex_); + return jsi::Value(static_cast(data_.size())); + } + + return jsi::Value::undefined(); +} + +std::vector SharedStore::getPropertyNames(jsi::Runtime &rt) { + std::vector props; + props.push_back(jsi::PropNameID::forUtf8(rt, "set")); + props.push_back(jsi::PropNameID::forUtf8(rt, "get")); + props.push_back(jsi::PropNameID::forUtf8(rt, "has")); + props.push_back(jsi::PropNameID::forUtf8(rt, "delete")); + props.push_back(jsi::PropNameID::forUtf8(rt, "keys")); + props.push_back(jsi::PropNameID::forUtf8(rt, "clear")); + props.push_back(jsi::PropNameID::forUtf8(rt, "size")); + return props; +} diff --git a/native-modules/react-native-background-thread/cpp/SharedStore.h b/native-modules/react-native-background-thread/cpp/SharedStore.h new file mode 100644 index 00000000..b7e17123 --- /dev/null +++ b/native-modules/react-native-background-thread/cpp/SharedStore.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace jsi = facebook::jsi; + +using StoreValue = std::variant; + +class SharedStore : public jsi::HostObject { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override; + std::vector getPropertyNames(jsi::Runtime &rt) override; + + static void install(jsi::Runtime &rt); + static void reset(); + +private: + static StoreValue extractValue(jsi::Runtime &rt, const jsi::Value &val); + static jsi::Value toJSI(jsi::Runtime &rt, const StoreValue &val); + + static std::mutex mutex_; + static std::unordered_map data_; +}; diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index ff69194e..4540c9fe 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -8,7 +8,8 @@ #include #include -#include "SharedBridge.h" +#include "SharedStore.h" +#include "SharedRPC.h" #import #import @@ -201,9 +202,10 @@ - (void)hostDidStart:(RCTHost *)host facebook::react::defineReadOnlyGlobal(runtime, "onHostMessage", [self createSetOnMessageFunction:runtime]); [self setupErrorHandler:runtime]; - // Install SharedBridge HostObject into background runtime - SharedBridge::install(runtime, /* isMain */ false); - [BTLogger info:@"SharedBridge installed in background runtime"]; + // Install SharedStore and SharedRPC into background runtime + SharedStore::install(runtime); + SharedRPC::install(runtime); + [BTLogger info:@"SharedStore and SharedRPC installed in background runtime"]; }]; } diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index ba451a12..62c67182 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -15,7 +15,8 @@ #import "BackgroundRunnerReactNativeDelegate.h" #import "BTLogger.h" -#include "SharedBridge.h" +#include "SharedStore.h" +#include "SharedRPC.h" #import #import @@ -69,8 +70,9 @@ + (void)installSharedBridgeInMainRuntime:(RCTHost *)host { } [instance callFunctionOnBufferedRuntimeExecutor:^(facebook::jsi::Runtime &runtime) { - SharedBridge::install(runtime, /* isMain */ true); - [BTLogger info:@"SharedBridge installed in main runtime"]; + SharedStore::install(runtime); + SharedRPC::install(runtime); + [BTLogger info:@"SharedStore and SharedRPC installed in main runtime"]; }]; } diff --git a/native-modules/react-native-background-thread/src/SharedBridge.ts b/native-modules/react-native-background-thread/src/SharedBridge.ts deleted file mode 100644 index 39a1db79..00000000 --- a/native-modules/react-native-background-thread/src/SharedBridge.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * SharedBridge — a JSI HostObject installed in both the main and background - * runtimes, backed by the same C++ queues. Available as `globalThis.sharedBridge` - * once installed on the native side. - * - * Main runtime: send() pushes to background queue, drain() pulls from main queue. - * Background: send() pushes to main queue, drain() pulls from background queue. - */ -export interface ISharedBridge { - /** Push a string message into the OTHER runtime's queue. */ - send(message: string): void; - - /** Pull all pending messages from THIS runtime's queue. */ - drain(): string[]; - - /** True if there are pending messages for THIS runtime. Atomic read, ~0 cost. */ - readonly hasMessages: boolean; - - /** True if this instance is installed in the main (UI) runtime. */ - readonly isMain: boolean; -} - -declare global { - // eslint-disable-next-line no-var - var sharedBridge: ISharedBridge | undefined; -} - -/** - * Get the SharedBridge instance from globalThis. - * Returns undefined if native side hasn't installed it yet. - */ -export function getSharedBridge(): ISharedBridge | undefined { - return globalThis.sharedBridge; -} diff --git a/native-modules/react-native-background-thread/src/SharedRPC.ts b/native-modules/react-native-background-thread/src/SharedRPC.ts new file mode 100644 index 00000000..7acd1815 --- /dev/null +++ b/native-modules/react-native-background-thread/src/SharedRPC.ts @@ -0,0 +1,15 @@ +export interface ISharedRPC { + write(callId: string, value: string | number | boolean): void; + read(callId: string): string | number | boolean | undefined; + has(callId: string): boolean; + readonly pendingCount: number; +} + +declare global { + // eslint-disable-next-line no-var + var sharedRPC: ISharedRPC | undefined; +} + +export function getSharedRPC(): ISharedRPC | undefined { + return globalThis.sharedRPC; +} diff --git a/native-modules/react-native-background-thread/src/SharedStore.ts b/native-modules/react-native-background-thread/src/SharedStore.ts new file mode 100644 index 00000000..9263dc6d --- /dev/null +++ b/native-modules/react-native-background-thread/src/SharedStore.ts @@ -0,0 +1,18 @@ +export interface ISharedStore { + set(key: string, value: string | number | boolean): void; + get(key: string): string | number | boolean | undefined; + has(key: string): boolean; + delete(key: string): boolean; + keys(): string[]; + clear(): void; + readonly size: number; +} + +declare global { + // eslint-disable-next-line no-var + var sharedStore: ISharedStore | undefined; +} + +export function getSharedStore(): ISharedStore | undefined { + return globalThis.sharedStore; +} diff --git a/native-modules/react-native-background-thread/src/index.tsx b/native-modules/react-native-background-thread/src/index.tsx index f8226d88..889f2712 100644 --- a/native-modules/react-native-background-thread/src/index.tsx +++ b/native-modules/react-native-background-thread/src/index.tsx @@ -1,5 +1,7 @@ import NativeBackgroundThread from './NativeBackgroundThread'; export const BackgroundThread = NativeBackgroundThread; -export { getSharedBridge } from './SharedBridge'; -export type { ISharedBridge } from './SharedBridge'; +export { getSharedStore } from './SharedStore'; +export type { ISharedStore } from './SharedStore'; +export { getSharedRPC } from './SharedRPC'; +export type { ISharedRPC } from './SharedRPC'; From 2562371cb4300fcb7eedcca27fd160f5ee7999d8 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 17:02:10 +0800 Subject: [PATCH 05/74] collapse identical consecutive messages into [N repeat] --- .../margelo/nitro/nativelogger/OneKeyLog.kt | 25 +++++++++++++++++++ .../native-logger/ios/OneKeyLog.swift | 25 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt index cb683dfd..1ebcdc91 100644 --- a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt +++ b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt @@ -243,7 +243,32 @@ object OneKeyLog { } } + // ----------------------------------------------------------------------- + // Dedup: collapse identical consecutive messages into [N repeat] + // ----------------------------------------------------------------------- + private val dedupLock = Any() + @Volatile private var prevLogMessage: String? = null + private var repeatCount: Int = 0 + private fun log(tag: String, level: String, message: String, androidLogLevel: Int) { + // Dedup identical consecutive messages + synchronized(dedupLock) { + if (message == prevLogMessage) { + repeatCount += 1 + return + } + val pendingRepeat = repeatCount + prevLogMessage = message + repeatCount = 0 + + if (pendingRepeat > 0) { + val repeatMsg = "[$pendingRepeat repeat]" + val l = logger + if (l != null) l.info(repeatMsg) + else android.util.Log.i("OneKeyLog", repeatMsg) + } + } + val decision = evaluateRateLimit(level) decision.report?.let { emitRateLimitReport(it) } if (decision.drop) return diff --git a/native-modules/native-logger/ios/OneKeyLog.swift b/native-modules/native-logger/ios/OneKeyLog.swift index c427c122..db5f75f2 100644 --- a/native-modules/native-logger/ios/OneKeyLog.swift +++ b/native-modules/native-logger/ios/OneKeyLog.swift @@ -232,6 +232,13 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { return (true, report) } + // ----------------------------------------------------------------------- + // Dedup: collapse identical consecutive messages into [N repeat] + // ----------------------------------------------------------------------- + private static let dedupLock = NSLock() + private static var prevLogMessage: String? + private static var repeatCount: Int = 0 + private static func log( _ level: String, _ tag: String, @@ -239,6 +246,24 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { writer: (String) -> Void ) { _ = configured + + // Dedup identical consecutive messages + dedupLock.lock() + let isDuplicate = (message == prevLogMessage) + if isDuplicate { + repeatCount += 1 + dedupLock.unlock() + return + } + let pendingRepeat = repeatCount + prevLogMessage = message + repeatCount = 0 + dedupLock.unlock() + + if pendingRepeat > 0 { + DDLogInfo("[\(pendingRepeat) repeat]") + } + let decision = evaluateRateLimit(for: level) if let report = decision.report { DDLogWarn(report) From 16ee6a4acebff4b40a514aeaca2350eb1339cc62 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 21:42:42 +0800 Subject: [PATCH 06/74] commit --- example/react-native/.ruby-version | 1 + example/react-native/ios/Podfile.lock | 72 +++++++++---------- .../nitro/nativelogger/NativeLogger.kt | 4 ++ .../margelo/nitro/nativelogger/OneKeyLog.kt | 20 ++++++ .../native-logger/ios/NativeLogger.swift | 4 ++ .../native-logger/ios/OneKeyLog.swift | 14 ++++ .../native-logger/src/NativeLogger.nitro.ts | 2 + 7 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 example/react-native/.ruby-version diff --git a/example/react-native/.ruby-version b/example/react-native/.ruby-version new file mode 100644 index 00000000..f9892605 --- /dev/null +++ b/example/react-native/.ruby-version @@ -0,0 +1 @@ +3.4.4 diff --git a/example/react-native/ios/Podfile.lock b/example/react-native/ios/Podfile.lock index d44bee95..958b6e4f 100644 --- a/example/react-native/ios/Podfile.lock +++ b/example/react-native/ios/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - AutoSizeInput (1.1.39): + - AutoSizeInput (1.1.46): - boost - DoubleConversion - fast_float @@ -29,7 +29,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - BackgroundThread (1.1.39): + - BackgroundThread (1.1.46): - boost - DoubleConversion - fast_float @@ -59,7 +59,7 @@ PODS: - SocketRocket - Yoga - boost (1.84.0) - - CloudKitModule (1.1.39): + - CloudKitModule (1.1.46): - boost - DoubleConversion - fast_float @@ -101,7 +101,7 @@ PODS: - hermes-engine (0.14.0): - hermes-engine/Pre-built (= 0.14.0) - hermes-engine/Pre-built (0.14.0) - - KeychainModule (1.1.39): + - KeychainModule (1.1.46): - boost - DoubleConversion - fast_float @@ -2079,7 +2079,7 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon/turbomodule/core - SocketRocket - - react-native-pager-view (1.1.39): + - react-native-pager-view (1.1.46): - boost - DoubleConversion - fast_float @@ -2194,7 +2194,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-tab-view (1.1.39): + - react-native-tab-view (1.1.46): - boost - DoubleConversion - fast_float @@ -2212,7 +2212,7 @@ PODS: - React-graphics - React-ImageManager - React-jsi - - react-native-tab-view/common (= 1.1.39) + - react-native-tab-view/common (= 1.1.46) - React-NativeModulesApple - React-RCTFabric - React-renderercss @@ -2223,7 +2223,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-tab-view/common (1.1.39): + - react-native-tab-view/common (1.1.46): - boost - DoubleConversion - fast_float @@ -2808,7 +2808,7 @@ PODS: - React-perflogger (= 0.83.0) - React-utils (= 0.83.0) - SocketRocket - - ReactNativeAppUpdate (1.1.39): + - ReactNativeAppUpdate (1.1.46): - boost - DoubleConversion - fast_float @@ -2839,7 +2839,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeBundleUpdate (1.1.40): + - ReactNativeBundleUpdate (1.1.46): - boost - DoubleConversion - fast_float @@ -2872,7 +2872,7 @@ PODS: - SocketRocket - SSZipArchive (~> 2.4) - Yoga - - ReactNativeCheckBiometricAuthChanged (1.1.39): + - ReactNativeCheckBiometricAuthChanged (1.1.46): - boost - DoubleConversion - fast_float @@ -2903,7 +2903,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeDeviceUtils (1.1.39): + - ReactNativeDeviceUtils (1.1.46): - boost - DoubleConversion - fast_float @@ -2934,7 +2934,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeGetRandomValues (1.1.39): + - ReactNativeGetRandomValues (1.1.46): - boost - DoubleConversion - fast_float @@ -2965,7 +2965,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeLiteCard (1.1.39): + - ReactNativeLiteCard (1.1.46): - boost - DoubleConversion - fast_float @@ -2994,7 +2994,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeNativeLogger (1.1.39): + - ReactNativeNativeLogger (1.1.46): - boost - CocoaLumberjack/Swift (~> 3.8) - DoubleConversion @@ -3025,7 +3025,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactNativePerfMemory (1.1.39): + - ReactNativePerfMemory (1.1.46): - boost - DoubleConversion - fast_float @@ -3056,7 +3056,7 @@ PODS: - ReactNativeNativeLogger - SocketRocket - Yoga - - ReactNativeSplashScreen (1.1.39): + - ReactNativeSplashScreen (1.1.46): - boost - DoubleConversion - fast_float @@ -3146,7 +3146,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ScrollGuard (1.1.39): + - ScrollGuard (1.1.46): - boost - DoubleConversion - fast_float @@ -3176,7 +3176,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - Skeleton (1.1.39): + - Skeleton (1.1.46): - boost - DoubleConversion - fast_float @@ -3520,10 +3520,10 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - AutoSizeInput: 4343dd8fea8c7e6347609231bb9c3f51a6867578 - BackgroundThread: 94e84403202f17cf3406f41d3737702778d3ee2b + AutoSizeInput: 547544cf73223cb8f1cfbf6619a07f6d1ee0f112 + BackgroundThread: 6771dc9c42c2b7756d88ae60f01b47057ae22f9e boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 - CloudKitModule: cafc8d819f8b737607281b16000217ebd6a15e02 + CloudKitModule: a57e684d58722f6b56beb86ac6c3dfb7a33f7769 CocoaLumberjack: 5644158777912b7de7469fa881f8a3f259c2512a DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 @@ -3531,7 +3531,7 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 70fdc9d0bb0d8532e0411dcb21e53ce5a160960a - KeychainModule: 9a80b4db184c587526b2082290edaaec2a23aadc + KeychainModule: deb625fa54cfe814f04479c69182c7cae2bcd01e MMKV: 1a8e7dbce7f9cad02c52e1b1091d07bd843aefaf MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df NitroMmkv: 0be91455465952f2b943f753b9ee7df028d89e5c @@ -3572,9 +3572,9 @@ SPEC CHECKSUMS: React-logger: 9e597cbeda7b8cc8aa8fb93860dade97190f69cc React-Mapbuffer: 20046c0447efaa7aace0b76085aa9bb35b0e8105 React-microtasksnativemodule: 0e837de56519c92d8a2e3097717df9497feb33cb - react-native-pager-view: 1cefe13a1ef7546f75644533226a384d20d9af9a + react-native-pager-view: 3ccf8c93ac34dffeee20e6fc73d85114e516ec64 react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460 - react-native-tab-view: 7f93995dd29f90b5c00fafa39150ed1c66b62c80 + react-native-tab-view: 1089831dd400a821342206c1419c5c7660a66d49 React-NativeModulesApple: 1a378198515f8e825c5931a7613e98da69320cee React-networking: bfd1695ada5a57023006ce05823ac5391c3ce072 React-oscompat: aedc0afbded67280de6bb6bfac8cfde0389e2b33 @@ -3608,18 +3608,18 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: ebcf3a78dc1bcdf054c9e8d309244bade6b31568 ReactCodegen: 554b421c45b7df35ac791da1b734335470b55fcc ReactCommon: 424cc34cf5055d69a3dcf02f3436481afb8b0f6f - ReactNativeAppUpdate: 07053378aecfdaaa23877f75c9c067fef7d58415 - ReactNativeBundleUpdate: 6b4bccc4975bd20ad6b2dfbca1f21da62d2b2e8d - ReactNativeCheckBiometricAuthChanged: 3fbd6bdc758ccc059ad2feaf3214b871c0ccf31e - ReactNativeDeviceUtils: cb1fa6e62e1ab4743fd9654f0124b23637ba62c5 - ReactNativeGetRandomValues: 7b24b5b17f6a676724bb673d76a8f9b0871aa4c7 - ReactNativeLiteCard: d657d524a48c8b810e9cc330956e0db8a3ec9700 - ReactNativeNativeLogger: 80760c0c6c0f7bc53641bd893bd0595ab0ad80ab - ReactNativePerfMemory: dffc94a953191cd81884314fecd10d115b00d64b - ReactNativeSplashScreen: c32fd6f34a4cb07529db03077f924b17aa32f38b + ReactNativeAppUpdate: d5ebd5255da5c6ca99f8cde73f1e61eb6636a9f9 + ReactNativeBundleUpdate: acb8b76a23c8dffbba7acebdb2e158d20f6ee0b0 + ReactNativeCheckBiometricAuthChanged: f9065a3a6983718f4630c1fa941c77fa6e9dc708 + ReactNativeDeviceUtils: 86cb5cd345c20b56b29226283948e13b4bc631f2 + ReactNativeGetRandomValues: 3c78fac4885e336474b87f6fbb48d85334d4eaef + ReactNativeLiteCard: 8f685421ed72c443a81806fde12002b5b54cd582 + ReactNativeNativeLogger: e4213b3507a2a0f5396b6f6063753b9a47dbe74a + ReactNativePerfMemory: 0fcee15f24a08bc56203dfd69a9f13a9e2436181 + ReactNativeSplashScreen: 9011ced09b04bc4af352f537b40bdef0e24276cd RNScreens: 7f643ee0fd1407dc5085c7795460bd93da113b8f - ScrollGuard: b4f927100c24c1d62f57de8fdbc949196eda3004 - Skeleton: 4afe54a514df5a0d0095d76e9e1f70945912280e + ScrollGuard: f87daaca0082b1b2c4967fc45b5d219cf7ec099f + Skeleton: 68d061f8700e3f54372d7428c55b0cfa11445da7 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef Yoga: 6ca93c8c13f56baeec55eb608577619b17a4d64e diff --git a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/NativeLogger.kt b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/NativeLogger.kt index 6e9bdc32..4b4ee716 100644 --- a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/NativeLogger.kt +++ b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/NativeLogger.kt @@ -36,6 +36,10 @@ class NativeLogger : HybridNativeLoggerSpec() { } } + override fun flushPendingRepeat() { + OneKeyLog.flushPendingRepeat() + } + override fun write(level: Double, msg: String) { val sanitized = sanitize(msg) when (level.toInt()) { diff --git a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt index 1ebcdc91..70211312 100644 --- a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt +++ b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt @@ -308,6 +308,26 @@ object OneKeyLog { } } + /** + * Flush any pending dedup repeat summary to the log file. + * Call before log export to ensure trailing repeated messages are included. + */ + @JvmStatic + fun flushPendingRepeat() { + synchronized(dedupLock) { + val pending = repeatCount + repeatCount = 0 + prevLogMessage = null + + if (pending > 0) { + val repeatMsg = "[$pending repeat]" + val l = logger + if (l != null) l.info(repeatMsg) + else android.util.Log.i("OneKeyLog", repeatMsg) + } + } + } + @JvmStatic fun debug(tag: String, message: String) { log(tag, "DEBUG", message, android.util.Log.DEBUG) } diff --git a/native-modules/native-logger/ios/NativeLogger.swift b/native-modules/native-logger/ios/NativeLogger.swift index f58606dc..0fab55dc 100644 --- a/native-modules/native-logger/ios/NativeLogger.swift +++ b/native-modules/native-logger/ios/NativeLogger.swift @@ -54,6 +54,10 @@ class NativeLogger: HybridNativeLoggerSpec { } } + func flushPendingRepeat() { + OneKeyLog.flushPendingRepeat() + } + func write(level: Double, msg: String) { let sanitized = NativeLogger.sanitize(msg) switch Int(level) { diff --git a/native-modules/native-logger/ios/OneKeyLog.swift b/native-modules/native-logger/ios/OneKeyLog.swift index db5f75f2..379ad6ff 100644 --- a/native-modules/native-logger/ios/OneKeyLog.swift +++ b/native-modules/native-logger/ios/OneKeyLog.swift @@ -319,6 +319,20 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { return truncate("\(time) | \(level) : [\(safeTag)] \(safeMessage)") } + /// Flush any pending dedup repeat summary to the log file. + /// Call before log export to ensure trailing repeated messages are included. + @objc public static func flushPendingRepeat() { + dedupLock.lock() + let pending = repeatCount + repeatCount = 0 + prevLogMessage = nil + dedupLock.unlock() + + if pending > 0 { + DDLogInfo("[\(pending) repeat]") + } + } + @objc public static func debug(_ tag: String, _ message: String) { log("DEBUG", tag, message) { DDLogDebug($0) } } diff --git a/native-modules/native-logger/src/NativeLogger.nitro.ts b/native-modules/native-logger/src/NativeLogger.nitro.ts index 7de21f2f..c849f8e7 100644 --- a/native-modules/native-logger/src/NativeLogger.nitro.ts +++ b/native-modules/native-logger/src/NativeLogger.nitro.ts @@ -3,6 +3,8 @@ import type { HybridObject } from 'react-native-nitro-modules'; export interface NativeLogger extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> { write(level: number, msg: string): void; + /** Flush any pending dedup repeat summary to the log file. Call before log export. */ + flushPendingRepeat(): void; getLogDirectory(): string; getLogFilePaths(): Promise; deleteLogFiles(): Promise; From ebed0cb386b147c54ae96e7b923231edc831888c Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 22:57:36 +0800 Subject: [PATCH 07/74] feat(background-thread): improve bridge messaging and apply react-native patch - Add JSON parse/stringify for cross-runtime message handling in background.js - Extract ReactNativeDelegate to separate ObjC++ files in iOS example - Fix RCTHost import path to ReactCommon and update podspec header config - Apply react-native 0.83.0 patch across all packages --- .../react-native-npm-0.83.0-577d0f2d83.patch | 34 +++++ example/react-native/Gemfile.lock | 141 ++++++++++++++++++ example/react-native/background.js | 22 ++- .../ios/Example-Bridging-header.h | 2 +- example/react-native/ios/Podfile | 1 + example/react-native/ios/Podfile.lock | 16 +- .../ios/example.xcodeproj/project.pbxproj | 6 + .../ios/example/AppDelegate.swift | 20 --- .../ios/example/ReactNativeDelegate.h | 14 ++ .../ios/example/ReactNativeDelegate.mm | 35 +++++ example/react-native/package.json | 2 +- native-modules/native-logger/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../BackgroundThread.podspec | 5 +- .../ios/BackgroundThreadManager.mm | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- package.json | 2 +- yarn.lock | 89 ++++++++--- 32 files changed, 349 insertions(+), 76 deletions(-) create mode 100644 .yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch create mode 100644 example/react-native/Gemfile.lock create mode 100644 example/react-native/ios/example/ReactNativeDelegate.h create mode 100644 example/react-native/ios/example/ReactNativeDelegate.mm diff --git a/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch b/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch new file mode 100644 index 00000000..bb42fc62 --- /dev/null +++ b/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch @@ -0,0 +1,34 @@ +diff --git a/third-party-podspecs/RCT-Folly.podspec b/third-party-podspecs/RCT-Folly.podspec +index 8852179b6ce2ef6ae64e0239edb2594925ff8bc1..040c4f0ca82e6a7342d5b3ed54e556431e5853d2 100644 +--- a/third-party-podspecs/RCT-Folly.podspec ++++ b/third-party-podspecs/RCT-Folly.podspec +@@ -25,7 +25,7 @@ Pod::Spec.new do |spec| + spec.dependency "DoubleConversion" + spec.dependency "glog" + spec.dependency "fast_float", "8.0.0" +- spec.dependency "fmt", "11.0.2" ++ spec.dependency "fmt", "12.1.0" + spec.compiler_flags = '-Wno-documentation -faligned-new' + spec.source_files = 'folly/String.cpp', + 'folly/Conv.cpp', +diff --git a/third-party-podspecs/fmt.podspec b/third-party-podspecs/fmt.podspec +index 2f38990e226c13f483aaf1b986302d4094243814..a40c5755e049974e98a4038c177661d2bdc5681f 100644 +--- a/third-party-podspecs/fmt.podspec ++++ b/third-party-podspecs/fmt.podspec +@@ -8,14 +8,14 @@ fmt_git_url = fmt_config[:git] + + Pod::Spec.new do |spec| + spec.name = "fmt" +- spec.version = "11.0.2" ++ spec.version = "12.1.0" + spec.license = { :type => "MIT" } + spec.homepage = "https://github.com/fmtlib/fmt" + spec.summary = "{fmt} is an open-source formatting library for C++. It can be used as a safe and fast alternative to (s)printf and iostreams." + spec.authors = "The fmt contributors" + spec.source = { + :git => fmt_git_url, +- :tag => "11.0.2" ++ :tag => "12.1.0" + } + spec.pod_target_xcconfig = { + "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), diff --git a/example/react-native/Gemfile.lock b/example/react-native/Gemfile.lock new file mode 100644 index 00000000..2446f56c --- /dev/null +++ b/example/react-native/Gemfile.lock @@ -0,0 +1,141 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + activesupport (7.2.3.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1, < 6) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.9) + public_suffix (>= 2.0.2, < 8.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.0) + claide (1.1.0) + cocoapods (1.15.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.15.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.3.3) + connection_pool (3.0.2) + drb (2.2.3) + escape (0.0.4) + ethon (0.18.0) + ffi (>= 1.15.0) + logger + ffi (1.17.4) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.9.0) + mutex_m + i18n (1.14.8) + concurrent-ruby (~> 1.0) + json (2.19.3) + logger (1.7.0) + minitest (5.27.0) + molinillo (0.8.0) + mutex_m (0.3.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + public_suffix (4.0.7) + rexml (3.4.4) + ruby-macho (2.5.1) + securerandom (0.4.1) + typhoeus (1.6.0) + ethon (>= 0.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + xcodeproj (1.25.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (>= 3.3.6, < 4.0) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + activesupport (>= 6.1.7.5, != 7.1.0) + benchmark + bigdecimal + cocoapods (>= 1.13, != 1.15.1, != 1.15.0) + concurrent-ruby (< 1.3.4) + logger + mutex_m + xcodeproj (< 1.26.0) + +RUBY VERSION + ruby 3.4.4p34 + +BUNDLED WITH + 2.6.9 diff --git a/example/react-native/background.js b/example/react-native/background.js index 0c9be38d..687e83f1 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -1,10 +1,19 @@ import ReactNative from 'react-native'; +let isReady = false; let waitMessages = []; const callbacks = new Set(); const onMessageCallback = (message) => { - callbacks.forEach((callback) => callback(message)); + let parsed = message; + if (typeof message === 'string') { + try { + parsed = JSON.parse(message); + } catch { + // keep as raw string + } + } + callbacks.forEach((callback) => callback(parsed)); }; function checkReady(times = 0) { @@ -36,7 +45,7 @@ const checkThread = () => { if (globalThis.$$isNativeUiThread) { // eslint-disable-next-line no-restricted-syntax throw new Error( - 'this function is not available in native background thread', + 'this function is not available in native UI thread', ); } }; @@ -44,11 +53,12 @@ const checkThread = () => { export const nativeBGBridge = { postHostMessage: (message) => { checkThread(); + const str = typeof message === 'string' ? message : JSON.stringify(message); if (!isReady) { - waitMessages.push(message); + waitMessages.push(str); return; } - globalThis.postHostMessage(JSON.stringify(message)); + globalThis.postHostMessage(str); }, onHostMessage: (callback) => { checkThread(); @@ -63,9 +73,9 @@ export const nativeBGBridge = { nativeBGBridge.onHostMessage((message) => { console.log('message', message); if (message.type === 'test1') { - alert(`${JSON.stringify(message)} in background, wait 3 seconds`); + console.log(`[BG] Received test1: ${JSON.stringify(message)}, will reply in 3s`); setTimeout(() => { - alert('post message from background thread'); + console.log('[BG] Sending test2 response'); nativeBGBridge.postHostMessage({ type: 'test2' }); }, 3000); } diff --git a/example/react-native/ios/Example-Bridging-header.h b/example/react-native/ios/Example-Bridging-header.h index d058d3a6..6f58c484 100644 --- a/example/react-native/ios/Example-Bridging-header.h +++ b/example/react-native/ios/Example-Bridging-header.h @@ -1,2 +1,2 @@ -#import "BackgroundRunnerModule.h" +#import "example/ReactNativeDelegate.h" #import "OneKeyLogBridge.h" diff --git a/example/react-native/ios/Podfile b/example/react-native/ios/Podfile index 5f8e4efb..864e70d7 100644 --- a/example/react-native/ios/Podfile +++ b/example/react-native/ios/Podfile @@ -32,5 +32,6 @@ target 'example' do :mac_catalyst_enabled => false, # :ccache_enabled => true ) + end end diff --git a/example/react-native/ios/Podfile.lock b/example/react-native/ios/Podfile.lock index 958b6e4f..6eb609b7 100644 --- a/example/react-native/ios/Podfile.lock +++ b/example/react-native/ios/Podfile.lock @@ -96,7 +96,7 @@ PODS: - DoubleConversion (1.1.6) - fast_float (8.0.0) - FBLazyVector (0.83.0) - - fmt (11.0.2) + - fmt (12.1.0) - glog (0.3.5) - hermes-engine (0.14.0): - hermes-engine/Pre-built (= 0.14.0) @@ -199,20 +199,20 @@ PODS: - boost - DoubleConversion - fast_float (= 8.0.0) - - fmt (= 11.0.2) + - fmt (= 12.1.0) - glog - RCT-Folly/Default (= 2024.11.18.00) - RCT-Folly/Default (2024.11.18.00): - boost - DoubleConversion - fast_float (= 8.0.0) - - fmt (= 11.0.2) + - fmt (= 12.1.0) - glog - RCT-Folly/Fabric (2024.11.18.00): - boost - DoubleConversion - fast_float (= 8.0.0) - - fmt (= 11.0.2) + - fmt (= 12.1.0) - glog - RCTDeprecation (0.83.0) - RCTRequired (0.83.0) @@ -3521,14 +3521,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AutoSizeInput: 547544cf73223cb8f1cfbf6619a07f6d1ee0f112 - BackgroundThread: 6771dc9c42c2b7756d88ae60f01b47057ae22f9e + BackgroundThread: 5f9ab77f204b961982fae9f2d025bcd645bd5216 boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 CloudKitModule: a57e684d58722f6b56beb86ac6c3dfb7a33f7769 CocoaLumberjack: 5644158777912b7de7469fa881f8a3f259c2512a DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBLazyVector: a293a88992c4c33f0aee184acab0b64a08ff9458 - fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd + fmt: 530618a01105dae0fa3a2f27c81ae11fa8f67eac glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 70fdc9d0bb0d8532e0411dcb21e53ce5a160960a KeychainModule: deb625fa54cfe814f04479c69182c7cae2bcd01e @@ -3536,7 +3536,7 @@ SPEC CHECKSUMS: MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df NitroMmkv: 0be91455465952f2b943f753b9ee7df028d89e5c NitroModules: 11bba9d065af151eae51e38a6425e04c3b223ff3 - RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + RCT-Folly: b29feb752b08042c62badaef7d453f3bb5e6ae23 RCTDeprecation: 2b70c6e3abe00396cefd8913efbf6a2db01a2b36 RCTRequired: f3540eee8094231581d40c5c6d41b0f170237a81 RCTSwiftUI: 5928f7ca7e9e2f1a82d85d4c79ea3065137ad81c @@ -3624,6 +3624,6 @@ SPEC CHECKSUMS: SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef Yoga: 6ca93c8c13f56baeec55eb608577619b17a4d64e -PODFILE CHECKSUM: 56b37b8a08f6427bcf7d82875a56b3f462979e26 +PODFILE CHECKSUM: dd92a8ce78a30e0a42b1ad8717f0b0bb35b2df5e COCOAPODS: 1.16.2 diff --git a/example/react-native/ios/example.xcodeproj/project.pbxproj b/example/react-native/ios/example.xcodeproj/project.pbxproj index 8f86577c..a832c520 100644 --- a/example/react-native/ios/example.xcodeproj/project.pbxproj +++ b/example/react-native/ios/example.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + C19BE8E0442D0CDAE91B484A /* ReactNativeDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77C46E7C500C7562D792C381 /* ReactNativeDelegate.mm */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -22,6 +23,7 @@ 074590972EF13928004098A9 /* BackgroundRunnerModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BackgroundRunnerModule.m; sourceTree = ""; }; 0773E5D62F53404600E76F7A /* OneKeyLogBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneKeyLogBridge.h; sourceTree = ""; }; 0773E5D72F53404600E76F7A /* OneKeyLogBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneKeyLogBridge.m; sourceTree = ""; }; + 0DA447673C267D48DAC8B035 /* ReactNativeDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ReactNativeDelegate.h; path = example/ReactNativeDelegate.h; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; @@ -30,6 +32,7 @@ 5709B34CF0A7D63546082F79 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = ""; }; 5DCACB8F33CDC322A6C60F78 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = ""; }; + 77C46E7C500C7562D792C381 /* ReactNativeDelegate.mm */ = {isa = PBXFileReference; includeInIndex = 1; name = ReactNativeDelegate.mm; path = example/ReactNativeDelegate.mm; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -59,6 +62,8 @@ 074590972EF13928004098A9 /* BackgroundRunnerModule.m */, 0773E5D62F53404600E76F7A /* OneKeyLogBridge.h */, 0773E5D72F53404600E76F7A /* OneKeyLogBridge.m */, + 0DA447673C267D48DAC8B035 /* ReactNativeDelegate.h */, + 77C46E7C500C7562D792C381 /* ReactNativeDelegate.mm */, ); name = example; sourceTree = ""; @@ -261,6 +266,7 @@ 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */, 074590982EF13928004098A9 /* BackgroundRunnerModule.m in Sources */, 0773E5D82F53404600E76F7A /* OneKeyLogBridge.m in Sources */, + C19BE8E0442D0CDAE91B484A /* ReactNativeDelegate.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/example/react-native/ios/example/AppDelegate.swift b/example/react-native/ios/example/AppDelegate.swift index cb9889a6..3db1f359 100644 --- a/example/react-native/ios/example/AppDelegate.swift +++ b/example/react-native/ios/example/AppDelegate.swift @@ -38,23 +38,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } } - -class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { - override func sourceURL(for bridge: RCTBridge) -> URL? { - self.bundleURL() - } - - override func bundleURL() -> URL? { -#if DEBUG - RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") -#else - Bundle.main.url(forResource: "main", withExtension: "jsbundle") -#endif - } - - override func hostDidStart(_ host: RCTHost) { - super.hostDidStart(host) - // Install SharedBridge HostObject into the main runtime - BackgroundThreadManager.installSharedBridge(inMainRuntime: host) - } -} diff --git a/example/react-native/ios/example/ReactNativeDelegate.h b/example/react-native/ios/example/ReactNativeDelegate.h new file mode 100644 index 00000000..1ccdf9d2 --- /dev/null +++ b/example/react-native/ios/example/ReactNativeDelegate.h @@ -0,0 +1,14 @@ +#import + +#if __has_include() +#import +#elif __has_include() +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate +@end + +NS_ASSUME_NONNULL_END diff --git a/example/react-native/ios/example/ReactNativeDelegate.mm b/example/react-native/ios/example/ReactNativeDelegate.mm new file mode 100644 index 00000000..4f6e82ee --- /dev/null +++ b/example/react-native/ios/example/ReactNativeDelegate.mm @@ -0,0 +1,35 @@ +#import "ReactNativeDelegate.h" +#import +#import +#import + +@implementation ReactNativeDelegate + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ + return [self bundleURL]; +} + +- (NSURL *)bundleURL +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +- (void)hostDidStart:(RCTHost *)host +{ + [super hostDidStart:host]; + [BackgroundThreadManager installSharedBridgeInMainRuntime:host]; + +#if DEBUG + NSString *bgURL = @"http://localhost:8082/background.bundle?platform=ios&dev=true&lazy=false&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true"; +#else + NSString *bgURL = @"background.bundle"; +#endif + [[BackgroundThreadManager sharedInstance] startBackgroundRunnerWithEntryURL:bgURL]; +} + +@end diff --git a/example/react-native/package.json b/example/react-native/package.json index ef60ee5a..7d16da94 100644 --- a/example/react-native/package.json +++ b/example/react-native/package.json @@ -33,7 +33,7 @@ "@react-navigation/native-stack": "^7.14.4", "fast-base64-decode": "*", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-mmkv": "^4.1.2", "react-native-safe-area-context": "^5.5.2", "react-native-screens": "^4.24.0" diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 670b8049..f49726ba 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 217ddb9d..f4e035cf 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-background-thread/BackgroundThread.podspec b/native-modules/react-native-background-thread/BackgroundThread.podspec index 15dc8e1b..9d87aa5f 100644 --- a/native-modules/react-native-background-thread/BackgroundThread.podspec +++ b/native-modules/react-native-background-thread/BackgroundThread.podspec @@ -14,8 +14,9 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-background-thread.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift,cpp}", "cpp/**/*.{h,cpp}" - s.public_header_files = "ios/**/*.h" - s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp"' } + s.public_header_files = "ios/BackgroundThreadManager.h", "ios/BTLogger.h" + s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp"', 'DEFINES_MODULE' => 'YES' } + s.user_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '"$(PODS_ROOT)/Headers/Public/BackgroundThread"' } s.dependency 'ReactNativeNativeLogger' diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 62c67182..216044f4 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -17,7 +17,7 @@ #include "SharedStore.h" #include "SharedRPC.h" -#import +#import #import @interface BackgroundThreadManager () diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index c8cf1520..8440bafd 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -76,7 +76,7 @@ "lefthook": "^2.0.3", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.17", "release-it": "^19.0.4", "turbo": "^2.5.6", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 0575c24e..382b3363 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index c14a3aac..5781d94c 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 7a9c749a..6acc314d 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 706c6266..07c1eacd 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 6c23847d..d65fe609 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index d368879a..40e2fe3b 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index a27845a5..f8fdce12 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -78,7 +78,7 @@ "lefthook": "^2.0.3", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "release-it": "^19.0.4", "turbo": "^2.5.6", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 74804866..1d406c10 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 34ad8be8..100f7d87 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index ed6e1866..44a0ad17 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 78aee6f8..8daf58ec 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -59,7 +59,7 @@ "devDependencies": { "@types/react": "^19.2.0", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "typescript": "^5.9.2" }, diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 28e52e01..f6d35de2 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -63,7 +63,7 @@ "del-cli": "^6.0.0", "nitrogen": "0.31.10", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "typescript": "^5.9.2" diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index c8a72ada..97d4b5dc 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -80,7 +80,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 3ce8e199..95f2090e 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -61,7 +61,7 @@ "devDependencies": { "@types/react": "^19.2.0", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "typescript": "^5.9.2" }, diff --git a/package.json b/package.json index 5c64ff81..3a094923 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "nitrogen": "0.31.10", "prettier": "^2.8.8", "react": "19.2.0", - "react-native": "0.83.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", "react-native-builder-bob": "^0.40.13", "react-native-nitro-modules": "0.33.2", "release-it": "^19.0.4", diff --git a/yarn.lock b/yarn.lock index d1558606..cd87ebd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2779,7 +2779,7 @@ __metadata: jest: "npm:^29.6.3" prettier: "npm:2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-mmkv: "npm:^4.1.2" react-native-nitro-modules: "npm:0.33.2" react-native-safe-area-context: "npm:^5.5.2" @@ -2813,7 +2813,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -2849,7 +2849,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -2885,7 +2885,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -2920,7 +2920,7 @@ __metadata: lefthook: "npm:^2.0.3" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.17" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" @@ -2954,7 +2954,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -2990,7 +2990,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3026,7 +3026,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3062,7 +3062,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3098,7 +3098,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3134,7 +3134,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3169,7 +3169,7 @@ __metadata: lefthook: "npm:^2.0.3" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" release-it: "npm:^19.0.4" turbo: "npm:^2.5.6" @@ -3203,7 +3203,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3222,7 +3222,7 @@ __metadata: dependencies: "@types/react": "npm:^19.2.0" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" typescript: "npm:^5.9.2" peerDependencies: @@ -3254,7 +3254,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3275,7 +3275,7 @@ __metadata: del-cli: "npm:^6.0.0" nitrogen: "npm:0.31.10" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" typescript: "npm:^5.9.2" @@ -3309,7 +3309,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3345,7 +3345,7 @@ __metadata: nitrogen: "npm:0.31.10" prettier: "npm:^2.8.8" react: "npm:19.2.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" react-native-nitro-modules: "npm:0.33.2" release-it: "npm:^19.0.4" @@ -3365,7 +3365,7 @@ __metadata: "@types/react": "npm:^19.2.0" react: "npm:19.2.0" react-freeze: "npm:^1.0.0" - react-native: "npm:0.83.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" react-native-builder-bob: "npm:^0.40.13" sf-symbols-typescript: "npm:^2.0.0" typescript: "npm:^5.9.2" @@ -11206,6 +11206,57 @@ __metadata: languageName: node linkType: hard +"react-native@patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch": + version: 0.83.0 + resolution: "react-native@patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch::version=0.83.0&hash=f8560f" + dependencies: + "@jest/create-cache-key-function": "npm:^29.7.0" + "@react-native/assets-registry": "npm:0.83.0" + "@react-native/codegen": "npm:0.83.0" + "@react-native/community-cli-plugin": "npm:0.83.0" + "@react-native/gradle-plugin": "npm:0.83.0" + "@react-native/js-polyfills": "npm:0.83.0" + "@react-native/normalize-colors": "npm:0.83.0" + "@react-native/virtualized-lists": "npm:0.83.0" + abort-controller: "npm:^3.0.0" + anser: "npm:^1.4.9" + ansi-regex: "npm:^5.0.0" + babel-jest: "npm:^29.7.0" + babel-plugin-syntax-hermes-parser: "npm:0.32.0" + base64-js: "npm:^1.5.1" + commander: "npm:^12.0.0" + flow-enums-runtime: "npm:^0.0.6" + glob: "npm:^7.1.1" + hermes-compiler: "npm:0.14.0" + invariant: "npm:^2.2.4" + jest-environment-node: "npm:^29.7.0" + memoize-one: "npm:^5.0.0" + metro-runtime: "npm:^0.83.3" + metro-source-map: "npm:^0.83.3" + nullthrows: "npm:^1.1.1" + pretty-format: "npm:^29.7.0" + promise: "npm:^8.3.0" + react-devtools-core: "npm:^6.1.5" + react-refresh: "npm:^0.14.0" + regenerator-runtime: "npm:^0.13.2" + scheduler: "npm:0.27.0" + semver: "npm:^7.1.3" + stacktrace-parser: "npm:^0.1.10" + whatwg-fetch: "npm:^3.0.0" + ws: "npm:^7.5.10" + yargs: "npm:^17.6.2" + peerDependencies: + "@types/react": ^19.1.1 + react: ^19.2.0 + peerDependenciesMeta: + "@types/react": + optional: true + bin: + react-native: cli.js + checksum: 10/7cbda17babe8957971b509c9ef33af857c8f051d11f03c2636259752355ad64691b52f9af86efa854cf99dd19bf9bdb409ed239a91ed72b6909583ec996cb0d5 + languageName: node + linkType: hard + "react-refresh@npm:^0.14.0": version: 0.14.2 resolution: "react-refresh@npm:0.14.2" From 16d68ae22b878fa4a11f124c2b4dacabde8c8af5 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 23:25:26 +0800 Subject: [PATCH 08/74] feat(shared-rpc): add onWrite cross-runtime notification, remove legacy messaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SharedRPC gains RuntimeExecutor per registered runtime. On write(), after storing the value, it invokes the other runtime's onWrite callback via its executor — enabling bidirectional notification without postHostMessage/ onHostMessage or bindMessageCallback. - Add RuntimeExecutor, RuntimeListener, onWrite to SharedRPC C++ - Wire callFunctionOnBufferedRuntimeExecutor as executor on iOS - Wire scheduleOnJSThread + nativeExecuteWork JNI callback on Android - Remove all legacy messaging: postHostMessage, onHostMessage, postBackgroundMessage, onBackgroundMessage, bindMessageCallback, initBackgroundThread, onBgMessage, nativeInstallBgBindings, nativePostToBackground - Replace with installSharedBridge() TurboModule method - Update example app to use SharedRPC.onWrite for RPC --- example/react-native/background.js | 105 +++--------- .../pages/BackgroundThreadTestPage.tsx | 57 ++----- .../android/src/main/cpp/cpp-adapter.cpp | 159 +++++------------- .../BackgroundThreadManager.kt | 64 +++---- .../BackgroundThreadModule.kt | 35 +--- .../cpp/SharedRPC.cpp | 78 ++++++++- .../cpp/SharedRPC.h | 19 +++ .../ios/BackgroundRunnerReactNativeDelegate.h | 17 -- .../BackgroundRunnerReactNativeDelegate.mm | 133 ++------------- .../ios/BackgroundThread.h | 1 + .../ios/BackgroundThread.mm | 28 +-- .../ios/BackgroundThreadManager.h | 12 -- .../ios/BackgroundThreadManager.mm | 39 ++--- .../src/NativeBackgroundThread.ts | 6 +- .../src/SharedRPC.ts | 1 + 15 files changed, 239 insertions(+), 515 deletions(-) diff --git a/example/react-native/background.js b/example/react-native/background.js index 687e83f1..a59abb1a 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -1,85 +1,39 @@ import ReactNative from 'react-native'; -let isReady = false; -let waitMessages = []; -const callbacks = new Set(); -const onMessageCallback = (message) => { - let parsed = message; - if (typeof message === 'string') { - try { - parsed = JSON.parse(message); - } catch { - // keep as raw string - } +// Wait for sharedRPC to be available, then set up onWrite listener +function waitForSharedRPC(times = 0) { + if (globalThis.$$isNativeUiThread) { + return; } - callbacks.forEach((callback) => callback(parsed)); -}; - -function checkReady(times = 0) { - if (globalThis.$$isNativeUiThread || times > 10_000) { + if (globalThis.sharedRPC) { + setupHandlers(); return; } - if ( - typeof globalThis.postHostMessage === 'function' && - typeof globalThis.onHostMessage === 'function' - ) { - isReady = true; - globalThis.onHostMessage(onMessageCallback); - setTimeout(() => { - console.log('waitMessages.length', waitMessages.length); - waitMessages.forEach((message) => { - globalThis.postHostMessage(message); - }); - waitMessages = []; - }, 0); - } else { - console.log('checkReady', times); - setTimeout(() => checkReady(times + 1), 10); + if (times > 5000) { + console.error('[BG] sharedRPC not available after timeout'); + return; } + setTimeout(() => waitForSharedRPC(times + 1), 10); } -checkReady(); +function setupHandlers() { + console.log('[BG] sharedRPC ready, setting up onWrite listener'); -const checkThread = () => { - if (globalThis.$$isNativeUiThread) { - // eslint-disable-next-line no-restricted-syntax - throw new Error( - 'this function is not available in native UI thread', - ); - } -}; + globalThis.sharedRPC.onWrite((callId) => { + console.log('[BG] onWrite notification:', callId); -export const nativeBGBridge = { - postHostMessage: (message) => { - checkThread(); - const str = typeof message === 'string' ? message : JSON.stringify(message); - if (!isReady) { - waitMessages.push(str); - return; - } - globalThis.postHostMessage(str); - }, - onHostMessage: (callback) => { - checkThread(); - callbacks.add(callback); - return () => { - callbacks.delete(callback); - }; - }, -}; + const params = globalThis.sharedRPC.read(callId); + if (params === undefined) return; + console.log('[BG] received RPC call:', callId, params); -nativeBGBridge.onHostMessage((message) => { - console.log('message', message); - if (message.type === 'test1') { - console.log(`[BG] Received test1: ${JSON.stringify(message)}, will reply in 3s`); - setTimeout(() => { - console.log('[BG] Sending test2 response'); - nativeBGBridge.postHostMessage({ type: 'test2' }); - }, 3000); - } -}); + // Process and write result back — this will notify main runtime + globalThis.sharedRPC.write(callId + ':result', 'echo: ' + params); + }); +} + +waitForSharedRPC(); // SharedStore: read config values set by main runtime function checkSharedStore() { @@ -92,16 +46,3 @@ function checkSharedStore() { setTimeout(checkSharedStore, 1000); } checkSharedStore(); - -// SharedRPC: handle RPC calls from main runtime via onHostMessage -nativeBGBridge.onHostMessage((message) => { - if (message.type === 'rpc' && message.callId) { - const params = globalThis.sharedRPC?.read(message.callId); - if (params !== undefined) { - console.log('[SharedRPC BG] received call:', message.callId, params); - // Echo back the params as the result - globalThis.sharedRPC?.write(message.callId, 'echo: ' + params); - nativeBGBridge.postHostMessage({ type: 'rpc_response', callId: message.callId }); - } - } -}); diff --git a/example/react-native/pages/BackgroundThreadTestPage.tsx b/example/react-native/pages/BackgroundThreadTestPage.tsx index b14ab597..501d6ee3 100644 --- a/example/react-native/pages/BackgroundThreadTestPage.tsx +++ b/example/react-native/pages/BackgroundThreadTestPage.tsx @@ -3,10 +3,9 @@ import { View, Text, StyleSheet } from 'react-native'; import { TestPageBase, TestButton, TestResult } from './TestPageBase'; import { BackgroundThread } from '@onekeyfe/react-native-background-thread'; -BackgroundThread.initBackgroundThread(); +BackgroundThread.installSharedBridge(); export function BackgroundThreadTestPage() { - const [pushResult, setPushResult] = useState(''); const [storeResult, setStoreResult] = useState(''); const [rpcResult, setRpcResult] = useState(''); const [storeAvailable, setStoreAvailable] = useState(false); @@ -21,33 +20,23 @@ export function BackgroundThreadTestPage() { return () => clearInterval(check); }, []); - // Listen for RPC responses from background + // Listen for RPC responses from background via SharedRPC.onWrite useEffect(() => { - const sub = BackgroundThread.onBackgroundMessage((msg) => { - try { - const parsed = JSON.parse(msg); - if (parsed.type === 'rpc_response' && parsed.callId) { - const result = globalThis.sharedRPC?.read(parsed.callId); - setRpcResult( - (prev) => - `${prev}\n[${new Date().toLocaleTimeString()}] Response: ${result}`, - ); - } else { - setPushResult(`Received: ${msg}`); - } - } catch { - setPushResult(`Received: ${msg}`); + if (!globalThis.sharedRPC) return; + + globalThis.sharedRPC.onWrite((callId: string) => { + // Only handle result callbacks + if (!callId.endsWith(':result')) return; + + const result = globalThis.sharedRPC?.read(callId); + if (result !== undefined) { + setRpcResult( + (prev) => + `${prev}\n[${new Date().toLocaleTimeString()}] Response: ${result}`, + ); } }); - return sub; - }, []); - - // Push model - const handlePushMessage = () => { - const message = { type: 'test1' }; - BackgroundThread.postBackgroundMessage(JSON.stringify(message)); - setPushResult(`Sent: ${JSON.stringify(message)}`); - }; + }, [storeAvailable]); // SharedStore test const handleStoreTest = () => { @@ -60,12 +49,12 @@ export function BackgroundThreadTestPage() { globalThis.sharedStore.set('devMode', true); const keys = globalThis.sharedStore.keys(); const values = keys - .map((k) => `${k}=${globalThis.sharedStore?.get(k)}`) + .map((k: string) => `${k}=${globalThis.sharedStore?.get(k)}`) .join(', '); setStoreResult(`Set 3 values. Current: ${values} | size=${globalThis.sharedStore.size}`); }; - // SharedRPC test + // SharedRPC test — write params, background onWrite fires, background writes result, main onWrite fires const handleRpcTest = () => { if (!globalThis.sharedRPC) { setRpcResult('SharedRPC not available'); @@ -76,9 +65,6 @@ export function BackgroundThreadTestPage() { callId, JSON.stringify({ method: 'echo', params: { ts: Date.now() } }), ); - BackgroundThread.postBackgroundMessage( - JSON.stringify({ type: 'rpc', callId }), - ); setRpcResult( (prev) => `${prev}\n[${new Date().toLocaleTimeString()}] Sent RPC: ${callId}`, @@ -87,13 +73,6 @@ export function BackgroundThreadTestPage() { return ( - {/* Push Model */} - - Push Model (postBackgroundMessage) - - - - {/* SharedStore */} SharedStore (persistent key-value) @@ -110,7 +89,7 @@ export function BackgroundThreadTestPage() { {/* SharedRPC */} - SharedRPC (temporary read-and-delete) + SharedRPC (onWrite cross-runtime) #include #include +#include #include "SharedStore.h" #include "SharedRPC.h" @@ -15,9 +16,6 @@ namespace jsi = facebook::jsi; static JavaVM *gJavaVM = nullptr; -static jobject gManagerRef = nullptr; -static std::mutex gCallbackMutex; -static std::shared_ptr gBgOnMessageCallback; extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { gJavaVM = vm; @@ -44,113 +42,32 @@ static void stubJsiFunction(jsi::Runtime &runtime, jsi::Object &object, const ch })); } -// ── nativeInstallBgBindings ───────────────────────────────────────────── -// Install postHostMessage / onHostMessage JSI globals into the background runtime. -// Also stores a global ref to the Java manager for callbacks. -extern "C" JNIEXPORT void JNICALL -Java_com_backgroundthread_BackgroundThreadManager_nativeInstallBgBindings( - JNIEnv *env, jobject thiz, jlong runtimePtr) { - - auto *runtime = reinterpret_cast(runtimePtr); - if (!runtime) return; - - // Store global ref to manager for JNI callbacks - if (gManagerRef) { - env->DeleteGlobalRef(gManagerRef); - } - gManagerRef = env->NewGlobalRef(thiz); +// ── Pending work map for cross-runtime executor ─────────────────────── +static std::mutex gWorkMutex; +static std::unordered_map> gPendingWork; +static int64_t gNextWorkId = 0; - // Reset previous callback - { - std::lock_guard lock(gCallbackMutex); - gBgOnMessageCallback.reset(); - } - - // postHostMessage(message: string) — background JS calls this to send to main - auto postHostMessage = jsi::Function::createFromHostFunction( - *runtime, - jsi::PropNameID::forAscii(*runtime, "postHostMessage"), - 1, - [](jsi::Runtime &rt, const jsi::Value &, - const jsi::Value *args, size_t count) -> jsi::Value { - if (count < 1 || !args[0].isString()) { - throw jsi::JSError(rt, "postHostMessage expects a string argument"); - } - std::string msg = args[0].getString(rt).utf8(rt); - - JNIEnv *env = getJNIEnv(); - if (env && gManagerRef) { - jclass cls = env->GetObjectClass(gManagerRef); - jmethodID mid = env->GetMethodID( - cls, "onBgMessage", "(Ljava/lang/String;)V"); - if (mid) { - jstring jmsg = env->NewStringUTF(msg.c_str()); - env->CallVoidMethod(gManagerRef, mid, jmsg); - env->DeleteLocalRef(jmsg); - } - env->DeleteLocalRef(cls); - } - return jsi::Value::undefined(); - }); - - runtime->global().setProperty( - *runtime, "postHostMessage", std::move(postHostMessage)); - - // onHostMessage(callback: function) — background JS registers a message handler - auto onHostMessage = jsi::Function::createFromHostFunction( - *runtime, - jsi::PropNameID::forAscii(*runtime, "onHostMessage"), - 1, - [](jsi::Runtime &rt, const jsi::Value &, - const jsi::Value *args, size_t count) -> jsi::Value { - if (count < 1 || !args[0].isObject() || - !args[0].asObject(rt).isFunction(rt)) { - throw jsi::JSError(rt, "onHostMessage expects a function"); - } - { - std::lock_guard lock(gCallbackMutex); - gBgOnMessageCallback = std::make_shared( - args[0].asObject(rt).asFunction(rt)); - } - return jsi::Value::undefined(); - }); - - runtime->global().setProperty( - *runtime, "onHostMessage", std::move(onHostMessage)); - - LOGI("JSI bindings (postHostMessage/onHostMessage) installed in background runtime"); -} - -// ── nativePostToBackground ────────────────────────────────────────────── -// Post a message from main to background JS. -// Must be called on the background JS thread. +// Called from Kotlin after runOnJSQueueThread dispatches to the correct thread. extern "C" JNIEXPORT void JNICALL -Java_com_backgroundthread_BackgroundThreadManager_nativePostToBackground( - JNIEnv *env, jobject thiz, jlong runtimePtr, jstring message) { +Java_com_backgroundthread_BackgroundThreadManager_nativeExecuteWork( + JNIEnv *env, jobject thiz, jlong runtimePtr, jlong workId) { + auto *rt = reinterpret_cast(runtimePtr); + if (!rt) return; - std::shared_ptr callback; + std::function work; { - std::lock_guard lock(gCallbackMutex); - callback = gBgOnMessageCallback; + std::lock_guard lock(gWorkMutex); + auto it = gPendingWork.find(workId); + if (it == gPendingWork.end()) return; + work = std::move(it->second); + gPendingWork.erase(it); } - if (!callback || runtimePtr == 0) return; - - auto *runtime = reinterpret_cast(runtimePtr); - const char *msgChars = env->GetStringUTFChars(message, nullptr); - std::string msg(msgChars); - env->ReleaseStringUTFChars(message, msgChars); - try { - auto parsedValue = runtime->global() - .getPropertyAsObject(*runtime, "JSON") - .getPropertyAsFunction(*runtime, "parse") - .call(*runtime, jsi::String::createFromUtf8(*runtime, msg)); - - callback->call(*runtime, {std::move(parsedValue)}); + work(*rt); } catch (const jsi::JSError &e) { - LOGE("JSError in postToBackground: %s", e.getMessage().c_str()); + LOGE("JSError in nativeExecuteWork: %s", e.getMessage().c_str()); } catch (const std::exception &e) { - LOGE("Error in postToBackground: %s", e.what()); + LOGE("Error in nativeExecuteWork: %s", e.what()); } } @@ -164,7 +81,31 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( if (!rt) return; SharedStore::install(*rt); - SharedRPC::install(*rt); + + // Create executor that schedules work on this runtime's JS thread via Kotlin + jobject ref = env->NewGlobalRef(thiz); + bool capturedIsMain = static_cast(isMain); + + RuntimeExecutor executor = [ref, capturedIsMain](std::function work) { + JNIEnv *env = getJNIEnv(); + if (!env || !ref) return; + + int64_t workId; + { + std::lock_guard lock(gWorkMutex); + workId = gNextWorkId++; + gPendingWork[workId] = std::move(work); + } + + jclass cls = env->GetObjectClass(ref); + jmethodID mid = env->GetMethodID(cls, "scheduleOnJSThread", "(ZJ)V"); + if (mid) { + env->CallVoidMethod(ref, mid, static_cast(capturedIsMain), static_cast(workId)); + } + env->DeleteLocalRef(cls); + }; + + SharedRPC::install(*rt, std::move(executor)); LOGI("SharedStore and SharedRPC installed (isMain=%d)", static_cast(isMain)); } @@ -233,21 +174,13 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeSetupErrorHandler( } // ── nativeDestroy ─────────────────────────────────────────────────────── -// Clean up JNI global references and callbacks. +// Clean up native resources. // Called from BackgroundThreadManager.destroy(). extern "C" JNIEXPORT void JNICALL Java_com_backgroundthread_BackgroundThreadManager_nativeDestroy( JNIEnv *env, jobject thiz) { - { - std::lock_guard lock(gCallbackMutex); - gBgOnMessageCallback.reset(); - } - - if (gManagerRef) { - env->DeleteGlobalRef(gManagerRef); - gManagerRef = nullptr; - } + SharedRPC::reset(); LOGI("Native resources cleaned up"); } diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 259658c6..b134ac99 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -20,7 +20,7 @@ import com.facebook.react.runtime.hermes.HermesInstance * Responsibilities: * - Manages background ReactHostImpl lifecycle * - Installs SharedBridge into main and background runtimes - * - Routes messages between runtimes via JNI/JSI + * - Cross-runtime communication via SharedRPC onWrite notifications */ class BackgroundThreadManager private constructor() { @@ -28,8 +28,11 @@ class BackgroundThreadManager private constructor() { @Volatile private var bgRuntimePtr: Long = 0 + + @Volatile + private var mainRuntimePtr: Long = 0 + private var mainReactContext: ReactApplicationContext? = null private var isStarted = false - private var onMessageCallback: ((String) -> Unit)? = null companion object { private const val MODULE_NAME = "background" @@ -51,23 +54,24 @@ class BackgroundThreadManager private constructor() { // ── JNI declarations ──────────────────────────────────────────────────── - private external fun nativeInstallBgBindings(runtimePtr: Long) - private external fun nativePostToBackground(runtimePtr: Long, message: String) private external fun nativeInstallSharedBridge(runtimePtr: Long, isMain: Boolean) private external fun nativeSetupErrorHandler(runtimePtr: Long) private external fun nativeDestroy() + private external fun nativeExecuteWork(runtimePtr: Long, workId: Long) // ── SharedBridge ──────────────────────────────────────────────────────── /** * Install SharedBridge HostObject into the main (UI) runtime. - * Call this from initBackgroundThread(). + * Call this from installSharedBridge(). */ fun installSharedBridgeInMainRuntime(context: ReactApplicationContext) { + mainReactContext = context context.runOnJSQueueThread { try { val ptr = context.javaScriptContextHolder?.get() ?: 0L if (ptr != 0L) { + mainRuntimePtr = ptr nativeInstallSharedBridge(ptr, true) BTLogger.info("SharedBridge installed in main runtime") } else { @@ -131,10 +135,9 @@ class BackgroundThreadManager private constructor() { val ptr = context.javaScriptContextHolder?.get() ?: 0L if (ptr != 0L) { bgRuntimePtr = ptr - nativeInstallBgBindings(ptr) nativeInstallSharedBridge(ptr, false) nativeSetupErrorHandler(ptr) - BTLogger.info("JSI bindings, SharedBridge, and error handler installed in background runtime") + BTLogger.info("SharedBridge and error handler installed in background runtime") } else { BTLogger.error("Background runtime pointer is 0") } @@ -148,39 +151,23 @@ class BackgroundThreadManager private constructor() { host.start() } - // ── Messaging ─────────────────────────────────────────────────────────── - - fun postBackgroundMessage(message: String) { - val ptr = bgRuntimePtr - if (ptr == 0L) { - BTLogger.warn("Cannot post message: background runtime not ready") - return - } - - bgReactHost?.currentReactContext?.runOnJSQueueThread { - try { - if (bgRuntimePtr != 0L) { - nativePostToBackground(bgRuntimePtr, message) - } - } catch (e: Exception) { - BTLogger.error("Error posting message to background: ${e.message}") - } - } - } - - fun setOnMessageCallback(callback: (String) -> Unit) { - onMessageCallback = callback - } - - fun checkMessageCallback(): Boolean = onMessageCallback != null - /** - * Called from C++ (via JNI) when background JS calls postHostMessage(message). - * Routes the message to the registered callback (which emits to the main JS runtime). + * Called from C++ RuntimeExecutor to schedule work on the correct JS thread. + * Routes to main or background runtime's JS queue thread, then calls nativeExecuteWork. */ @DoNotStrip - fun onBgMessage(message: String) { - onMessageCallback?.invoke(message) + fun scheduleOnJSThread(isMain: Boolean, workId: Long) { + val context = if (isMain) mainReactContext else bgReactHost?.currentReactContext + val ptr = if (isMain) mainRuntimePtr else bgRuntimePtr + context?.runOnJSQueueThread { + if (ptr != 0L) { + try { + nativeExecuteWork(ptr, workId) + } catch (e: Exception) { + BTLogger.error("Error executing work on JS thread: ${e.message}") + } + } + } } // ── Lifecycle ─────────────────────────────────────────────────────────── @@ -190,9 +177,10 @@ class BackgroundThreadManager private constructor() { fun destroy() { nativeDestroy() bgRuntimePtr = 0 + mainRuntimePtr = 0 + mainReactContext = null bgReactHost?.destroy("BackgroundThreadManager destroyed", null) bgReactHost = null isStarted = false - onMessageCallback = null } } diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt index e02d3564..eeb73056 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt @@ -1,7 +1,6 @@ package com.backgroundthread import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.module.annotations.ReactModule /** @@ -20,41 +19,11 @@ class BackgroundThreadModule(reactContext: ReactApplicationContext) : override fun getName(): String = NAME - /** - * Force register event callback during initialization. - * This is mainly to handle the scenario of restarting in development environment. - */ - override fun initBackgroundThread() { - bindMessageCallback() + override fun installSharedBridge() { BackgroundThreadManager.getInstance().installSharedBridgeInMainRuntime(reactApplicationContext) } override fun startBackgroundRunnerWithEntryURL(entryURL: String) { - val manager = BackgroundThreadManager.getInstance() - if (!manager.checkMessageCallback()) { - bindMessageCallback() - } - manager.startBackgroundRunnerWithEntryURL(reactApplicationContext, entryURL) + BackgroundThreadManager.getInstance().startBackgroundRunnerWithEntryURL(reactApplicationContext, entryURL) } - - override fun postBackgroundMessage(message: String) { - val manager = BackgroundThreadManager.getInstance() - if (!manager.checkMessageCallback()) { - bindMessageCallback() - } - manager.postBackgroundMessage(message) - } - - private fun bindMessageCallback() { - BackgroundThreadManager.getInstance().setOnMessageCallback { message -> - UiThreadUtil.runOnUiThread { - try { - emitOnBackgroundMessage(message) - } catch (e: Exception) { - BTLogger.error("Error emitting background message: ${e.message}") - } - } - } - } - } diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index bdcb3047..7dec3069 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -1,8 +1,8 @@ #include "SharedRPC.h" -// Static member definitions std::mutex SharedRPC::mutex_; std::unordered_map SharedRPC::slots_; +std::vector SharedRPC::listeners_; void SharedRPC::install(jsi::Runtime &rt) { auto rpc = std::make_shared(); @@ -10,9 +10,51 @@ void SharedRPC::install(jsi::Runtime &rt) { rt.global().setProperty(rt, "sharedRPC", std::move(obj)); } +void SharedRPC::install(jsi::Runtime &rt, RuntimeExecutor executor) { + auto rpc = std::make_shared(); + auto obj = jsi::Object::createFromHostObject(rt, rpc); + rt.global().setProperty(rt, "sharedRPC", std::move(obj)); + + std::lock_guard lock(mutex_); + // Remove any existing listener for this runtime (reload scenario) + listeners_.erase( + std::remove_if(listeners_.begin(), listeners_.end(), + [&rt](const RuntimeListener &l) { return l.runtime == &rt; }), + listeners_.end()); + listeners_.push_back({&rt, std::move(executor), nullptr}); +} + void SharedRPC::reset() { std::lock_guard lock(mutex_); slots_.clear(); + listeners_.clear(); +} + +void SharedRPC::notifyOtherRuntime(jsi::Runtime &callerRt, const std::string &callId) { + // Collect executors and callbacks under lock, then invoke outside lock + // to avoid deadlock (executor may schedule work that also acquires mutex_). + std::vector>> toNotify; + { + std::lock_guard lock(mutex_); + for (auto &listener : listeners_) { + if (listener.runtime == &callerRt) continue; + if (!listener.callback) continue; + toNotify.emplace_back(listener.executor, listener.callback); + } + } + + for (auto &[executor, cb] : toNotify) { + auto id = callId; + executor([cb, id](jsi::Runtime &rt) { + try { + cb->call(rt, jsi::String::createFromUtf8(rt, id)); + } catch (const jsi::JSError &) { + // Swallow — listener threw, not our problem + } catch (...) { + // Runtime may be torn down + } + }); + } } RPCValue SharedRPC::extractValue(jsi::Runtime &rt, const jsi::Value &val) { @@ -48,8 +90,8 @@ jsi::Value SharedRPC::get(jsi::Runtime &rt, const jsi::PropNameID &name) { if (prop == "write") { return jsi::Function::createFromHostFunction( rt, name, 2, - [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, - size_t count) -> jsi::Value { + [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { if (count < 2 || !args[0].isString()) { throw jsi::JSError( rt, "SharedRPC.write expects (callId: string, value)"); @@ -58,8 +100,10 @@ jsi::Value SharedRPC::get(jsi::Runtime &rt, const jsi::PropNameID &name) { auto value = extractValue(rt, args[1]); { std::lock_guard lock(mutex_); - slots_.insert_or_assign(std::move(callId), std::move(value)); + slots_.insert_or_assign(callId, std::move(value)); } + // Notify OUTSIDE the lock + notifyOtherRuntime(rt, callId); return jsi::Value::undefined(); }); } @@ -113,6 +157,31 @@ jsi::Value SharedRPC::get(jsi::Runtime &rt, const jsi::PropNameID &name) { return jsi::Value(static_cast(slots_.size())); } + // onWrite(callback: (callId: string) => void): void + if (prop == "onWrite") { + return jsi::Function::createFromHostFunction( + rt, name, 1, + [](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isObject() || + !args[0].asObject(rt).isFunction(rt)) { + throw jsi::JSError(rt, "SharedRPC.onWrite expects a function"); + } + auto fn = std::make_shared( + args[0].asObject(rt).asFunction(rt)); + { + std::lock_guard lock(mutex_); + for (auto &listener : listeners_) { + if (listener.runtime == &rt) { + listener.callback = std::move(fn); + break; + } + } + } + return jsi::Value::undefined(); + }); + } + return jsi::Value::undefined(); } @@ -122,5 +191,6 @@ std::vector SharedRPC::getPropertyNames(jsi::Runtime &rt) { props.push_back(jsi::PropNameID::forUtf8(rt, "read")); props.push_back(jsi::PropNameID::forUtf8(rt, "has")); props.push_back(jsi::PropNameID::forUtf8(rt, "pendingCount")); + props.push_back(jsi::PropNameID::forUtf8(rt, "onWrite")); return props; } diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.h b/native-modules/react-native-background-thread/cpp/SharedRPC.h index adec32ab..df6eb99f 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.h +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include #include @@ -11,18 +13,35 @@ namespace jsi = facebook::jsi; using RPCValue = std::variant; +// Executes a callback on a specific runtime's JS thread. +// The implementation is platform-specific (iOS vs Android). +using RuntimeExecutor = std::function)>; + +struct RuntimeListener { + jsi::Runtime *runtime; + RuntimeExecutor executor; + std::shared_ptr callback; // JS onWrite callback +}; + class SharedRPC : public jsi::HostObject { public: jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override; std::vector getPropertyNames(jsi::Runtime &rt) override; + /// Legacy install without executor (no cross-runtime notification) static void install(jsi::Runtime &rt); + + /// Install with executor — enables cross-runtime write notifications + static void install(jsi::Runtime &rt, RuntimeExecutor executor); + static void reset(); private: static RPCValue extractValue(jsi::Runtime &rt, const jsi::Value &val); static jsi::Value toJSI(jsi::Runtime &rt, const RPCValue &val); + void notifyOtherRuntime(jsi::Runtime &callerRt, const std::string &callId); static std::mutex mutex_; static std::unordered_map slots_; + static std::vector listeners_; }; diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h index 2b4cb138..59ca4200 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h @@ -18,7 +18,6 @@ NS_ASSUME_NONNULL_BEGIN @interface BackgroundReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate -//@property (nonatomic) std::shared_ptr eventEmitter; @property (nonatomic, assign) BOOL hasOnMessageHandler; @property (nonatomic, assign) BOOL hasOnErrorHandler; @@ -26,28 +25,12 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readwrite) std::string origin; -@property (nonatomic, copy) void (^onMessageCallback)(NSString *message); - /** * Initializes the delegate. * @return Initialized delegate instance with filtered module access */ - (instancetype)init; -/** - * Posts a message to the JavaScript runtime. - * @param message C++ string containing the JSON.stringified message - */ -- (void)postMessage:(const std::string &)message; - -/** - * Routes a message to a specific sandbox delegate. - * @param message The message to route - * @param targetId The ID of the target sandbox - * @return true if the message was successfully routed, false otherwise - */ -- (bool)routeMessage:(const std::string &)message toSandbox:(const std::string &)targetId; - @end NS_ASSUME_NONNULL_END diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 4540c9fe..45a30cb0 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -54,26 +54,13 @@ static void stubJsiFunction(jsi::Runtime &runtime, jsi::Object &object, const ch })); } -static std::string safeGetStringProperty(jsi::Runtime &rt, const jsi::Object &obj, const char *key) -{ - if (!obj.hasProperty(rt, key)) { - return ""; - } - jsi::Value value = obj.getProperty(rt, key); - return value.isString() ? value.getString(rt).utf8(rt) : ""; -} - @interface BackgroundReactNativeDelegate () { RCTInstance *_rctInstance; - std::shared_ptr _onMessageSandbox; std::string _origin; std::string _jsBundleSource; } - (void)cleanupResources; - -- (jsi::Function)createPostMessageFunction:(jsi::Runtime &)runtime; -- (jsi::Function)createSetOnMessageFunction:(jsi::Runtime &)runtime; - (void)setupErrorHandler:(jsi::Runtime &)runtime; @end @@ -94,7 +81,6 @@ - (instancetype)init - (void)cleanupResources { - _onMessageSandbox.reset(); _rctInstance = nil; } @@ -137,56 +123,12 @@ - (NSURL *)bundleURL return [[NSBundle mainBundle] URLForResource: @"background" withExtension: @"bundle"]; } -- (void)postMessage:(const std::string &)message -{ - if (!_onMessageSandbox || !_rctInstance) { - return; - } - - [_rctInstance callFunctionOnBufferedRuntimeExecutor:[=](jsi::Runtime &runtime) { - try { - // Validate runtime before any JSI operations - runtime.global(); // Test if runtime is accessible - - // Double-check the JSI function is still valid - if (!_onMessageSandbox) { - return; - } - - jsi::Value parsedValue = runtime.global() - .getPropertyAsObject(runtime, "JSON") - .getPropertyAsFunction(runtime, "parse") - .call(runtime, jsi::String::createFromUtf8(runtime, message)); - - _onMessageSandbox->call(runtime, {std::move(parsedValue)}); - } catch (const jsi::JSError &e) { - [BTLogger error:[NSString stringWithFormat:@"JSError during postMessage: %s", e.getMessage().c_str()]]; - } catch (const std::exception &e) { - [BTLogger error:[NSString stringWithFormat:@"RuntimeError during postMessage: %s", e.what()]]; - } catch (...) { - [BTLogger error:[NSString stringWithFormat:@"Runtime invalid during postMessage for sandbox %s", _origin.c_str()]]; - } - }]; -} - -- (bool)routeMessage:(const std::string &)message toSandbox:(const std::string &)targetId -{ - // Sandbox routing is not yet implemented. Deny all cross-sandbox messages by default. - [BTLogger warn:@"routeMessage denied: sandbox routing not implemented"]; - return false; -} - - (void)hostDidStart:(RCTHost *)host { if (!host) { return; } - // Safely clear any existing JSI function and instance before new runtime setup - // This prevents crash on reload when old function is tied to invalid runtime - _onMessageSandbox.reset(); - _onMessageSandbox = nullptr; - // Clear old instance reference before setting new one _rctInstance = nil; @@ -198,13 +140,19 @@ - (void)hostDidStart:(RCTHost *)host } [_rctInstance callFunctionOnBufferedRuntimeExecutor:[=](jsi::Runtime &runtime) { - facebook::react::defineReadOnlyGlobal(runtime, "postHostMessage", [self createPostMessageFunction:runtime]); - facebook::react::defineReadOnlyGlobal(runtime, "onHostMessage", [self createSetOnMessageFunction:runtime]); [self setupErrorHandler:runtime]; - // Install SharedStore and SharedRPC into background runtime + // Install SharedStore into background runtime SharedStore::install(runtime); - SharedRPC::install(runtime); + + // Install SharedRPC with executor for cross-runtime notifications + RCTInstance *bgInstance = _rctInstance; + RuntimeExecutor bgExecutor = [bgInstance](std::function work) { + [bgInstance callFunctionOnBufferedRuntimeExecutor:[work](jsi::Runtime &rt) { + work(rt); + }]; + }; + SharedRPC::install(runtime, std::move(bgExecutor)); [BTLogger info:@"SharedStore and SharedRPC installed in background runtime"]; }]; } @@ -222,67 +170,6 @@ - (void)hostDidStart:(RCTHost *)host return [super getTurboModule:name jsInvoker:jsInvoker]; } -- (jsi::Function)createPostMessageFunction:(jsi::Runtime &)runtime -{ - return jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii(runtime, "postMessage"), - 2, // Updated to accept up to 2 arguments - [=](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, size_t count) { - // Validate runtime before any JSI operations - try { - rt.global(); // Test if runtime is accessible - } catch (...) { - return jsi::Value::undefined(); - } - - if (count < 1 || count > 2) { - throw jsi::JSError(rt, "Expected 1 or 2 arguments: postMessage(message, targetOrigin?)"); - } - - const jsi::Value &messageArg = args[0]; - if (!messageArg.isString()) { - throw jsi::JSError(rt, "Expected an string as the first argument"); - } -// jsi::Object jsonObject = rt.global().getPropertyAsObject(rt, "JSON"); -// jsi::Function jsonStringify = jsonObject.getPropertyAsFunction(rt, "stringify"); -// jsi::Value jsonResult = jsonStringify.call(rt, messageArg); - std::string messageJson = messageArg.getString(rt).utf8(rt); - NSString *messageNS = [NSString stringWithUTF8String:messageJson.c_str()]; - dispatch_async(dispatch_get_main_queue(), ^{ - if (self.onMessageCallback) { - self.onMessageCallback(messageNS); - } - }); - return jsi::Value::undefined(); - }); -} - -- (jsi::Function)createSetOnMessageFunction:(jsi::Runtime &)runtime -{ - return jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii(runtime, "setOnMessage"), - 1, - [=](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, size_t count) { - if (count != 1) { - throw jsi::JSError(rt, "Expected exactly one argument"); - } - - const jsi::Value &arg = args[0]; - if (!arg.isObject() || !arg.asObject(rt).isFunction(rt)) { - throw jsi::JSError(rt, "Expected a function as the first argument"); - } - - jsi::Function fn = arg.asObject(rt).asFunction(rt); - - _onMessageSandbox.reset(); - _onMessageSandbox = std::make_shared(std::move(fn)); - - return jsi::Value::undefined(); - }); -} - - (void)setupErrorHandler:(jsi::Runtime &)runtime { // Get ErrorUtils diff --git a/native-modules/react-native-background-thread/ios/BackgroundThread.h b/native-modules/react-native-background-thread/ios/BackgroundThread.h index 275a9e2f..b6704c7e 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThread.h +++ b/native-modules/react-native-background-thread/ios/BackgroundThread.h @@ -4,5 +4,6 @@ - (void)startBackgroundRunner; - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL; +- (void)installSharedBridge; @end diff --git a/native-modules/react-native-background-thread/ios/BackgroundThread.mm b/native-modules/react-native-background-thread/ios/BackgroundThread.mm index 81e51998..d25a3ac8 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThread.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThread.mm @@ -18,31 +18,15 @@ - (void)startBackgroundRunner { } - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL { - BackgroundThreadManager *manager = [BackgroundThreadManager sharedInstance]; - [manager startBackgroundRunnerWithEntryURL:entryURL]; -} - -// Force register event callback during initialization -// This is mainly to handle the scenario of restarting in development environment -- (void)initBackgroundThread { - [self bindMessageCallback]; -} - -- (void)bindMessageCallback { BackgroundThreadManager *manager = [BackgroundThreadManager sharedInstance]; - __weak __typeof__(self) weakSelf = self; - [manager setOnMessageCallback:^(NSString *message) { - [weakSelf emitOnBackgroundMessage:message]; - }]; + [manager startBackgroundRunnerWithEntryURL:entryURL]; } -- (void)postBackgroundMessage:(nonnull NSString *)message { - BackgroundThreadManager *manager = [BackgroundThreadManager - sharedInstance]; - if (!manager.checkMessageCallback) { - [self bindMessageCallback]; - } - [[BackgroundThreadManager sharedInstance] postBackgroundMessage:message]; +- (void)installSharedBridge { + // On iOS, SharedBridge is installed from AppDelegate's hostDidStart: callback + // via +[BackgroundThreadManager installSharedBridgeInMainRuntime:]. + // This is a no-op here — kept for API parity with Android. + [BTLogger info:@"installSharedBridge called (no-op on iOS, installed from AppDelegate)"]; } + (NSString *)moduleName diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h index 5d73432f..0521baf6 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h @@ -23,18 +23,6 @@ NS_ASSUME_NONNULL_BEGIN /// @param entryURL The custom entry URL for the background runner - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL; -/// Post message to background runner -/// @param message The message to post -- (void)postBackgroundMessage:(NSString *)message; - -/// Set callback for handling background messages -/// @param callback The callback block to handle messages -- (void)setOnMessageCallback:(void (^)(NSString *message))callback; - -/// Check if message callback is set -/// @return YES if message callback is set, NO otherwise -- (BOOL)checkMessageCallback; - /// Check if background runner is started @property (nonatomic, readonly) BOOL isStarted; diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 216044f4..2145d7e1 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -25,7 +25,6 @@ @interface BackgroundThreadManager () @property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory; @property (nonatomic, assign) BOOL hasListeners; @property (nonatomic, assign, readwrite) BOOL isStarted; -@property (nonatomic, copy) void (^onMessageCallback)(NSString *message); @end @implementation BackgroundThreadManager @@ -71,7 +70,15 @@ + (void)installSharedBridgeInMainRuntime:(RCTHost *)host { [instance callFunctionOnBufferedRuntimeExecutor:^(facebook::jsi::Runtime &runtime) { SharedStore::install(runtime); - SharedRPC::install(runtime); + + // Install SharedRPC with executor for cross-runtime notifications + __block id capturedInstance = instance; + RuntimeExecutor mainExecutor = [capturedInstance](std::function work) { + [capturedInstance callFunctionOnBufferedRuntimeExecutor:[work](jsi::Runtime &rt) { + work(rt); + }]; + }; + SharedRPC::install(runtime, std::move(mainExecutor)); [BTLogger info:@"SharedStore and SharedRPC installed in main runtime"]; }]; } @@ -99,39 +106,15 @@ - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL { NSDictionary *launchOptions = @{}; self.reactNativeFactoryDelegate = [[BackgroundReactNativeDelegate alloc] init]; self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self.reactNativeFactoryDelegate]; - + #if DEBUG [self.reactNativeFactoryDelegate setJsBundleSource:std::string([entryURL UTF8String])]; #endif - + [self.reactNativeFactory.rootViewFactory viewWithModuleName:MODULE_NAME initialProperties:initialProperties launchOptions:launchOptions]; - - __weak __typeof__(self) weakSelf = self; - [self.reactNativeFactoryDelegate setOnMessageCallback:^(NSString *message) { - if (weakSelf.onMessageCallback) { - weakSelf.onMessageCallback(message); - } - }]; }); } -- (void)postBackgroundMessage:(NSString *)message { - if (self.reactNativeFactoryDelegate) { - [self.reactNativeFactoryDelegate postMessage:std::string([message UTF8String])]; - } -} - -- (void)setOnMessageCallback:(void (^)(NSString *message))callback { - _onMessageCallback = callback; -} - -- (BOOL)checkMessageCallback { - if (self.onMessageCallback) { - return YES; - } - return NO; -} - @end diff --git a/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts b/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts index 63ae5c19..2ff5b946 100644 --- a/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts +++ b/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts @@ -1,11 +1,9 @@ import { TurboModuleRegistry } from 'react-native'; -import type { CodegenTypes, TurboModule } from 'react-native'; +import type { TurboModule } from 'react-native'; export interface Spec extends TurboModule { - readonly onBackgroundMessage: CodegenTypes.EventEmitter; - postBackgroundMessage(message: string): void; startBackgroundRunnerWithEntryURL(entryURL: string): void; - initBackgroundThread(): void; + installSharedBridge(): void; } export default TurboModuleRegistry.getEnforcing('BackgroundThread'); diff --git a/native-modules/react-native-background-thread/src/SharedRPC.ts b/native-modules/react-native-background-thread/src/SharedRPC.ts index 7acd1815..e30afde1 100644 --- a/native-modules/react-native-background-thread/src/SharedRPC.ts +++ b/native-modules/react-native-background-thread/src/SharedRPC.ts @@ -3,6 +3,7 @@ export interface ISharedRPC { read(callId: string): string | number | boolean | undefined; has(callId: string): boolean; readonly pendingCount: number; + onWrite(callback: (callId: string) => void): void; } declare global { From 9e2349994e596d49f5781d065010624e446f06af Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 23:38:34 +0800 Subject: [PATCH 09/74] fix(shared-rpc): rename RuntimeExecutor to RPCRuntimeExecutor to avoid RN conflict - Rename RuntimeExecutor typedef to RPCRuntimeExecutor to avoid ambiguity with facebook::react::RuntimeExecutor - Remove __block from capturedInstance (not needed for lambda capture) - Update example app with proper RPC method dispatch --- example/react-native/background.js | 70 ++++++--- .../pages/BackgroundThreadTestPage.tsx | 139 ++++++++++-------- .../android/src/main/cpp/cpp-adapter.cpp | 2 +- .../cpp/SharedRPC.cpp | 4 +- .../cpp/SharedRPC.h | 6 +- .../BackgroundRunnerReactNativeDelegate.mm | 2 +- .../ios/BackgroundThreadManager.mm | 4 +- 7 files changed, 141 insertions(+), 86 deletions(-) diff --git a/example/react-native/background.js b/example/react-native/background.js index a59abb1a..9ebff635 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -1,13 +1,13 @@ - import ReactNative from 'react-native'; -// Wait for sharedRPC to be available, then set up onWrite listener +// ── SharedRPC onWrite handler ────────────────────────────────────────── +// Background runtime listens for writes from main runtime, +// processes the RPC call, and writes the result back. + function waitForSharedRPC(times = 0) { - if (globalThis.$$isNativeUiThread) { - return; - } + if (globalThis.$$isNativeUiThread) return; if (globalThis.sharedRPC) { - setupHandlers(); + setupRPCHandler(); return; } if (times > 5000) { @@ -17,32 +17,64 @@ function waitForSharedRPC(times = 0) { setTimeout(() => waitForSharedRPC(times + 1), 10); } -function setupHandlers() { - console.log('[BG] sharedRPC ready, setting up onWrite listener'); +function setupRPCHandler() { + console.log('[BG] sharedRPC ready, registering onWrite listener'); globalThis.sharedRPC.onWrite((callId) => { - console.log('[BG] onWrite notification:', callId); + // Skip result writes (those are our own responses) + if (callId.endsWith(':result')) return; + + const raw = globalThis.sharedRPC.read(callId); + if (raw === undefined) return; - const params = globalThis.sharedRPC.read(callId); - if (params === undefined) return; + console.log('[BG] RPC call received:', callId, raw); - console.log('[BG] received RPC call:', callId, params); + let params; + try { + params = typeof raw === 'string' ? JSON.parse(raw) : raw; + } catch { + params = raw; + } - // Process and write result back — this will notify main runtime - globalThis.sharedRPC.write(callId + ':result', 'echo: ' + params); + // Dispatch to handler by method name + const result = handleRPC(params); + + // Write result back — triggers main runtime's onWrite + globalThis.sharedRPC.write( + callId + ':result', + typeof result === 'string' ? result : JSON.stringify(result), + ); + console.log('[BG] RPC result written:', callId + ':result'); }); } +function handleRPC(params) { + const method = params?.method; + switch (method) { + case 'echo': + return { method: 'echo', result: params.params, ts: Date.now() }; + case 'add': + return { method: 'add', result: (params.params?.a ?? 0) + (params.params?.b ?? 0) }; + case 'delay': + // Simulate async — but onWrite is synchronous, so just return immediately + return { method: 'delay', result: 'done', requestedMs: params.params?.ms }; + default: + return { error: 'unknown method', method }; + } +} + waitForSharedRPC(); -// SharedStore: read config values set by main runtime -function checkSharedStore() { +// ── SharedStore demo ─────────────────────────────────────────────────── +// Periodically read config values set by the main runtime. + +function pollSharedStore() { if (globalThis.sharedStore) { const locale = globalThis.sharedStore.get('locale'); if (locale) { - console.log('[SharedStore BG] locale =', locale); + console.log('[BG SharedStore] locale =', locale); } } - setTimeout(checkSharedStore, 1000); + setTimeout(pollSharedStore, 3000); } -checkSharedStore(); +pollSharedStore(); diff --git a/example/react-native/pages/BackgroundThreadTestPage.tsx b/example/react-native/pages/BackgroundThreadTestPage.tsx index 501d6ee3..12f1912a 100644 --- a/example/react-native/pages/BackgroundThreadTestPage.tsx +++ b/example/react-native/pages/BackgroundThreadTestPage.tsx @@ -1,49 +1,51 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { TestPageBase, TestButton, TestResult } from './TestPageBase'; import { BackgroundThread } from '@onekeyfe/react-native-background-thread'; +// Install SharedStore & SharedRPC into main runtime (no-op on iOS, needed on Android) BackgroundThread.installSharedBridge(); export function BackgroundThreadTestPage() { const [storeResult, setStoreResult] = useState(''); - const [rpcResult, setRpcResult] = useState(''); - const [storeAvailable, setStoreAvailable] = useState(false); + const [rpcLog, setRpcLog] = useState(''); + const [ready, setReady] = useState(false); + // Wait for sharedStore & sharedRPC to be available useEffect(() => { - const check = setInterval(() => { + const timer = setInterval(() => { if (globalThis.sharedStore && globalThis.sharedRPC) { - setStoreAvailable(true); - clearInterval(check); + setReady(true); + clearInterval(timer); } }, 100); - return () => clearInterval(check); + return () => clearInterval(timer); }, []); - // Listen for RPC responses from background via SharedRPC.onWrite + // Register onWrite listener for RPC responses from background useEffect(() => { - if (!globalThis.sharedRPC) return; - - globalThis.sharedRPC.onWrite((callId: string) => { - // Only handle result callbacks + if (!ready) return; + globalThis.sharedRPC!.onWrite((callId: string) => { if (!callId.endsWith(':result')) return; - - const result = globalThis.sharedRPC?.read(callId); - if (result !== undefined) { - setRpcResult( - (prev) => - `${prev}\n[${new Date().toLocaleTimeString()}] Response: ${result}`, - ); - } + const raw = globalThis.sharedRPC?.read(callId); + if (raw === undefined) return; + const time = new Date().toLocaleTimeString(); + setRpcLog((prev) => `${prev}[${time}] ← ${raw}\n`); }); - }, [storeAvailable]); + }, [ready]); - // SharedStore test - const handleStoreTest = () => { - if (!globalThis.sharedStore) { - setStoreResult('SharedStore not available'); - return; - } + const appendLog = useCallback( + (msg: string) => { + const time = new Date().toLocaleTimeString(); + setRpcLog((prev) => `${prev}[${time}] → ${msg}\n`); + }, + [], + ); + + // ── SharedStore tests ──────────────────────────────────────────────── + + const handleStoreWrite = () => { + if (!globalThis.sharedStore) return; globalThis.sharedStore.set('locale', 'zh-CN'); globalThis.sharedStore.set('networkId', 42); globalThis.sharedStore.set('devMode', true); @@ -51,58 +53,68 @@ export function BackgroundThreadTestPage() { const values = keys .map((k: string) => `${k}=${globalThis.sharedStore?.get(k)}`) .join(', '); - setStoreResult(`Set 3 values. Current: ${values} | size=${globalThis.sharedStore.size}`); + setStoreResult(`Wrote 3 values → ${values} (size=${globalThis.sharedStore.size})`); }; - // SharedRPC test — write params, background onWrite fires, background writes result, main onWrite fires - const handleRpcTest = () => { - if (!globalThis.sharedRPC) { - setRpcResult('SharedRPC not available'); - return; - } + // ── SharedRPC tests ────────────────────────────────────────────────── + + const sendRPC = (method: string, params: Record) => { + if (!globalThis.sharedRPC) return; const callId = `rpc_${Date.now()}`; - globalThis.sharedRPC.write( - callId, - JSON.stringify({ method: 'echo', params: { ts: Date.now() } }), - ); - setRpcResult( - (prev) => - `${prev}\n[${new Date().toLocaleTimeString()}] Sent RPC: ${callId}`, - ); + const payload = JSON.stringify({ method, params }); + globalThis.sharedRPC.write(callId, payload); + appendLog(`${method}(${JSON.stringify(params)}) id=${callId}`); }; return ( + {/* Status */} + + SharedStore / SharedRPC: {ready ? 'Ready' : 'Waiting…'} + + {/* SharedStore */} - SharedStore (persistent key-value) - - Available: {storeAvailable ? 'Yes' : 'Waiting...'} - + SharedStore {/* SharedRPC */} - SharedRPC (onWrite cross-runtime) - + SharedRPC (onWrite) + + sendRPC('echo', { msg: 'hello', ts: Date.now() })} + disabled={!ready} + style={styles.rowButton} + /> + sendRPC('add', { a: 3, b: 7 })} + disabled={!ready} + style={styles.rowButton} + /> + sendRPC('foo', {})} + disabled={!ready} + style={[styles.rowButton, styles.warnButton]} + /> + setRpcResult('')} + onPress={() => setRpcLog('')} style={styles.clearButton} /> - {rpcResult ? ( + {rpcLog ? ( - {rpcResult.trim()} + {rpcLog.trimEnd()} ) : null} @@ -124,6 +136,17 @@ const styles = StyleSheet.create({ fontSize: 13, color: '#666', fontFamily: 'Courier New', + marginBottom: 4, + }, + buttonRow: { + flexDirection: 'row', + gap: 8, + }, + rowButton: { + flex: 1, + }, + warnButton: { + backgroundColor: '#FF9500', }, clearButton: { backgroundColor: '#8E8E93', diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index 6624cd29..2fe0c3e3 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -86,7 +86,7 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( jobject ref = env->NewGlobalRef(thiz); bool capturedIsMain = static_cast(isMain); - RuntimeExecutor executor = [ref, capturedIsMain](std::function work) { + RPCRuntimeExecutor executor = [ref, capturedIsMain](std::function work) { JNIEnv *env = getJNIEnv(); if (!env || !ref) return; diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index 7dec3069..660f63e7 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -10,7 +10,7 @@ void SharedRPC::install(jsi::Runtime &rt) { rt.global().setProperty(rt, "sharedRPC", std::move(obj)); } -void SharedRPC::install(jsi::Runtime &rt, RuntimeExecutor executor) { +void SharedRPC::install(jsi::Runtime &rt, RPCRuntimeExecutor executor) { auto rpc = std::make_shared(); auto obj = jsi::Object::createFromHostObject(rt, rpc); rt.global().setProperty(rt, "sharedRPC", std::move(obj)); @@ -33,7 +33,7 @@ void SharedRPC::reset() { void SharedRPC::notifyOtherRuntime(jsi::Runtime &callerRt, const std::string &callId) { // Collect executors and callbacks under lock, then invoke outside lock // to avoid deadlock (executor may schedule work that also acquires mutex_). - std::vector>> toNotify; + std::vector>> toNotify; { std::lock_guard lock(mutex_); for (auto &listener : listeners_) { diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.h b/native-modules/react-native-background-thread/cpp/SharedRPC.h index df6eb99f..1ec6e854 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.h +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.h @@ -15,11 +15,11 @@ using RPCValue = std::variant; // Executes a callback on a specific runtime's JS thread. // The implementation is platform-specific (iOS vs Android). -using RuntimeExecutor = std::function)>; +using RPCRuntimeExecutor = std::function)>; struct RuntimeListener { jsi::Runtime *runtime; - RuntimeExecutor executor; + RPCRuntimeExecutor executor; std::shared_ptr callback; // JS onWrite callback }; @@ -32,7 +32,7 @@ class SharedRPC : public jsi::HostObject { static void install(jsi::Runtime &rt); /// Install with executor — enables cross-runtime write notifications - static void install(jsi::Runtime &rt, RuntimeExecutor executor); + static void install(jsi::Runtime &rt, RPCRuntimeExecutor executor); static void reset(); diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 45a30cb0..d6129159 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -147,7 +147,7 @@ - (void)hostDidStart:(RCTHost *)host // Install SharedRPC with executor for cross-runtime notifications RCTInstance *bgInstance = _rctInstance; - RuntimeExecutor bgExecutor = [bgInstance](std::function work) { + RPCRuntimeExecutor bgExecutor = [bgInstance](std::function work) { [bgInstance callFunctionOnBufferedRuntimeExecutor:[work](jsi::Runtime &rt) { work(rt); }]; diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 2145d7e1..fb4aa4a8 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -72,8 +72,8 @@ + (void)installSharedBridgeInMainRuntime:(RCTHost *)host { SharedStore::install(runtime); // Install SharedRPC with executor for cross-runtime notifications - __block id capturedInstance = instance; - RuntimeExecutor mainExecutor = [capturedInstance](std::function work) { + id capturedInstance = instance; + RPCRuntimeExecutor mainExecutor = [capturedInstance](std::function work) { [capturedInstance callFunctionOnBufferedRuntimeExecutor:[work](jsi::Runtime &rt) { work(rt); }]; From 43f85ea9dc3e848064a52e261f328b30aec9c432 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 23:47:06 +0800 Subject: [PATCH 10/74] fix(shared-rpc): prevent crash on JS reload by deduplicating listeners with runtimeId MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a JS reload the main runtime gets a new jsi::Runtime* address, but the old listener (with stale executor capturing a deallocated RCTInstance) remained in listeners_ because dedup compared raw pointers. - Add runtimeId ("main"/"background") to RuntimeListener, dedup by id instead of runtime pointer on install — old stale listener is removed - Move ptr read inside runOnJSQueueThread block on Android to avoid race between scheduling and execution during reload --- .../android/src/main/cpp/cpp-adapter.cpp | 3 ++- .../com/backgroundthread/BackgroundThreadManager.kt | 4 +++- .../react-native-background-thread/cpp/SharedRPC.cpp | 12 ++++++++---- .../react-native-background-thread/cpp/SharedRPC.h | 5 ++++- .../ios/BackgroundRunnerReactNativeDelegate.mm | 2 +- .../ios/BackgroundThreadManager.mm | 2 +- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index 2fe0c3e3..a962afad 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -105,7 +105,8 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( env->DeleteLocalRef(cls); }; - SharedRPC::install(*rt, std::move(executor)); + std::string runtimeId = isMain ? "main" : "background"; + SharedRPC::install(*rt, std::move(executor), runtimeId); LOGI("SharedStore and SharedRPC installed (isMain=%d)", static_cast(isMain)); } diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index b134ac99..dd59c680 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -158,8 +158,10 @@ class BackgroundThreadManager private constructor() { @DoNotStrip fun scheduleOnJSThread(isMain: Boolean, workId: Long) { val context = if (isMain) mainReactContext else bgReactHost?.currentReactContext - val ptr = if (isMain) mainRuntimePtr else bgRuntimePtr context?.runOnJSQueueThread { + // Re-read ptr inside the block — if a reload happened between + // scheduling and execution, the old ptr may be stale. + val ptr = if (isMain) mainRuntimePtr else bgRuntimePtr if (ptr != 0L) { try { nativeExecuteWork(ptr, workId) diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index 660f63e7..5c47434b 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -10,18 +10,22 @@ void SharedRPC::install(jsi::Runtime &rt) { rt.global().setProperty(rt, "sharedRPC", std::move(obj)); } -void SharedRPC::install(jsi::Runtime &rt, RPCRuntimeExecutor executor) { +void SharedRPC::install(jsi::Runtime &rt, RPCRuntimeExecutor executor, + const std::string &runtimeId) { auto rpc = std::make_shared(); auto obj = jsi::Object::createFromHostObject(rt, rpc); rt.global().setProperty(rt, "sharedRPC", std::move(obj)); std::lock_guard lock(mutex_); - // Remove any existing listener for this runtime (reload scenario) + // Remove any existing listener with the same runtimeId (reload scenario — + // the old jsi::Runtime* may differ from &rt after reload) listeners_.erase( std::remove_if(listeners_.begin(), listeners_.end(), - [&rt](const RuntimeListener &l) { return l.runtime == &rt; }), + [&runtimeId](const RuntimeListener &l) { + return l.runtimeId == runtimeId; + }), listeners_.end()); - listeners_.push_back({&rt, std::move(executor), nullptr}); + listeners_.push_back({runtimeId, &rt, std::move(executor), nullptr}); } void SharedRPC::reset() { diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.h b/native-modules/react-native-background-thread/cpp/SharedRPC.h index 1ec6e854..570e04e7 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.h +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.h @@ -18,6 +18,7 @@ using RPCValue = std::variant; using RPCRuntimeExecutor = std::function)>; struct RuntimeListener { + std::string runtimeId; // "main" or "background" jsi::Runtime *runtime; RPCRuntimeExecutor executor; std::shared_ptr callback; // JS onWrite callback @@ -32,7 +33,9 @@ class SharedRPC : public jsi::HostObject { static void install(jsi::Runtime &rt); /// Install with executor — enables cross-runtime write notifications - static void install(jsi::Runtime &rt, RPCRuntimeExecutor executor); + /// runtimeId should be "main" or "background" — used for dedup on reload. + static void install(jsi::Runtime &rt, RPCRuntimeExecutor executor, + const std::string &runtimeId); static void reset(); diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index d6129159..9325cee2 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -152,7 +152,7 @@ - (void)hostDidStart:(RCTHost *)host work(rt); }]; }; - SharedRPC::install(runtime, std::move(bgExecutor)); + SharedRPC::install(runtime, std::move(bgExecutor), "background"); [BTLogger info:@"SharedStore and SharedRPC installed in background runtime"]; }]; } diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index fb4aa4a8..9c1e2eac 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -78,7 +78,7 @@ + (void)installSharedBridgeInMainRuntime:(RCTHost *)host { work(rt); }]; }; - SharedRPC::install(runtime, std::move(mainExecutor)); + SharedRPC::install(runtime, std::move(mainExecutor), "main"); [BTLogger info:@"SharedStore and SharedRPC installed in main runtime"]; }]; } From 92ce34a36f8e42c79d8c060b26d4fcc3411497ca Mon Sep 17 00:00:00 2001 From: huhuanming Date: Mon, 30 Mar 2026 23:57:46 +0800 Subject: [PATCH 11/74] fix(shared-rpc): leak stale jsi::Function callback on reload to prevent crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On JS reload, the old runtime is destroyed before SharedRPC::install() is called for the new runtime. Erasing the old listener triggers ~jsi::Function() which needs the dead runtime → null deref crash in Pointer::~Pointer(). Fix: move the old callback shared_ptr to the heap (intentional leak) before erasing, so ~jsi::Function() is never called on a dead runtime. --- .../react-native-background-thread/cpp/SharedRPC.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index 5c47434b..8e4997e5 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -17,8 +17,16 @@ void SharedRPC::install(jsi::Runtime &rt, RPCRuntimeExecutor executor, rt.global().setProperty(rt, "sharedRPC", std::move(obj)); std::lock_guard lock(mutex_); - // Remove any existing listener with the same runtimeId (reload scenario — - // the old jsi::Runtime* may differ from &rt after reload) + // Remove any existing listener with the same runtimeId (reload scenario). + // IMPORTANT: The old listener's callback is a jsi::Function tied to the old + // runtime. On reload, that runtime is already destroyed, so calling + // ~jsi::Function() would crash (null deref in Pointer::~Pointer). + // We intentionally leak the callback to avoid this. + for (auto &listener : listeners_) { + if (listener.runtimeId == runtimeId && listener.callback) { + new std::shared_ptr(std::move(listener.callback)); + } + } listeners_.erase( std::remove_if(listeners_.begin(), listeners_.end(), [&runtimeId](const RuntimeListener &l) { From 700ea1bdb96287a554aa9352ab1130c302ca6863 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 00:39:18 +0800 Subject: [PATCH 12/74] fix: initialize Android shared bridge at app startup --- .../main/java/com/example/MainApplication.kt | 22 ++++++++++++++++++ example/react-native/package.json | 2 +- .../pages/BackgroundThreadTestPage.tsx | 4 ---- .../android/src/main/cpp/cpp-adapter.cpp | 18 ++++++++++++++- .../BackgroundThreadManager.kt | 23 ++++++++++++++++++- .../cpp/SharedRPC.cpp | 21 ++++++++++++++--- 6 files changed, 80 insertions(+), 10 deletions(-) diff --git a/example/react-native/android/app/src/main/java/com/example/MainApplication.kt b/example/react-native/android/app/src/main/java/com/example/MainApplication.kt index 41f852a5..3a068b86 100644 --- a/example/react-native/android/app/src/main/java/com/example/MainApplication.kt +++ b/example/react-native/android/app/src/main/java/com/example/MainApplication.kt @@ -4,8 +4,11 @@ import android.app.Application import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactHost +import com.facebook.react.ReactInstanceEventListener import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative +import com.facebook.react.bridge.ReactContext import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.backgroundthread.BackgroundThreadManager import com.margelo.nitro.nativelogger.OneKeyLog class MainApplication : Application(), ReactApplication { @@ -25,5 +28,24 @@ class MainApplication : Application(), ReactApplication { super.onCreate() OneKeyLog.info("App", "Application started") loadReactNative(this) + + // Mirror iOS AppDelegate's hostDidStart: — install SharedBridge and start + // background runner as soon as the main React context is ready. + reactHost.addReactInstanceEventListener(object : ReactInstanceEventListener { + override fun onReactContextInitialized(context: ReactContext) { + val manager = BackgroundThreadManager.getInstance() + val reactAppContext = context as com.facebook.react.bridge.ReactApplicationContext + manager.installSharedBridgeInMainRuntime(reactAppContext) + + val bgURL = if (BuildConfig.DEBUG) { + // Use the same host detection as React Native (emulator vs device) + val host = com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getServerHost(this@MainApplication, 8082) + "http://$host/background.bundle?platform=android&dev=true&lazy=false&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true" + } else { + "background.bundle" + } + manager.startBackgroundRunnerWithEntryURL(reactAppContext, bgURL) + } + }) } } diff --git a/example/react-native/package.json b/example/react-native/package.json index 7d16da94..67008ca3 100644 --- a/example/react-native/package.json +++ b/example/react-native/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "private": true, "scripts": { - "android": "react-native run-android", + "android": "node ./scripts/run-android.js", "background": "react-native start --port 8082", "ios": "react-native run-ios", "lint": "eslint .", diff --git a/example/react-native/pages/BackgroundThreadTestPage.tsx b/example/react-native/pages/BackgroundThreadTestPage.tsx index 12f1912a..b15fa981 100644 --- a/example/react-native/pages/BackgroundThreadTestPage.tsx +++ b/example/react-native/pages/BackgroundThreadTestPage.tsx @@ -1,10 +1,6 @@ import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { TestPageBase, TestButton, TestResult } from './TestPageBase'; -import { BackgroundThread } from '@onekeyfe/react-native-background-thread'; - -// Install SharedStore & SharedRPC into main runtime (no-op on iOS, needed on Android) -BackgroundThread.installSharedBridge(); export function BackgroundThreadTestPage() { const [storeResult, setStoreResult] = useState(''); diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index a962afad..d1a32115 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -51,6 +51,7 @@ static int64_t gNextWorkId = 0; extern "C" JNIEXPORT void JNICALL Java_com_backgroundthread_BackgroundThreadManager_nativeExecuteWork( JNIEnv *env, jobject thiz, jlong runtimePtr, jlong workId) { + LOGI("nativeExecuteWork: runtimePtr=%ld, workId=%ld", (long)runtimePtr, (long)workId); auto *rt = reinterpret_cast(runtimePtr); if (!rt) return; @@ -88,7 +89,10 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( RPCRuntimeExecutor executor = [ref, capturedIsMain](std::function work) { JNIEnv *env = getJNIEnv(); - if (!env || !ref) return; + if (!env || !ref) { + LOGE("executor: env=%p, ref=%p — aborting", env, ref); + return; + } int64_t workId; { @@ -100,7 +104,19 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( jclass cls = env->GetObjectClass(ref); jmethodID mid = env->GetMethodID(cls, "scheduleOnJSThread", "(ZJ)V"); if (mid) { + LOGI("executor: calling scheduleOnJSThread(isMain=%d, workId=%ld)", capturedIsMain, (long)workId); env->CallVoidMethod(ref, mid, static_cast(capturedIsMain), static_cast(workId)); + if (env->ExceptionCheck()) { + LOGE("executor: JNI exception after scheduleOnJSThread"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } else { + LOGE("executor: scheduleOnJSThread method not found!"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } } env->DeleteLocalRef(cls); }; diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index dd59c680..990e8095 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -97,9 +97,23 @@ class BackgroundThreadManager private constructor() { val appContext = context.applicationContext val bundleLoader = if (entryURL.startsWith("http")) { + // Dev server: download bundle to temp file first, then load from file. + // loadScriptFromFile only accepts local file paths, not HTTP URLs. object : JSBundleLoader() { override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { - delegate.loadScriptFromFile(entryURL, entryURL, false) + val tempFile = java.io.File(appContext.cacheDir, "background.bundle") + try { + java.net.URL(entryURL).openStream().use { input -> + tempFile.outputStream().use { output -> + input.copyTo(output) + } + } + BTLogger.info("Background bundle downloaded to ${tempFile.absolutePath}") + } catch (e: Exception) { + BTLogger.error("Failed to download background bundle: ${e.message}") + throw RuntimeException("Failed to download background bundle from $entryURL", e) + } + delegate.loadScriptFromFile(tempFile.absolutePath, entryURL, false) return entryURL } } @@ -158,16 +172,23 @@ class BackgroundThreadManager private constructor() { @DoNotStrip fun scheduleOnJSThread(isMain: Boolean, workId: Long) { val context = if (isMain) mainReactContext else bgReactHost?.currentReactContext + BTLogger.info("scheduleOnJSThread: isMain=$isMain, workId=$workId, context=${context != null}") + if (context == null) { + BTLogger.error("scheduleOnJSThread: context is null! isMain=$isMain, mainCtx=${mainReactContext != null}, bgHost=${bgReactHost != null}, bgCtx=${bgReactHost?.currentReactContext != null}") + } context?.runOnJSQueueThread { // Re-read ptr inside the block — if a reload happened between // scheduling and execution, the old ptr may be stale. val ptr = if (isMain) mainRuntimePtr else bgRuntimePtr + BTLogger.info("scheduleOnJSThread runOnJSQueueThread: isMain=$isMain, workId=$workId, ptr=$ptr") if (ptr != 0L) { try { nativeExecuteWork(ptr, workId) } catch (e: Exception) { BTLogger.error("Error executing work on JS thread: ${e.message}") } + } else { + BTLogger.error("scheduleOnJSThread: ptr is 0! isMain=$isMain") } } } diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index 8e4997e5..72cf4da6 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -1,5 +1,12 @@ #include "SharedRPC.h" +#ifdef __ANDROID__ +#include +#define RPC_LOG(...) __android_log_print(ANDROID_LOG_INFO, "SharedRPC", __VA_ARGS__) +#else +#define RPC_LOG(...) +#endif + std::mutex SharedRPC::mutex_; std::unordered_map SharedRPC::slots_; std::vector SharedRPC::listeners_; @@ -48,22 +55,30 @@ void SharedRPC::notifyOtherRuntime(jsi::Runtime &callerRt, const std::string &ca std::vector>> toNotify; { std::lock_guard lock(mutex_); + RPC_LOG("notifyOtherRuntime: callId=%s, listeners=%zu, callerRt=%p", + callId.c_str(), listeners_.size(), &callerRt); for (auto &listener : listeners_) { + RPC_LOG(" listener: id=%s, rt=%p, hasCallback=%d", + listener.runtimeId.c_str(), listener.runtime, listener.callback != nullptr); if (listener.runtime == &callerRt) continue; if (!listener.callback) continue; toNotify.emplace_back(listener.executor, listener.callback); } + RPC_LOG(" toNotify count: %zu", toNotify.size()); } for (auto &[executor, cb] : toNotify) { auto id = callId; + RPC_LOG(" invoking executor for callId=%s", id.c_str()); executor([cb, id](jsi::Runtime &rt) { + RPC_LOG(" executor work running for callId=%s", id.c_str()); try { cb->call(rt, jsi::String::createFromUtf8(rt, id)); - } catch (const jsi::JSError &) { - // Swallow — listener threw, not our problem + RPC_LOG(" cb->call succeeded for callId=%s", id.c_str()); + } catch (const jsi::JSError &e) { + RPC_LOG(" JSError in cb->call: %s", e.getMessage().c_str()); } catch (...) { - // Runtime may be torn down + RPC_LOG(" Unknown error in cb->call"); } }); } From e10c79c5e14b4e48322521678acda4ad906df444 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 01:06:28 +0800 Subject: [PATCH 13/74] fix: stabilize background thread runtime init --- .../main/java/com/example/MainApplication.kt | 1 + example/react-native/background.js | 29 +++++-------------- .../android/src/main/cpp/cpp-adapter.cpp | 19 ++++++++++++ .../BackgroundThreadManager.kt | 16 +++++++++- .../BackgroundRunnerReactNativeDelegate.mm | 18 ++++++++++++ 5 files changed, 61 insertions(+), 22 deletions(-) diff --git a/example/react-native/android/app/src/main/java/com/example/MainApplication.kt b/example/react-native/android/app/src/main/java/com/example/MainApplication.kt index 3a068b86..6fea8e2e 100644 --- a/example/react-native/android/app/src/main/java/com/example/MainApplication.kt +++ b/example/react-native/android/app/src/main/java/com/example/MainApplication.kt @@ -35,6 +35,7 @@ class MainApplication : Application(), ReactApplication { override fun onReactContextInitialized(context: ReactContext) { val manager = BackgroundThreadManager.getInstance() val reactAppContext = context as com.facebook.react.bridge.ReactApplicationContext + manager.setReactPackages(PackageList(this@MainApplication).packages) manager.installSharedBridgeInMainRuntime(reactAppContext) val bgURL = if (BuildConfig.DEBUG) { diff --git a/example/react-native/background.js b/example/react-native/background.js index 9ebff635..394d41ef 100644 --- a/example/react-native/background.js +++ b/example/react-native/background.js @@ -4,21 +4,11 @@ import ReactNative from 'react-native'; // Background runtime listens for writes from main runtime, // processes the RPC call, and writes the result back. -function waitForSharedRPC(times = 0) { - if (globalThis.$$isNativeUiThread) return; - if (globalThis.sharedRPC) { - setupRPCHandler(); - return; - } - if (times > 5000) { - console.error('[BG] sharedRPC not available after timeout'); - return; - } - setTimeout(() => waitForSharedRPC(times + 1), 10); -} +let hasRegisteredRPCHandler = false; function setupRPCHandler() { - console.log('[BG] sharedRPC ready, registering onWrite listener'); + if (hasRegisteredRPCHandler || !globalThis.sharedRPC) return false; + hasRegisteredRPCHandler = true; globalThis.sharedRPC.onWrite((callId) => { // Skip result writes (those are our own responses) @@ -27,8 +17,6 @@ function setupRPCHandler() { const raw = globalThis.sharedRPC.read(callId); if (raw === undefined) return; - console.log('[BG] RPC call received:', callId, raw); - let params; try { params = typeof raw === 'string' ? JSON.parse(raw) : raw; @@ -44,8 +32,9 @@ function setupRPCHandler() { callId + ':result', typeof result === 'string' ? result : JSON.stringify(result), ); - console.log('[BG] RPC result written:', callId + ':result'); }); + + return true; } function handleRPC(params) { @@ -63,17 +52,15 @@ function handleRPC(params) { } } -waitForSharedRPC(); +globalThis.__setupBackgroundRPCHandler = setupRPCHandler; +setupRPCHandler(); // ── SharedStore demo ─────────────────────────────────────────────────── // Periodically read config values set by the main runtime. function pollSharedStore() { if (globalThis.sharedStore) { - const locale = globalThis.sharedStore.get('locale'); - if (locale) { - console.log('[BG SharedStore] locale =', locale); - } + globalThis.sharedStore.get('locale'); } setTimeout(pollSharedStore, 3000); } diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index d1a32115..70f40dc1 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -42,6 +42,22 @@ static void stubJsiFunction(jsi::Runtime &runtime, jsi::Object &object, const ch })); } +static void invokeOptionalGlobalFunction(jsi::Runtime &runtime, const char *name) { + try { + auto fnValue = runtime.global().getProperty(runtime, name); + if (!fnValue.isObject() || !fnValue.asObject(runtime).isFunction(runtime)) { + return; + } + + auto fn = fnValue.asObject(runtime).asFunction(runtime); + fn.call(runtime); + } catch (const jsi::JSError &e) { + LOGE("JSError calling global function %s: %s", name, e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("Error calling global function %s: %s", name, e.what()); + } +} + // ── Pending work map for cross-runtime executor ─────────────────────── static std::mutex gWorkMutex; static std::unordered_map> gPendingWork; @@ -124,6 +140,9 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( std::string runtimeId = isMain ? "main" : "background"; SharedRPC::install(*rt, std::move(executor), runtimeId); LOGI("SharedStore and SharedRPC installed (isMain=%d)", static_cast(isMain)); + if (!capturedIsMain) { + invokeOptionalGlobalFunction(*rt, "__setupBackgroundRPCHandler"); + } } // ── nativeSetupErrorHandler ───────────────────────────────────────────── diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 990e8095..3ccd329d 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -1,5 +1,6 @@ package com.backgroundthread +import com.facebook.react.ReactPackage import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.ReactInstanceEventListener import com.facebook.react.bridge.JSBundleLoader @@ -12,6 +13,7 @@ import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate import com.facebook.react.fabric.ComponentFactory import com.facebook.react.runtime.ReactHostImpl import com.facebook.react.runtime.hermes.HermesInstance +import com.facebook.react.shell.MainReactPackage /** * Singleton manager for the background React Native runtime. @@ -25,6 +27,7 @@ import com.facebook.react.runtime.hermes.HermesInstance class BackgroundThreadManager private constructor() { private var bgReactHost: ReactHostImpl? = null + private var reactPackages: List = emptyList() @Volatile private var bgRuntimePtr: Long = 0 @@ -65,6 +68,10 @@ class BackgroundThreadManager private constructor() { * Install SharedBridge HostObject into the main (UI) runtime. * Call this from installSharedBridge(). */ + fun setReactPackages(packages: List) { + reactPackages = packages.toList() + } + fun installSharedBridgeInMainRuntime(context: ReactApplicationContext) { mainReactContext = context context.runOnJSQueueThread { @@ -95,6 +102,13 @@ class BackgroundThreadManager private constructor() { BTLogger.info("Starting background runner with entryURL: $entryURL") val appContext = context.applicationContext + val packages = + if (reactPackages.isNotEmpty()) { + reactPackages + } else { + BTLogger.warn("No ReactPackages registered for background runtime; falling back to MainReactPackage only") + listOf(MainReactPackage()) + } val bundleLoader = if (entryURL.startsWith("http")) { // Dev server: download bundle to temp file first, then load from file. @@ -124,7 +138,7 @@ class BackgroundThreadManager private constructor() { val delegate = DefaultReactHostDelegate( jsMainModulePath = MODULE_NAME, jsBundleLoader = bundleLoader, - reactPackages = emptyList(), + reactPackages = packages, jsRuntimeFactory = HermesInstance(), turboModuleManagerDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder(), ) diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 9325cee2..4e45c2b0 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -54,6 +54,23 @@ static void stubJsiFunction(jsi::Runtime &runtime, jsi::Object &object, const ch })); } +static void invokeOptionalGlobalFunction(jsi::Runtime &runtime, const char *name) +{ + try { + jsi::Value fnValue = runtime.global().getProperty(runtime, name); + if (!fnValue.isObject() || !fnValue.asObject(runtime).isFunction(runtime)) { + return; + } + + jsi::Function fn = fnValue.asObject(runtime).asFunction(runtime); + fn.call(runtime); + } catch (const jsi::JSError &e) { + [BTLogger error:[NSString stringWithFormat:@"JSError calling global function %s: %s", name, e.getMessage().c_str()]]; + } catch (const std::exception &e) { + [BTLogger error:[NSString stringWithFormat:@"Error calling global function %s: %s", name, e.what()]]; + } +} + @interface BackgroundReactNativeDelegate () { RCTInstance *_rctInstance; std::string _origin; @@ -154,6 +171,7 @@ - (void)hostDidStart:(RCTHost *)host }; SharedRPC::install(runtime, std::move(bgExecutor), "background"); [BTLogger info:@"SharedStore and SharedRPC installed in background runtime"]; + invokeOptionalGlobalFunction(runtime, "__setupBackgroundRPCHandler"); }]; } From 6556814c6519688b097ae844917cc48b9962c2a3 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 01:11:14 +0800 Subject: [PATCH 14/74] Update package.json --- example/react-native/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/react-native/package.json b/example/react-native/package.json index 67008ca3..7d16da94 100644 --- a/example/react-native/package.json +++ b/example/react-native/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "private": true, "scripts": { - "android": "node ./scripts/run-android.js", + "android": "react-native run-android", "background": "react-native start --port 8082", "ios": "react-native run-ios", "lint": "eslint .", From e90945bdcdbae5f587c7f0c5bfb9c4e1bc7a539f Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 01:11:42 +0800 Subject: [PATCH 15/74] 1.1.47 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index f49726ba..ce54f2ec 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index f4e035cf..fe22485f 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 8440bafd..3a8e0502 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 382b3363..ebf4c8d0 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 5781d94c..8790714a 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 6acc314d..29f1a337 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 07c1eacd..ecb8883b 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index d65fe609..e7bc7806 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 40e2fe3b..d5d79fe0 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index f8fdce12..25385afa 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.46", + "version": "1.1.47", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 1d406c10..ab23c705 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 100f7d87..9b25e558 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 44a0ad17..bf63766a 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.46", + "version": "1.1.47", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 8daf58ec..e95442d6 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.46", + "version": "1.1.47", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index f6d35de2..ec984f85 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.46", + "version": "1.1.47", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 97d4b5dc..e452efad 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.46", + "version": "1.1.47", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 95f2090e..32bef153 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.46", + "version": "1.1.47", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 205d051ae93bdf96af4d12b5f65108fc2b507726 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 03:03:11 +0800 Subject: [PATCH 16/74] feat: support background bundle pair bootstrap --- .../BackgroundThreadManager.kt | 85 ++++++--- .../BackgroundRunnerReactNativeDelegate.mm | 61 +++++- .../ios/BackgroundThreadManager.mm | 4 +- .../ReactNativeBundleUpdate.kt | 135 +++++++++++-- .../ios/ReactNativeBundleUpdate.swift | 178 ++++++++++++++++-- .../src/ReactNativeBundleUpdate.nitro.ts | 2 + 6 files changed, 405 insertions(+), 60 deletions(-) diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 3ccd329d..526405e4 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -1,5 +1,6 @@ package com.backgroundthread +import android.net.Uri import com.facebook.react.ReactPackage import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.ReactInstanceEventListener @@ -14,6 +15,7 @@ import com.facebook.react.fabric.ComponentFactory import com.facebook.react.runtime.ReactHostImpl import com.facebook.react.runtime.hermes.HermesInstance import com.facebook.react.shell.MainReactPackage +import java.io.File /** * Singleton manager for the background React Native runtime. @@ -92,13 +94,61 @@ class BackgroundThreadManager private constructor() { // ── Background runner lifecycle ───────────────────────────────────────── + private fun isRemoteBundleUrl(entryURL: String): Boolean { + return entryURL.startsWith("http://") || entryURL.startsWith("https://") + } + + private fun resolveLocalBundlePath(entryURL: String): String? { + if (entryURL.startsWith("file://")) { + return Uri.parse(entryURL).path + } + if (entryURL.startsWith("/")) { + return entryURL + } + return null + } + + private fun createDownloadedBundleLoader(appContext: android.content.Context, entryURL: String): JSBundleLoader { + return object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + val tempFile = File(appContext.cacheDir, "background.bundle") + try { + java.net.URL(entryURL).openStream().use { input -> + tempFile.outputStream().use { output -> + input.copyTo(output) + } + } + BTLogger.info("Background bundle downloaded to ${tempFile.absolutePath}") + } catch (e: Exception) { + BTLogger.error("Failed to download background bundle: ${e.message}") + throw RuntimeException("Failed to download background bundle from $entryURL", e) + } + delegate.loadScriptFromFile(tempFile.absolutePath, entryURL, false) + return entryURL + } + } + } + + private fun createLocalFileBundleLoader(localPath: String, sourceURL: String): JSBundleLoader { + return object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + val bundleFile = File(localPath) + if (!bundleFile.exists()) { + BTLogger.error("Background bundle file does not exist: $localPath") + throw RuntimeException("Background bundle file does not exist: $localPath") + } + delegate.loadScriptFromFile(bundleFile.absolutePath, sourceURL, false) + return sourceURL + } + } + } + @OptIn(UnstableReactNativeAPI::class) fun startBackgroundRunnerWithEntryURL(context: ReactApplicationContext, entryURL: String) { if (isStarted) { BTLogger.warn("Background runner already started") return } - isStarted = true BTLogger.info("Starting background runner with entryURL: $entryURL") val appContext = context.applicationContext @@ -106,34 +156,18 @@ class BackgroundThreadManager private constructor() { if (reactPackages.isNotEmpty()) { reactPackages } else { - BTLogger.warn("No ReactPackages registered for background runtime; falling back to MainReactPackage only") + BTLogger.warn("No ReactPackages registered for background runtime; call setReactPackages(...) from host before start. Falling back to MainReactPackage only.") listOf(MainReactPackage()) } - val bundleLoader = if (entryURL.startsWith("http")) { - // Dev server: download bundle to temp file first, then load from file. - // loadScriptFromFile only accepts local file paths, not HTTP URLs. - object : JSBundleLoader() { - override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { - val tempFile = java.io.File(appContext.cacheDir, "background.bundle") - try { - java.net.URL(entryURL).openStream().use { input -> - tempFile.outputStream().use { output -> - input.copyTo(output) - } - } - BTLogger.info("Background bundle downloaded to ${tempFile.absolutePath}") - } catch (e: Exception) { - BTLogger.error("Failed to download background bundle: ${e.message}") - throw RuntimeException("Failed to download background bundle from $entryURL", e) - } - delegate.loadScriptFromFile(tempFile.absolutePath, entryURL, false) - return entryURL - } + val localBundlePath = resolveLocalBundlePath(entryURL) + val bundleLoader = + when { + isRemoteBundleUrl(entryURL) -> createDownloadedBundleLoader(appContext, entryURL) + localBundlePath != null -> createLocalFileBundleLoader(localBundlePath, entryURL) + entryURL.startsWith("assets://") -> JSBundleLoader.createAssetLoader(appContext, entryURL, true) + else -> JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) } - } else { - JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) - } val delegate = DefaultReactHostDelegate( jsMainModulePath = MODULE_NAME, @@ -177,6 +211,7 @@ class BackgroundThreadManager private constructor() { }) host.start() + isStarted = true } /** diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 4e45c2b0..15729622 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -71,6 +71,51 @@ static void invokeOptionalGlobalFunction(jsi::Runtime &runtime, const char *name } } +static NSURL *resolveMainBundleResourceURL(NSString *resourceName) +{ + if (resourceName.length == 0) { + return nil; + } + + NSURL *directURL = [[NSBundle mainBundle] URLForResource:resourceName withExtension:nil]; + if (directURL) { + return directURL; + } + + NSString *normalizedName = [resourceName hasPrefix:@"/"] + ? resourceName.lastPathComponent + : resourceName; + NSString *extension = normalizedName.pathExtension; + NSString *baseName = normalizedName.stringByDeletingPathExtension; + if (baseName.length == 0) { + return nil; + } + + return [[NSBundle mainBundle] URLForResource:baseName + withExtension:extension.length > 0 ? extension : nil]; +} + +static NSURL *resolveBundleSourceURL(NSString *jsBundleSourceNS) +{ + if (jsBundleSourceNS.length == 0) { + return nil; + } + + NSURL *parsedURL = [NSURL URLWithString:jsBundleSourceNS]; + if (parsedURL.scheme.length > 0) { + if (parsedURL.isFileURL && parsedURL.path.length > 0) { + return [NSURL fileURLWithPath:parsedURL.path]; + } + return parsedURL; + } + + if ([jsBundleSourceNS hasPrefix:@"/"]) { + return [NSURL fileURLWithPath:jsBundleSourceNS]; + } + + return resolveMainBundleResourceURL(jsBundleSourceNS); +} + @interface BackgroundReactNativeDelegate () { RCTInstance *_rctInstance; std::string _origin; @@ -127,17 +172,19 @@ - (NSURL *)bundleURL { if (!_jsBundleSource.empty()) { NSString *jsBundleSourceNS = [NSString stringWithUTF8String:_jsBundleSource.c_str()]; - NSURL *url = [NSURL URLWithString:jsBundleSourceNS]; - if (url && url.scheme) { - return url; + NSURL *resolvedURL = resolveBundleSourceURL(jsBundleSourceNS); + if (resolvedURL) { + return resolvedURL; } - if ([jsBundleSourceNS hasSuffix:@".jsbundle"]) { - return [[NSBundle mainBundle] URLForResource:jsBundleSourceNS withExtension:nil]; - } + [BTLogger warn:[NSString stringWithFormat:@"Unable to resolve custom jsBundleSource=%@", jsBundleSourceNS]]; } - return [[NSBundle mainBundle] URLForResource: @"background" withExtension: @"bundle"]; + NSURL *defaultBundleURL = resolveMainBundleResourceURL(@"background.bundle"); + if (defaultBundleURL) { + return defaultBundleURL; + } + return [[NSBundle mainBundle] URLForResource:@"background" withExtension:@"bundle"]; } - (void)hostDidStart:(RCTHost *)host diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 9c1e2eac..4e3101bf 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -107,9 +107,7 @@ - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL { self.reactNativeFactoryDelegate = [[BackgroundReactNativeDelegate alloc] init]; self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self.reactNativeFactoryDelegate]; - #if DEBUG - [self.reactNativeFactoryDelegate setJsBundleSource:std::string([entryURL UTF8String])]; - #endif + [self.reactNativeFactoryDelegate setJsBundleSource:std::string([entryURL UTF8String])]; [self.reactNativeFactory.rootViewFactory viewWithModuleName:MODULE_NAME initialProperties:initialProperties diff --git a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt index da55c424..5bd05071 100644 --- a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt +++ b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt @@ -97,6 +97,11 @@ object BundleUpdateStoreAndroid { private const val PREFS_NAME = "BundleUpdatePrefs" internal const val NATIVE_VERSION_PREFS_NAME = "NativeVersionPrefs" private const val CURRENT_BUNDLE_VERSION_KEY = "currentBundleVersion" + private const val MAIN_JS_BUNDLE_FILE_NAME = "main.jsbundle.hbc" + private const val BACKGROUND_BUNDLE_FILE_NAME = "background.bundle" + private const val METADATA_REQUIRES_BACKGROUND_BUNDLE_KEY = "requiresBackgroundBundle" + private const val METADATA_BACKGROUND_PROTOCOL_VERSION_KEY = "backgroundProtocolVersion" + private const val SUPPORTED_BACKGROUND_PROTOCOL_VERSION = "1" fun getDownloadBundleDir(context: Context): String { val dir = File(context.filesDir, "onekey-bundle-download") @@ -401,6 +406,26 @@ object BundleUpdateStoreAndroid { return metadata } + private fun isReservedMetadataKey(key: String): Boolean { + return key == METADATA_REQUIRES_BACKGROUND_BUNDLE_KEY || + key == METADATA_BACKGROUND_PROTOCOL_VERSION_KEY + } + + private fun getFileMetadataEntries(metadata: Map): Map { + return metadata.filterKeys { key -> !isReservedMetadataKey(key) } + } + + private fun metadataRequiresBackgroundBundle(metadata: Map): Boolean { + return metadata[METADATA_REQUIRES_BACKGROUND_BUNDLE_KEY] + ?.lowercase() + ?.let { value -> value == "1" || value == "true" || value == "yes" } + ?: false + } + + private fun metadataBackgroundProtocolVersion(metadata: Map): String { + return metadata[METADATA_BACKGROUND_PROTOCOL_VERSION_KEY] ?: "" + } + fun readMetadataFileSha256(signature: String?): String? { if (signature.isNullOrEmpty()) return null @@ -534,11 +559,12 @@ object BundleUpdateStoreAndroid { val parentBundleDir = getBundleDir(context) val folderName = "$appVersion-$bundleVersion" val jsBundleDir = File(parentBundleDir, folderName).absolutePath + "/" + val fileEntries = getFileMetadataEntries(metadata) - if (!validateFilesRecursive(dir, metadata, jsBundleDir)) return false + if (!validateFilesRecursive(dir, fileEntries, jsBundleDir)) return false // Verify completeness - for (entry in metadata.entries) { + for (entry in fileEntries.entries) { val expectedFile = File(jsBundleDir + entry.key) if (!expectedFile.exists()) { OneKeyLog.error("BundleUpdate", "[bundle-verify] File listed in metadata but missing on disk: ${entry.key}") @@ -637,7 +663,48 @@ object BundleUpdateStoreAndroid { } } - fun getCurrentBundleMainJSBundle(context: Context): String? { + fun validateBundlePairCompatibility(bundleDir: String, metadata: Map): Boolean { + val mainBundleFile = File(bundleDir, MAIN_JS_BUNDLE_FILE_NAME) + if (!mainBundleFile.exists()) { + OneKeyLog.error( + "BundleUpdate", + "bundle pair invalid: main.jsbundle.hbc is missing at ${mainBundleFile.absolutePath}", + ) + return false + } + + if (!metadataRequiresBackgroundBundle(metadata)) { + return true + } + + val protocolVersion = metadataBackgroundProtocolVersion(metadata) + if (protocolVersion.isEmpty() || protocolVersion != SUPPORTED_BACKGROUND_PROTOCOL_VERSION) { + OneKeyLog.error( + "BundleUpdate", + "backgroundProtocolVersion mismatch: expected=$SUPPORTED_BACKGROUND_PROTOCOL_VERSION, actual=$protocolVersion", + ) + return false + } + + val backgroundBundleFile = File(bundleDir, BACKGROUND_BUNDLE_FILE_NAME) + if (!backgroundBundleFile.exists()) { + OneKeyLog.error( + "BundleUpdate", + "requiresBackgroundBundle is true but background.bundle is missing at ${backgroundBundleFile.absolutePath}", + ) + return false + } + + return true + } + + private data class ValidatedBundleInfo( + val bundleDir: String, + val currentBundleVersion: String, + val metadata: Map, + ) + + private fun getValidatedCurrentBundleInfo(context: Context): ValidatedBundleInfo? { processPreLaunchPendingTask(context) return try { val currentAppVersion = getAppVersion(context) @@ -651,7 +718,7 @@ object BundleUpdateStoreAndroid { val prevNativeVersion = getNativeVersion(context) if (prevNativeVersion.isEmpty()) { OneKeyLog.warn("BundleUpdate", "getJsBundlePath: prevNativeVersion is empty") - return "" + return null } if (currentAppVersion != prevNativeVersion) { @@ -707,23 +774,42 @@ object BundleUpdateStoreAndroid { } } - val mainJSBundleFile = File(bundleDir, "main.jsbundle.hbc") - val mainJSBundlePath = mainJSBundleFile.absolutePath - OneKeyLog.info("BundleUpdate", "mainJSBundlePath: $mainJSBundlePath") - if (!mainJSBundleFile.exists()) { - OneKeyLog.info("BundleUpdate", "mainJSBundleFile does not exist") + if (!validateBundlePairCompatibility(bundleDir, metadata)) { return null } - mainJSBundlePath + + ValidatedBundleInfo( + bundleDir = bundleDir, + currentBundleVersion = currentBundleVersion, + metadata = metadata, + ) } catch (e: Exception) { OneKeyLog.error("BundleUpdate", "Error getting bundle: ${e.message}") null } } + fun getCurrentBundleEntryPath(context: Context, entryFileName: String): String? { + val bundleInfo = getValidatedCurrentBundleInfo(context) ?: return null + val entryFile = File(bundleInfo.bundleDir, entryFileName) + if (!entryFile.exists()) { + OneKeyLog.info("BundleUpdate", "$entryFileName does not exist") + return null + } + return entryFile.absolutePath + } + + fun getCurrentBundleMainJSBundle(context: Context): String? { + return getCurrentBundleEntryPath(context, MAIN_JS_BUNDLE_FILE_NAME) + } + + fun getCurrentBundleBackgroundJSBundle(context: Context): String? { + return getCurrentBundleEntryPath(context, BACKGROUND_BUNDLE_FILE_NAME) + } + fun getWebEmbedPath(context: Context): String { - val currentBundleDir = getCurrentBundleDir(context, getCurrentBundleVersion(context)) ?: return "" - return File(currentBundleDir, "web-embed").absolutePath + val bundleInfo = getValidatedCurrentBundleInfo(context) ?: return "" + return File(bundleInfo.bundleDir, "web-embed").absolutePath } /** @@ -1098,6 +1184,11 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() { BundleUpdateStoreAndroid.deleteDir(destinationDir) throw Exception("Extracted files verification against metadata failed") } + if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(destination, metadata)) { + OneKeyLog.error("BundleUpdate", "verifyBundleASC: bundle pair compatibility check failed") + BundleUpdateStoreAndroid.deleteDir(destinationDir) + throw Exception("Bundle pair compatibility check failed") + } OneKeyLog.info("BundleUpdate", "verifyBundleASC: all verifications passed, appVersion=$appVersion, bundleVersion=$bundleVersion") } catch (e: Exception) { @@ -1366,6 +1457,22 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() { } } + override fun getBackgroundJsBundlePath(): String { + val context = NitroModules.applicationContext ?: return "" + val path = BundleUpdateStoreAndroid.getCurrentBundleBackgroundJSBundle(context) ?: "" + OneKeyLog.debug("BundleUpdate", "getBackgroundJsBundlePath: ${if (path.isEmpty()) "(empty/no bundle)" else path}") + return path + } + + override fun getBackgroundJsBundlePathAsync(): Promise { + return Promise.async { + val context = getContext() + val path = BundleUpdateStoreAndroid.getCurrentBundleBackgroundJSBundle(context) ?: "" + OneKeyLog.info("BundleUpdate", "getBackgroundJsBundlePathAsync: ${if (path.isEmpty()) "(empty/no bundle)" else path}") + path + } + } + override fun getNativeAppVersion(): Promise { return Promise.async { val context = getContext() @@ -1480,6 +1587,10 @@ n2DMz6gqk326W6SFynYtvuiXo7wG4Cmn3SuIU8xfv9rJqunpZGYchMd7nZektmEJ OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: file integrity check failed") throw Exception("File integrity check failed") } + if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(bundlePath.absolutePath, metadata)) { + OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: bundle pair compatibility check failed") + throw Exception("Bundle pair compatibility check failed") + } OneKeyLog.info("BundleUpdate", "verifyExtractedBundle: all files verified OK, fileCount=${metadata.size}") } } diff --git a/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift b/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift index da4a77de..586b6714 100644 --- a/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift +++ b/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift @@ -68,6 +68,11 @@ public class BundleUpdateStore: NSObject { private static let bundlePrefsKey = "currentBundleVersion" private static let nativeVersionKey = "nativeVersion" private static let nativeBuildNumberKey = "nativeBuildNumber" + private static let mainBundleEntryFileName = "main.jsbundle.hbc" + private static let backgroundBundleEntryFileName = "background.bundle" + private static let metadataRequiresBackgroundBundleKey = "requiresBackgroundBundle" + private static let metadataBackgroundProtocolVersionKey = "backgroundProtocolVersion" + private static let supportedBackgroundProtocolVersion = "1" public static func documentDirectory() -> String { NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] @@ -147,8 +152,8 @@ public class BundleUpdateStore: NSObject { } public static func getWebEmbedPath() -> String { - guard let dir = currentBundleDir() else { return "" } - return (dir as NSString).appendingPathComponent("web-embed") + guard let bundleInfo = validatedCurrentBundleInfo() else { return "" } + return (bundleInfo.bundleDirPath as NSString).appendingPathComponent("web-embed") } public static func calculateSHA256(_ filePath: String) -> String? { @@ -310,13 +315,65 @@ public class BundleUpdateStore: NSObject { return metadataPath } - public static func getMetadataFileContent(_ currentBundleVersion: String) -> [String: String]? { + public static func getMetadataFileContent(_ currentBundleVersion: String) -> [String: Any]? { guard let path = getMetadataFilePath(currentBundleVersion), let data = FileManager.default.contents(atPath: path), - let json = try? JSONSerialization.jsonObject(with: data) as? [String: String] else { return nil } + let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil } return json } + private static func isReservedMetadataKey(_ key: String) -> Bool { + key == metadataRequiresBackgroundBundleKey || key == metadataBackgroundProtocolVersionKey + } + + private static func metadataStringValue( + _ metadata: [String: Any], + key: String, + ) -> String? { + if let value = metadata[key] as? String { + return value + } + if let value = metadata[key] as? NSNumber { + return value.stringValue + } + if let value = metadata[key] as? Bool { + return value ? "true" : "false" + } + return nil + } + + private static func metadataBoolValue( + _ metadata: [String: Any], + key: String, + ) -> Bool { + if let value = metadata[key] as? Bool { + return value + } + if let value = metadata[key] as? NSNumber { + return value.boolValue + } + if let value = metadata[key] as? String { + return ["1", "true", "yes"].contains(value.lowercased()) + } + return false + } + + private static func fileMetadataEntries( + from metadata: [String: Any], + ) -> [String: String] { + var entries: [String: String] = [:] + for (key, value) in metadata { + if isReservedMetadataKey(key) { + continue + } + guard let hash = value as? String else { + continue + } + entries[key] = hash + } + return entries + } + /// Returns true if OneKey developer mode (DevSettings) is enabled. /// Reads the persisted value from MMKV storage written by the JS ServiceDevSetting layer. public static func isDevSettingsEnabled() -> Bool { @@ -466,11 +523,12 @@ public class BundleUpdateStore: NSObject { return true } - public static func validateAllFilesInDir(_ dirPath: String, metadata: [String: String], appVersion: String, bundleVersion: String) -> Bool { + public static func validateAllFilesInDir(_ dirPath: String, metadata: [String: Any], appVersion: String, bundleVersion: String) -> Bool { let parentBundleDir = bundleDir() let folderName = "\(appVersion)-\(bundleVersion)" let jsBundleDir = (parentBundleDir as NSString).appendingPathComponent(folderName) + "/" let fm = FileManager.default + let fileEntries = fileMetadataEntries(from: metadata) guard let enumerator = fm.enumerator(atPath: dirPath) else { return false } while let file = enumerator.nextObject() as? String { @@ -480,7 +538,7 @@ public class BundleUpdateStore: NSObject { if fm.fileExists(atPath: fullPath, isDirectory: &isDir), isDir.boolValue { continue } let relativePath = fullPath.replacingOccurrences(of: jsBundleDir, with: "") - guard let expectedSHA256 = metadata[relativePath] else { + guard let expectedSHA256 = fileEntries[relativePath] else { OneKeyLog.error("BundleUpdate", "[bundle-verify] File on disk not found in metadata: \(relativePath)") return false } @@ -495,7 +553,7 @@ public class BundleUpdateStore: NSObject { } // Verify completeness - for key in metadata.keys { + for key in fileEntries.keys { let expectedFilePath = jsBundleDir + key if !fm.fileExists(atPath: expectedFilePath) { OneKeyLog.error("BundleUpdate", "[bundle-verify] File listed in metadata but missing on disk: \(key)") @@ -505,7 +563,58 @@ public class BundleUpdateStore: NSObject { return true } - public static func currentBundleMainJSBundle() -> String? { + static func validateBundlePairCompatibility( + bundleDirPath: String, + metadata: [String: Any], + ) -> Bool { + let mainBundlePath = (bundleDirPath as NSString) + .appendingPathComponent(mainBundleEntryFileName) + guard FileManager.default.fileExists(atPath: mainBundlePath) else { + OneKeyLog.error( + "BundleUpdate", + "bundle pair invalid: main.jsbundle.hbc is missing at \(mainBundlePath)", + ) + return false + } + + let requiresBackgroundBundle = metadataBoolValue( + metadata, + key: metadataRequiresBackgroundBundleKey, + ) + if !requiresBackgroundBundle { + return true + } + + let protocolVersion = metadataStringValue( + metadata, + key: metadataBackgroundProtocolVersionKey, + ) ?? "" + if protocolVersion.isEmpty || protocolVersion != supportedBackgroundProtocolVersion { + OneKeyLog.error( + "BundleUpdate", + "backgroundProtocolVersion mismatch: expected=\(supportedBackgroundProtocolVersion), actual=\(protocolVersion)", + ) + return false + } + + let backgroundBundlePath = (bundleDirPath as NSString) + .appendingPathComponent(backgroundBundleEntryFileName) + guard FileManager.default.fileExists(atPath: backgroundBundlePath) else { + OneKeyLog.error( + "BundleUpdate", + "requiresBackgroundBundle is true but background.bundle is missing at \(backgroundBundlePath)", + ) + return false + } + + return true + } + + private static func validatedCurrentBundleInfo() -> ( + bundleDirPath: String, + currentBundleVersion: String, + metadata: [String: Any] + )? { processPreLaunchPendingTask() guard let currentBundleVer = currentBundleVersion() else { OneKeyLog.warn("BundleUpdate", "getJsBundlePath: no currentBundleVersion stored") @@ -582,12 +691,32 @@ public class BundleUpdateStore: NSObject { } } - let mainJSBundle = (folderName as NSString).appendingPathComponent("main.jsbundle.hbc") - guard FileManager.default.fileExists(atPath: mainJSBundle) else { - OneKeyLog.info("BundleUpdate", "mainJSBundleFile does not exist") + if !validateBundlePairCompatibility(bundleDirPath: folderName, metadata: metadata) { return nil } - return mainJSBundle + + return (folderName, currentBundleVer, metadata) + } + + private static func currentBundleEntryPath(_ entryFileName: String) -> String? { + guard let bundleInfo = validatedCurrentBundleInfo() else { + return nil + } + + let entryPath = (bundleInfo.bundleDirPath as NSString).appendingPathComponent(entryFileName) + guard FileManager.default.fileExists(atPath: entryPath) else { + OneKeyLog.info("BundleUpdate", "\(entryFileName) does not exist") + return nil + } + return entryPath + } + + public static func currentBundleMainJSBundle() -> String? { + currentBundleEntryPath(mainBundleEntryFileName) + } + + public static func currentBundleBackgroundJSBundle() -> String? { + currentBundleEntryPath(backgroundBundleEntryFileName) } // Fallback data management @@ -1050,6 +1179,11 @@ class ReactNativeBundleUpdate: HybridReactNativeBundleUpdateSpec { try? FileManager.default.removeItem(atPath: destination) throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "Extracted files verification against metadata failed"]) } + if !BundleUpdateStore.validateBundlePairCompatibility(bundleDirPath: destination, metadata: metadata) { + OneKeyLog.error("BundleUpdate", "verifyBundleASC: bundle pair compatibility check failed") + try? FileManager.default.removeItem(atPath: destination) + throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "Bundle pair compatibility check failed"]) + } OneKeyLog.info("BundleUpdate", "verifyBundleASC: all verifications passed, appVersion=\(appVersion), bundleVersion=\(bundleVersion)") } @@ -1314,6 +1448,20 @@ class ReactNativeBundleUpdate: HybridReactNativeBundleUpdateSpec { } } + func getBackgroundJsBundlePath() throws -> String { + let path = BundleUpdateStore.currentBundleBackgroundJSBundle() ?? "" + OneKeyLog.debug("BundleUpdate", "getBackgroundJsBundlePath: \(path.isEmpty ? "(empty/no bundle)" : path)") + return path + } + + func getBackgroundJsBundlePathAsync() throws -> Promise { + return Promise.async { + let path = BundleUpdateStore.currentBundleBackgroundJSBundle() ?? "" + OneKeyLog.info("BundleUpdate", "getBackgroundJsBundlePathAsync: \(path.isEmpty ? "(empty/no bundle)" : path)") + return path + } + } + func getNativeAppVersion() throws -> Promise { return Promise.async { let version = BundleUpdateStore.getCurrentNativeVersion() @@ -1422,7 +1570,7 @@ class ReactNativeBundleUpdate: HybridReactNativeBundleUpdateSpec { throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "metadata.json not found"]) } guard let data = FileManager.default.contents(atPath: metadataJsonPath), - let metadata = try? JSONSerialization.jsonObject(with: data) as? [String: String] else { + let metadata = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: failed to parse metadata.json") throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse metadata.json"]) } @@ -1431,6 +1579,10 @@ class ReactNativeBundleUpdate: HybridReactNativeBundleUpdateSpec { OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: file integrity check failed") throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "File integrity check failed"]) } + if !BundleUpdateStore.validateBundlePairCompatibility(bundleDirPath: bundlePath, metadata: metadata) { + OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: bundle pair compatibility check failed") + throw NSError(domain: "BundleUpdate", code: -1, userInfo: [NSLocalizedDescriptionKey: "Bundle pair compatibility check failed"]) + } OneKeyLog.info("BundleUpdate", "verifyExtractedBundle: all files verified OK, fileCount=\(metadata.count)") } } diff --git a/native-modules/react-native-bundle-update/src/ReactNativeBundleUpdate.nitro.ts b/native-modules/react-native-bundle-update/src/ReactNativeBundleUpdate.nitro.ts index 71fb379d..5a993236 100644 --- a/native-modules/react-native-bundle-update/src/ReactNativeBundleUpdate.nitro.ts +++ b/native-modules/react-native-bundle-update/src/ReactNativeBundleUpdate.nitro.ts @@ -109,6 +109,8 @@ export interface ReactNativeBundleUpdate getWebEmbedPathAsync(): Promise; getJsBundlePath(): string; getJsBundlePathAsync(): Promise; + getBackgroundJsBundlePath(): string; + getBackgroundJsBundlePathAsync(): Promise; getNativeAppVersion(): Promise; getNativeBuildNumber(): Promise; getBuiltinBundleVersion(): Promise; From d393581aebd760805421d698f1bf8036ed005b66 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Tue, 31 Mar 2026 03:10:29 +0800 Subject: [PATCH 17/74] 1.1.48 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index ce54f2ec..c9b487ec 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index fe22485f..a9e610f5 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 3a8e0502..6e4eecd0 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index ebf4c8d0..e7afcad6 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 8790714a..845c7c68 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 29f1a337..f4485021 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index ecb8883b..5b9bc0a7 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index e7bc7806..e871c687 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index d5d79fe0..2e19e013 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 25385afa..6d7eed94 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.47", + "version": "1.1.48", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index ab23c705..33290e0c 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 9b25e558..b15d7ca5 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index bf63766a..71b3fa84 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.47", + "version": "1.1.48", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index e95442d6..bd190cce 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.47", + "version": "1.1.48", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index ec984f85..1e4a16f1 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.47", + "version": "1.1.48", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index e452efad..1576b905 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.47", + "version": "1.1.48", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 32bef153..2aadca10 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.47", + "version": "1.1.48", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 3f8756d24517958519874630ef9534912634fc02 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 03:45:04 +0800 Subject: [PATCH 18/74] feat: add registerSegmentInBackground for late HBC segment loading (Phase 2.5 spike) iOS: - BackgroundReactNativeDelegate.registerSegmentWithId:path: uses RCTInstance registerSegmentWithId:path: on the background runtime - BackgroundThreadManager.registerSegmentInBackground:path:completion: validates file existence and delegates to delegate Android: - BackgroundThreadManager.registerSegmentInBackground(segmentId, path) uses CatalystInstance.registerSegment() on the background ReactContext JS queue thread Both platforms use the same underlying Hermes evaluateJavaScript() API which accepts HBC bytecode. This spike proves background runtime supports late segment registration. --- .../BackgroundThreadManager.kt | 39 +++++++++++++++++++ .../ios/BackgroundRunnerReactNativeDelegate.h | 7 ++++ .../BackgroundRunnerReactNativeDelegate.mm | 28 +++++++++++++ .../ios/BackgroundThreadManager.h | 8 ++++ .../ios/BackgroundThreadManager.mm | 36 +++++++++++++++++ 5 files changed, 118 insertions(+) diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 526405e4..8744986c 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -242,6 +242,45 @@ class BackgroundThreadManager private constructor() { } } + // ── Segment Registration (Phase 2.5 spike) ───────────────────────────── + + /** + * Register a HBC segment in the background runtime. + * Uses CatalystInstance.registerSegment() on the background ReactContext. + * + * @param segmentId The segment ID to register + * @param path Absolute file path to the .seg.hbc file + * @throws IllegalStateException if background runtime is not started + * @throws IllegalArgumentException if segment file does not exist + */ + fun registerSegmentInBackground(segmentId: Int, path: String) { + if (!isStarted) { + throw IllegalStateException("Background runtime not started") + } + + val file = File(path) + if (!file.exists()) { + throw IllegalArgumentException("Segment file not found: $path") + } + + val context = bgReactHost?.currentReactContext + ?: throw IllegalStateException("Background ReactContext not available") + + context.runOnJSQueueThread { + try { + if (context.hasCatalystInstance()) { + context.catalystInstance.registerSegment(segmentId, path) + BTLogger.info("Segment registered in background runtime: id=$segmentId, path=$path") + } else { + BTLogger.error("Background CatalystInstance not available for segment registration") + } + } catch (e: Exception) { + BTLogger.error("Failed to register segment in background runtime: ${e.message}") + throw e + } + } + } + // ── Lifecycle ─────────────────────────────────────────────────────────── val isBackgroundStarted: Boolean get() = isStarted diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h index 59ca4200..0b7c8823 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.h @@ -31,6 +31,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)init; +/** + * Register a HBC segment in the background runtime (Phase 2.5 spike). + * Uses RCTInstance's registerSegmentWithId:path: API. + * Must be called after hostDidStart: has completed. + */ +- (BOOL)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path; + @end NS_ASSUME_NONNULL_END diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 15729622..575f081a 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -222,6 +222,34 @@ - (void)hostDidStart:(RCTHost *)host }]; } +#pragma mark - Segment Registration (Phase 2.5 spike) + +- (BOOL)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path +{ + if (!_rctInstance) { + [BTLogger error:@"Cannot register segment: background RCTInstance not available"]; + return NO; + } + + @try { + SEL sel = NSSelectorFromString(@"registerSegmentWithId:path:"); + if ([_rctInstance respondsToSelector:sel]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [_rctInstance performSelector:sel withObject:segmentId withObject:path]; +#pragma clang diagnostic pop + [BTLogger info:[NSString stringWithFormat:@"Segment registered in background runtime: id=%@, path=%@", segmentId, path]]; + return YES; + } else { + [BTLogger error:@"RCTInstance does not respond to registerSegmentWithId:path:"]; + return NO; + } + } @catch (NSException *exception) { + [BTLogger error:[NSString stringWithFormat:@"Failed to register segment: %@", exception.reason]]; + return NO; + } +} + #pragma mark - RCTTurboModuleManagerDelegate - (id)getModuleProvider:(const char *)name diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h index 0521baf6..ea241c0a 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.h @@ -26,6 +26,14 @@ NS_ASSUME_NONNULL_BEGIN /// Check if background runner is started @property (nonatomic, readonly) BOOL isStarted; +/// Register a HBC segment in the background runtime (Phase 2.5 spike) +/// @param segmentId The segment ID to register +/// @param path Absolute file path to the .seg.hbc file +/// @param completion Callback with nil error on success, or NSError on failure +- (void)registerSegmentInBackground:(NSNumber *)segmentId + path:(NSString *)path + completion:(void (^)(NSError * _Nullable error))completion; + @end NS_ASSUME_NONNULL_END diff --git a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm index 4e3101bf..c525de27 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThreadManager.mm @@ -115,4 +115,40 @@ - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL { }); } +#pragma mark - Segment Registration (Phase 2.5 spike) + +- (void)registerSegmentInBackground:(NSNumber *)segmentId + path:(NSString *)path + completion:(void (^)(NSError * _Nullable error))completion +{ + if (!self.isStarted || !self.reactNativeFactoryDelegate) { + NSError *error = [NSError errorWithDomain:@"BackgroundThread" + code:1 + userInfo:@{NSLocalizedDescriptionKey: @"Background runtime not started"}]; + if (completion) completion(error); + return; + } + + // Verify the file exists + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + NSError *error = [NSError errorWithDomain:@"BackgroundThread" + code:2 + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Segment file not found: %@", path]}]; + if (completion) completion(error); + return; + } + + BOOL success = [self.reactNativeFactoryDelegate registerSegmentWithId:segmentId path:path]; + if (success) { + if (completion) completion(nil); + } else { + NSError *error = [NSError errorWithDomain:@"BackgroundThread" + code:3 + userInfo:@{NSLocalizedDescriptionKey: + @"Failed to register segment in background runtime"}]; + if (completion) completion(error); + } +} + @end From 827b4ba765df9e85972d34109e70631bf02a16e6 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 10:11:35 +0800 Subject: [PATCH 19/74] feat: expose loadSegmentInBackground from TurboModule API Add loadSegmentInBackground(segmentId, path) to the TurboModule spec and both native implementations. JS can now directly call: BackgroundThread.loadSegmentInBackground(segmentId, absolutePath) This is cleaner than wrapping through a separate SplitBundleLoader module, since react-native-background-thread already owns the background runtime lifecycle and holds the RCTInstance/ReactContext. - NativeBackgroundThread.ts: add Promise-returning spec method - BackgroundThread.mm: delegate to BackgroundThreadManager - BackgroundThreadModule.kt: delegate to BackgroundThreadManager --- .../backgroundthread/BackgroundThreadModule.kt | 11 +++++++++++ .../ios/BackgroundThread.h | 4 ++++ .../ios/BackgroundThread.mm | 16 ++++++++++++++++ .../src/NativeBackgroundThread.ts | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt index eeb73056..ed79c23d 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt @@ -1,5 +1,6 @@ package com.backgroundthread +import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.annotations.ReactModule @@ -26,4 +27,14 @@ class BackgroundThreadModule(reactContext: ReactApplicationContext) : override fun startBackgroundRunnerWithEntryURL(entryURL: String) { BackgroundThreadManager.getInstance().startBackgroundRunnerWithEntryURL(reactApplicationContext, entryURL) } + + override fun loadSegmentInBackground(segmentId: Double, path: String, promise: Promise) { + try { + BackgroundThreadManager.getInstance() + .registerSegmentInBackground(segmentId.toInt(), path) + promise.resolve(null) + } catch (e: Exception) { + promise.reject("BG_SEGMENT_LOAD_ERROR", e.message, e) + } + } } diff --git a/native-modules/react-native-background-thread/ios/BackgroundThread.h b/native-modules/react-native-background-thread/ios/BackgroundThread.h index b6704c7e..c381d742 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThread.h +++ b/native-modules/react-native-background-thread/ios/BackgroundThread.h @@ -5,5 +5,9 @@ - (void)startBackgroundRunner; - (void)startBackgroundRunnerWithEntryURL:(NSString *)entryURL; - (void)installSharedBridge; +- (void)loadSegmentInBackground:(double)segmentId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; @end diff --git a/native-modules/react-native-background-thread/ios/BackgroundThread.mm b/native-modules/react-native-background-thread/ios/BackgroundThread.mm index d25a3ac8..1d54b5cc 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundThread.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundThread.mm @@ -29,6 +29,22 @@ - (void)installSharedBridge { [BTLogger info:@"installSharedBridge called (no-op on iOS, installed from AppDelegate)"]; } +- (void)loadSegmentInBackground:(double)segmentId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + BackgroundThreadManager *manager = [BackgroundThreadManager sharedInstance]; + [manager registerSegmentInBackground:@((int)segmentId) + path:path + completion:^(NSError * _Nullable error) { + if (error) { + reject(@"BG_SEGMENT_LOAD_ERROR", error.localizedDescription, error); + } else { + resolve(nil); + } + }]; +} + + (NSString *)moduleName { return @"BackgroundThread"; diff --git a/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts b/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts index 2ff5b946..e97ba60a 100644 --- a/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts +++ b/native-modules/react-native-background-thread/src/NativeBackgroundThread.ts @@ -4,6 +4,10 @@ import type { TurboModule } from 'react-native'; export interface Spec extends TurboModule { startBackgroundRunnerWithEntryURL(entryURL: string): void; installSharedBridge(): void; + loadSegmentInBackground( + segmentId: number, + path: string, + ): Promise; } export default TurboModuleRegistry.getEnforcing('BackgroundThread'); From 6652eddc92fc7c489b685200e8a04e0d74682ae6 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 10:39:27 +0800 Subject: [PATCH 20/74] feat: add react-native-split-bundle-loader TurboModule Add native module for split bundle loading with iOS (Obj-C) and Android (Kotlin) implementations. Exposes getRuntimeBundleContext and loadSegment APIs via TurboModule spec. --- .../SplitBundleLoader.podspec | 22 ++ .../android/build.gradle | 77 +++++++ .../android/src/main/AndroidManifest.xml | 2 + .../java/com/splitbundleloader/SBLLogger.kt | 55 +++++ .../SplitBundleLoaderModule.kt | 199 ++++++++++++++++++ .../SplitBundleLoaderPackage.kt | 33 +++ .../babel.config.js | 12 ++ .../ios/SBLLogger.h | 16 ++ .../ios/SBLLogger.m | 42 ++++ .../ios/SplitBundleLoader.h | 14 ++ .../ios/SplitBundleLoader.mm | 149 +++++++++++++ .../package.json | 162 ++++++++++++++ .../src/NativeSplitBundleLoader.ts | 22 ++ .../src/__tests__/index.test.tsx | 1 + .../src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../tsconfig.json | 30 +++ .../turbo.json | 43 ++++ 18 files changed, 887 insertions(+) create mode 100644 native-modules/react-native-split-bundle-loader/SplitBundleLoader.podspec create mode 100644 native-modules/react-native-split-bundle-loader/android/build.gradle create mode 100644 native-modules/react-native-split-bundle-loader/android/src/main/AndroidManifest.xml create mode 100644 native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SBLLogger.kt create mode 100644 native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt create mode 100644 native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderPackage.kt create mode 100644 native-modules/react-native-split-bundle-loader/babel.config.js create mode 100644 native-modules/react-native-split-bundle-loader/ios/SBLLogger.h create mode 100644 native-modules/react-native-split-bundle-loader/ios/SBLLogger.m create mode 100644 native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h create mode 100644 native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm create mode 100644 native-modules/react-native-split-bundle-loader/package.json create mode 100644 native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts create mode 100644 native-modules/react-native-split-bundle-loader/src/__tests__/index.test.tsx create mode 100644 native-modules/react-native-split-bundle-loader/src/index.tsx create mode 100644 native-modules/react-native-split-bundle-loader/tsconfig.build.json create mode 100644 native-modules/react-native-split-bundle-loader/tsconfig.json create mode 100644 native-modules/react-native-split-bundle-loader/turbo.json diff --git a/native-modules/react-native-split-bundle-loader/SplitBundleLoader.podspec b/native-modules/react-native-split-bundle-loader/SplitBundleLoader.podspec new file mode 100644 index 00000000..1ec1c725 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/SplitBundleLoader.podspec @@ -0,0 +1,22 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "SplitBundleLoader" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + s.public_header_files = "ios/SBLLogger.h" + + s.dependency 'ReactNativeNativeLogger' + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-split-bundle-loader/android/build.gradle b/native-modules/react-native-split-bundle-loader/android/build.gradle new file mode 100644 index 00000000..7c23f785 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['SplitBundleLoader_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["SplitBundleLoader_" + name]).toInteger() +} + +android { + namespace "com.splitbundleloader" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/AndroidManifest.xml b/native-modules/react-native-split-bundle-loader/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a2f47b60 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SBLLogger.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SBLLogger.kt new file mode 100644 index 00000000..e868ebe5 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SBLLogger.kt @@ -0,0 +1,55 @@ +package com.splitbundleloader + +/** + * Lightweight logging wrapper that dynamically dispatches to OneKeyLog. + * Uses reflection to avoid a hard dependency on the native-logger module. + * Falls back to android.util.Log when OneKeyLog is not available. + * + * Mirrors iOS SBLLogger. + */ +object SBLLogger { + private const val TAG = "SplitBundleLoader" + + private val logClass: Class<*>? by lazy { + try { + Class.forName("com.margelo.nitro.nativelogger.OneKeyLog") + } catch (_: ClassNotFoundException) { + null + } + } + + private val methods by lazy { + val cls = logClass ?: return@lazy null + mapOf( + "debug" to cls.getMethod("debug", String::class.java, String::class.java), + "info" to cls.getMethod("info", String::class.java, String::class.java), + "warn" to cls.getMethod("warn", String::class.java, String::class.java), + "error" to cls.getMethod("error", String::class.java, String::class.java), + ) + } + + @JvmStatic + fun debug(message: String) = log("debug", message, android.util.Log.DEBUG) + + @JvmStatic + fun info(message: String) = log("info", message, android.util.Log.INFO) + + @JvmStatic + fun warn(message: String) = log("warn", message, android.util.Log.WARN) + + @JvmStatic + fun error(message: String) = log("error", message, android.util.Log.ERROR) + + private fun log(level: String, message: String, androidLogLevel: Int) { + val method = methods?.get(level) + if (method != null) { + try { + method.invoke(null, TAG, message) + return + } catch (_: Exception) { + // Fall through to android.util.Log + } + } + android.util.Log.println(androidLogLevel, TAG, message) + } +} diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt new file mode 100644 index 00000000..2a1657e0 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt @@ -0,0 +1,199 @@ +package com.splitbundleloader + +import android.content.Context +import android.content.res.AssetManager +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import java.io.File +import java.io.FileOutputStream +import java.io.IOException + +/** + * TurboModule entry point for SplitBundleLoader. + * + * Provides two methods to JS: + * 1. getRuntimeBundleContext() — Returns current runtime's bundle paths and source kind + * 2. loadSegment(params) — Registers a HBC segment with the current Hermes runtime + * + * Mirrors iOS SplitBundleLoader.mm. + */ +@ReactModule(name = SplitBundleLoaderModule.NAME) +class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : + NativeSplitBundleLoaderSpec(reactContext) { + + companion object { + const val NAME = "SplitBundleLoader" + private const val BUILTIN_EXTRACT_DIR = "onekey-builtin-segments" + } + + override fun getName(): String = NAME + + // ----------------------------------------------------------------------- + // getRuntimeBundleContext + // ----------------------------------------------------------------------- + + override fun getRuntimeBundleContext(promise: Promise) { + try { + val context = reactApplicationContext + val runtimeKind = "main" + var sourceKind = "builtin" + var bundleRoot = "" + var nativeVersion = "" + val bundleVersion = "" + + try { + nativeVersion = context.packageManager + .getPackageInfo(context.packageName, 0).versionName ?: "" + } catch (_: Exception) { + } + + // Check OTA bundle path + val otaBundlePath = getOtaBundlePath() + if (!otaBundlePath.isNullOrEmpty()) { + val otaFile = File(otaBundlePath) + if (otaFile.exists()) { + sourceKind = "ota" + bundleRoot = otaFile.parent ?: "" + } + } + + val builtinExtractRoot = File( + context.filesDir, + "$BUILTIN_EXTRACT_DIR/$nativeVersion" + ).absolutePath + + val result = Arguments.createMap() + result.putString("runtimeKind", runtimeKind) + result.putString("sourceKind", sourceKind) + result.putString("bundleRoot", bundleRoot) + result.putString("builtinExtractRoot", builtinExtractRoot) + result.putString("nativeVersion", nativeVersion) + result.putString("bundleVersion", bundleVersion) + + promise.resolve(result) + } catch (e: Exception) { + promise.reject("SPLIT_BUNDLE_CONTEXT_ERROR", e.message, e) + } + } + + // ----------------------------------------------------------------------- + // loadSegment + // ----------------------------------------------------------------------- + + override fun loadSegment( + segmentId: Double, + segmentKey: String, + relativePath: String, + sha256: String, + promise: Promise + ) { + try { + val segId = segmentId.toInt() + + val absolutePath = resolveSegmentPath(relativePath) + if (absolutePath == null) { + promise.reject( + "SPLIT_BUNDLE_NOT_FOUND", + "Segment file not found: $relativePath (key=$segmentKey)" + ) + return + } + + // Register segment via CatalystInstance + val reactContext = reactApplicationContext + if (reactContext.hasCatalystInstance()) { + reactContext.catalystInstance.registerSegment(segId, absolutePath) + SBLLogger.info("Loaded segment $segmentKey (id=$segId)") + promise.resolve(null) + } else { + promise.reject( + "SPLIT_BUNDLE_NO_INSTANCE", + "CatalystInstance not available" + ) + } + } catch (e: Exception) { + promise.reject("SPLIT_BUNDLE_LOAD_ERROR", e.message, e) + } + } + + // ----------------------------------------------------------------------- + // Path resolution helpers + // ----------------------------------------------------------------------- + + private fun resolveSegmentPath(relativePath: String): String? { + // 1. Try OTA bundle directory first + val otaBundlePath = getOtaBundlePath() + if (!otaBundlePath.isNullOrEmpty()) { + val otaRoot = File(otaBundlePath).parentFile + if (otaRoot != null) { + val candidate = File(otaRoot, relativePath) + if (candidate.exists()) { + return candidate.absolutePath + } + } + } + + // 2. Try builtin: extract from assets if needed + return extractBuiltinSegmentIfNeeded(relativePath) + } + + /** + * For Android builtin segments, APK assets can't be passed directly as file paths. + * Extract the asset to the extract cache directory on first access. + */ + private fun extractBuiltinSegmentIfNeeded(relativePath: String): String? { + val context = reactApplicationContext + val nativeVersion = try { + context.packageManager + .getPackageInfo(context.packageName, 0).versionName ?: "unknown" + } catch (_: Exception) { + "unknown" + } + + val extractDir = File(context.filesDir, "$BUILTIN_EXTRACT_DIR/$nativeVersion") + val extractedFile = File(extractDir, relativePath) + + // Already extracted + if (extractedFile.exists()) { + return extractedFile.absolutePath + } + + // Extract from assets + val assets: AssetManager = context.assets + return try { + assets.open(relativePath).use { input -> + extractedFile.parentFile?.let { parent -> + if (!parent.exists()) parent.mkdirs() + } + FileOutputStream(extractedFile).use { output -> + val buffer = ByteArray(8192) + var len: Int + while (input.read(buffer).also { len = it } != -1) { + output.write(buffer, 0, len) + } + } + } + extractedFile.absolutePath + } catch (_: IOException) { + null + } + } + + private fun getOtaBundlePath(): String? { + return try { + val bundleUpdateStore = Class.forName( + "expo.modules.onekeybundleupdate.BundleUpdateStore" + ) + val method = bundleUpdateStore.getMethod( + "getCurrentBundleMainJSBundle", + Context::class.java + ) + val result = method.invoke(null, reactApplicationContext) + result?.toString() + } catch (_: Exception) { + null + } + } +} diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderPackage.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderPackage.kt new file mode 100644 index 00000000..d6e6d07a --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderPackage.kt @@ -0,0 +1,33 @@ +package com.splitbundleloader + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class SplitBundleLoaderPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == SplitBundleLoaderModule.NAME) { + SplitBundleLoaderModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[SplitBundleLoaderModule.NAME] = ReactModuleInfo( + SplitBundleLoaderModule.NAME, + SplitBundleLoaderModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-split-bundle-loader/babel.config.js b/native-modules/react-native-split-bundle-loader/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-split-bundle-loader/ios/SBLLogger.h b/native-modules/react-native-split-bundle-loader/ios/SBLLogger.h new file mode 100644 index 00000000..707b6d4a --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/ios/SBLLogger.h @@ -0,0 +1,16 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Lightweight logging wrapper that dynamically dispatches to OneKeyLog. +/// Avoids `@import ReactNativeNativeLogger` which fails in .mm (Objective-C++) files. +@interface SBLLogger : NSObject + ++ (void)debug:(NSString *)message; ++ (void)info:(NSString *)message; ++ (void)warn:(NSString *)message; ++ (void)error:(NSString *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/native-modules/react-native-split-bundle-loader/ios/SBLLogger.m b/native-modules/react-native-split-bundle-loader/ios/SBLLogger.m new file mode 100644 index 00000000..986c68b2 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/ios/SBLLogger.m @@ -0,0 +1,42 @@ +#import "SBLLogger.h" + +static NSString *const kTag = @"SplitBundleLoader"; + +@implementation SBLLogger + ++ (void)debug:(NSString *)message { + [self _log:@"debug::" message:message]; +} + ++ (void)info:(NSString *)message { + [self _log:@"info::" message:message]; +} + ++ (void)warn:(NSString *)message { + [self _log:@"warn::" message:message]; +} + ++ (void)error:(NSString *)message { + [self _log:@"error::" message:message]; +} + +#pragma mark - Private + ++ (void)_log:(NSString *)selectorName message:(NSString *)message { + Class logClass = NSClassFromString(@"ReactNativeNativeLogger.OneKeyLog"); + if (!logClass) { + logClass = NSClassFromString(@"OneKeyLog"); + } + if (!logClass) { + return; + } + SEL sel = NSSelectorFromString(selectorName); + if (![logClass respondsToSelector:sel]) { + return; + } + typedef void (*LogFunc)(id, SEL, NSString *, NSString *); + LogFunc func = (LogFunc)[logClass methodForSelector:sel]; + func(logClass, sel, kTag, message); +} + +@end diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h new file mode 100644 index 00000000..81c2982a --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h @@ -0,0 +1,14 @@ +#import + +@interface SplitBundleLoader : NativeSplitBundleLoaderSpecBase + +- (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)loadSegment:(double)segmentId + segmentKey:(NSString *)segmentKey + relativePath:(NSString *)relativePath + sha256:(NSString *)sha256 + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm new file mode 100644 index 00000000..f93f1c82 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -0,0 +1,149 @@ +#import "SplitBundleLoader.h" +#import "SBLLogger.h" +#import + +@implementation SplitBundleLoader + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + [SBLLogger info:@"SplitBundleLoader module initialized"]; + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"SplitBundleLoader"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - getRuntimeBundleContext + +- (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + @try { + NSString *runtimeKind = @"main"; + NSString *sourceKind = @"builtin"; + NSString *bundleRoot = @""; + NSString *nativeVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] ?: @""; + NSString *bundleVersion = @""; + + // Check if OTA bundle is active via BundleUpdateStore + Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore"); + if (bundleUpdateStoreClass) { + NSString *otaBundlePath = nil; + SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle"); + if ([bundleUpdateStoreClass respondsToSelector:sel]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id result = [bundleUpdateStoreClass performSelector:sel]; +#pragma clang diagnostic pop + otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil; + } + if (otaBundlePath && otaBundlePath.length > 0) { + NSString *filePath = otaBundlePath; + if ([otaBundlePath hasPrefix:@"file://"]) { + filePath = [[NSURL URLWithString:otaBundlePath] path]; + } + if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + sourceKind = @"ota"; + bundleRoot = [filePath stringByDeletingLastPathComponent]; + } + } + } + + // Builtin: use main bundle resource path + if ([sourceKind isEqualToString:@"builtin"]) { + bundleRoot = [[NSBundle mainBundle] resourcePath] ?: @""; + } + + resolve(@{ + @"runtimeKind": runtimeKind, + @"sourceKind": sourceKind, + @"bundleRoot": bundleRoot, + @"nativeVersion": nativeVersion, + @"bundleVersion": bundleVersion, + }); + } @catch (NSException *exception) { + reject(@"SPLIT_BUNDLE_CONTEXT_ERROR", exception.reason, nil); + } +} + +// MARK: - loadSegment + +- (void)loadSegment:(double)segmentId + segmentKey:(NSString *)segmentKey + relativePath:(NSString *)relativePath + sha256:(NSString *)sha256 + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + @try { + int segId = (int)segmentId; + + // Resolve absolute path + NSString *absolutePath = nil; + + // 1. Try OTA bundle root first + Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore"); + if (bundleUpdateStoreClass) { + NSString *otaBundlePath = nil; + SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle"); + if ([bundleUpdateStoreClass respondsToSelector:sel]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id result = [bundleUpdateStoreClass performSelector:sel]; +#pragma clang diagnostic pop + otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil; + } + if (otaBundlePath && otaBundlePath.length > 0) { + NSString *filePath = otaBundlePath; + if ([otaBundlePath hasPrefix:@"file://"]) { + filePath = [[NSURL URLWithString:otaBundlePath] path]; + } + NSString *otaRoot = [filePath stringByDeletingLastPathComponent]; + NSString *candidate = [otaRoot stringByAppendingPathComponent:relativePath]; + if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { + absolutePath = candidate; + } + } + } + + // 2. Fallback to builtin resource path + if (!absolutePath) { + NSString *builtinRoot = [[NSBundle mainBundle] resourcePath]; + NSString *candidate = [builtinRoot stringByAppendingPathComponent:relativePath]; + if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { + absolutePath = candidate; + } + } + + if (!absolutePath) { + reject(@"SPLIT_BUNDLE_NOT_FOUND", + [NSString stringWithFormat:@"Segment file not found: %@ (key=%@)", relativePath, segmentKey], + nil); + return; + } + + // Register segment via RCTBridge + RCTBridge *bridge = [RCTBridge currentBridge]; + if (bridge) { + [bridge registerSegmentWithId:@(segId) path:absolutePath]; + [SBLLogger info:[NSString stringWithFormat:@"Loaded segment %@ (id=%d)", segmentKey, segId]]; + resolve(nil); + } else { + reject(@"SPLIT_BUNDLE_NO_BRIDGE", @"RCTBridge not available", nil); + } + } @catch (NSException *exception) { + reject(@"SPLIT_BUNDLE_LOAD_ERROR", + [NSString stringWithFormat:@"Failed to load segment %@: %@", segmentKey, exception.reason], + nil); + } +} + +@end diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json new file mode 100644 index 00000000..433f2bf6 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -0,0 +1,162 @@ +{ + "name": "@onekeyfe/react-native-split-bundle-loader", + "version": "0.1.0", + "description": "react-native-split-bundle-loader", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "android", + "ios", + "*.podspec", + "!ios/build", + "!android/build", + "!android/gradle", + "!android/gradlew", + "!android/gradlew.bat", + "!android/local.properties", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "SplitBundleLoaderSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.splitbundleloader" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/example/node_modules", + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts b/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts new file mode 100644 index 00000000..d962124b --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts @@ -0,0 +1,22 @@ +import { TurboModuleRegistry } from 'react-native'; + +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + getRuntimeBundleContext(): Promise<{ + runtimeKind: string; + sourceKind: string; + bundleRoot: string; + builtinExtractRoot?: string; + nativeVersion: string; + bundleVersion?: string; + }>; + loadSegment( + segmentId: number, + segmentKey: string, + relativePath: string, + sha256: string, + ): Promise; +} + +export default TurboModuleRegistry.getEnforcing('SplitBundleLoader'); diff --git a/native-modules/react-native-split-bundle-loader/src/__tests__/index.test.tsx b/native-modules/react-native-split-bundle-loader/src/__tests__/index.test.tsx new file mode 100644 index 00000000..bf84291a --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/src/__tests__/index.test.tsx @@ -0,0 +1 @@ +it.todo('write a test'); diff --git a/native-modules/react-native-split-bundle-loader/src/index.tsx b/native-modules/react-native-split-bundle-loader/src/index.tsx new file mode 100644 index 00000000..8204180a --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/src/index.tsx @@ -0,0 +1,4 @@ +import NativeSplitBundleLoader from './NativeSplitBundleLoader'; + +export const SplitBundleLoader = NativeSplitBundleLoader; +export type { Spec as SplitBundleLoaderSpec } from './NativeSplitBundleLoader'; diff --git a/native-modules/react-native-split-bundle-loader/tsconfig.build.json b/native-modules/react-native-split-bundle-loader/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-split-bundle-loader/tsconfig.json b/native-modules/react-native-split-bundle-loader/tsconfig.json new file mode 100644 index 00000000..b38fdc5b --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-split-bundle-loader": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-split-bundle-loader/turbo.json b/native-modules/react-native-split-bundle-loader/turbo.json new file mode 100644 index 00000000..8b2bf087 --- /dev/null +++ b/native-modules/react-native-split-bundle-loader/turbo.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/android", + "!example/android/.gradle", + "!example/android/build", + "!example/android/app/build" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/ios", + "!example/ios/build", + "!example/ios/Pods" + ], + "outputs": [] + } + } +} From f33a914cc375f488f0fdd7abb2b3ee87e53788ce Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 10:40:07 +0800 Subject: [PATCH 21/74] 1.1.49 --- native-modules/native-logger/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- yarn.lock | 33 +++++++++++++++++++ 19 files changed, 51 insertions(+), 18 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index c9b487ec..09a3ed6a 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index a9e610f5..3aa31e7c 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 6e4eecd0..a2c0e59c 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index e7afcad6..5988f14d 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 845c7c68..9a67df1c 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index f4485021..a7dd0d11 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 5b9bc0a7..d12dbc50 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index e871c687..60d4b39a 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 2e19e013..6cf4970d 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 6d7eed94..44eb1b31 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.48", + "version": "1.1.49", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 33290e0c..19235368 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index b15d7ca5..b5a70a40 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 433f2bf6..e69b93d6 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "0.1.0", + "version": "0.1.1", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 71b3fa84..80f66a80 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.48", + "version": "1.1.49", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index bd190cce..4d3dd54b 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.48", + "version": "1.1.49", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 1e4a16f1..d6d8ee60 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.48", + "version": "1.1.49", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 1576b905..f6aadb70 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.48", + "version": "1.1.49", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 2aadca10..00bdf2b2 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.48", + "version": "1.1.49", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/yarn.lock b/yarn.lock index cd87ebd9..47788932 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3358,6 +3358,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-split-bundle-loader@workspace:native-modules/react-native-split-bundle-loader": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-split-bundle-loader@workspace:native-modules/react-native-split-bundle-loader" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-tab-view@workspace:*, @onekeyfe/react-native-tab-view@workspace:native-views/react-native-tab-view": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-tab-view@workspace:native-views/react-native-tab-view" From ac4cafd126350dffa52babecbbd78c1fd3d855e0 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 11:37:42 +0800 Subject: [PATCH 22/74] feat: enhance split-bundle-loader with bridgeless support and robustness improvements - Add bridgeless (RCTHost / ReactHost) segment registration for new arch - Extract OTA path helper to deduplicate iOS logic - Add asset extraction size validation and atomic rename on Android - Limit concurrent extractions with semaphore - Auto-cleanup old version extract directories - Bump all package versions to 1.1.50 --- native-modules/native-logger/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../SplitBundleLoaderModule.kt | 151 +++++++++++++++--- .../ios/SplitBundleLoader.mm | 139 ++++++++++------ .../package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 20 files changed, 235 insertions(+), 91 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 09a3ed6a..68a0b4ad 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 3aa31e7c..17c0b287 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index a2c0e59c..f19a66d5 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 5988f14d..5d17c0b4 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 9a67df1c..0ef49052 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index a7dd0d11..37d6b903 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index d12dbc50..36373eeb 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 60d4b39a..a02ef660 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 6cf4970d..c25d5402 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 44eb1b31..4b25f637 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.49", + "version": "1.1.50", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 19235368..4ac544a2 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index b5a70a40..2a3d5741 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt index 2a1657e0..8ed4efc5 100644 --- a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt @@ -9,6 +9,7 @@ import com.facebook.react.module.annotations.ReactModule import java.io.File import java.io.FileOutputStream import java.io.IOException +import java.util.concurrent.Semaphore /** * TurboModule entry point for SplitBundleLoader. @@ -26,6 +27,9 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : companion object { const val NAME = "SplitBundleLoader" private const val BUILTIN_EXTRACT_DIR = "onekey-builtin-segments" + // #18: Limit concurrent asset extractions to avoid I/O contention + private const val MAX_CONCURRENT_EXTRACTS = 2 + private val extractSemaphore = Semaphore(MAX_CONCURRENT_EXTRACTS) } override fun getName(): String = NAME @@ -73,6 +77,9 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : result.putString("bundleVersion", bundleVersion) promise.resolve(result) + + // #17: Clean up old version extract directories asynchronously + cleanupOldExtractDirs(context, nativeVersion) } catch (e: Exception) { promise.reject("SPLIT_BUNDLE_CONTEXT_ERROR", e.message, e) } @@ -92,7 +99,7 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : try { val segId = segmentId.toInt() - val absolutePath = resolveSegmentPath(relativePath) + val absolutePath = resolveSegmentPath(relativePath, sha256) if (absolutePath == null) { promise.reject( "SPLIT_BUNDLE_NOT_FOUND", @@ -101,28 +108,56 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : return } - // Register segment via CatalystInstance + // #19: Try CatalystInstance first (bridge mode), fall back to + // ReactHost registerSegment if available (bridgeless / new arch). val reactContext = reactApplicationContext if (reactContext.hasCatalystInstance()) { reactContext.catalystInstance.registerSegment(segId, absolutePath) SBLLogger.info("Loaded segment $segmentKey (id=$segId)") promise.resolve(null) } else { - promise.reject( - "SPLIT_BUNDLE_NO_INSTANCE", - "CatalystInstance not available" - ) + // Bridgeless: try ReactHost via reflection + val registered = tryRegisterViaBridgeless(segId, absolutePath) + if (registered) { + SBLLogger.info("Loaded segment $segmentKey (id=$segId) via bridgeless") + promise.resolve(null) + } else { + promise.reject( + "SPLIT_BUNDLE_NO_INSTANCE", + "Neither CatalystInstance nor ReactHost available" + ) + } } } catch (e: Exception) { promise.reject("SPLIT_BUNDLE_LOAD_ERROR", e.message, e) } } + // ----------------------------------------------------------------------- + // Bridgeless support (#19) + // ----------------------------------------------------------------------- + + private fun tryRegisterViaBridgeless(segmentId: Int, path: String): Boolean { + return try { + val appContext = reactApplicationContext.applicationContext + val appClass = appContext.javaClass + val hostMethod = appClass.getMethod("getReactHost") + val host = hostMethod.invoke(appContext) ?: return false + val registerMethod = host.javaClass.getMethod( + "registerSegment", Int::class.java, String::class.java + ) + registerMethod.invoke(host, segmentId, path) + true + } catch (_: Exception) { + false + } + } + // ----------------------------------------------------------------------- // Path resolution helpers // ----------------------------------------------------------------------- - private fun resolveSegmentPath(relativePath: String): String? { + private fun resolveSegmentPath(relativePath: String, expectedSha256: String): String? { // 1. Try OTA bundle directory first val otaBundlePath = getOtaBundlePath() if (!otaBundlePath.isNullOrEmpty()) { @@ -136,14 +171,17 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : } // 2. Try builtin: extract from assets if needed - return extractBuiltinSegmentIfNeeded(relativePath) + return extractBuiltinSegmentIfNeeded(relativePath, expectedSha256) } /** * For Android builtin segments, APK assets can't be passed directly as file paths. * Extract the asset to the extract cache directory on first access. + * + * #16: Validates extracted file size against the asset to detect truncated extractions. + * #18: Uses semaphore to limit concurrent extractions. */ - private fun extractBuiltinSegmentIfNeeded(relativePath: String): String? { + private fun extractBuiltinSegmentIfNeeded(relativePath: String, expectedSha256: String): String? { val context = reactApplicationContext val nativeVersion = try { context.packageManager @@ -155,32 +193,101 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : val extractDir = File(context.filesDir, "$BUILTIN_EXTRACT_DIR/$nativeVersion") val extractedFile = File(extractDir, relativePath) - // Already extracted + // #16: If file exists, verify it's not truncated by checking size against asset if (extractedFile.exists()) { - return extractedFile.absolutePath + val assetSize = getAssetSize(context.assets, relativePath) + if (assetSize >= 0 && extractedFile.length() == assetSize) { + return extractedFile.absolutePath + } + // Truncated or size mismatch — delete and re-extract + SBLLogger.warn("Extracted file size mismatch for $relativePath, re-extracting") + extractedFile.delete() } - // Extract from assets - val assets: AssetManager = context.assets - return try { - assets.open(relativePath).use { input -> - extractedFile.parentFile?.let { parent -> - if (!parent.exists()) parent.mkdirs() + // #18: Limit concurrent extractions + extractSemaphore.acquire() + try { + // Double-check after acquiring semaphore (another thread may have extracted) + if (extractedFile.exists()) { + return extractedFile.absolutePath + } + + val assets: AssetManager = context.assets + return try { + // Extract to temp file first, then atomically rename + val tempFile = File(extractedFile.parentFile, "${extractedFile.name}.tmp") + assets.open(relativePath).use { input -> + extractedFile.parentFile?.let { parent -> + if (!parent.exists()) parent.mkdirs() + } + FileOutputStream(tempFile).use { output -> + val buffer = ByteArray(8192) + var len: Int + while (input.read(buffer).also { len = it } != -1) { + output.write(buffer, 0, len) + } + } } - FileOutputStream(extractedFile).use { output -> + // Atomic rename prevents partial file observation + if (tempFile.renameTo(extractedFile)) { + extractedFile.absolutePath + } else { + tempFile.delete() + null + } + } catch (_: IOException) { + null + } + } finally { + extractSemaphore.release() + } + } + + /** + * Returns the size of an asset file, or -1 if it can't be determined. + */ + private fun getAssetSize(assets: AssetManager, assetPath: String): Long { + return try { + assets.openFd(assetPath).use { it.length } + } catch (_: IOException) { + // Asset may be compressed; fall back to reading the stream + try { + assets.open(assetPath).use { input -> + var size = 0L val buffer = ByteArray(8192) var len: Int while (input.read(buffer).also { len = it } != -1) { - output.write(buffer, 0, len) + size += len } + size } + } catch (_: IOException) { + -1 } - extractedFile.absolutePath - } catch (_: IOException) { - null } } + /** + * #17: Asynchronously clean up extract directories from previous native versions. + */ + private fun cleanupOldExtractDirs(context: Context, currentVersion: String) { + Thread { + try { + val baseDir = File(context.filesDir, BUILTIN_EXTRACT_DIR) + if (!baseDir.exists() || !baseDir.isDirectory) return@Thread + val dirs = baseDir.listFiles() ?: return@Thread + for (dir in dirs) { + if (dir.isDirectory && dir.name != currentVersion) { + SBLLogger.info("Cleaning up old extract dir: ${dir.name}") + dir.deleteRecursively() + } + } + } catch (e: Exception) { + SBLLogger.warn("Failed to cleanup old extract dirs: ${e.message}") + } + }.start() + } + private fun getOtaBundlePath(): String? { return try { val bundleUpdateStore = Class.forName( diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm index f93f1c82..a4bc47a4 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -2,6 +2,11 @@ #import "SBLLogger.h" #import +// Bridgeless (New Architecture) support: RCTHost segment registration +@interface RCTHost (SplitBundle) +- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path; +@end + @implementation SplitBundleLoader - (std::shared_ptr)getTurboModule: @@ -21,6 +26,73 @@ + (BOOL)requiresMainQueueSetup return NO; } +// MARK: - OTA bundle path helper + +/// Safely retrieves the OTA bundle path via typed NSInvocation to avoid +/// performSelector ARC/signature issues (#15). ++ (nullable NSString *)otaBundlePath +{ + Class cls = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore"); + if (!cls) return nil; + + SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle"); + if (![cls respondsToSelector:sel]) return nil; + + NSMethodSignature *sig = [cls methodSignatureForSelector:sel]; + if (!sig || strcmp(sig.methodReturnType, @encode(id)) != 0) { + [SBLLogger warn:@"OTA method signature mismatch — skipping"]; + return nil; + } + + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig]; + inv.target = cls; + inv.selector = sel; + [inv invoke]; + + __unsafe_unretained id rawResult = nil; + [inv getReturnValue:&rawResult]; + if (![rawResult isKindOfClass:[NSString class]]) return nil; + + NSString *result = (NSString *)rawResult; + if (result.length == 0) return nil; + + if ([result hasPrefix:@"file://"]) { + result = [[NSURL URLWithString:result] path]; + } + return result; +} + +// MARK: - Segment registration helper + +/// Registers a segment with the current runtime, supporting both legacy bridge +/// and bridgeless (RCTHost) architectures (#13). ++ (BOOL)registerSegment:(int)segmentId path:(NSString *)path error:(NSError **)outError +{ + // Try legacy bridge first + RCTBridge *bridge = [RCTBridge currentBridge]; + if (bridge && [bridge respondsToSelector:@selector(registerSegmentWithId:path:)]) { + [bridge registerSegmentWithId:@(segmentId) path:path]; + return YES; + } + + // Try bridgeless RCTHost via AppDelegate + id appDelegate = [UIApplication sharedApplication].delegate; + if ([appDelegate respondsToSelector:NSSelectorFromString(@"reactHost")]) { + id host = [appDelegate performSelector:NSSelectorFromString(@"reactHost")]; + if (host && [host respondsToSelector:@selector(registerSegmentWithId:path:)]) { + [host registerSegmentWithId:@(segmentId) path:path]; + return YES; + } + } + + if (outError) { + *outError = [NSError errorWithDomain:@"SplitBundleLoader" + code:1 + userInfo:@{NSLocalizedDescriptionKey: @"Neither RCTBridge nor RCTHost available for segment registration"}]; + } + return NO; +} + // MARK: - getRuntimeBundleContext - (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve @@ -33,31 +105,12 @@ - (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve NSString *nativeVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] ?: @""; NSString *bundleVersion = @""; - // Check if OTA bundle is active via BundleUpdateStore - Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore"); - if (bundleUpdateStoreClass) { - NSString *otaBundlePath = nil; - SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle"); - if ([bundleUpdateStoreClass respondsToSelector:sel]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - id result = [bundleUpdateStoreClass performSelector:sel]; -#pragma clang diagnostic pop - otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil; - } - if (otaBundlePath && otaBundlePath.length > 0) { - NSString *filePath = otaBundlePath; - if ([otaBundlePath hasPrefix:@"file://"]) { - filePath = [[NSURL URLWithString:otaBundlePath] path]; - } - if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { - sourceKind = @"ota"; - bundleRoot = [filePath stringByDeletingLastPathComponent]; - } - } + NSString *otaPath = [SplitBundleLoader otaBundlePath]; + if (otaPath && [[NSFileManager defaultManager] fileExistsAtPath:otaPath]) { + sourceKind = @"ota"; + bundleRoot = [otaPath stringByDeletingLastPathComponent]; } - // Builtin: use main bundle resource path if ([sourceKind isEqualToString:@"builtin"]) { bundleRoot = [[NSBundle mainBundle] resourcePath] ?: @""; } @@ -85,32 +138,15 @@ - (void)loadSegment:(double)segmentId { @try { int segId = (int)segmentId; - - // Resolve absolute path NSString *absolutePath = nil; // 1. Try OTA bundle root first - Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore"); - if (bundleUpdateStoreClass) { - NSString *otaBundlePath = nil; - SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle"); - if ([bundleUpdateStoreClass respondsToSelector:sel]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - id result = [bundleUpdateStoreClass performSelector:sel]; -#pragma clang diagnostic pop - otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil; - } - if (otaBundlePath && otaBundlePath.length > 0) { - NSString *filePath = otaBundlePath; - if ([otaBundlePath hasPrefix:@"file://"]) { - filePath = [[NSURL URLWithString:otaBundlePath] path]; - } - NSString *otaRoot = [filePath stringByDeletingLastPathComponent]; - NSString *candidate = [otaRoot stringByAppendingPathComponent:relativePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { - absolutePath = candidate; - } + NSString *otaPath = [SplitBundleLoader otaBundlePath]; + if (otaPath) { + NSString *otaRoot = [otaPath stringByDeletingLastPathComponent]; + NSString *candidate = [otaRoot stringByAppendingPathComponent:relativePath]; + if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { + absolutePath = candidate; } } @@ -130,14 +166,15 @@ - (void)loadSegment:(double)segmentId return; } - // Register segment via RCTBridge - RCTBridge *bridge = [RCTBridge currentBridge]; - if (bridge) { - [bridge registerSegmentWithId:@(segId) path:absolutePath]; + // Register segment (#13: supports both bridge and bridgeless) + NSError *regError = nil; + if ([SplitBundleLoader registerSegment:segId path:absolutePath error:®Error]) { [SBLLogger info:[NSString stringWithFormat:@"Loaded segment %@ (id=%d)", segmentKey, segId]]; resolve(nil); } else { - reject(@"SPLIT_BUNDLE_NO_BRIDGE", @"RCTBridge not available", nil); + reject(@"SPLIT_BUNDLE_NO_RUNTIME", + regError.localizedDescription ?: @"Runtime not available", + regError); } } @catch (NSException *exception) { reject(@"SPLIT_BUNDLE_LOAD_ERROR", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index e69b93d6..8b45508e 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "0.1.1", + "version": "1.1.50", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 80f66a80..2bfd14a0 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.49", + "version": "1.1.50", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 4d3dd54b..3f99f476 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.49", + "version": "1.1.50", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index d6d8ee60..640c3105 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.49", + "version": "1.1.50", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index f6aadb70..9a28c808 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.49", + "version": "1.1.50", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 00bdf2b2..ca2eb8a2 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.49", + "version": "1.1.50", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 9d37806eeaf71e77c982f41b69dad74c31f0ab33 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 15:11:46 +0800 Subject: [PATCH 23/74] fix: resolve Android registerSegmentInBackground race condition BackgroundThreadModule resolved the promise immediately after dispatching registerSegment to the JS queue thread, before registration completed. JS would mark the segment as ready and require() it, but the segment wasn't registered yet. Fix: registerSegmentInBackground now takes a callback that fires after registerSegment executes on the JS queue thread. The module resolves/rejects the promise only in the callback. --- .../BackgroundThreadManager.kt | 27 ++++++++++++++----- .../BackgroundThreadModule.kt | 15 ++++++----- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 8744986c..75aa67ae 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -253,30 +253,45 @@ class BackgroundThreadManager private constructor() { * @throws IllegalStateException if background runtime is not started * @throws IllegalArgumentException if segment file does not exist */ - fun registerSegmentInBackground(segmentId: Int, path: String) { + /** + * Register a HBC segment in the background runtime with completion callback. + * Dispatches to the background JS queue thread and invokes the callback + * only after registerSegment has actually executed. + * + * @param segmentId The segment ID to register + * @param path Absolute file path to the .seg.hbc file + * @param onComplete Called with null on success, or an Exception on failure + */ + fun registerSegmentInBackground(segmentId: Int, path: String, onComplete: (Exception?) -> Unit) { if (!isStarted) { - throw IllegalStateException("Background runtime not started") + onComplete(IllegalStateException("Background runtime not started")) + return } val file = File(path) if (!file.exists()) { - throw IllegalArgumentException("Segment file not found: $path") + onComplete(IllegalArgumentException("Segment file not found: $path")) + return } val context = bgReactHost?.currentReactContext - ?: throw IllegalStateException("Background ReactContext not available") + if (context == null) { + onComplete(IllegalStateException("Background ReactContext not available")) + return + } context.runOnJSQueueThread { try { if (context.hasCatalystInstance()) { context.catalystInstance.registerSegment(segmentId, path) BTLogger.info("Segment registered in background runtime: id=$segmentId, path=$path") + onComplete(null) } else { - BTLogger.error("Background CatalystInstance not available for segment registration") + onComplete(IllegalStateException("Background CatalystInstance not available for segment registration")) } } catch (e: Exception) { BTLogger.error("Failed to register segment in background runtime: ${e.message}") - throw e + onComplete(e) } } } diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt index ed79c23d..c67349fc 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadModule.kt @@ -29,12 +29,13 @@ class BackgroundThreadModule(reactContext: ReactApplicationContext) : } override fun loadSegmentInBackground(segmentId: Double, path: String, promise: Promise) { - try { - BackgroundThreadManager.getInstance() - .registerSegmentInBackground(segmentId.toInt(), path) - promise.resolve(null) - } catch (e: Exception) { - promise.reject("BG_SEGMENT_LOAD_ERROR", e.message, e) - } + BackgroundThreadManager.getInstance() + .registerSegmentInBackground(segmentId.toInt(), path) { error -> + if (error != null) { + promise.reject("BG_SEGMENT_LOAD_ERROR", error.message, error) + } else { + promise.resolve(null) + } + } } } From 1088bfc61dfbef4a8ff30a0d0ba74445c4b300ca Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 15:29:01 +0800 Subject: [PATCH 24/74] feat: add resolveSegmentPath API and path traversal protection - Add resolveSegmentPath TurboModule method for path-only resolution - Extract shared path resolution helper on iOS - Add path traversal guard rejecting ".." in relative paths - Add canonicalPath boundary check on Android OTA resolution - Document sha256 verification design decision --- .../SplitBundleLoaderModule.kt | 41 ++++++++- .../ios/SplitBundleLoader.h | 4 + .../ios/SplitBundleLoader.mm | 85 +++++++++++++++---- .../src/NativeSplitBundleLoader.ts | 1 + 4 files changed, 113 insertions(+), 18 deletions(-) diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt index 8ed4efc5..708fe2cb 100644 --- a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt @@ -85,6 +85,26 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : } } + // ----------------------------------------------------------------------- + // resolveSegmentPath (Phase 3) + // ----------------------------------------------------------------------- + + override fun resolveSegmentPath(relativePath: String, sha256: String, promise: Promise) { + try { + val absolutePath = resolveSegmentPath(relativePath, sha256) + if (absolutePath != null) { + promise.resolve(absolutePath) + } else { + promise.reject( + "SPLIT_BUNDLE_NOT_FOUND", + "Segment file not found: $relativePath" + ) + } + } catch (e: Exception) { + promise.reject("SPLIT_BUNDLE_RESOLVE_ERROR", e.message, e) + } + } + // ----------------------------------------------------------------------- // loadSegment // ----------------------------------------------------------------------- @@ -96,6 +116,10 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : sha256: String, promise: Promise ) { + // NOTE (#44): sha256 param is not verified at load time by design. + // Per §6.4.1, runtime trusts that OTA install has already verified + // segment integrity. Builtin segments are signed as part of the APK/IPA. + // If runtime SHA-256 verification is needed, add it here. try { val segId = segmentId.toInt() @@ -157,14 +181,29 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : // Path resolution helpers // ----------------------------------------------------------------------- + /** + * Verify resolved path stays within the expected root directory (#45). + * Prevents path traversal via ".." components in relativePath. + */ + private fun isPathWithinRoot(root: File, resolved: File): Boolean { + return resolved.canonicalPath.startsWith(root.canonicalPath + File.separator) || + resolved.canonicalPath == root.canonicalPath + } + private fun resolveSegmentPath(relativePath: String, expectedSha256: String): String? { + // Path traversal guard (#45) + if (relativePath.contains("..")) { + SBLLogger.warn("Path traversal rejected: $relativePath") + return null + } + // 1. Try OTA bundle directory first val otaBundlePath = getOtaBundlePath() if (!otaBundlePath.isNullOrEmpty()) { val otaRoot = File(otaBundlePath).parentFile if (otaRoot != null) { val candidate = File(otaRoot, relativePath) - if (candidate.exists()) { + if (candidate.exists() && isPathWithinRoot(otaRoot, candidate)) { return candidate.absolutePath } } diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h index 81c2982a..dbe589c6 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h @@ -10,5 +10,9 @@ sha256:(NSString *)sha256 resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)resolveSegmentPath:(NSString *)relativePath + sha256:(NSString *)sha256 + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; @end diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm index a4bc47a4..62b95537 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -66,6 +66,11 @@ + (nullable NSString *)otaBundlePath /// Registers a segment with the current runtime, supporting both legacy bridge /// and bridgeless (RCTHost) architectures (#13). +/// +/// Thread safety (#57): This method is called from the TurboModule (JS thread). +/// RCTBridge.registerSegmentWithId:path: internally registers the segment with +/// the Hermes runtime on the JS thread, which is the correct calling context. +/// No queue dispatch is needed. + (BOOL)registerSegment:(int)segmentId path:(NSString *)path error:(NSError **)outError { // Try legacy bridge first @@ -127,6 +132,62 @@ - (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve } } +// MARK: - Path resolution helper + +/// Resolves a relative segment path to an absolute path, checking OTA then builtin. +/// Returns nil if the segment file is not found. ++ (nullable NSString *)resolveAbsolutePath:(NSString *)relativePath +{ + // 1. Try OTA bundle root first + NSString *otaPath = [SplitBundleLoader otaBundlePath]; + if (otaPath) { + NSString *otaRoot = [otaPath stringByDeletingLastPathComponent]; + NSString *candidate = [[otaRoot stringByAppendingPathComponent:relativePath] stringByStandardizingPath]; + if ([candidate hasPrefix:otaRoot] && + [[NSFileManager defaultManager] fileExistsAtPath:candidate]) { + return candidate; + } + } + + // 2. Fallback to builtin resource path + NSString *builtinRoot = [[NSBundle mainBundle] resourcePath]; + NSString *candidate = [[builtinRoot stringByAppendingPathComponent:relativePath] stringByStandardizingPath]; + if ([candidate hasPrefix:builtinRoot] && + [[NSFileManager defaultManager] fileExistsAtPath:candidate]) { + return candidate; + } + + return nil; +} + +// MARK: - resolveSegmentPath (Phase 3) + +- (void)resolveSegmentPath:(NSString *)relativePath + sha256:(NSString *)sha256 + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + @try { + if ([relativePath containsString:@".."]) { + reject(@"SPLIT_BUNDLE_INVALID_PATH", + [NSString stringWithFormat:@"Path traversal rejected: %@", relativePath], + nil); + return; + } + + NSString *absolutePath = [SplitBundleLoader resolveAbsolutePath:relativePath]; + if (absolutePath) { + resolve(absolutePath); + } else { + reject(@"SPLIT_BUNDLE_NOT_FOUND", + [NSString stringWithFormat:@"Segment file not found: %@", relativePath], + nil); + } + } @catch (NSException *exception) { + reject(@"SPLIT_BUNDLE_RESOLVE_ERROR", exception.reason, nil); + } +} + // MARK: - loadSegment - (void)loadSegment:(double)segmentId @@ -138,26 +199,16 @@ - (void)loadSegment:(double)segmentId { @try { int segId = (int)segmentId; - NSString *absolutePath = nil; - // 1. Try OTA bundle root first - NSString *otaPath = [SplitBundleLoader otaBundlePath]; - if (otaPath) { - NSString *otaRoot = [otaPath stringByDeletingLastPathComponent]; - NSString *candidate = [otaRoot stringByAppendingPathComponent:relativePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { - absolutePath = candidate; - } + // Path traversal guard (#45) + if ([relativePath containsString:@".."]) { + reject(@"SPLIT_BUNDLE_INVALID_PATH", + [NSString stringWithFormat:@"Path traversal rejected: %@", relativePath], + nil); + return; } - // 2. Fallback to builtin resource path - if (!absolutePath) { - NSString *builtinRoot = [[NSBundle mainBundle] resourcePath]; - NSString *candidate = [builtinRoot stringByAppendingPathComponent:relativePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) { - absolutePath = candidate; - } - } + NSString *absolutePath = [SplitBundleLoader resolveAbsolutePath:relativePath]; if (!absolutePath) { reject(@"SPLIT_BUNDLE_NOT_FOUND", diff --git a/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts b/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts index d962124b..11b7609b 100644 --- a/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts +++ b/native-modules/react-native-split-bundle-loader/src/NativeSplitBundleLoader.ts @@ -17,6 +17,7 @@ export interface Spec extends TurboModule { relativePath: string, sha256: string, ): Promise; + resolveSegmentPath(relativePath: string, sha256: string): Promise; } export default TurboModuleRegistry.getEnforcing('SplitBundleLoader'); From 19a0e103d26433365eee3e457093a89a3c3d265c Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 1 Apr 2026 15:29:23 +0800 Subject: [PATCH 25/74] 1.1.51 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 68a0b4ad..41e83b95 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 17c0b287..750cb46c 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index f19a66d5..2505eeca 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 5d17c0b4..0b5b1fdd 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 0ef49052..4ce80633 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 37d6b903..c33dc4c3 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 36373eeb..fb962620 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index a02ef660..9cca6e7d 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index c25d5402..9c436b08 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 4b25f637..86365de3 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.50", + "version": "1.1.51", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 4ac544a2..289c83d6 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 2a3d5741..fcc17250 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 8b45508e..b6950fd0 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 2bfd14a0..3f793bde 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.50", + "version": "1.1.51", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 3f99f476..7e767dca 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.50", + "version": "1.1.51", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 640c3105..89532edf 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.50", + "version": "1.1.51", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 9a28c808..18c63872 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.50", + "version": "1.1.51", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index ca2eb8a2..30240ec6 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.50", + "version": "1.1.51", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From bc8ed7d1b56ce2c714f02e1171432dafd12c2130 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 13:10:15 +0800 Subject: [PATCH 26/74] feat: add split-bundle common+entry loading strategy - Android: sequential bundle loader for assets and file-based OTA - iOS: load common.jsbundle first, then evaluate entry bundle via jsi - Add loadEntryBundle:inHost: to SplitBundleLoader for runtime eval - Add common bundle path resolver to BundleUpdateStore --- .../BackgroundThreadManager.kt | 121 +++++++++++++++++- .../BackgroundRunnerReactNativeDelegate.mm | 49 ++++++- .../ReactNativeBundleUpdate.kt | 5 + .../ios/SplitBundleLoader.h | 10 ++ .../ios/SplitBundleLoader.mm | 41 ++++++ 5 files changed, 219 insertions(+), 7 deletions(-) diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index 75aa67ae..d620fe93 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -108,6 +108,88 @@ class BackgroundThreadManager private constructor() { return null } + /** + * Creates a JSBundleLoader that loads two bundles sequentially from Android assets: + * first the common bundle (polyfills + shared modules), then the + * entry-specific bundle (entry-only modules + require(entryId)). + */ + private fun createSequentialAssetBundleLoader( + appContext: android.content.Context, + commonAssetName: String, + entryAssetName: String + ): JSBundleLoader { + return object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + // Step 1: Load common bundle (polyfills + shared modules) + delegate.loadScriptFromAssets(appContext.assets, "assets://$commonAssetName", false) + BTLogger.info("Common bundle loaded from assets: $commonAssetName") + + // Step 2: Load entry-specific bundle + delegate.loadScriptFromAssets(appContext.assets, "assets://$entryAssetName", false) + BTLogger.info("Entry bundle loaded from assets: $entryAssetName") + + return "assets://$entryAssetName" + } + } + } + + /** + * Creates a JSBundleLoader that loads two bundles sequentially from local files: + * first the common bundle, then the entry-specific bundle. + */ + private fun createSequentialFileBundleLoader( + commonPath: String, + entryPath: String, + entrySourceURL: String + ): JSBundleLoader { + return object : JSBundleLoader() { + override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + // Step 1: Load common bundle (polyfills + shared modules) + val commonFile = File(commonPath) + if (!commonFile.exists()) { + BTLogger.error("Common bundle file does not exist: $commonPath") + throw RuntimeException("Common bundle file does not exist: $commonPath") + } + delegate.loadScriptFromFile(commonFile.absolutePath, "common.bundle", false) + BTLogger.info("Common bundle loaded from file: $commonPath") + + // Step 2: Load entry-specific bundle + val entryFile = File(entryPath) + if (!entryFile.exists()) { + BTLogger.error("Entry bundle file does not exist: $entryPath") + throw RuntimeException("Entry bundle file does not exist: $entryPath") + } + delegate.loadScriptFromFile(entryFile.absolutePath, entrySourceURL, false) + BTLogger.info("Entry bundle loaded from file: $entryPath") + + return entrySourceURL + } + } + } + + /** + * Check if common.bundle exists in the Android assets directory. + */ + private fun hasCommonBundleInAssets(appContext: android.content.Context): Boolean { + return try { + appContext.assets.open("common.bundle").close() + true + } catch (e: Exception) { + false + } + } + + /** + * Resolve the common bundle path for OTA (file-based) loading. + * Looks for common.bundle in the same directory as the entry bundle. + */ + private fun resolveCommonBundlePath(entryBundlePath: String): String? { + val entryFile = File(entryBundlePath) + val parentDir = entryFile.parentFile ?: return null + val commonFile = File(parentDir, "common.bundle") + return if (commonFile.exists()) commonFile.absolutePath else null + } + private fun createDownloadedBundleLoader(appContext: android.content.Context, entryURL: String): JSBundleLoader { return object : JSBundleLoader() { override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { @@ -163,10 +245,43 @@ class BackgroundThreadManager private constructor() { val localBundlePath = resolveLocalBundlePath(entryURL) val bundleLoader = when { + // Debug mode: remote URL — use single bundle (Metro dev server) isRemoteBundleUrl(entryURL) -> createDownloadedBundleLoader(appContext, entryURL) - localBundlePath != null -> createLocalFileBundleLoader(localBundlePath, entryURL) - entryURL.startsWith("assets://") -> JSBundleLoader.createAssetLoader(appContext, entryURL, true) - else -> JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) + + // OTA / local file path — try sequential loading with common bundle + localBundlePath != null -> { + val commonPath = resolveCommonBundlePath(localBundlePath) + if (commonPath != null) { + BTLogger.info("Using sequential file bundle loader: common=$commonPath, entry=$localBundlePath") + createSequentialFileBundleLoader(commonPath, localBundlePath, entryURL) + } else { + BTLogger.info("No common bundle found for OTA path, using single bundle: $localBundlePath") + createLocalFileBundleLoader(localBundlePath, entryURL) + } + } + + // Assets-based loading — try sequential loading with common.bundle in assets + entryURL.startsWith("assets://") -> { + val entryAssetName = entryURL.removePrefix("assets://") + if (hasCommonBundleInAssets(appContext)) { + BTLogger.info("Using sequential asset bundle loader: common=common.bundle, entry=$entryAssetName") + createSequentialAssetBundleLoader(appContext, "common.bundle", entryAssetName) + } else { + BTLogger.info("No common.bundle in assets, using single bundle: $entryURL") + JSBundleLoader.createAssetLoader(appContext, entryURL, true) + } + } + + // Bare filename (e.g. "background.bundle") — treat as asset + else -> { + if (hasCommonBundleInAssets(appContext)) { + BTLogger.info("Using sequential asset bundle loader: common=common.bundle, entry=$entryURL") + createSequentialAssetBundleLoader(appContext, "common.bundle", entryURL) + } else { + BTLogger.info("No common.bundle in assets, using single bundle: assets://$entryURL") + JSBundleLoader.createAssetLoader(appContext, "assets://$entryURL", true) + } + } } val delegate = DefaultReactHostDelegate( diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 575f081a..49bc7923 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -170,6 +170,8 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge - (NSURL *)bundleURL { + // When _jsBundleSource is set (dev mode or explicit override), use it as-is. + // This is a single full bundle (not split), so DON'T use common+entry strategy. if (!_jsBundleSource.empty()) { NSString *jsBundleSourceNS = [NSString stringWithUTF8String:_jsBundleSource.c_str()]; NSURL *resolvedURL = resolveBundleSourceURL(jsBundleSourceNS); @@ -180,11 +182,19 @@ - (NSURL *)bundleURL [BTLogger warn:[NSString stringWithFormat:@"Unable to resolve custom jsBundleSource=%@", jsBundleSourceNS]]; } - NSURL *defaultBundleURL = resolveMainBundleResourceURL(@"background.bundle"); - if (defaultBundleURL) { - return defaultBundleURL; + // Default: load common bundle (shared polyfills + modules). + // The background entry bundle is loaded later in hostDidStart:. + NSURL *commonURL = resolveMainBundleResourceURL(@"common.jsbundle"); + if (commonURL) { + return commonURL; } - return [[NSBundle mainBundle] URLForResource:@"background" withExtension:@"bundle"]; + return [[NSBundle mainBundle] URLForResource:@"common" withExtension:@"jsbundle"]; +} + +- (NSString *)resolveBackgroundEntryBundlePath +{ + NSURL *url = resolveMainBundleResourceURL(@"background.bundle"); + return url.path; } - (void)hostDidStart:(RCTHost *)host @@ -203,6 +213,26 @@ - (void)hostDidStart:(RCTHost *)host return; } + // When _jsBundleSource is set, the bundle loaded in bundleURL was already + // a full single bundle (dev mode / explicit override), so skip entry loading. + BOOL isSplitBundle = _jsBundleSource.empty(); + + // Read the background entry bundle data before entering the executor block + // (only needed in split-bundle mode). + NSData *bgBundleData = nil; + NSString *bgBundleSourceURL = nil; + if (isSplitBundle) { + NSString *bgBundlePath = [self resolveBackgroundEntryBundlePath]; + if (bgBundlePath) { + bgBundleData = [NSData dataWithContentsOfFile:bgBundlePath]; + bgBundleSourceURL = bgBundlePath.lastPathComponent ?: @"background.bundle"; + [BTLogger info:[NSString stringWithFormat:@"Background entry bundle loaded from %@ (%lu bytes)", + bgBundlePath, (unsigned long)bgBundleData.length]]; + } else { + [BTLogger warn:@"Background entry bundle not found, __setupBackgroundRPCHandler may not be defined"]; + } + } + [_rctInstance callFunctionOnBufferedRuntimeExecutor:[=](jsi::Runtime &runtime) { [self setupErrorHandler:runtime]; @@ -218,6 +248,17 @@ - (void)hostDidStart:(RCTHost *)host }; SharedRPC::install(runtime, std::move(bgExecutor), "background"); [BTLogger info:@"SharedStore and SharedRPC installed in background runtime"]; + + // In split-bundle mode, evaluate the background entry bundle now. + // This must happen BEFORE invokeOptionalGlobalFunction since the entry + // bundle defines __setupBackgroundRPCHandler. + if (isSplitBundle && bgBundleData && bgBundleData.length > 0) { + auto buffer = std::make_shared( + std::string(static_cast(bgBundleData.bytes), bgBundleData.length)); + runtime.evaluateJavaScript(std::move(buffer), [bgBundleSourceURL UTF8String]); + [BTLogger info:@"Background entry bundle evaluated in runtime"]; + } + invokeOptionalGlobalFunction(runtime, "__setupBackgroundRPCHandler"); }]; } diff --git a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt index 5bd05071..a4a68d83 100644 --- a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt +++ b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt @@ -99,6 +99,7 @@ object BundleUpdateStoreAndroid { private const val CURRENT_BUNDLE_VERSION_KEY = "currentBundleVersion" private const val MAIN_JS_BUNDLE_FILE_NAME = "main.jsbundle.hbc" private const val BACKGROUND_BUNDLE_FILE_NAME = "background.bundle" + private const val COMMON_BUNDLE_FILE_NAME = "common.bundle" private const val METADATA_REQUIRES_BACKGROUND_BUNDLE_KEY = "requiresBackgroundBundle" private const val METADATA_BACKGROUND_PROTOCOL_VERSION_KEY = "backgroundProtocolVersion" private const val SUPPORTED_BACKGROUND_PROTOCOL_VERSION = "1" @@ -807,6 +808,10 @@ object BundleUpdateStoreAndroid { return getCurrentBundleEntryPath(context, BACKGROUND_BUNDLE_FILE_NAME) } + fun getCurrentBundleCommonJSBundle(context: Context): String? { + return getCurrentBundleEntryPath(context, COMMON_BUNDLE_FILE_NAME) + } + fun getWebEmbedPath(context: Context): String { val bundleInfo = getValidatedCurrentBundleInfo(context) ?: return "" return File(bundleInfo.bundleDir, "web-embed").absolutePath diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h index dbe589c6..816f1431 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.h @@ -15,4 +15,14 @@ resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +/// Evaluate a JS bundle file inside the given RCTHost's runtime. +/// Used for the common + entry split-bundle loading strategy: +/// 1. RCTHost boots with common.jsbundle (polyfills + shared modules) +/// 2. After the runtime is ready, this evaluates the entry-specific bundle +/// (main.jsbundle or background.bundle) via jsi::Runtime::evaluateJavaScript. +/// +/// @param bundlePath Absolute filesystem path to the bundle file. +/// @param host The RCTHost whose runtime should evaluate the bundle. ++ (void)loadEntryBundle:(NSString *)bundlePath inHost:(id)host; + @end diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm index 62b95537..3c2591cd 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -1,6 +1,8 @@ #import "SplitBundleLoader.h" #import "SBLLogger.h" #import +#import +#include // Bridgeless (New Architecture) support: RCTHost segment registration @interface RCTHost (SplitBundle) @@ -188,6 +190,45 @@ - (void)resolveSegmentPath:(NSString *)relativePath } } +// MARK: - loadEntryBundle (common + entry split loading) + ++ (void)loadEntryBundle:(NSString *)bundlePath inHost:(id)host +{ + if (!host || bundlePath.length == 0) { + [SBLLogger warn:[NSString stringWithFormat:@"loadEntryBundle: invalid arguments (host=%@, path=%@)", host, bundlePath]]; + return; + } + + Ivar ivar = class_getInstanceVariable([host class], "_instance"); + if (!ivar) { + [SBLLogger warn:[NSString stringWithFormat:@"loadEntryBundle: _instance ivar not found on %@", [host class]]]; + return; + } + + id instance = object_getIvar(host, ivar); + if (!instance) { + [SBLLogger warn:@"loadEntryBundle: _instance is nil"]; + return; + } + + NSData *data = [NSData dataWithContentsOfFile:bundlePath]; + if (!data || data.length == 0) { + [SBLLogger warn:[NSString stringWithFormat:@"loadEntryBundle: failed to read bundle at %@", bundlePath]]; + return; + } + + NSString *sourceURL = bundlePath.lastPathComponent ?: bundlePath; + [SBLLogger info:[NSString stringWithFormat:@"loadEntryBundle: evaluating %@ (%lu bytes)", sourceURL, (unsigned long)data.length]]; + + [instance callFunctionOnBufferedRuntimeExecutor:^(facebook::jsi::Runtime &runtime) { + @autoreleasepool { + auto buffer = std::make_shared( + std::string(static_cast(data.bytes), data.length)); + runtime.evaluateJavaScript(std::move(buffer), [sourceURL UTF8String]); + } + }]; +} + // MARK: - loadSegment - (void)loadSegment:(double)segmentId From 6a07497ddc32180e86f99cb2360892ad5f326100 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 13:10:37 +0800 Subject: [PATCH 27/74] 1.1.52 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 41e83b95..e9272166 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 750cb46c..afb337d4 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 2505eeca..c6640c19 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 0b5b1fdd..c1d2a407 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 4ce80633..78906b54 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index c33dc4c3..3e9533fc 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index fb962620..6cfef0ee 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 9cca6e7d..7dc4be40 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 9c436b08..e17bd26f 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 86365de3..f509ef91 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.51", + "version": "1.1.52", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 289c83d6..62c4f0db 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index fcc17250..dee4231a 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index b6950fd0..6d12c4f0 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 3f793bde..3d42b39e 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.51", + "version": "1.1.52", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 7e767dca..3ca9f118 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.51", + "version": "1.1.52", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 89532edf..b5c50d65 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.51", + "version": "1.1.52", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 18c63872..9fe353a9 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.51", + "version": "1.1.52", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 30240ec6..bea5f331 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.51", + "version": "1.1.52", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 68ad1ff15acd1aa0660274af98e3c3cb270adecb Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 15:56:17 +0800 Subject: [PATCH 28/74] feat: add comprehensive timing logs for three-bundle split verification --- .../ios/BackgroundRunnerReactNativeDelegate.mm | 9 ++++++++- .../ios/SplitBundleLoader.mm | 13 +++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm index 49bc7923..a17700ca 100644 --- a/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm +++ b/native-modules/react-native-background-thread/ios/BackgroundRunnerReactNativeDelegate.mm @@ -233,6 +233,8 @@ - (void)hostDidStart:(RCTHost *)host } } + CFAbsoluteTime bgStartTime = CFAbsoluteTimeGetCurrent(); + [_rctInstance callFunctionOnBufferedRuntimeExecutor:[=](jsi::Runtime &runtime) { [self setupErrorHandler:runtime]; @@ -253,12 +255,17 @@ - (void)hostDidStart:(RCTHost *)host // This must happen BEFORE invokeOptionalGlobalFunction since the entry // bundle defines __setupBackgroundRPCHandler. if (isSplitBundle && bgBundleData && bgBundleData.length > 0) { + CFAbsoluteTime bgEvalStart = CFAbsoluteTimeGetCurrent(); auto buffer = std::make_shared( std::string(static_cast(bgBundleData.bytes), bgBundleData.length)); runtime.evaluateJavaScript(std::move(buffer), [bgBundleSourceURL UTF8String]); - [BTLogger info:@"Background entry bundle evaluated in runtime"]; + double bgEvalMs = (CFAbsoluteTimeGetCurrent() - bgEvalStart) * 1000.0; + [BTLogger info:[NSString stringWithFormat:@"[SplitBundle] bg entry evaluated in %.1fms", bgEvalMs]]; } + double bgTotalMs = (CFAbsoluteTimeGetCurrent() - bgStartTime) * 1000.0; + [BTLogger info:[NSString stringWithFormat:@"[SplitBundle] bg hostDidStart total setup in %.1fms", bgTotalMs]]; + invokeOptionalGlobalFunction(runtime, "__setupBackgroundRPCHandler"); }]; } diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm index 3c2591cd..cc56caea 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -218,15 +218,22 @@ + (void)loadEntryBundle:(NSString *)bundlePath inHost:(id)host } NSString *sourceURL = bundlePath.lastPathComponent ?: bundlePath; - [SBLLogger info:[NSString stringWithFormat:@"loadEntryBundle: evaluating %@ (%lu bytes)", sourceURL, (unsigned long)data.length]]; + CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); + [SBLLogger info:[NSString stringWithFormat:@"[SplitBundle] loadEntryBundle: evaluating %@ (%lu bytes)", sourceURL, (unsigned long)data.length]]; [instance callFunctionOnBufferedRuntimeExecutor:^(facebook::jsi::Runtime &runtime) { @autoreleasepool { + CFAbsoluteTime evalStart = CFAbsoluteTimeGetCurrent(); auto buffer = std::make_shared( std::string(static_cast(data.bytes), data.length)); runtime.evaluateJavaScript(std::move(buffer), [sourceURL UTF8String]); + double evalMs = (CFAbsoluteTimeGetCurrent() - evalStart) * 1000.0; + [SBLLogger info:[NSString stringWithFormat:@"[SplitBundle] loadEntryBundle: %@ evaluated in %.1fms", sourceURL, evalMs]]; } }]; + + double totalMs = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0; + [SBLLogger info:[NSString stringWithFormat:@"[SplitBundle] loadEntryBundle: %@ dispatched in %.1fms (eval is async)", sourceURL, totalMs]]; } // MARK: - loadSegment @@ -240,6 +247,7 @@ - (void)loadSegment:(double)segmentId { @try { int segId = (int)segmentId; + CFAbsoluteTime segStart = CFAbsoluteTimeGetCurrent(); // Path traversal guard (#45) if ([relativePath containsString:@".."]) { @@ -261,7 +269,8 @@ - (void)loadSegment:(double)segmentId // Register segment (#13: supports both bridge and bridgeless) NSError *regError = nil; if ([SplitBundleLoader registerSegment:segId path:absolutePath error:®Error]) { - [SBLLogger info:[NSString stringWithFormat:@"Loaded segment %@ (id=%d)", segmentKey, segId]]; + double segMs = (CFAbsoluteTimeGetCurrent() - segStart) * 1000.0; + [SBLLogger info:[NSString stringWithFormat:@"[SplitBundle] Loaded segment %@ (id=%d) in %.1fms", segmentKey, segId, segMs]]; resolve(nil); } else { reject(@"SPLIT_BUNDLE_NO_RUNTIME", From b406d7cac088f24906ce580d53fb7d0a35e4a30d Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 16:00:13 +0800 Subject: [PATCH 29/74] feat: add split-bundle timing instrumentation and update PGP public key - Add timing logs for sequential bundle loading (common + entry) - Add timing for background ReactContext initialization - Add timing for segment registration in SplitBundleLoader - Update PGP public key across bundle-update, app-update, and example - Update test metadata to v6.1.0 format --- .../pages/BundleUpdateTestPage.tsx | 80 ++++++++++--------- .../ReactNativeAppUpdate.kt | 62 ++++++++------ .../BackgroundThreadManager.kt | 34 ++++++-- .../ReactNativeBundleUpdate.kt | 62 ++++++++------ .../ios/ReactNativeBundleUpdate.swift | 62 ++++++++------ .../SplitBundleLoaderModule.kt | 7 +- 6 files changed, 186 insertions(+), 121 deletions(-) diff --git a/example/react-native/pages/BundleUpdateTestPage.tsx b/example/react-native/pages/BundleUpdateTestPage.tsx index 7fe3e93e..327e8293 100644 --- a/example/react-native/pages/BundleUpdateTestPage.tsx +++ b/example/react-native/pages/BundleUpdateTestPage.tsx @@ -238,26 +238,30 @@ Hash: SHA256 { "fileName": "metadata.json", - "sha256": "8c71473ccb1c590e8c13642559600eb0c8e2649c9567236e2ac27e79e919a12c", - "size": 23123, - "generatedAt": "2025-10-22T09:50:50.446Z" + "sha256": "bf3734ac6e59388fe23c40ce2960b6fd197c596af05dd08b3ccc8b201b78c52b", + "size": 167265, + "generatedAt": "2026-03-31T03:25:05.000Z", + "appVersion": "6.1.0", + "buildNumber": "2026032032", + "bundleVersion": "7701116", + "appType": "electron" } -----BEGIN PGP SIGNATURE----- -iQJCBAEBCAAsFiEE62iuVE8f3YzSZGJPs2mmepC/OHsFAmj/ZF0OHGRldkBvbmVr -ZXkuc28ACgkQs2mmepC/OHuVZhAArMmwReTpiw+XoKTw7bwlVrz0OWHfAkdh6lFY -xQpGj+AsY38NKJImrK7IQLhcnTJIwycY0a5eh8Wnqs0sxtmmwwyWQs+RHSwIdlTJ -CLpTUGxowNiD0ldz0LVLjPFqZz3/fYKkpGW1+ejkMdRXBbUrFGTa+XsEd0k3TWj2 -bxFrhy128SpQ1NJ8AXXWRzZaenFAADa5ZEJUMV4Q8sjV+C8OXtVKeW1IDXAvWEzx -x9SWU4HD4ciKYT6yRZ6RuHJ3YXFdIDPMrPXDSPTjcZUnhsadT0qFoRck6ya4uyQP -SNvEge9W9Kcup0XfKkK5SnIRyZeKgW5Zn39W8C5equqmrGy581E6R28KS3KHsE66 -Pf6WmVE/XuAKt5F++TmC6RBZ9PISPdOVhWcPZ74ySsFOUQ0nswMg1GLQ/kfixXIl -8ejFGhzhCRDmxYZ1aEJeMAAQhBuXM5TKtY79TIT9lNlttM0J/hl3rTTVxt9xSsMW -MCduz+A1mdO8T/DPqvpJksOO/YOT4gzHT9OSXNsYdte1QJKHmQdeAfzi/m66Z2/L -1qqTvwH3byXreUAjXwAWZLIbAQJ6zeeIrVKiut7DCJOHE+kGS2vdQiM2NmRFE0hP -qxdzLH784DPCWB36Xd3VZfbUxKOc06+bHlFCEXyylWD3schXV9c8Amz4DoriYIdi -Ni3q+jg= -=BVQy +iQJCBAEBCAAsFiEE62iuVE8f3YzSZGJPs2mmepC/OHsFAmnLXs0OHGRldkBvbmVr +ZXkuc28ACgkQs2mmepC/OHtUkhAAoMZQc/Z1slPudePNjgO33XZwhWJNQkLeyPRL +Evz6JowioGdQjk1yJ+2jleSDDHRCceh6BzeqZqCFP58oRqug3MS4x1/7Egvza3l8 +5vW+NeX9Ai8l4PniUDcC9IwBITsVz/wzjQdhOuVbtYcP4y/48JvctBNBj5cG7cG7 +pMvOiXffUWjrBHToAKJec6V1N5L2b/2K3dutp10o3+tkfOznsHaD1vCpwxaeWcMx +W2I2SsH3uBDRYisY5W5mb5mDPbEuyqL+M+TLxHAGPwRe3+ExeipakPIJFfYsf5zi +6AnlllUv/QBH+1VZ7KauadPLD1HfMCPSbqQuTsgay56H7fvUe9khp2ysftgQ2tpc +NzTtQyZqIUeiUwBSTGqUvuLMCRChfGo7OBJE7Ec/VRzUIwGmN4Je+nY1JTYW+iR5 +cRQ9j+aNAhLYLPkdUr9hMXaDjpSdGCBM0YpEoqSOzbuZEVCD92tzdfMUI+bdC6a/ +I5cI5w1KTRKJ8irMfzm/TDcIenoUTvhzwqm+v69vFSR1LqWQMXnRvhONNTa9haov ++s+6KSUKPMH4Pa5AgRu5dkoj3UrbZUwt3tOIao97PXVXaFuSBLNhFEjS5yV+uOgK +Wfi3u5D2NWfhq0ZaV25yC16xDIe7SOXgHjNnR1vtt5L9ThZ2deidyiBJA6BFHZK6 +RNAOJKE= +=JKzr -----END PGP SIGNATURE-----` }, android: { @@ -271,30 +275,30 @@ Hash: SHA256 { "fileName": "metadata.json", - "sha256": "cece2fccea3c3a43e0da7ab803f44e5a4850a8b06f2df06db3e7f16860080a40", - "size": 28919, - "generatedAt": "2026-01-06T05:42:35.407Z", - "appType": "android", - "appVersion": "5.19.2", - "buildNumber": "2026010644", - "bundleVersion": "2" + "sha256": "bf3734ac6e59388fe23c40ce2960b6fd197c596af05dd08b3ccc8b201b78c52b", + "size": 167265, + "generatedAt": "2026-03-31T03:25:05.000Z", + "appVersion": "6.1.0", + "buildNumber": "2026032032", + "bundleVersion": "7701116", + "appType": "electron" } -----BEGIN PGP SIGNATURE----- -iQJCBAEBCAAsFiEE62iuVE8f3YzSZGJPs2mmepC/OHsFAmlcvy8OHGRldkBvbmVr -ZXkuc28ACgkQs2mmepC/OHtxlA//QEvclfq0X9isJXBHFsRZx+JhfGOao60Sl0rW -m11AU6utvOAXHwxnhtLENuB2cDhhKkDrN582R2QhsdRJngRqWafwuBaVBJx+ErZV -KqvAlTj9hcLACXBw/dOyQ4JwDwm2jwloH4H//eiQdFcp1MT/uiGf3Yu9fonEC6ap -URBiiA7wAPg2o9V6zJchv/CM/xGA9G/I337lR0yAID2Y6Oteu9CftCSGqav4va4O -C94nW/wWQdt+XllY+i46mXxKOOoaIxUMP5K6q1q5CcjZBNm6Pgkay5YEDmbershP -/DeSpHwTk2APOIoaw1JVeKP8HrhIg4iGjmrUkveBoHJrGu1x6FjZ0tGqVJkG7b8f -wuBBHoPlCULbR38eFudv6UBYsJ2Zb2MEwMEC4quBczU6wg4NnOSKFK03kqsStyxG -0F+HShqAPZZrvGUUOMBMWhyxpDmbslkXtQntPhaMM8+NGqegTMiLZQnWkvzCIdoc -EYJOSlAICF/VkFzo8+LSuUgCQbqXF5qnFhcsIdzR8rguFKHC9/8/umlVjua5ilnu -bxULNIeYztMeXB29J8JXpu4efz+v5r9/HsddXlY0wMrmEWNiw+bG+ruT3O9pC9k9 -hGatKzsRToFrdoTaHG6xnKhiVH7MhQHGjvEK5KpyXIvQxy9SCIloAqs0oXrW4Yuz -H3bEFZ8= -=ZjEV +iQJCBAEBCAAsFiEE62iuVE8f3YzSZGJPs2mmepC/OHsFAmnLXs0OHGRldkBvbmVr +ZXkuc28ACgkQs2mmepC/OHtUkhAAoMZQc/Z1slPudePNjgO33XZwhWJNQkLeyPRL +Evz6JowioGdQjk1yJ+2jleSDDHRCceh6BzeqZqCFP58oRqug3MS4x1/7Egvza3l8 +5vW+NeX9Ai8l4PniUDcC9IwBITsVz/wzjQdhOuVbtYcP4y/48JvctBNBj5cG7cG7 +pMvOiXffUWjrBHToAKJec6V1N5L2b/2K3dutp10o3+tkfOznsHaD1vCpwxaeWcMx +W2I2SsH3uBDRYisY5W5mb5mDPbEuyqL+M+TLxHAGPwRe3+ExeipakPIJFfYsf5zi +6AnlllUv/QBH+1VZ7KauadPLD1HfMCPSbqQuTsgay56H7fvUe9khp2ysftgQ2tpc +NzTtQyZqIUeiUwBSTGqUvuLMCRChfGo7OBJE7Ec/VRzUIwGmN4Je+nY1JTYW+iR5 +cRQ9j+aNAhLYLPkdUr9hMXaDjpSdGCBM0YpEoqSOzbuZEVCD92tzdfMUI+bdC6a/ +I5cI5w1KTRKJ8irMfzm/TDcIenoUTvhzwqm+v69vFSR1LqWQMXnRvhONNTa9haov ++s+6KSUKPMH4Pa5AgRu5dkoj3UrbZUwt3tOIao97PXVXaFuSBLNhFEjS5yV+uOgK +Wfi3u5D2NWfhq0ZaV25yC16xDIe7SOXgHjNnR1vtt5L9ThZ2deidyiBJA6BFHZK6 +RNAOJKE= +=JKzr -----END PGP SIGNATURE-----` } }) ?? { diff --git a/native-modules/react-native-app-update/android/src/main/java/com/margelo/nitro/reactnativeappupdate/ReactNativeAppUpdate.kt b/native-modules/react-native-app-update/android/src/main/java/com/margelo/nitro/reactnativeappupdate/ReactNativeAppUpdate.kt index da579cc6..ab129afa 100644 --- a/native-modules/react-native-app-update/android/src/main/java/com/margelo/nitro/reactnativeappupdate/ReactNativeAppUpdate.kt +++ b/native-modules/react-native-app-update/android/src/main/java/com/margelo/nitro/reactnativeappupdate/ReactNativeAppUpdate.kt @@ -65,31 +65,43 @@ fpqe0vKYUlT092joT0o6nT2MzmLmHUW0kDqD9p6JEJEZUZpqcSRE84eMTFNyu966 xy/rjN2SMJTFzkNXPkwXYrMYoahGez1oZfLzV6SQ0+blNc3aATt9aQW6uaCZtMw1 ibcfWW9neHVpRtTlMYCoa2reGaBGCv0Nd8pMcyFUQkVaes5cQHkh3r5Dba+YrVvp l4P8HMbN8/LqAv7eBfj3ylPa/8eEPWVifcum2Y9TqherN1C2JDqWIpH4EsApek3k -NMK6q0lPxXjZ3Pa5Ag0EYkBMbAEQAM1R4N3bBkwKkHeYwsQASevUkHwY4eg6Ncgp -f9NbmJHcEioqXTIv0nHCQbos3P2NhXvDowj4JFkK/ZbpP9yo0p7TI4fckseVSWwI -tiF9l/8OmXvYZMtw3hHcUUZVdJnk0xrqT6ni6hyRFIfbqous6/vpqi0GG7nB/+lU -E5StGN8696ZWRyAX9MmwoRoods3ShNJP0+GCYHfIcG0XRhEDMJph+7mWPlkQUcza -4aEjxOQ4Stwwp+ZL1rXSlyJIPk1S9/FIS/Uw5GgqFJXIf5n+SCVtUZ8lGedEWwe4 -wXsoPFxxOc2Gqw5r4TrJFdgA3MptYebXmb2LGMssXQTM1AQS2LdpnWw44+X1CHvQ -0m4pEw/g2OgeoJPBurVUnu2mU/M+ARZiS4ceAR0pLZN7Yq48p1wr6EOBQdA3Usby -uc17MORG/IjRmjz4SK/luQLXjN+0jwQSoM1kcIHoRk37B8feHjVufJDKlqtw83H1 -uNu6lGwb8MxDgTuuHloDijCDQsn6m7ZKU1qqLDGtdvCUY2ovzuOUS9vv6MAhR86J -kqoU3sOBMeQhnBaTNKU0IjT4M+ERCWQ7MewlzXuPHgyb4xow1SKZny+f+fYXPy9+ -hx4/j5xaKrZKdq5zIo+GRGe4lA088l253nGeLgSnXsbSxqADqKK73d7BXLCVEZHx -f4Sa5JN7ABEBAAGJAjwEGAEIACYWIQTraK5UTx/djNJkYk+zaaZ6kL84ewUCYkBM -bAIbDAUJB4YfRAAKCRCzaaZ6kL84e0UGD/4mVWyGoQC86TyPoU4Pb5r8mynXWmiH -ZGKu2ll8qn3l5Q67OophgbA1I0GTBFsYK2f91ahgs7FEsLrmz/25E8ybcdJipITE -6869nyE1b37jVb3z3BJLYS/4MaNvugNz4VjMHWVAL52glXLN+SJBSNscmWZDKnVn -Rnrn+kBEvOWZgLbi4MpPiNVwm2PGnrtPzudTcg/NS3HOcmJTfG3mrnwwNJybTVAx -txlQPoXUpJQqJjtkPPW+CqosolpRdugQ5zpFSg05iL+vN+CMrVPkk85w87dtsidl -yZl/ZNITrLzym9d2UFVQZY2rRohNdRfx3l4rfXJFLaqQtihRvBIiMKTbUb2V0pd3 -rVLz2Ck3gJqPfPEEmCWS0Nx6rME8m0sOkNyMau3dMUUAs4j2c3pOQmsZRjKo7LAc -7/GahKFhZ2aBCQzvcTES+gPH1Z5HnivkcnUF2gnQV9x7UOr1Q/euKJsxPl5CCZtM -N9GFW10cDxFo7cO5Ch+/BkkkfebuI/4Wa1SQTzawsxTx4eikKwcemgfDsyIqRs2W -62PBrqCzs9Tg19l35sCdmvYsvMadrYFXukHXiUKEpwJMdTLAtjJ+AX84YLwuHi3+ -qZ5okRCqZH+QpSojSScT9H5ze4ZpuP0d8pKycxb8M2RfYdyOtT/eqsZ/1EQPg7kq -P2Q5dClenjjjVA== -=F0np +NMK6q0lPxXjZ3PaJAlQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AW +IQTraK5UTx/djNJkYk+zaaZ6kL84ewUCactdeAUJDxpqwwAKCRCzaaZ6kL84e8TX +EACtuZUT79PZx964iUf6T04IZ/SFqftMdIPrvCOpyYUkzFfTjufZSP7S5dmut/dl +VLQnPjip0ZGeHeSX2ersXmmp7Ny2zqZr858ZIdLpamkEg6hRi5LWOOK4clnKzTLe +OGWlA6WzF3cb4YB4NiNOX1yxxtggZrndyMxLfSU27aZ4h98/g5j/o/FRCt0OzibH +IGKl+tUayKEEtq7+CrxWHwCXY+wFeeJFm2yhEMqeAZlVpsvGgtfWevQwHaRcld99 +5ousZOOqsCkl1J7rCeaIFowIEA3TzH0FWIQGahGiHN/+zwc7iSIL9gNEq4/AYJWK +80jPqyrRDia7VfZA/SULbWaPmmqrn/Y8qYl3jDvT/6BuwXFAgK9pz5NkWggkjAMX +nGylez9tZBfv+Bymv5RTRAHey49noF/6ZcF5fidtXAS2tfhuRIlOUfEY+QyB3lXj +kxeOOAGJ2ejTVBVIJnfoSFSsG+LH1tvzbDJvNQcMh0oQD849fip+6O0Ae3KfNZpw +aNkIdxThvBU0XCPgmyEXll/mkS5QlUQUo+EwbZOjr6xGmi310DgJo3Ry1dfZ8qBq +F3DD6NK40bkfw8I6Qjwf/IXd921ZbKe88UMjVBTpm2IH3WXR51My9LN/2gzV9zL+ +7odaaXfd+u2x9RuZ1caLXSv4Qyc/7Le1d2T4LpevA7GwMrkCDQRiQExsARAAzVHg +3dsGTAqQd5jCxABJ69SQfBjh6Do1yCl/01uYkdwSKipdMi/SccJBuizc/Y2Fe8Oj +CPgkWQr9luk/3KjSntMjh9ySx5VJbAi2IX2X/w6Ze9hky3DeEdxRRlV0meTTGupP +qeLqHJEUh9uqi6zr++mqLQYbucH/6VQTlK0Y3zr3plZHIBf0ybChGih2zdKE0k/T +4YJgd8hwbRdGEQMwmmH7uZY+WRBRzNrhoSPE5DhK3DCn5kvWtdKXIkg+TVL38UhL +9TDkaCoUlch/mf5IJW1RnyUZ50RbB7jBeyg8XHE5zYarDmvhOskV2ADcym1h5teZ +vYsYyyxdBMzUBBLYt2mdbDjj5fUIe9DSbikTD+DY6B6gk8G6tVSe7aZT8z4BFmJL +hx4BHSktk3tirjynXCvoQ4FB0DdSxvK5zXsw5Eb8iNGaPPhIr+W5AteM37SPBBKg +zWRwgehGTfsHx94eNW58kMqWq3DzcfW427qUbBvwzEOBO64eWgOKMINCyfqbtkpT +WqosMa128JRjai/O45RL2+/owCFHzomSqhTew4Ex5CGcFpM0pTQiNPgz4REJZDsx +7CXNe48eDJvjGjDVIpmfL5/59hc/L36HHj+PnFoqtkp2rnMij4ZEZ7iUDTzyXbne +cZ4uBKdextLGoAOoorvd3sFcsJURkfF/hJrkk3sAEQEAAYkCPAQYAQgAJhYhBOto +rlRPH92M0mRiT7NppnqQvzh7BQJiQExsAhsMBQkHhh9EAAoJELNppnqQvzh7RQYP +/iZVbIahALzpPI+hTg9vmvybKddaaIdkYq7aWXyqfeXlDrs6imGBsDUjQZMEWxgr +Z/3VqGCzsUSwuubP/bkTzJtx0mKkhMTrzr2fITVvfuNVvfPcEkthL/gxo2+6A3Ph +WMwdZUAvnaCVcs35IkFI2xyZZkMqdWdGeuf6QES85ZmAtuLgyk+I1XCbY8aeu0/O +51NyD81Lcc5yYlN8beaufDA0nJtNUDG3GVA+hdSklComO2Q89b4KqiyiWlF26BDn +OkVKDTmIv6834IytU+STznDzt22yJ2XJmX9k0hOsvPKb13ZQVVBljatGiE11F/He +Xit9ckUtqpC2KFG8EiIwpNtRvZXSl3etUvPYKTeAmo988QSYJZLQ3HqswTybSw6Q +3Ixq7d0xRQCziPZzek5CaxlGMqjssBzv8ZqEoWFnZoEJDO9xMRL6A8fVnkeeK+Ry +dQXaCdBX3HtQ6vVD964omzE+XkIJm0w30YVbXRwPEWjtw7kKH78GSSR95u4j/hZr +VJBPNrCzFPHh6KQrBx6aB8OzIipGzZbrY8GuoLOz1ODX2XfmwJ2a9iy8xp2tgVe6 +QdeJQoSnAkx1MsC2Mn4BfzhgvC4eLf6pnmiREKpkf5ClKiNJJxP0fnN7hmm4/R3y +krJzFvwzZF9h3I61P96qxn/URA+DuSo/ZDl0KV6eOONU +=HlTQ -----END PGP PUBLIC KEY BLOCK-----""" private data class Listener( diff --git a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt index d620fe93..b997680f 100644 --- a/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt +++ b/native-modules/react-native-background-thread/android/src/main/java/com/backgroundthread/BackgroundThreadManager.kt @@ -120,13 +120,22 @@ class BackgroundThreadManager private constructor() { ): JSBundleLoader { return object : JSBundleLoader() { override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + val totalStart = System.nanoTime() + // Step 1: Load common bundle (polyfills + shared modules) + val commonStart = System.nanoTime() delegate.loadScriptFromAssets(appContext.assets, "assets://$commonAssetName", false) - BTLogger.info("Common bundle loaded from assets: $commonAssetName") + val commonMs = (System.nanoTime() - commonStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] common bundle loaded from assets in ${String.format("%.1f", commonMs)}ms: $commonAssetName") // Step 2: Load entry-specific bundle + val entryStart = System.nanoTime() delegate.loadScriptFromAssets(appContext.assets, "assets://$entryAssetName", false) - BTLogger.info("Entry bundle loaded from assets: $entryAssetName") + val entryMs = (System.nanoTime() - entryStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] entry bundle loaded from assets in ${String.format("%.1f", entryMs)}ms: $entryAssetName") + + val totalMs = (System.nanoTime() - totalStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] sequential asset load total: ${String.format("%.1f", totalMs)}ms (common=${String.format("%.1f", commonMs)}ms + entry=${String.format("%.1f", entryMs)}ms)") return "assets://$entryAssetName" } @@ -144,14 +153,19 @@ class BackgroundThreadManager private constructor() { ): JSBundleLoader { return object : JSBundleLoader() { override fun loadScript(delegate: com.facebook.react.bridge.JSBundleLoaderDelegate): String { + val totalStart = System.nanoTime() + // Step 1: Load common bundle (polyfills + shared modules) val commonFile = File(commonPath) if (!commonFile.exists()) { BTLogger.error("Common bundle file does not exist: $commonPath") throw RuntimeException("Common bundle file does not exist: $commonPath") } + BTLogger.info("[SplitBundle] common bundle file: ${commonFile.length() / 1024}KB") + val commonStart = System.nanoTime() delegate.loadScriptFromFile(commonFile.absolutePath, "common.bundle", false) - BTLogger.info("Common bundle loaded from file: $commonPath") + val commonMs = (System.nanoTime() - commonStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] common bundle loaded from file in ${String.format("%.1f", commonMs)}ms: $commonPath") // Step 2: Load entry-specific bundle val entryFile = File(entryPath) @@ -159,8 +173,14 @@ class BackgroundThreadManager private constructor() { BTLogger.error("Entry bundle file does not exist: $entryPath") throw RuntimeException("Entry bundle file does not exist: $entryPath") } + BTLogger.info("[SplitBundle] entry bundle file: ${entryFile.length() / 1024}KB") + val entryStart = System.nanoTime() delegate.loadScriptFromFile(entryFile.absolutePath, entrySourceURL, false) - BTLogger.info("Entry bundle loaded from file: $entryPath") + val entryMs = (System.nanoTime() - entryStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] entry bundle loaded from file in ${String.format("%.1f", entryMs)}ms: $entryPath") + + val totalMs = (System.nanoTime() - totalStart) / 1_000_000.0 + BTLogger.info("[SplitBundle] sequential file load total: ${String.format("%.1f", totalMs)}ms (common=${String.format("%.1f", commonMs)}ms + entry=${String.format("%.1f", entryMs)}ms)") return entrySourceURL } @@ -231,7 +251,8 @@ class BackgroundThreadManager private constructor() { BTLogger.warn("Background runner already started") return } - BTLogger.info("Starting background runner with entryURL: $entryURL") + val bgStartTime = System.nanoTime() + BTLogger.info("[SplitBundle] background runner starting with entryURL: $entryURL") val appContext = context.applicationContext val packages = @@ -306,7 +327,8 @@ class BackgroundThreadManager private constructor() { host.addReactInstanceEventListener(object : ReactInstanceEventListener { override fun onReactContextInitialized(context: ReactContext) { - BTLogger.info("Background ReactContext initialized") + val initMs = (System.nanoTime() - bgStartTime) / 1_000_000.0 + BTLogger.info("[SplitBundle] background ReactContext initialized in ${String.format("%.1f", initMs)}ms") context.runOnJSQueueThread { try { val ptr = context.javaScriptContextHolder?.get() ?: 0L diff --git a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt index a4a68d83..4907ccdd 100644 --- a/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt +++ b/native-modules/react-native-bundle-update/android/src/main/java/com/margelo/nitro/reactnativebundleupdate/ReactNativeBundleUpdate.kt @@ -64,31 +64,43 @@ fpqe0vKYUlT092joT0o6nT2MzmLmHUW0kDqD9p6JEJEZUZpqcSRE84eMTFNyu966 xy/rjN2SMJTFzkNXPkwXYrMYoahGez1oZfLzV6SQ0+blNc3aATt9aQW6uaCZtMw1 ibcfWW9neHVpRtTlMYCoa2reGaBGCv0Nd8pMcyFUQkVaes5cQHkh3r5Dba+YrVvp l4P8HMbN8/LqAv7eBfj3ylPa/8eEPWVifcum2Y9TqherN1C2JDqWIpH4EsApek3k -NMK6q0lPxXjZ3Pa5Ag0EYkBMbAEQAM1R4N3bBkwKkHeYwsQASevUkHwY4eg6Ncgp -f9NbmJHcEioqXTIv0nHCQbos3P2NhXvDowj4JFkK/ZbpP9yo0p7TI4fckseVSWwI -tiF9l/8OmXvYZMtw3hHcUUZVdJnk0xrqT6ni6hyRFIfbqous6/vpqi0GG7nB/+lU -E5StGN8696ZWRyAX9MmwoRoods3ShNJP0+GCYHfIcG0XRhEDMJph+7mWPlkQUcza -4aEjxOQ4Stwwp+ZL1rXSlyJIPk1S9/FIS/Uw5GgqFJXIf5n+SCVtUZ8lGedEWwe4 -wXsoPFxxOc2Gqw5r4TrJFdgA3MptYebXmb2LGMssXQTM1AQS2LdpnWw44+X1CHvQ -0m4pEw/g2OgeoJPBurVUnu2mU/M+ARZiS4ceAR0pLZN7Yq48p1wr6EOBQdA3Usby -uc17MORG/IjRmjz4SK/luQLXjN+0jwQSoM1kcIHoRk37B8feHjVufJDKlqtw83H1 -uNu6lGwb8MxDgTuuHloDijCDQsn6m7ZKU1qqLDGtdvCUY2ovzuOUS9vv6MAhR86J -kqoU3sOBMeQhnBaTNKU0IjT4M+ERCWQ7MewlzXuPHgyb4xow1SKZny+f+fYXPy9+ -hx4/j5xaKrZKdq5zIo+GRGe4lA088l253nGeLgSnXsbSxqADqKK73d7BXLCVEZHx -f4Sa5JN7ABEBAAGJAjwEGAEIACYWIQTraK5UTx/djNJkYk+zaaZ6kL84ewUCYkBM -bAIbDAUJB4YfRAAKCRCzaaZ6kL84e0UGD/4mVWyGoQC86TyPoU4Pb5r8mynXWmiH -ZGKu2ll8qn3l5Q67OophgbA1I0GTBFsYK2f91ahgs7FEsLrmz/25E8ybcdJipITE -6869nyE1b37jVb3z3BJLYS/4MaNvugNz4VjMHWVAL52glXLN+SJBSNscmWZDKnVn -Rnrn+kBEvOWZgLbi4MpPiNVwm2PGnrtPzudTcg/NS3HOcmJTfG3mrnwwNJybTVAx -txlQPoXUpJQqJjtkPPW+CqosolpRdugQ5zpFSg05iL+vN+CMrVPkk85w87dtsidl -yZl/ZNITrLzym9d2UFVQZY2rRohNdRfx3l4rfXJFLaqQtihRvBIiMKTbUb2V0pd3 -rVLz2Ck3gJqPfPEEmCWS0Nx6rME8m0sOkNyMau3dMUUAs4j2c3pOQmsZRjKo7LAc -7/GahKFhZ2aBCQzvcTES+gPH1Z5HnivkcnUF2gnQV9x7UOr1Q/euKJsxPl5CCZtM -N9GFW10cDxFo7cO5Ch+/BkkkfebuI/4Wa1SQTzawsxTx4eikKwcemgfDsyIqRs2W -62PBrqCzs9Tg19l35sCdmvYsvMadrYFXukHXiUKEpwJMdTLAtjJ+AX84YLwuHi3+ -qZ5okRCqZH+QpSojSScT9H5ze4ZpuP0d8pKycxb8M2RfYdyOtT/eqsZ/1EQPg7kq -P2Q5dClenjjjVA== -=F0np +NMK6q0lPxXjZ3PaJAlQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AW +IQTraK5UTx/djNJkYk+zaaZ6kL84ewUCactdeAUJDxpqwwAKCRCzaaZ6kL84e8TX +EACtuZUT79PZx964iUf6T04IZ/SFqftMdIPrvCOpyYUkzFfTjufZSP7S5dmut/dl +VLQnPjip0ZGeHeSX2ersXmmp7Ny2zqZr858ZIdLpamkEg6hRi5LWOOK4clnKzTLe +OGWlA6WzF3cb4YB4NiNOX1yxxtggZrndyMxLfSU27aZ4h98/g5j/o/FRCt0OzibH +IGKl+tUayKEEtq7+CrxWHwCXY+wFeeJFm2yhEMqeAZlVpsvGgtfWevQwHaRcld99 +5ousZOOqsCkl1J7rCeaIFowIEA3TzH0FWIQGahGiHN/+zwc7iSIL9gNEq4/AYJWK +80jPqyrRDia7VfZA/SULbWaPmmqrn/Y8qYl3jDvT/6BuwXFAgK9pz5NkWggkjAMX +nGylez9tZBfv+Bymv5RTRAHey49noF/6ZcF5fidtXAS2tfhuRIlOUfEY+QyB3lXj +kxeOOAGJ2ejTVBVIJnfoSFSsG+LH1tvzbDJvNQcMh0oQD849fip+6O0Ae3KfNZpw +aNkIdxThvBU0XCPgmyEXll/mkS5QlUQUo+EwbZOjr6xGmi310DgJo3Ry1dfZ8qBq +F3DD6NK40bkfw8I6Qjwf/IXd921ZbKe88UMjVBTpm2IH3WXR51My9LN/2gzV9zL+ +7odaaXfd+u2x9RuZ1caLXSv4Qyc/7Le1d2T4LpevA7GwMrkCDQRiQExsARAAzVHg +3dsGTAqQd5jCxABJ69SQfBjh6Do1yCl/01uYkdwSKipdMi/SccJBuizc/Y2Fe8Oj +CPgkWQr9luk/3KjSntMjh9ySx5VJbAi2IX2X/w6Ze9hky3DeEdxRRlV0meTTGupP +qeLqHJEUh9uqi6zr++mqLQYbucH/6VQTlK0Y3zr3plZHIBf0ybChGih2zdKE0k/T +4YJgd8hwbRdGEQMwmmH7uZY+WRBRzNrhoSPE5DhK3DCn5kvWtdKXIkg+TVL38UhL +9TDkaCoUlch/mf5IJW1RnyUZ50RbB7jBeyg8XHE5zYarDmvhOskV2ADcym1h5teZ +vYsYyyxdBMzUBBLYt2mdbDjj5fUIe9DSbikTD+DY6B6gk8G6tVSe7aZT8z4BFmJL +hx4BHSktk3tirjynXCvoQ4FB0DdSxvK5zXsw5Eb8iNGaPPhIr+W5AteM37SPBBKg +zWRwgehGTfsHx94eNW58kMqWq3DzcfW427qUbBvwzEOBO64eWgOKMINCyfqbtkpT +WqosMa128JRjai/O45RL2+/owCFHzomSqhTew4Ex5CGcFpM0pTQiNPgz4REJZDsx +7CXNe48eDJvjGjDVIpmfL5/59hc/L36HHj+PnFoqtkp2rnMij4ZEZ7iUDTzyXbne +cZ4uBKdextLGoAOoorvd3sFcsJURkfF/hJrkk3sAEQEAAYkCPAQYAQgAJhYhBOto +rlRPH92M0mRiT7NppnqQvzh7BQJiQExsAhsMBQkHhh9EAAoJELNppnqQvzh7RQYP +/iZVbIahALzpPI+hTg9vmvybKddaaIdkYq7aWXyqfeXlDrs6imGBsDUjQZMEWxgr +Z/3VqGCzsUSwuubP/bkTzJtx0mKkhMTrzr2fITVvfuNVvfPcEkthL/gxo2+6A3Ph +WMwdZUAvnaCVcs35IkFI2xyZZkMqdWdGeuf6QES85ZmAtuLgyk+I1XCbY8aeu0/O +51NyD81Lcc5yYlN8beaufDA0nJtNUDG3GVA+hdSklComO2Q89b4KqiyiWlF26BDn +OkVKDTmIv6834IytU+STznDzt22yJ2XJmX9k0hOsvPKb13ZQVVBljatGiE11F/He +Xit9ckUtqpC2KFG8EiIwpNtRvZXSl3etUvPYKTeAmo988QSYJZLQ3HqswTybSw6Q +3Ixq7d0xRQCziPZzek5CaxlGMqjssBzv8ZqEoWFnZoEJDO9xMRL6A8fVnkeeK+Ry +dQXaCdBX3HtQ6vVD964omzE+XkIJm0w30YVbXRwPEWjtw7kKH78GSSR95u4j/hZr +VJBPNrCzFPHh6KQrBx6aB8OzIipGzZbrY8GuoLOz1ODX2XfmwJ2a9iy8xp2tgVe6 +QdeJQoSnAkx1MsC2Mn4BfzhgvC4eLf6pnmiREKpkf5ClKiNJJxP0fnN7hmm4/R3y +krJzFvwzZF9h3I61P96qxn/URA+DuSo/ZDl0KV6eOONU +=HlTQ -----END PGP PUBLIC KEY BLOCK-----""" // Public static store for CustomReactNativeHost access (called before JS starts) diff --git a/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift b/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift index 586b6714..adcdc135 100644 --- a/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift +++ b/native-modules/react-native-bundle-update/ios/ReactNativeBundleUpdate.swift @@ -34,31 +34,43 @@ fpqe0vKYUlT092joT0o6nT2MzmLmHUW0kDqD9p6JEJEZUZpqcSRE84eMTFNyu966 xy/rjN2SMJTFzkNXPkwXYrMYoahGez1oZfLzV6SQ0+blNc3aATt9aQW6uaCZtMw1 ibcfWW9neHVpRtTlMYCoa2reGaBGCv0Nd8pMcyFUQkVaes5cQHkh3r5Dba+YrVvp l4P8HMbN8/LqAv7eBfj3ylPa/8eEPWVifcum2Y9TqherN1C2JDqWIpH4EsApek3k -NMK6q0lPxXjZ3Pa5Ag0EYkBMbAEQAM1R4N3bBkwKkHeYwsQASevUkHwY4eg6Ncgp -f9NbmJHcEioqXTIv0nHCQbos3P2NhXvDowj4JFkK/ZbpP9yo0p7TI4fckseVSWwI -tiF9l/8OmXvYZMtw3hHcUUZVdJnk0xrqT6ni6hyRFIfbqous6/vpqi0GG7nB/+lU -E5StGN8696ZWRyAX9MmwoRoods3ShNJP0+GCYHfIcG0XRhEDMJph+7mWPlkQUcza -4aEjxOQ4Stwwp+ZL1rXSlyJIPk1S9/FIS/Uw5GgqFJXIf5n+SCVtUZ8lGedEWwe4 -wXsoPFxxOc2Gqw5r4TrJFdgA3MptYebXmb2LGMssXQTM1AQS2LdpnWw44+X1CHvQ -0m4pEw/g2OgeoJPBurVUnu2mU/M+ARZiS4ceAR0pLZN7Yq48p1wr6EOBQdA3Usby -uc17MORG/IjRmjz4SK/luQLXjN+0jwQSoM1kcIHoRk37B8feHjVufJDKlqtw83H1 -uNu6lGwb8MxDgTuuHloDijCDQsn6m7ZKU1qqLDGtdvCUY2ovzuOUS9vv6MAhR86J -kqoU3sOBMeQhnBaTNKU0IjT4M+ERCWQ7MewlzXuPHgyb4xow1SKZny+f+fYXPy9+ -hx4/j5xaKrZKdq5zIo+GRGe4lA088l253nGeLgSnXsbSxqADqKK73d7BXLCVEZHx -f4Sa5JN7ABEBAAGJAjwEGAEIACYWIQTraK5UTx/djNJkYk+zaaZ6kL84ewUCYkBM -bAIbDAUJB4YfRAAKCRCzaaZ6kL84e0UGD/4mVWyGoQC86TyPoU4Pb5r8mynXWmiH -ZGKu2ll8qn3l5Q67OophgbA1I0GTBFsYK2f91ahgs7FEsLrmz/25E8ybcdJipITE -6869nyE1b37jVb3z3BJLYS/4MaNvugNz4VjMHWVAL52glXLN+SJBSNscmWZDKnVn -Rnrn+kBEvOWZgLbi4MpPiNVwm2PGnrtPzudTcg/NS3HOcmJTfG3mrnwwNJybTVAx -txlQPoXUpJQqJjtkPPW+CqosolpRdugQ5zpFSg05iL+vN+CMrVPkk85w87dtsidl -yZl/ZNITrLzym9d2UFVQZY2rRohNdRfx3l4rfXJFLaqQtihRvBIiMKTbUb2V0pd3 -rVLz2Ck3gJqPfPEEmCWS0Nx6rME8m0sOkNyMau3dMUUAs4j2c3pOQmsZRjKo7LAc -7/GahKFhZ2aBCQzvcTES+gPH1Z5HnivkcnUF2gnQV9x7UOr1Q/euKJsxPl5CCZtM -N9GFW10cDxFo7cO5Ch+/BkkkfebuI/4Wa1SQTzawsxTx4eikKwcemgfDsyIqRs2W -62PBrqCzs9Tg19l35sCdmvYsvMadrYFXukHXiUKEpwJMdTLAtjJ+AX84YLwuHi3+ -qZ5okRCqZH+QpSojSScT9H5ze4ZpuP0d8pKycxb8M2RfYdyOtT/eqsZ/1EQPg7kq -P2Q5dClenjjjVA== -=F0np +NMK6q0lPxXjZ3PaJAlQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AW +IQTraK5UTx/djNJkYk+zaaZ6kL84ewUCactdeAUJDxpqwwAKCRCzaaZ6kL84e8TX +EACtuZUT79PZx964iUf6T04IZ/SFqftMdIPrvCOpyYUkzFfTjufZSP7S5dmut/dl +VLQnPjip0ZGeHeSX2ersXmmp7Ny2zqZr858ZIdLpamkEg6hRi5LWOOK4clnKzTLe +OGWlA6WzF3cb4YB4NiNOX1yxxtggZrndyMxLfSU27aZ4h98/g5j/o/FRCt0OzibH +IGKl+tUayKEEtq7+CrxWHwCXY+wFeeJFm2yhEMqeAZlVpsvGgtfWevQwHaRcld99 +5ousZOOqsCkl1J7rCeaIFowIEA3TzH0FWIQGahGiHN/+zwc7iSIL9gNEq4/AYJWK +80jPqyrRDia7VfZA/SULbWaPmmqrn/Y8qYl3jDvT/6BuwXFAgK9pz5NkWggkjAMX +nGylez9tZBfv+Bymv5RTRAHey49noF/6ZcF5fidtXAS2tfhuRIlOUfEY+QyB3lXj +kxeOOAGJ2ejTVBVIJnfoSFSsG+LH1tvzbDJvNQcMh0oQD849fip+6O0Ae3KfNZpw +aNkIdxThvBU0XCPgmyEXll/mkS5QlUQUo+EwbZOjr6xGmi310DgJo3Ry1dfZ8qBq +F3DD6NK40bkfw8I6Qjwf/IXd921ZbKe88UMjVBTpm2IH3WXR51My9LN/2gzV9zL+ +7odaaXfd+u2x9RuZ1caLXSv4Qyc/7Le1d2T4LpevA7GwMrkCDQRiQExsARAAzVHg +3dsGTAqQd5jCxABJ69SQfBjh6Do1yCl/01uYkdwSKipdMi/SccJBuizc/Y2Fe8Oj +CPgkWQr9luk/3KjSntMjh9ySx5VJbAi2IX2X/w6Ze9hky3DeEdxRRlV0meTTGupP +qeLqHJEUh9uqi6zr++mqLQYbucH/6VQTlK0Y3zr3plZHIBf0ybChGih2zdKE0k/T +4YJgd8hwbRdGEQMwmmH7uZY+WRBRzNrhoSPE5DhK3DCn5kvWtdKXIkg+TVL38UhL +9TDkaCoUlch/mf5IJW1RnyUZ50RbB7jBeyg8XHE5zYarDmvhOskV2ADcym1h5teZ +vYsYyyxdBMzUBBLYt2mdbDjj5fUIe9DSbikTD+DY6B6gk8G6tVSe7aZT8z4BFmJL +hx4BHSktk3tirjynXCvoQ4FB0DdSxvK5zXsw5Eb8iNGaPPhIr+W5AteM37SPBBKg +zWRwgehGTfsHx94eNW58kMqWq3DzcfW427qUbBvwzEOBO64eWgOKMINCyfqbtkpT +WqosMa128JRjai/O45RL2+/owCFHzomSqhTew4Ex5CGcFpM0pTQiNPgz4REJZDsx +7CXNe48eDJvjGjDVIpmfL5/59hc/L36HHj+PnFoqtkp2rnMij4ZEZ7iUDTzyXbne +cZ4uBKdextLGoAOoorvd3sFcsJURkfF/hJrkk3sAEQEAAYkCPAQYAQgAJhYhBOto +rlRPH92M0mRiT7NppnqQvzh7BQJiQExsAhsMBQkHhh9EAAoJELNppnqQvzh7RQYP +/iZVbIahALzpPI+hTg9vmvybKddaaIdkYq7aWXyqfeXlDrs6imGBsDUjQZMEWxgr +Z/3VqGCzsUSwuubP/bkTzJtx0mKkhMTrzr2fITVvfuNVvfPcEkthL/gxo2+6A3Ph +WMwdZUAvnaCVcs35IkFI2xyZZkMqdWdGeuf6QES85ZmAtuLgyk+I1XCbY8aeu0/O +51NyD81Lcc5yYlN8beaufDA0nJtNUDG3GVA+hdSklComO2Q89b4KqiyiWlF26BDn +OkVKDTmIv6834IytU+STznDzt22yJ2XJmX9k0hOsvPKb13ZQVVBljatGiE11F/He +Xit9ckUtqpC2KFG8EiIwpNtRvZXSl3etUvPYKTeAmo988QSYJZLQ3HqswTybSw6Q +3Ixq7d0xRQCziPZzek5CaxlGMqjssBzv8ZqEoWFnZoEJDO9xMRL6A8fVnkeeK+Ry +dQXaCdBX3HtQ6vVD964omzE+XkIJm0w30YVbXRwPEWjtw7kKH78GSSR95u4j/hZr +VJBPNrCzFPHh6KQrBx6aB8OzIipGzZbrY8GuoLOz1ODX2XfmwJ2a9iy8xp2tgVe6 +QdeJQoSnAkx1MsC2Mn4BfzhgvC4eLf6pnmiREKpkf5ClKiNJJxP0fnN7hmm4/R3y +krJzFvwzZF9h3I61P96qxn/URA+DuSo/ZDl0KV6eOONU +=HlTQ -----END PGP PUBLIC KEY BLOCK----- """ diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt index 708fe2cb..58617b16 100644 --- a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt @@ -135,15 +135,18 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : // #19: Try CatalystInstance first (bridge mode), fall back to // ReactHost registerSegment if available (bridgeless / new arch). val reactContext = reactApplicationContext + val segStart = System.nanoTime() if (reactContext.hasCatalystInstance()) { reactContext.catalystInstance.registerSegment(segId, absolutePath) - SBLLogger.info("Loaded segment $segmentKey (id=$segId)") + val segMs = (System.nanoTime() - segStart) / 1_000_000.0 + SBLLogger.info("[SplitBundle] segment $segmentKey (id=$segId) registered in ${String.format("%.1f", segMs)}ms") promise.resolve(null) } else { // Bridgeless: try ReactHost via reflection val registered = tryRegisterViaBridgeless(segId, absolutePath) + val segMs = (System.nanoTime() - segStart) / 1_000_000.0 if (registered) { - SBLLogger.info("Loaded segment $segmentKey (id=$segId) via bridgeless") + SBLLogger.info("[SplitBundle] segment $segmentKey (id=$segId) registered via bridgeless in ${String.format("%.1f", segMs)}ms") promise.resolve(null) } else { promise.reject( From b650153cbc23647ea54daa9c13b54bce69fa7a3b Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 16:00:36 +0800 Subject: [PATCH 30/74] 1.1.53 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index e9272166..c00da4fe 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index afb337d4..f704d125 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index c6640c19..4ac9707b 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index c1d2a407..3c383653 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 78906b54..805fd805 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 3e9533fc..12fa8faf 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 6cfef0ee..40752f23 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 7dc4be40..7b3e9a2d 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index e17bd26f..ac8be811 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index f509ef91..a442bcbe 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.52", + "version": "1.1.53", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 62c4f0db..a071551d 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index dee4231a..97f6d806 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 6d12c4f0..d6163245 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 3d42b39e..3dd6f1f3 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.52", + "version": "1.1.53", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 3ca9f118..371f94b1 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.52", + "version": "1.1.53", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index b5c50d65..8787e593 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.52", + "version": "1.1.53", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 9fe353a9..e7a32487 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.52", + "version": "1.1.53", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index bea5f331..820ba037 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.52", + "version": "1.1.53", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 16cbb2ca36d52646a578ba72d72499b385d7d643 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 2 Apr 2026 20:23:30 +0800 Subject: [PATCH 31/74] 1.1.54 feat: drop legacy RCTBridge path, use typed RCTHost/RCTInstance for bridgeless-only segment loading --- native-modules/native-logger/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../ios/SplitBundleLoader.mm | 29 +++++-------------- .../package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 19 files changed, 26 insertions(+), 39 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index c00da4fe..d581ce4f 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index f704d125..674dbe0a 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 4ac9707b..5ddefc15 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 3c383653..9e7f8c33 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 805fd805..c55b1d09 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 12fa8faf..8bcc9e6d 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 40752f23..9a3ce935 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 7b3e9a2d..9bdec02d 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index ac8be811..90de1103 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index a442bcbe..2456898c 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.53", + "version": "1.1.54", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index a071551d..a5272dc8 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 97f6d806..c2807df7 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm index cc56caea..4bc44931 100644 --- a/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm +++ b/native-modules/react-native-split-bundle-loader/ios/SplitBundleLoader.mm @@ -1,14 +1,11 @@ #import "SplitBundleLoader.h" #import "SBLLogger.h" -#import +#import +#import +#import #import #include -// Bridgeless (New Architecture) support: RCTHost segment registration -@interface RCTHost (SplitBundle) -- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path; -@end - @implementation SplitBundleLoader - (std::shared_ptr)getTurboModule: @@ -66,26 +63,16 @@ + (nullable NSString *)otaBundlePath // MARK: - Segment registration helper -/// Registers a segment with the current runtime, supporting both legacy bridge -/// and bridgeless (RCTHost) architectures (#13). +/// Registers a segment with the current runtime via bridgeless (RCTHost) architecture (#13). /// /// Thread safety (#57): This method is called from the TurboModule (JS thread). -/// RCTBridge.registerSegmentWithId:path: internally registers the segment with -/// the Hermes runtime on the JS thread, which is the correct calling context. /// No queue dispatch is needed. + (BOOL)registerSegment:(int)segmentId path:(NSString *)path error:(NSError **)outError { - // Try legacy bridge first - RCTBridge *bridge = [RCTBridge currentBridge]; - if (bridge && [bridge respondsToSelector:@selector(registerSegmentWithId:path:)]) { - [bridge registerSegmentWithId:@(segmentId) path:path]; - return YES; - } - - // Try bridgeless RCTHost via AppDelegate + // Bridgeless (New Architecture): get RCTHost via AppDelegate id appDelegate = [UIApplication sharedApplication].delegate; if ([appDelegate respondsToSelector:NSSelectorFromString(@"reactHost")]) { - id host = [appDelegate performSelector:NSSelectorFromString(@"reactHost")]; + RCTHost *host = [appDelegate performSelector:NSSelectorFromString(@"reactHost")]; if (host && [host respondsToSelector:@selector(registerSegmentWithId:path:)]) { [host registerSegmentWithId:@(segmentId) path:path]; return YES; @@ -95,7 +82,7 @@ + (BOOL)registerSegment:(int)segmentId path:(NSString *)path error:(NSError **)o if (outError) { *outError = [NSError errorWithDomain:@"SplitBundleLoader" code:1 - userInfo:@{NSLocalizedDescriptionKey: @"Neither RCTBridge nor RCTHost available for segment registration"}]; + userInfo:@{NSLocalizedDescriptionKey: @"RCTHost not available for segment registration"}]; } return NO; } @@ -205,7 +192,7 @@ + (void)loadEntryBundle:(NSString *)bundlePath inHost:(id)host return; } - id instance = object_getIvar(host, ivar); + RCTInstance *instance = object_getIvar(host, ivar); if (!instance) { [SBLLogger warn:@"loadEntryBundle: _instance is nil"]; return; diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index d6163245..741b8997 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 3dd6f1f3..2652d8b2 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.53", + "version": "1.1.54", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 371f94b1..2945bbc5 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.53", + "version": "1.1.54", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 8787e593..0480c884 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.53", + "version": "1.1.54", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index e7a32487..7c6c8eec 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.53", + "version": "1.1.54", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 820ba037..4f5142b4 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.53", + "version": "1.1.54", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From ed223fb9b0daeeff7aec9c650dbf07b8c94fedbe Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:36:46 +0800 Subject: [PATCH 32/74] feat: add TurboModule replacements for legacy bridge modules New packages (all proper TurboModules, no RCT_EXPORT_MODULE/METHOD): - @onekeyfe/react-native-async-storage - @onekeyfe/react-native-aes-crypto - @onekeyfe/react-native-pbkdf2 - @onekeyfe/react-native-dns-lookup - @onekeyfe/react-native-network-info - @onekeyfe/react-native-ping - @onekeyfe/react-native-zip-archive - @onekeyfe/react-native-cloud-fs - @onekeyfe/react-native-tcp-socket These replace legacy bridge modules that hang in the iOS background Hermes runtime due to missing RCTBridgelessInteropLayer setup. --- .../react-native-aes-crypto/AesCrypto.podspec | 21 + .../react-native-aes-crypto/babel.config.js | 12 + .../react-native-aes-crypto/ios/AesCrypto.h | 56 ++ .../react-native-aes-crypto/ios/AesCrypto.mm | 419 ++++++++ .../react-native-aes-crypto/package.json | 155 +++ .../src/NativeAesCrypto.ts | 33 + .../react-native-aes-crypto/src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../react-native-aes-crypto/tsconfig.json | 30 + .../react-native-aes-crypto/turbo.json | 34 + .../AsyncStorage.podspec | 19 + .../babel.config.js | 12 + .../ios/AsyncStorage.h | 27 + .../ios/AsyncStorage.mm | 714 +++++++++++++ .../react-native-async-storage/package.json | 155 +++ .../src/NativeAsyncStorage.ts | 13 + .../react-native-async-storage/src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../react-native-async-storage/tsconfig.json | 30 + .../react-native-async-storage/turbo.json | 23 + .../react-native-cloud-fs/CloudFs.podspec | 19 + .../react-native-cloud-fs/babel.config.js | 12 + .../react-native-cloud-fs/ios/CloudFs.h | 7 + .../react-native-cloud-fs/ios/CloudFs.mm | 416 ++++++++ .../react-native-cloud-fs/package.json | 85 ++ .../src/NativeCloudFs.ts | 15 + .../react-native-cloud-fs/src/index.tsx | 4 + .../react-native-cloud-fs/tsconfig.build.json | 4 + .../react-native-cloud-fs/tsconfig.json | 29 + .../react-native-dns-lookup/DnsLookup.podspec | 19 + .../android/build.gradle | 77 ++ .../java/com/rnsdnslookup/DnsLookupModule.kt | 33 + .../java/com/rnsdnslookup/DnsLookupPackage.kt | 33 + .../react-native-dns-lookup/babel.config.js | 12 + .../react-native-dns-lookup/ios/DnsLookup.h | 9 + .../react-native-dns-lookup/ios/DnsLookup.mm | 99 ++ .../react-native-dns-lookup/package.json | 162 +++ .../src/NativeDnsLookup.ts | 8 + .../react-native-dns-lookup/src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../react-native-dns-lookup/tsconfig.json | 30 + .../react-native-dns-lookup/turbo.json | 43 + .../NetworkInfo.podspec | 20 + .../android/build.gradle | 77 ++ .../com/rnnetworkinfo/NetworkInfoModule.kt | 265 +++++ .../com/rnnetworkinfo/NetworkInfoPackage.kt | 33 + .../react-native-network-info/babel.config.js | 12 + .../ios/NetworkInfo.h | 24 + .../ios/NetworkInfo.mm | 347 +++++++ .../ios/getgateway.c | 83 ++ .../ios/getgateway.h | 15 + .../react-native-network-info/package.json | 162 +++ .../src/NativeNetworkInfo.ts | 16 + .../react-native-network-info/src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../react-native-network-info/tsconfig.json | 30 + .../react-native-network-info/turbo.json | 43 + .../react-native-pbkdf2/Pbkdf2.podspec | 19 + .../react-native-pbkdf2/babel.config.js | 12 + .../react-native-pbkdf2/ios/Pbkdf2.h | 13 + .../react-native-pbkdf2/ios/Pbkdf2.mm | 62 ++ .../react-native-pbkdf2/package.json | 155 +++ .../react-native-pbkdf2/src/NativePbkdf2.ts | 14 + .../react-native-pbkdf2/src/index.tsx | 4 + .../react-native-pbkdf2/tsconfig.build.json | 4 + .../react-native-pbkdf2/tsconfig.json | 30 + native-modules/react-native-pbkdf2/turbo.json | 34 + native-modules/react-native-ping/Ping.podspec | 19 + .../react-native-ping/babel.config.js | 12 + .../react-native-ping/ios/GBPing/GBPing.h | 50 + .../react-native-ping/ios/GBPing/GBPing.m | 944 ++++++++++++++++++ .../ios/GBPing/GBPingSummary.h | 24 + .../ios/GBPing/GBPingSummary.m | 67 ++ .../react-native-ping/ios/GBPing/ICMPHeader.h | 79 ++ .../ios/LHNetwork/LHDefinition.h | 24 + .../ios/LHNetwork/LHNetwork.h | 34 + .../ios/LHNetwork/LHNetwork.m | 223 +++++ native-modules/react-native-ping/ios/Ping.h | 10 + native-modules/react-native-ping/ios/Ping.mm | 91 ++ native-modules/react-native-ping/package.json | 85 ++ .../react-native-ping/src/NativePing.ts | 8 + .../react-native-ping/src/index.tsx | 4 + .../react-native-ping/tsconfig.build.json | 4 + .../react-native-ping/tsconfig.json | 29 + .../react-native-tcp-socket/TcpSocket.podspec | 19 + .../react-native-tcp-socket/babel.config.js | 12 + .../react-native-tcp-socket/ios/TcpSocket.h | 5 + .../react-native-tcp-socket/ios/TcpSocket.mm | 151 +++ .../react-native-tcp-socket/package.json | 156 +++ .../src/NativeTcpSocket.ts | 17 + .../react-native-tcp-socket/src/index.tsx | 57 ++ .../tsconfig.build.json | 4 + .../react-native-tcp-socket/tsconfig.json | 30 + .../react-native-tcp-socket/turbo.json | 32 + .../ZipArchive.podspec | 21 + .../react-native-zip-archive/babel.config.js | 12 + .../react-native-zip-archive/ios/ZipArchive.h | 10 + .../ios/ZipArchive.mm | 182 ++++ .../react-native-zip-archive/package.json | 85 ++ .../src/NativeZipArchive.ts | 13 + .../react-native-zip-archive/src/index.tsx | 4 + .../tsconfig.build.json | 4 + .../react-native-zip-archive/tsconfig.json | 29 + 103 files changed, 6925 insertions(+) create mode 100644 native-modules/react-native-aes-crypto/AesCrypto.podspec create mode 100644 native-modules/react-native-aes-crypto/babel.config.js create mode 100644 native-modules/react-native-aes-crypto/ios/AesCrypto.h create mode 100644 native-modules/react-native-aes-crypto/ios/AesCrypto.mm create mode 100644 native-modules/react-native-aes-crypto/package.json create mode 100644 native-modules/react-native-aes-crypto/src/NativeAesCrypto.ts create mode 100644 native-modules/react-native-aes-crypto/src/index.tsx create mode 100644 native-modules/react-native-aes-crypto/tsconfig.build.json create mode 100644 native-modules/react-native-aes-crypto/tsconfig.json create mode 100644 native-modules/react-native-aes-crypto/turbo.json create mode 100644 native-modules/react-native-async-storage/AsyncStorage.podspec create mode 100644 native-modules/react-native-async-storage/babel.config.js create mode 100644 native-modules/react-native-async-storage/ios/AsyncStorage.h create mode 100644 native-modules/react-native-async-storage/ios/AsyncStorage.mm create mode 100644 native-modules/react-native-async-storage/package.json create mode 100644 native-modules/react-native-async-storage/src/NativeAsyncStorage.ts create mode 100644 native-modules/react-native-async-storage/src/index.tsx create mode 100644 native-modules/react-native-async-storage/tsconfig.build.json create mode 100644 native-modules/react-native-async-storage/tsconfig.json create mode 100644 native-modules/react-native-async-storage/turbo.json create mode 100644 native-modules/react-native-cloud-fs/CloudFs.podspec create mode 100644 native-modules/react-native-cloud-fs/babel.config.js create mode 100644 native-modules/react-native-cloud-fs/ios/CloudFs.h create mode 100644 native-modules/react-native-cloud-fs/ios/CloudFs.mm create mode 100644 native-modules/react-native-cloud-fs/package.json create mode 100644 native-modules/react-native-cloud-fs/src/NativeCloudFs.ts create mode 100644 native-modules/react-native-cloud-fs/src/index.tsx create mode 100644 native-modules/react-native-cloud-fs/tsconfig.build.json create mode 100644 native-modules/react-native-cloud-fs/tsconfig.json create mode 100644 native-modules/react-native-dns-lookup/DnsLookup.podspec create mode 100644 native-modules/react-native-dns-lookup/android/build.gradle create mode 100644 native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt create mode 100644 native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupPackage.kt create mode 100644 native-modules/react-native-dns-lookup/babel.config.js create mode 100644 native-modules/react-native-dns-lookup/ios/DnsLookup.h create mode 100644 native-modules/react-native-dns-lookup/ios/DnsLookup.mm create mode 100644 native-modules/react-native-dns-lookup/package.json create mode 100644 native-modules/react-native-dns-lookup/src/NativeDnsLookup.ts create mode 100644 native-modules/react-native-dns-lookup/src/index.tsx create mode 100644 native-modules/react-native-dns-lookup/tsconfig.build.json create mode 100644 native-modules/react-native-dns-lookup/tsconfig.json create mode 100644 native-modules/react-native-dns-lookup/turbo.json create mode 100644 native-modules/react-native-network-info/NetworkInfo.podspec create mode 100644 native-modules/react-native-network-info/android/build.gradle create mode 100644 native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt create mode 100644 native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoPackage.kt create mode 100644 native-modules/react-native-network-info/babel.config.js create mode 100644 native-modules/react-native-network-info/ios/NetworkInfo.h create mode 100644 native-modules/react-native-network-info/ios/NetworkInfo.mm create mode 100644 native-modules/react-native-network-info/ios/getgateway.c create mode 100644 native-modules/react-native-network-info/ios/getgateway.h create mode 100644 native-modules/react-native-network-info/package.json create mode 100644 native-modules/react-native-network-info/src/NativeNetworkInfo.ts create mode 100644 native-modules/react-native-network-info/src/index.tsx create mode 100644 native-modules/react-native-network-info/tsconfig.build.json create mode 100644 native-modules/react-native-network-info/tsconfig.json create mode 100644 native-modules/react-native-network-info/turbo.json create mode 100644 native-modules/react-native-pbkdf2/Pbkdf2.podspec create mode 100644 native-modules/react-native-pbkdf2/babel.config.js create mode 100644 native-modules/react-native-pbkdf2/ios/Pbkdf2.h create mode 100644 native-modules/react-native-pbkdf2/ios/Pbkdf2.mm create mode 100644 native-modules/react-native-pbkdf2/package.json create mode 100644 native-modules/react-native-pbkdf2/src/NativePbkdf2.ts create mode 100644 native-modules/react-native-pbkdf2/src/index.tsx create mode 100644 native-modules/react-native-pbkdf2/tsconfig.build.json create mode 100644 native-modules/react-native-pbkdf2/tsconfig.json create mode 100644 native-modules/react-native-pbkdf2/turbo.json create mode 100644 native-modules/react-native-ping/Ping.podspec create mode 100644 native-modules/react-native-ping/babel.config.js create mode 100755 native-modules/react-native-ping/ios/GBPing/GBPing.h create mode 100755 native-modules/react-native-ping/ios/GBPing/GBPing.m create mode 100755 native-modules/react-native-ping/ios/GBPing/GBPingSummary.h create mode 100755 native-modules/react-native-ping/ios/GBPing/GBPingSummary.m create mode 100755 native-modules/react-native-ping/ios/GBPing/ICMPHeader.h create mode 100644 native-modules/react-native-ping/ios/LHNetwork/LHDefinition.h create mode 100755 native-modules/react-native-ping/ios/LHNetwork/LHNetwork.h create mode 100755 native-modules/react-native-ping/ios/LHNetwork/LHNetwork.m create mode 100644 native-modules/react-native-ping/ios/Ping.h create mode 100644 native-modules/react-native-ping/ios/Ping.mm create mode 100644 native-modules/react-native-ping/package.json create mode 100644 native-modules/react-native-ping/src/NativePing.ts create mode 100644 native-modules/react-native-ping/src/index.tsx create mode 100644 native-modules/react-native-ping/tsconfig.build.json create mode 100644 native-modules/react-native-ping/tsconfig.json create mode 100644 native-modules/react-native-tcp-socket/TcpSocket.podspec create mode 100644 native-modules/react-native-tcp-socket/babel.config.js create mode 100644 native-modules/react-native-tcp-socket/ios/TcpSocket.h create mode 100644 native-modules/react-native-tcp-socket/ios/TcpSocket.mm create mode 100644 native-modules/react-native-tcp-socket/package.json create mode 100644 native-modules/react-native-tcp-socket/src/NativeTcpSocket.ts create mode 100644 native-modules/react-native-tcp-socket/src/index.tsx create mode 100644 native-modules/react-native-tcp-socket/tsconfig.build.json create mode 100644 native-modules/react-native-tcp-socket/tsconfig.json create mode 100644 native-modules/react-native-tcp-socket/turbo.json create mode 100644 native-modules/react-native-zip-archive/ZipArchive.podspec create mode 100644 native-modules/react-native-zip-archive/babel.config.js create mode 100644 native-modules/react-native-zip-archive/ios/ZipArchive.h create mode 100644 native-modules/react-native-zip-archive/ios/ZipArchive.mm create mode 100644 native-modules/react-native-zip-archive/package.json create mode 100644 native-modules/react-native-zip-archive/src/NativeZipArchive.ts create mode 100644 native-modules/react-native-zip-archive/src/index.tsx create mode 100644 native-modules/react-native-zip-archive/tsconfig.build.json create mode 100644 native-modules/react-native-zip-archive/tsconfig.json diff --git a/native-modules/react-native-aes-crypto/AesCrypto.podspec b/native-modules/react-native-aes-crypto/AesCrypto.podspec new file mode 100644 index 00000000..907b4eed --- /dev/null +++ b/native-modules/react-native-aes-crypto/AesCrypto.podspec @@ -0,0 +1,21 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "AesCrypto" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-aes-crypto.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + s.frameworks = 'Security' + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-aes-crypto/babel.config.js b/native-modules/react-native-aes-crypto/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-aes-crypto/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-aes-crypto/ios/AesCrypto.h b/native-modules/react-native-aes-crypto/ios/AesCrypto.h new file mode 100644 index 00000000..138f3786 --- /dev/null +++ b/native-modules/react-native-aes-crypto/ios/AesCrypto.h @@ -0,0 +1,56 @@ +#import + +@interface AesCrypto : NativeAesCryptoSpecBase + +- (void)encrypt:(NSString *)data + key:(NSString *)key + iv:(NSString *)iv + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)decrypt:(NSString *)base64 + key:(NSString *)key + iv:(NSString *)iv + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)pbkdf2:(NSString *)password + salt:(NSString *)salt + cost:(double)cost + length:(double)length + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)hmac256:(NSString *)base64 + key:(NSString *)key + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)hmac512:(NSString *)base64 + key:(NSString *)key + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)sha1:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)sha256:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)sha512:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)randomUuid:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)randomKey:(double)length + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-aes-crypto/ios/AesCrypto.mm b/native-modules/react-native-aes-crypto/ios/AesCrypto.mm new file mode 100644 index 00000000..c16fb2b1 --- /dev/null +++ b/native-modules/react-native-aes-crypto/ios/AesCrypto.mm @@ -0,0 +1,419 @@ +#import "AesCrypto.h" +#import +#import +#import +#import +#import + +// --------------------------------------------------------------------------- +// MARK: - Internal helpers +// --------------------------------------------------------------------------- + +static NSString *toHex(NSData *data) { + const unsigned char *bytes = (const unsigned char *)data.bytes; + NSMutableString *hex = [NSMutableString new]; + for (NSUInteger i = 0; i < data.length; i++) { + [hex appendFormat:@"%02x", bytes[i]]; + } + return [hex copy]; +} + +static NSData *fromHex(NSString *string) { + NSMutableData *data = [[NSMutableData alloc] init]; + unsigned char whole_byte; + char byte_chars[3] = {'\0', '\0', '\0'}; + NSUInteger len = string.length / 2; + for (NSUInteger i = 0; i < len; i++) { + byte_chars[0] = (char)[string characterAtIndex:i * 2]; + byte_chars[1] = (char)[string characterAtIndex:i * 2 + 1]; + whole_byte = (unsigned char)strtol(byte_chars, NULL, 16); + [data appendBytes:&whole_byte length:1]; + } + return data; +} + +static NSData *aesCBC(NSString *operation, NSData *inputData, NSString *key, NSString *iv, NSString *algorithm) { + NSData *keyData = fromHex(key); + NSData *ivData = fromHex(iv); + + NSArray *algorithms = @[@"aes-128-cbc", @"aes-192-cbc", @"aes-256-cbc"]; + NSUInteger item = [algorithms indexOfObject:algorithm]; + size_t keyLength; + switch (item) { + case 0: keyLength = kCCKeySizeAES128; break; + case 1: keyLength = kCCKeySizeAES192; break; + default: keyLength = kCCKeySizeAES256; break; + } + + NSMutableData *buffer = [[NSMutableData alloc] initWithLength:inputData.length + kCCBlockSizeAES128]; + size_t numBytes = 0; + + CCCryptorStatus status = CCCrypt( + [operation isEqualToString:@"encrypt"] ? kCCEncrypt : kCCDecrypt, + kCCAlgorithmAES, + kCCOptionPKCS7Padding, + keyData.bytes, keyLength, + ivData.length ? ivData.bytes : nil, + inputData.bytes, inputData.length, + buffer.mutableBytes, buffer.length, + &numBytes); + + if (status == kCCSuccess) { + [buffer setLength:numBytes]; + return buffer; + } + return nil; +} + +static NSData *aesCTR(NSString *operation, NSData *inputData, NSString *key, NSString *iv, NSString *algorithm) { + NSData *keyData = fromHex(key); + NSData *ivData = fromHex(iv); + + NSArray *algorithms = @[@"aes-128-ctr", @"aes-192-ctr", @"aes-256-ctr"]; + NSUInteger item = [algorithms indexOfObject:algorithm]; + size_t keyLength; + switch (item) { + case 0: keyLength = kCCKeySizeAES128; break; + case 1: keyLength = kCCKeySizeAES192; break; + default: keyLength = kCCKeySizeAES256; break; + } + + NSMutableData *buffer = [[NSMutableData alloc] initWithLength:inputData.length + kCCBlockSizeAES128]; + size_t numBytes = 0; + CCCryptorRef cryptor = NULL; + + CCCryptorStatus status = CCCryptorCreateWithMode( + [operation isEqualToString:@"encrypt"] ? kCCEncrypt : kCCDecrypt, + kCCModeCTR, + kCCAlgorithmAES, + ccPKCS7Padding, + ivData.length ? ivData.bytes : nil, + keyData.bytes, + keyLength, + NULL, 0, 0, + kCCModeOptionCTR_BE, + &cryptor); + + if (status != kCCSuccess) { + return nil; + } + + CCCryptorStatus updateStatus = CCCryptorUpdate( + cryptor, + inputData.bytes, inputData.length, + buffer.mutableBytes, buffer.length, + &numBytes); + + if (updateStatus != kCCSuccess) { + CCCryptorRelease(cryptor); + return nil; + } + buffer.length = numBytes; + + size_t finalBytes = 0; + CCCryptorStatus finalStatus = CCCryptorFinal( + cryptor, + buffer.mutableBytes, buffer.length, + &finalBytes); + + CCCryptorRelease(cryptor); + + if (finalStatus != kCCSuccess) { + return nil; + } + return buffer; +} + +// --------------------------------------------------------------------------- +// MARK: - TurboModule implementation +// --------------------------------------------------------------------------- + +@implementation AesCrypto + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"AesCrypto"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - encrypt + +- (void)encrypt:(NSString *)data + key:(NSString *)key + iv:(NSString *)iv + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *inputData = fromHex(data); + NSData *result = nil; + if ([algorithm containsString:@"ctr"]) { + result = aesCTR(@"encrypt", inputData, key, iv, algorithm); + } else { + result = aesCBC(@"encrypt", inputData, key, iv, algorithm); + } + if (result == nil) { + reject(@"encrypt_fail", @"Encrypt error", nil); + } else { + resolve(toHex(result)); + } + } @catch (NSException *exception) { + reject(@"encrypt_fail", exception.reason, nil); + } + }); +} + +// MARK: - decrypt + +- (void)decrypt:(NSString *)base64 + key:(NSString *)key + iv:(NSString *)iv + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *inputData = fromHex(base64); + NSData *result = nil; + if ([algorithm containsString:@"ctr"]) { + result = aesCTR(@"decrypt", inputData, key, iv, algorithm); + } else { + result = aesCBC(@"decrypt", inputData, key, iv, algorithm); + } + if (result == nil) { + reject(@"decrypt_fail", @"Decrypt failed", nil); + } else { + resolve(toHex(result)); + } + } @catch (NSException *exception) { + reject(@"decrypt_fail", exception.reason, nil); + } + }); +} + +// MARK: - pbkdf2 + +- (void)pbkdf2:(NSString *)password + salt:(NSString *)salt + cost:(double)cost + length:(double)length + algorithm:(NSString *)algorithm + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *passwordData = fromHex(password); + NSData *saltData = fromHex(salt); + // length is in bits, convert to bytes + NSUInteger keyLengthBytes = (NSUInteger)(length / 8); + NSMutableData *hashKeyData = [NSMutableData dataWithLength:keyLengthBytes]; + + CCPseudoRandomAlgorithm prf = kCCPRFHmacAlgSHA512; + NSString *algoLower = [algorithm lowercaseString]; + if ([algoLower isEqualToString:@"sha1"]) { + prf = kCCPRFHmacAlgSHA1; + } else if ([algoLower isEqualToString:@"sha256"]) { + prf = kCCPRFHmacAlgSHA256; + } else if ([algoLower isEqualToString:@"sha512"]) { + prf = kCCPRFHmacAlgSHA512; + } + + int status = CCKeyDerivationPBKDF( + kCCPBKDF2, + passwordData.bytes, passwordData.length, + saltData.bytes, saltData.length, + prf, + (unsigned int)cost, + hashKeyData.mutableBytes, hashKeyData.length); + + if (status == kCCParamError) { + reject(@"keygen_fail", @"Key derivation parameter error", nil); + } else { + resolve(toHex(hashKeyData)); + } + } @catch (NSException *exception) { + reject(@"keygen_fail", exception.reason, nil); + } + }); +} + +// MARK: - hmac256 + +- (void)hmac256:(NSString *)base64 + key:(NSString *)key + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *keyData = fromHex(key); + NSData *inputData = fromHex(base64); + void *buffer = malloc(CC_SHA256_DIGEST_LENGTH); + if (!buffer) { + reject(@"hmac_fail", @"Memory allocation error", nil); + return; + } + CCHmac(kCCHmacAlgSHA256, + keyData.bytes, keyData.length, + inputData.bytes, inputData.length, + buffer); + NSData *result = [NSData dataWithBytesNoCopy:buffer + length:CC_SHA256_DIGEST_LENGTH + freeWhenDone:YES]; + resolve(toHex(result)); + } @catch (NSException *exception) { + reject(@"hmac_fail", exception.reason, nil); + } + }); +} + +// MARK: - hmac512 + +- (void)hmac512:(NSString *)base64 + key:(NSString *)key + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *keyData = fromHex(key); + NSData *inputData = fromHex(base64); + void *buffer = malloc(CC_SHA512_DIGEST_LENGTH); + if (!buffer) { + reject(@"hmac_fail", @"Memory allocation error", nil); + return; + } + CCHmac(kCCHmacAlgSHA512, + keyData.bytes, keyData.length, + inputData.bytes, inputData.length, + buffer); + NSData *result = [NSData dataWithBytesNoCopy:buffer + length:CC_SHA512_DIGEST_LENGTH + freeWhenDone:YES]; + resolve(toHex(result)); + } @catch (NSException *exception) { + reject(@"hmac_fail", exception.reason, nil); + } + }); +} + +// MARK: - sha1 + +- (void)sha1:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *inputData = fromHex(text); + NSMutableData *result = [[NSMutableData alloc] initWithLength:CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(inputData.bytes, (CC_LONG)inputData.length, result.mutableBytes); + resolve(toHex(result)); + } @catch (NSException *exception) { + reject(@"sha1_fail", exception.reason, nil); + } + }); +} + +// MARK: - sha256 + +- (void)sha256:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *inputData = fromHex(text); + unsigned char *buffer = (unsigned char *)malloc(CC_SHA256_DIGEST_LENGTH); + if (!buffer) { + reject(@"sha256_fail", @"Memory allocation error", nil); + return; + } + CC_SHA256(inputData.bytes, (CC_LONG)inputData.length, buffer); + NSData *result = [NSData dataWithBytesNoCopy:buffer + length:CC_SHA256_DIGEST_LENGTH + freeWhenDone:YES]; + resolve(toHex(result)); + } @catch (NSException *exception) { + reject(@"sha256_fail", exception.reason, nil); + } + }); +} + +// MARK: - sha512 + +- (void)sha512:(NSString *)text + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *inputData = fromHex(text); + unsigned char *buffer = (unsigned char *)malloc(CC_SHA512_DIGEST_LENGTH); + if (!buffer) { + reject(@"sha512_fail", @"Memory allocation error", nil); + return; + } + CC_SHA512(inputData.bytes, (CC_LONG)inputData.length, buffer); + NSData *result = [NSData dataWithBytesNoCopy:buffer + length:CC_SHA512_DIGEST_LENGTH + freeWhenDone:YES]; + resolve(toHex(result)); + } @catch (NSException *exception) { + reject(@"sha512_fail", exception.reason, nil); + } + }); +} + +// MARK: - randomUuid + +- (void)randomUuid:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *uuid = [[NSUUID UUID] UUIDString]; + resolve(uuid); + } @catch (NSException *exception) { + reject(@"uuid_fail", exception.reason, nil); + } + }); +} + +// MARK: - randomKey + +- (void)randomKey:(double)length + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSUInteger len = (NSUInteger)length; + NSMutableData *data = [NSMutableData dataWithLength:len]; + int result = SecRandomCopyBytes(kSecRandomDefault, len, data.mutableBytes); + if (result != errSecSuccess) { + reject(@"random_fail", @"Random key generation error", nil); + } else { + resolve(toHex(data)); + } + } @catch (NSException *exception) { + reject(@"random_fail", exception.reason, nil); + } + }); +} + +@end diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json new file mode 100644 index 00000000..c8dde6c8 --- /dev/null +++ b/native-modules/react-native-aes-crypto/package.json @@ -0,0 +1,155 @@ +{ + "name": "@onekeyfe/react-native-aes-crypto", + "version": "1.1.54", + "description": "react-native-aes-crypto", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-aes-crypto.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-aes-crypto/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-aes-crypto#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "AesCryptoSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.aescrypto" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-aes-crypto/src/NativeAesCrypto.ts b/native-modules/react-native-aes-crypto/src/NativeAesCrypto.ts new file mode 100644 index 00000000..27465870 --- /dev/null +++ b/native-modules/react-native-aes-crypto/src/NativeAesCrypto.ts @@ -0,0 +1,33 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + encrypt( + data: string, + key: string, + iv: string, + algorithm: string, + ): Promise; + decrypt( + base64: string, + key: string, + iv: string, + algorithm: string, + ): Promise; + pbkdf2( + password: string, + salt: string, + cost: number, + length: number, + algorithm: string, + ): Promise; + hmac256(base64: string, key: string): Promise; + hmac512(base64: string, key: string): Promise; + sha1(text: string): Promise; + sha256(text: string): Promise; + sha512(text: string): Promise; + randomUuid(): Promise; + randomKey(length: number): Promise; +} + +export default TurboModuleRegistry.getEnforcing('AesCrypto'); diff --git a/native-modules/react-native-aes-crypto/src/index.tsx b/native-modules/react-native-aes-crypto/src/index.tsx new file mode 100644 index 00000000..dfb905d9 --- /dev/null +++ b/native-modules/react-native-aes-crypto/src/index.tsx @@ -0,0 +1,4 @@ +import NativeAesCrypto from './NativeAesCrypto'; + +export default NativeAesCrypto; +export type { Spec as AesCryptoSpec } from './NativeAesCrypto'; diff --git a/native-modules/react-native-aes-crypto/tsconfig.build.json b/native-modules/react-native-aes-crypto/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-aes-crypto/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-aes-crypto/tsconfig.json b/native-modules/react-native-aes-crypto/tsconfig.json new file mode 100644 index 00000000..b8eac8b1 --- /dev/null +++ b/native-modules/react-native-aes-crypto/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-aes-crypto": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-aes-crypto/turbo.json b/native-modules/react-native-aes-crypto/turbo.json new file mode 100644 index 00000000..e094f154 --- /dev/null +++ b/native-modules/react-native-aes-crypto/turbo.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-async-storage/AsyncStorage.podspec b/native-modules/react-native-async-storage/AsyncStorage.podspec new file mode 100644 index 00000000..f9de49d6 --- /dev/null +++ b/native-modules/react-native-async-storage/AsyncStorage.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "AsyncStorage" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-async-storage.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-async-storage/babel.config.js b/native-modules/react-native-async-storage/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-async-storage/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-async-storage/ios/AsyncStorage.h b/native-modules/react-native-async-storage/ios/AsyncStorage.h new file mode 100644 index 00000000..89a04466 --- /dev/null +++ b/native-modules/react-native-async-storage/ios/AsyncStorage.h @@ -0,0 +1,27 @@ +#import + +@interface AsyncStorage : NativeRNCAsyncStorageSpecBase + +- (void)multiGet:(NSArray *)keys + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)multiSet:(NSArray *> *)keyValuePairs + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)multiRemove:(NSArray *)keys + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)multiMerge:(NSArray *> *)keyValuePairs + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)getAllKeys:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +- (void)clear:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-async-storage/ios/AsyncStorage.mm b/native-modules/react-native-async-storage/ios/AsyncStorage.mm new file mode 100644 index 00000000..fa5dd526 --- /dev/null +++ b/native-modules/react-native-async-storage/ios/AsyncStorage.mm @@ -0,0 +1,714 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * Adapted to a proper TurboModule (no RCT_EXPORT_MODULE / RCT_EXPORT_METHOD) + * so it works in both the main and background Hermes runtimes. + */ + +#import "AsyncStorage.h" + +#import +#import +#import + +static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1"; +static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; +static NSString *const RCTExpoStorageDirectory = @"RCTAsyncLocalStorage"; +static NSString *const RCTManifestFileName = @"manifest.json"; +static const NSUInteger RCTInlineValueThreshold = 1024; + +#pragma mark - Static helper functions + +static NSDictionary *RCTErrorForKey(NSString *key) +{ + if (![key isKindOfClass:[NSString class]]) { + return RCTMakeAndLogError(@"Invalid key - must be a string. Key: ", key, @{@"key": key}); + } else if (key.length < 1) { + return RCTMakeAndLogError( + @"Invalid key - must be at least one character. Key: ", key, @{@"key": key}); + } else { + return nil; + } +} + +static BOOL RCTAsyncStorageSetExcludedFromBackup(NSString *path, NSNumber *isExcluded) +{ + NSFileManager *fileManager = [[NSFileManager alloc] init]; + + BOOL isDir; + BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDir]; + BOOL success = false; + + if (isDir && exists) { + NSURL *pathUrl = [NSURL fileURLWithPath:path]; + NSError *error = nil; + success = [pathUrl setResourceValue:isExcluded + forKey:NSURLIsExcludedFromBackupKey + error:&error]; + + if (!success) { + NSLog(@"Could not exclude AsyncStorage dir from backup %@", error); + } + } + return success; +} + +static void RCTAppendError(NSDictionary *error, NSMutableArray **errors) +{ + if (error && errors) { + if (!*errors) { + *errors = [NSMutableArray new]; + } + [*errors addObject:error]; + } +} + +static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut) +{ + if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + NSError *error; + NSStringEncoding encoding; + NSString *entryString = [NSString stringWithContentsOfFile:filePath + usedEncoding:&encoding + error:&error]; + NSDictionary *extraData = @{@"key": RCTNullIfNil(key)}; + + if (error) { + if (errorOut) { + *errorOut = RCTMakeError(@"Failed to read storage file.", error, extraData); + } + return nil; + } + + if (encoding != NSUTF8StringEncoding) { + if (errorOut) { + *errorOut = + RCTMakeError(@"Incorrect encoding of storage file: ", @(encoding), extraData); + } + return nil; + } + return entryString; + } + + return nil; +} + +static NSString *RCTCreateStorageDirectoryPath_deprecated(NSString *storageDir) +{ + NSString *storageDirectoryPath; +#if TARGET_OS_TV + storageDirectoryPath = + NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; +#else + storageDirectoryPath = + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; +#endif + storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir]; + return storageDirectoryPath; +} + +static NSString *RCTCreateStorageDirectoryPath(NSString *storageDir) +{ + NSString *storageDirectoryPath = @""; + +#if TARGET_OS_TV + storageDirectoryPath = + NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; +#else + storageDirectoryPath = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) + .firstObject; + storageDirectoryPath = [storageDirectoryPath + stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]; +#endif + + storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir]; + + return storageDirectoryPath; +} + +static NSString *RCTGetStorageDirectory() +{ + static NSString *storageDirectory = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if TARGET_OS_TV + RCTLogWarn( + @"Persistent storage is not supported on tvOS, your data may be removed at any point."); +#endif + storageDirectory = RCTCreateStorageDirectoryPath(RCTStorageDirectory); + }); + return storageDirectory; +} + +static NSString *RCTCreateManifestFilePath(NSString *storageDirectory) +{ + return [storageDirectory stringByAppendingPathComponent:RCTManifestFileName]; +} + +static NSString *RCTGetManifestFilePath() +{ + static NSString *manifestFilePath = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manifestFilePath = RCTCreateManifestFilePath(RCTStorageDirectory); + }); + return manifestFilePath; +} + +// Only merges objects - all other types are just clobbered (including arrays) +static BOOL RCTMergeRecursive(NSMutableDictionary *destination, NSDictionary *source) +{ + BOOL modified = NO; + for (NSString *key in source) { + id sourceValue = source[key]; + id destinationValue = destination[key]; + if ([sourceValue isKindOfClass:[NSDictionary class]]) { + if ([destinationValue isKindOfClass:[NSDictionary class]]) { + if ([destinationValue classForCoder] != [NSMutableDictionary class]) { + destinationValue = [destinationValue mutableCopy]; + } + if (RCTMergeRecursive(destinationValue, sourceValue)) { + destination[key] = destinationValue; + modified = YES; + } + } else { + destination[key] = [sourceValue copy]; + modified = YES; + } + } else if (![source isEqual:destinationValue]) { + destination[key] = [sourceValue copy]; + modified = YES; + } + } + return modified; +} + +static dispatch_queue_t RCTGetMethodQueue() +{ + // We want all instances to share the same queue since they will be reading/writing the same + // files. + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = + dispatch_queue_create("com.facebook.react.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +static NSCache *RCTGetCache() +{ + // We want all instances to share the same cache since they will be reading/writing the same + // files. + static NSCache *cache; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cache = [NSCache new]; + cache.totalCostLimit = 2 * 1024 * 1024; // 2MB + +#if !TARGET_OS_OSX + // Clear cache in the event of a memory warning + [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationDidReceiveMemoryWarningNotification + object:nil + queue:nil + usingBlock:^(__unused NSNotification *note) { + [cache removeAllObjects]; + }]; +#endif // !TARGET_OS_OSX + }); + return cache; +} + +static BOOL RCTHasCreatedStorageDirectory = NO; + +static NSDictionary *RCTDeleteStorageDirectory() +{ + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]; + RCTHasCreatedStorageDirectory = NO; + if (error && error.code != NSFileNoSuchFileError) { + return RCTMakeError(@"Failed to delete storage directory.", error, nil); + } + return nil; +} + +static NSDate *RCTManifestModificationDate(NSString *manifestFilePath) +{ + NSDictionary *attributes = + [[NSFileManager defaultManager] attributesOfItemAtPath:manifestFilePath error:nil]; + return [attributes fileModificationDate]; +} + +static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error) +{ + RCTLogWarn(@"%@: %@", reason, error ? error.description : @""); +} + +static void RCTStorageDirectoryCleanupOld(NSString *oldDirectoryPath) +{ + NSError *error; + if (![[NSFileManager defaultManager] removeItemAtPath:oldDirectoryPath error:&error]) { + RCTStorageDirectoryMigrationLogError( + @"Failed to remove old storage directory during migration", error); + } +} + +static void _createStorageDirectory(NSString *storageDirectory, NSError **error) +{ + [[NSFileManager defaultManager] createDirectoryAtPath:storageDirectory + withIntermediateDirectories:YES + attributes:nil + error:error]; +} + +static void RCTStorageDirectoryMigrate(NSString *oldDirectoryPath, + NSString *newDirectoryPath, + BOOL shouldCleanupOldDirectory) +{ + NSError *error; + if (![[NSFileManager defaultManager] copyItemAtPath:oldDirectoryPath + toPath:newDirectoryPath + error:&error]) { + if (error != nil && error.code == 4 && + [newDirectoryPath isEqualToString:RCTGetStorageDirectory()]) { + error = nil; + _createStorageDirectory(RCTCreateStorageDirectoryPath(@""), &error); + if (error == nil) { + RCTStorageDirectoryMigrate( + oldDirectoryPath, newDirectoryPath, shouldCleanupOldDirectory); + } else { + RCTStorageDirectoryMigrationLogError( + @"Failed to create storage directory during migration.", error); + } + } else { + RCTStorageDirectoryMigrationLogError( + @"Failed to copy old storage directory to new storage directory location during " + @"migration", + error); + } + } else if (shouldCleanupOldDirectory) { + RCTStorageDirectoryCleanupOld(oldDirectoryPath); + } +} + +static NSString *RCTGetStoragePathForMigration() +{ + BOOL isDir; + NSString *oldStoragePath = RCTCreateStorageDirectoryPath_deprecated(RCTOldStorageDirectory); + NSString *expoStoragePath = RCTCreateStorageDirectoryPath_deprecated(RCTExpoStorageDirectory); + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL oldStorageDirectoryExists = + [fileManager fileExistsAtPath:oldStoragePath isDirectory:&isDir] && isDir; + BOOL expoStorageDirectoryExists = + [fileManager fileExistsAtPath:expoStoragePath isDirectory:&isDir] && isDir; + + if (oldStorageDirectoryExists && expoStorageDirectoryExists) { + if ([RCTManifestModificationDate(RCTCreateManifestFilePath(oldStoragePath)) + compare:RCTManifestModificationDate(RCTCreateManifestFilePath(expoStoragePath))] == + NSOrderedDescending) { + RCTStorageDirectoryCleanupOld(expoStoragePath); + return oldStoragePath; + } else { + RCTStorageDirectoryCleanupOld(oldStoragePath); + return expoStoragePath; + } + } else if (oldStorageDirectoryExists) { + return oldStoragePath; + } else if (expoStorageDirectoryExists) { + return expoStoragePath; + } else { + return nil; + } +} + +static void RCTStorageDirectoryMigrationCheck(NSString *fromStorageDirectory, + NSString *toStorageDirectory, + BOOL shouldCleanupOldDirectoryAndOverwriteNewDirectory) +{ + NSError *error; + BOOL isDir; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:fromStorageDirectory isDirectory:&isDir] && isDir) { + if ([fileManager fileExistsAtPath:toStorageDirectory]) { + if ([RCTManifestModificationDate(RCTCreateManifestFilePath(toStorageDirectory)) + compare:RCTManifestModificationDate( + RCTCreateManifestFilePath(fromStorageDirectory))] == 1) { + if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) { + RCTStorageDirectoryCleanupOld(fromStorageDirectory); + } + } else if (shouldCleanupOldDirectoryAndOverwriteNewDirectory) { + if (![fileManager removeItemAtPath:toStorageDirectory error:&error]) { + RCTStorageDirectoryMigrationLogError( + @"Failed to remove new storage directory during migration", error); + } else { + RCTStorageDirectoryMigrate(fromStorageDirectory, + toStorageDirectory, + shouldCleanupOldDirectoryAndOverwriteNewDirectory); + } + } + } else { + RCTStorageDirectoryMigrate(fromStorageDirectory, + toStorageDirectory, + shouldCleanupOldDirectoryAndOverwriteNewDirectory); + } + } +} + +#pragma mark - AsyncStorage + +@implementation AsyncStorage { + BOOL _haveSetup; + // The manifest is a dictionary of all keys with small values inlined. Null values indicate + // values that are stored in separate files (as opposed to nil values which don't exist). The + // manifest is read off disk at startup, and written to disk after all mutations. + NSMutableDictionary *_manifest; +} + ++ (NSString *)moduleName +{ + return @"RNCAsyncStorage"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + +- (instancetype)init +{ + if (!(self = [super init])) { + return nil; + } + + NSString *oldStoragePath = RCTGetStoragePathForMigration(); + if (oldStoragePath != nil) { + RCTStorageDirectoryMigrationCheck( + oldStoragePath, RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), YES); + } + + RCTStorageDirectoryMigrationCheck(RCTCreateStorageDirectoryPath_deprecated(RCTStorageDirectory), + RCTCreateStorageDirectoryPath(RCTStorageDirectory), + NO); + + return self; +} + +- (NSString *)_filePathForKey:(NSString *)key +{ + NSString *safeFileName = RCTMD5Hash(key); + return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName]; +} + +- (NSDictionary *)_ensureSetup +{ + NSError *error = nil; + if (!RCTHasCreatedStorageDirectory) { + _createStorageDirectory(RCTGetStorageDirectory(), &error); + if (error) { + return RCTMakeError(@"Failed to create storage directory.", error, nil); + } + RCTHasCreatedStorageDirectory = YES; + } + + if (!_haveSetup) { + NSNumber *isExcludedFromBackup = + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"RCTAsyncStorageExcludeFromBackup"]; + if (isExcludedFromBackup == nil) { + isExcludedFromBackup = @YES; + } + RCTAsyncStorageSetExcludedFromBackup(RCTCreateStorageDirectoryPath(RCTStorageDirectory), + isExcludedFromBackup); + + NSDictionary *errorOut = nil; + NSString *serialized = RCTReadFile(RCTCreateStorageDirectoryPath(RCTGetManifestFilePath()), + RCTManifestFileName, + &errorOut); + if (!serialized) { + if (errorOut) { + RCTLogError( + @"Could not open the existing manifest, perhaps data protection is " + @"enabled?\n\n%@", + errorOut); + return errorOut; + } else { + _manifest = [NSMutableDictionary new]; + } + } else { + _manifest = RCTJSONParseMutable(serialized, &error); + if (!_manifest) { + RCTLogError(@"Failed to parse manifest - creating a new one.\n\n%@", error); + _manifest = [NSMutableDictionary new]; + } + } + _haveSetup = YES; + } + + return nil; +} + +- (NSDictionary *)_writeManifest:(NSMutableArray *__autoreleasing *)errors +{ + NSError *error; + NSString *serialized = RCTJSONStringify(_manifest, &error); + [serialized writeToFile:RCTCreateStorageDirectoryPath(RCTGetManifestFilePath()) + atomically:YES + encoding:NSUTF8StringEncoding + error:&error]; + NSDictionary *errorOut; + if (error) { + errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil); + RCTAppendError(errorOut, errors); + } + return errorOut; +} + +- (NSString *)_getValueForKey:(NSString *)key errorOut:(NSDictionary *__autoreleasing *)errorOut +{ + NSString *value = _manifest[key]; + if (value == (id)kCFNull) { + value = [RCTGetCache() objectForKey:key]; + if (!value) { + NSString *filePath = [self _filePathForKey:key]; + value = RCTReadFile(filePath, key, errorOut); + if (value) { + [RCTGetCache() setObject:value forKey:key cost:value.length]; + } else { + [_manifest removeObjectForKey:key]; + } + } + } + return value; +} + +- (NSDictionary *)_writeEntry:(NSArray *)entry changedManifest:(BOOL *)changedManifest +{ + if (entry.count != 2) { + return RCTMakeAndLogError( + @"Entries must be arrays of the form [key: string, value: string], got: ", entry, nil); + } + NSString *key = entry[0]; + NSDictionary *errorOut = RCTErrorForKey(key); + if (errorOut) { + return errorOut; + } + NSString *value = entry[1]; + NSString *filePath = [self _filePathForKey:key]; + NSError *error; + if (value.length <= RCTInlineValueThreshold) { + if (_manifest[key] == (id)kCFNull) { + [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; + [RCTGetCache() removeObjectForKey:key]; + } + *changedManifest = YES; + _manifest[key] = value; + return nil; + } + [value writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error]; + [RCTGetCache() setObject:value forKey:key cost:value.length]; + if (error) { + errorOut = RCTMakeError(@"Failed to write value.", error, @{@"key": key}); + } else if (_manifest[key] != (id)kCFNull) { + *changedManifest = YES; + _manifest[key] = (id)kCFNull; + } + return errorOut; +} + +#pragma mark - TurboModule methods + +- (void)multiGet:(NSArray *)keys + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + NSDictionary *ensureSetupError = [self _ensureSetup]; + if (ensureSetupError) { + reject(@"ASYNC_STORAGE_ERROR", + ensureSetupError[@"message"] ?: @"Storage setup failed", + nil); + return; + } + + NSMutableArray *result = [NSMutableArray arrayWithCapacity:keys.count]; + for (NSString *key in keys) { + NSDictionary *keyError = RCTErrorForKey(key); + if (keyError) { + [result addObject:@[RCTNullIfNil(key), (id)kCFNull]]; + } else { + NSDictionary *errorOut = nil; + NSString *value = [self _getValueForKey:key errorOut:&errorOut]; + [result addObject:@[key, RCTNullIfNil(value)]]; + } + } + resolve(result); + }); +} + +- (void)multiSet:(NSArray *> *)keyValuePairs + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + NSDictionary *ensureSetupError = [self _ensureSetup]; + if (ensureSetupError) { + reject(@"ASYNC_STORAGE_ERROR", + ensureSetupError[@"message"] ?: @"Storage setup failed", + nil); + return; + } + + BOOL changedManifest = NO; + NSMutableArray *errors; + for (NSArray *entry in keyValuePairs) { + NSDictionary *keyError = [self _writeEntry:entry changedManifest:&changedManifest]; + RCTAppendError(keyError, &errors); + } + if (changedManifest) { + [self _writeManifest:&errors]; + } + if (errors.count > 0) { + reject(@"ASYNC_STORAGE_ERROR", + @"One or more keys failed to set", + nil); + } else { + resolve(nil); + } + }); +} + +- (void)multiRemove:(NSArray *)keys + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + NSDictionary *ensureSetupError = [self _ensureSetup]; + if (ensureSetupError) { + reject(@"ASYNC_STORAGE_ERROR", + ensureSetupError[@"message"] ?: @"Storage setup failed", + nil); + return; + } + + NSMutableArray *errors; + BOOL changedManifest = NO; + for (NSString *key in keys) { + NSDictionary *keyError = RCTErrorForKey(key); + if (!keyError) { + if (self->_manifest[key] == (id)kCFNull) { + NSString *filePath = [self _filePathForKey:key]; + [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; + [RCTGetCache() removeObjectForKey:key]; + } + if (self->_manifest[key]) { + changedManifest = YES; + [self->_manifest removeObjectForKey:key]; + } + } + RCTAppendError(keyError, &errors); + } + if (changedManifest) { + [self _writeManifest:&errors]; + } + if (errors.count > 0) { + reject(@"ASYNC_STORAGE_ERROR", + @"One or more keys failed to remove", + nil); + } else { + resolve(nil); + } + }); +} + +- (void)multiMerge:(NSArray *> *)keyValuePairs + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + NSDictionary *ensureSetupError = [self _ensureSetup]; + if (ensureSetupError) { + reject(@"ASYNC_STORAGE_ERROR", + ensureSetupError[@"message"] ?: @"Storage setup failed", + nil); + return; + } + + BOOL changedManifest = NO; + NSMutableArray *errors; + for (__strong NSArray *entry in keyValuePairs) { + NSDictionary *keyError; + NSString *value = [self _getValueForKey:entry[0] errorOut:&keyError]; + if (!keyError) { + if (value) { + NSError *jsonError; + NSMutableDictionary *mergedVal = RCTJSONParseMutable(value, &jsonError); + NSDictionary *mergingValue = RCTJSONParse(entry[1], &jsonError); + if (!mergingValue.count || RCTMergeRecursive(mergedVal, mergingValue)) { + entry = @[entry[0], RCTNullIfNil(RCTJSONStringify(mergedVal, NULL))]; + } + if (jsonError) { + keyError = RCTJSErrorFromNSError(jsonError); + } + } + if (!keyError) { + keyError = [self _writeEntry:entry changedManifest:&changedManifest]; + } + } + RCTAppendError(keyError, &errors); + } + if (changedManifest) { + [self _writeManifest:&errors]; + } + if (errors.count > 0) { + reject(@"ASYNC_STORAGE_ERROR", + @"One or more keys failed to merge", + nil); + } else { + resolve(nil); + } + }); +} + +- (void)getAllKeys:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + NSDictionary *ensureSetupError = [self _ensureSetup]; + if (ensureSetupError) { + reject(@"ASYNC_STORAGE_ERROR", + ensureSetupError[@"message"] ?: @"Storage setup failed", + nil); + return; + } + resolve(self->_manifest.allKeys); + }); +} + +- (void)clear:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(RCTGetMethodQueue(), ^{ + [self->_manifest removeAllObjects]; + [RCTGetCache() removeAllObjects]; + NSDictionary *error = RCTDeleteStorageDirectory(); + if (error) { + reject(@"ASYNC_STORAGE_ERROR", + error[@"message"] ?: @"Failed to clear storage", + nil); + } else { + resolve(nil); + } + }); +} + +@end diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json new file mode 100644 index 00000000..cf9973d1 --- /dev/null +++ b/native-modules/react-native-async-storage/package.json @@ -0,0 +1,155 @@ +{ + "name": "@onekeyfe/react-native-async-storage", + "version": "1.1.54", + "description": "react-native-async-storage", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "async-storage" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-async-storage.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-async-storage/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-async-storage#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "AsyncStorageSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.asyncstorage" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts new file mode 100644 index 00000000..3c43b075 --- /dev/null +++ b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts @@ -0,0 +1,13 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + multiGet(keys: string[]): Promise<[string, string | null][]>; + multiSet(keyValuePairs: [string, string][]): Promise; + multiRemove(keys: string[]): Promise; + multiMerge(keyValuePairs: [string, string][]): Promise; + getAllKeys(): Promise; + clear(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage'); diff --git a/native-modules/react-native-async-storage/src/index.tsx b/native-modules/react-native-async-storage/src/index.tsx new file mode 100644 index 00000000..d4a6579a --- /dev/null +++ b/native-modules/react-native-async-storage/src/index.tsx @@ -0,0 +1,4 @@ +import NativeAsyncStorage from './NativeAsyncStorage'; + +export default NativeAsyncStorage; +export type { Spec as AsyncStorageSpec } from './NativeAsyncStorage'; diff --git a/native-modules/react-native-async-storage/tsconfig.build.json b/native-modules/react-native-async-storage/tsconfig.build.json new file mode 100644 index 00000000..34699441 --- /dev/null +++ b/native-modules/react-native-async-storage/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["lib"] +} diff --git a/native-modules/react-native-async-storage/tsconfig.json b/native-modules/react-native-async-storage/tsconfig.json new file mode 100644 index 00000000..06c7d88e --- /dev/null +++ b/native-modules/react-native-async-storage/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "@onekeyfe/react-native-async-storage": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-async-storage/turbo.json b/native-modules/react-native-async-storage/turbo.json new file mode 100644 index 00000000..2345e23a --- /dev/null +++ b/native-modules/react-native-async-storage/turbo.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-cloud-fs/CloudFs.podspec b/native-modules/react-native-cloud-fs/CloudFs.podspec new file mode 100644 index 00000000..be9e77c4 --- /dev/null +++ b/native-modules/react-native-cloud-fs/CloudFs.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "CloudFs" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-cloud-fs.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-cloud-fs/babel.config.js b/native-modules/react-native-cloud-fs/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-cloud-fs/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.h b/native-modules/react-native-cloud-fs/ios/CloudFs.h new file mode 100644 index 00000000..b176f25b --- /dev/null +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.h @@ -0,0 +1,7 @@ +#import + +@interface CloudFs : NativeRNCloudFsSpecBase + +@property (nonatomic, strong) NSMetadataQuery *query; + +@end diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.mm b/native-modules/react-native-cloud-fs/ios/CloudFs.mm new file mode 100644 index 00000000..43811eb6 --- /dev/null +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.mm @@ -0,0 +1,416 @@ +#import "CloudFs.h" +#import +#import + +@implementation CloudFs + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNCloudFs"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (dispatch_queue_t)methodQueue +{ + return dispatch_queue_create("com.onekey.CloudFs.queue", DISPATCH_QUEUE_SERIAL); +} + +// MARK: - isAvailable + +- (void)isAvailable:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSURL *ubiquityURL = [self icloudDirectory]; + if (ubiquityURL != nil) { + return resolve(@YES); + } + return resolve(@NO); +} + +// MARK: - createFile + +- (void)createFile:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSString *destinationPath = [options objectForKey:@"targetPath"]; + NSString *content = [options objectForKey:@"content"]; + NSString *scope = [options objectForKey:@"scope"]; + bool documentsFolder = !scope || [scope caseInsensitiveCompare:@"visible"] == NSOrderedSame; + + NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + + NSError *error; + [content writeToFile:tempFile atomically:YES encoding:NSUTF8StringEncoding error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + + [self moveToICloudDirectory:documentsFolder tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; +} + +// MARK: - fileExists + +- (void)fileExists:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSString *destinationPath = [options objectForKey:@"targetPath"]; + NSString *scope = [options objectForKey:@"scope"]; + bool documentsFolder = !scope || [scope caseInsensitiveCompare:@"visible"] == NSOrderedSame; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *ubiquityURL = documentsFolder ? [self icloudDocumentsDirectory] : [self icloudDirectory]; + + if (ubiquityURL) { + NSURL *dir = [ubiquityURL URLByAppendingPathComponent:destinationPath]; + NSString *dirPath = [dir.path stringByStandardizingPath]; + bool exists = [fileManager fileExistsAtPath:dirPath]; + return resolve(@(exists)); + } else { + return reject(@"error", [NSString stringWithFormat:@"could not access iCloud drive '%@'", destinationPath], nil); + } +} + +// MARK: - listFiles + +- (void)listFiles:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSString *destinationPath = [options objectForKey:@"targetPath"]; + NSString *scope = [options objectForKey:@"scope"]; + bool documentsFolder = !scope || [scope caseInsensitiveCompare:@"visible"] == NSOrderedSame; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZ"]; + + NSURL *ubiquityURL = documentsFolder ? [self icloudDocumentsDirectory] : [self icloudDirectory]; + + if (ubiquityURL) { + NSURL *target = [ubiquityURL URLByAppendingPathComponent:destinationPath]; + NSMutableArray *fileData = [NSMutableArray new]; + NSError *error = nil; + + BOOL isDirectory; + [fileManager fileExistsAtPath:[target path] isDirectory:&isDirectory]; + + NSURL *dirPath; + NSArray *contents; + if (isDirectory) { + contents = [fileManager contentsOfDirectoryAtPath:[target path] error:&error]; + dirPath = target; + } else { + contents = @[[target lastPathComponent]]; + dirPath = [target URLByDeletingLastPathComponent]; + } + + if (error) { + return reject(@"error", error.description, nil); + } + + [contents enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) { + NSURL *fileUrl = [dirPath URLByAppendingPathComponent:object]; + NSError *attrError; + NSDictionary *attributes = [fileManager attributesOfItemAtPath:[fileUrl path] error:&attrError]; + if (attrError) { + return; + } + + NSFileAttributeType type = [attributes objectForKey:NSFileType]; + bool isDir = type == NSFileTypeDirectory; + bool isFile = type == NSFileTypeRegular; + + if (!isDir && !isFile) return; + + NSDate *modDate = [attributes objectForKey:NSFileModificationDate]; + NSError *shareError; + NSURL *shareUrl = [fileManager URLForPublishingUbiquitousItemAtURL:fileUrl expirationDate:nil error:&shareError]; + + [fileData addObject:@{ + @"name": object, + @"path": [fileUrl path], + @"uri": shareUrl ? [shareUrl absoluteString] : [NSNull null], + @"size": [attributes objectForKey:NSFileSize], + @"lastModified": [dateFormatter stringFromDate:modDate], + @"isDirectory": @(isDir), + @"isFile": @(isFile) + }]; + }]; + + NSString *relativePath = [[dirPath path] stringByReplacingOccurrencesOfString:[ubiquityURL path] withString:@"."]; + + return resolve(@{ + @"files": fileData, + @"path": relativePath + }); + } else { + return reject(@"error", [NSString stringWithFormat:@"could not list iCloud drive '%@'", destinationPath], nil); + } +} + +// MARK: - getIcloudDocument + +- (void)getIcloudDocument:(NSString *)filename + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + __block bool resolved = NO; + _query = [[NSMetadataQuery alloc] init]; + [_query setSearchScopes:@[NSMetadataQueryUbiquitousDocumentsScope, NSMetadataQueryUbiquitousDataScope]]; + + NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K == %@", NSMetadataItemFSNameKey, filename]; + [_query setPredicate:pred]; + + [[NSNotificationCenter defaultCenter] addObserverForName:NSMetadataQueryDidFinishGatheringNotification + object:_query + queue:[NSOperationQueue currentQueue] + usingBlock:^(NSNotification __strong *notification) { + NSMetadataQuery *query = [notification object]; + [query disableUpdates]; + [query stopQuery]; + for (NSMetadataItem *item in query.results) { + if ([[item valueForAttribute:NSMetadataItemFSNameKey] isEqualToString:filename]) { + resolved = YES; + NSURL *url = [item valueForAttribute:NSMetadataItemURLKey]; + bool fileIsReady = [self downloadFileIfNotAvailable:item]; + if (fileIsReady) { + NSData *data = [NSData dataWithContentsOfURL:url]; + NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return resolve(content); + } else { + [self getIcloudDocument:filename resolve:resolve reject:reject]; + } + } + } + if (!resolved) { + return reject(@"error", [NSString stringWithFormat:@"item not found '%@'", filename], nil); + } + }]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self->_query startQuery]; + }); +} + +// MARK: - deleteFromCloud + +- (void)deleteFromCloud:(NSDictionary *)item + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSError *error; + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager removeItemAtPath:item[@"path"] error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + return resolve(@YES); +} + +// MARK: - copyToCloud + +- (void)copyToCloud:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSDictionary *source = [options objectForKey:@"sourcePath"]; + NSString *destinationPath = [options objectForKey:@"targetPath"]; + NSString *scope = [options objectForKey:@"scope"]; + bool documentsFolder = !scope || [scope caseInsensitiveCompare:@"visible"] == NSOrderedSame; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *sourceUri = [source objectForKey:@"uri"]; + if (!sourceUri) { + sourceUri = [source objectForKey:@"path"]; + } + + if ([sourceUri hasPrefix:@"assets-library"]) { + ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; + [library assetForURL:[NSURL URLWithString:sourceUri] resultBlock:^(ALAsset *asset) { + ALAssetRepresentation *rep = [asset defaultRepresentation]; + Byte *buffer = (Byte *)malloc(rep.size); + NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil]; + NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; + if (data) { + NSString *filename = [sourceUri lastPathComponent]; + NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + [data writeToFile:tempFile atomically:YES]; + [self moveToICloudDirectory:documentsFolder tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; + } else { + return reject(@"error", [NSString stringWithFormat:@"failed to copy asset '%@'", sourceUri], nil); + } + } failureBlock:^(NSError *error) { + return reject(@"error", error.description, nil); + }]; + } else if ([sourceUri hasPrefix:@"file:/"] || [sourceUri hasPrefix:@"/"]) { + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^file:/+" options:NSRegularExpressionCaseInsensitive error:nil]; + NSString *modifiedSourceUri = [regex stringByReplacingMatchesInString:sourceUri options:0 range:NSMakeRange(0, [sourceUri length]) withTemplate:@"/"]; + + if ([fileManager fileExistsAtPath:modifiedSourceUri isDirectory:nil]) { + NSURL *sourceURL = [NSURL fileURLWithPath:modifiedSourceUri]; + NSString *filename = [sourceUri lastPathComponent]; + NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + + NSError *error; + if ([fileManager fileExistsAtPath:tempFile]) { + [fileManager removeItemAtPath:tempFile error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + } + + [fileManager copyItemAtPath:[sourceURL path] toPath:tempFile error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + + [self moveToICloudDirectory:documentsFolder tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; + } else { + return reject(@"error", [NSString stringWithFormat:@"no such file or directory, open '%@'", sourceUri], nil); + } + } else { + NSURL *url = [NSURL URLWithString:sourceUri]; + NSData *urlData = [NSData dataWithContentsOfURL:url]; + if (urlData) { + NSString *filename = [sourceUri lastPathComponent]; + NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + [urlData writeToFile:tempFile atomically:YES]; + [self moveToICloudDirectory:documentsFolder tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; + } else { + return reject(@"error", [NSString stringWithFormat:@"cannot download '%@'", sourceUri], nil); + } + } +} + +// MARK: - syncCloud + +- (void)syncCloud:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + _query = [[NSMetadataQuery alloc] init]; + [_query setSearchScopes:@[NSMetadataQueryUbiquitousDocumentsScope, NSMetadataQueryUbiquitousDataScope]]; + [_query setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE '*'", NSMetadataItemFSNameKey]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + BOOL startedQuery = [self->_query startQuery]; + if (!startedQuery) { + reject(@"error", @"Failed to start query.\n", nil); + } + }); + + [[NSNotificationCenter defaultCenter] addObserverForName:NSMetadataQueryDidFinishGatheringNotification + object:_query + queue:[NSOperationQueue currentQueue] + usingBlock:^(NSNotification __strong *notification) { + NSMetadataQuery *query = [notification object]; + [query disableUpdates]; + [query stopQuery]; + for (NSMetadataItem *item in query.results) { + [self downloadFileIfNotAvailable:item]; + } + return resolve(nil); + }]; +} + +// MARK: - Private helpers + +- (void)moveToICloudDirectory:(bool)documentsFolder + tempFile:(NSString *)tempFile + destinationPath:(NSString *)destinationPath + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSURL *ubiquityURL = documentsFolder ? [self icloudDocumentsDirectory] : [self icloudDirectory]; + [self moveToICloud:ubiquityURL tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; +} + +- (void)moveToICloud:(NSURL *)ubiquityURL + tempFile:(NSString *)tempFile + destinationPath:(NSString *)destinationPath + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSString *destPath = destinationPath; + while ([destPath hasPrefix:@"/"]) { + destPath = [destPath substringFromIndex:1]; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + if (ubiquityURL) { + NSURL *targetFile = [ubiquityURL URLByAppendingPathComponent:destPath]; + NSURL *dir = [targetFile URLByDeletingLastPathComponent]; + NSURL *uniqueFile = targetFile; + + if ([fileManager fileExistsAtPath:uniqueFile.path]) { + NSError *error; + [fileManager removeItemAtPath:uniqueFile.path error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + } + + if (![fileManager fileExistsAtPath:dir.path]) { + [fileManager createDirectoryAtURL:dir withIntermediateDirectories:YES attributes:nil error:nil]; + } + + NSError *error; + [fileManager setUbiquitous:YES itemAtURL:[NSURL fileURLWithPath:tempFile] destinationURL:uniqueFile error:&error]; + if (error) { + return reject(@"error", error.description, nil); + } + + [fileManager removeItemAtPath:tempFile error:&error]; + return resolve(uniqueFile.path); + } else { + NSError *error; + [fileManager removeItemAtPath:tempFile error:&error]; + return reject(@"error", [NSString stringWithFormat:@"could not copy '%@' to iCloud drive", tempFile], nil); + } +} + +- (NSURL *)icloudDocumentsDirectory +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootDirectory = [[self icloudDirectory] URLByAppendingPathComponent:@"Documents"]; + if (rootDirectory) { + if (![fileManager fileExistsAtPath:rootDirectory.path isDirectory:nil]) { + [fileManager createDirectoryAtURL:rootDirectory withIntermediateDirectories:YES attributes:nil error:nil]; + } + } + return rootDirectory; +} + +- (NSURL *)icloudDirectory +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *rootDirectory = [fileManager URLForUbiquityContainerIdentifier:nil]; + return rootDirectory; +} + +- (BOOL)downloadFileIfNotAvailable:(NSMetadataItem *)item +{ + if ([[item valueForAttribute:NSMetadataUbiquitousItemDownloadingStatusKey] isEqualToString:NSMetadataUbiquitousItemDownloadingStatusCurrent]) { + return YES; + } + NSFileManager *fm = [NSFileManager defaultManager]; + NSError *downloadError = nil; + [fm startDownloadingUbiquitousItemAtURL:[item valueForAttribute:NSMetadataItemURLKey] error:&downloadError]; + [NSThread sleepForTimeInterval:0.3]; + return NO; +} + +@end diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json new file mode 100644 index 00000000..01f1b4a2 --- /dev/null +++ b/native-modules/react-native-cloud-fs/package.json @@ -0,0 +1,85 @@ +{ + "name": "@onekeyfe/react-native-cloud-fs", + "version": "1.1.54", + "description": "react-native-cloud-fs TurboModule for OneKey", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "prepare": "bob build", + "typecheck": "tsc" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-cloud-fs.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-cloud-fs/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-cloud-fs#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "devDependencies": { + "@react-native/babel-preset": "0.83.0", + "react": "19.2.0", + "react-native": "0.83.0", + "react-native-builder-bob": "^0.40.17", + "typescript": "^5.9.2" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNCloudFsSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rncloudfs" + } + } +} diff --git a/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts b/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts new file mode 100644 index 00000000..459d5a84 --- /dev/null +++ b/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts @@ -0,0 +1,15 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + isAvailable(): Promise; + createFile(options: Object): Promise; + fileExists(options: Object): Promise; + listFiles(options: Object): Promise; + getIcloudDocument(filename: string): Promise; + deleteFromCloud(item: Object): Promise; + copyToCloud(options: Object): Promise; + syncCloud(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNCloudFs'); diff --git a/native-modules/react-native-cloud-fs/src/index.tsx b/native-modules/react-native-cloud-fs/src/index.tsx new file mode 100644 index 00000000..fbb02bb6 --- /dev/null +++ b/native-modules/react-native-cloud-fs/src/index.tsx @@ -0,0 +1,4 @@ +import NativeCloudFs from './NativeCloudFs'; + +export const CloudFs = NativeCloudFs; +export type { Spec as CloudFsSpec } from './NativeCloudFs'; diff --git a/native-modules/react-native-cloud-fs/tsconfig.build.json b/native-modules/react-native-cloud-fs/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-cloud-fs/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-cloud-fs/tsconfig.json b/native-modules/react-native-cloud-fs/tsconfig.json new file mode 100644 index 00000000..761ac268 --- /dev/null +++ b/native-modules/react-native-cloud-fs/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-cloud-fs": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-dns-lookup/DnsLookup.podspec b/native-modules/react-native-dns-lookup/DnsLookup.podspec new file mode 100644 index 00000000..e56e6855 --- /dev/null +++ b/native-modules/react-native-dns-lookup/DnsLookup.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "DnsLookup" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-dns-lookup.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-dns-lookup/android/build.gradle b/native-modules/react-native-dns-lookup/android/build.gradle new file mode 100644 index 00000000..6c02ca8f --- /dev/null +++ b/native-modules/react-native-dns-lookup/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['DnsLookup_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["DnsLookup_" + name]).toInteger() +} + +android { + namespace "com.rnsdnslookup" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt new file mode 100644 index 00000000..cf0d529c --- /dev/null +++ b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt @@ -0,0 +1,33 @@ +package com.rnsdnslookup + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.WritableNativeArray +import com.facebook.react.module.annotations.ReactModule +import java.net.InetAddress + +@ReactModule(name = DnsLookupModule.NAME) +class DnsLookupModule(reactContext: ReactApplicationContext) : + NativeRNDnsLookupSpec(reactContext) { + + companion object { + const val NAME = "RNDnsLookup" + } + + override fun getName(): String = NAME + + override fun getIpAddresses(hostname: String, promise: Promise) { + Thread { + try { + val addresses = InetAddress.getAllByName(hostname) + val result = WritableNativeArray() + for (address in addresses) { + result.pushString(address.hostAddress) + } + promise.resolve(result) + } catch (e: Exception) { + promise.reject("DNS_LOOKUP_ERROR", e.message, e) + } + }.start() + } +} diff --git a/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupPackage.kt b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupPackage.kt new file mode 100644 index 00000000..2570efc9 --- /dev/null +++ b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupPackage.kt @@ -0,0 +1,33 @@ +package com.rnsdnslookup + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class DnsLookupPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == DnsLookupModule.NAME) { + DnsLookupModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[DnsLookupModule.NAME] = ReactModuleInfo( + DnsLookupModule.NAME, + DnsLookupModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-dns-lookup/babel.config.js b/native-modules/react-native-dns-lookup/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-dns-lookup/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-dns-lookup/ios/DnsLookup.h b/native-modules/react-native-dns-lookup/ios/DnsLookup.h new file mode 100644 index 00000000..69dc15bb --- /dev/null +++ b/native-modules/react-native-dns-lookup/ios/DnsLookup.h @@ -0,0 +1,9 @@ +#import + +@interface DnsLookup : NativeRNDnsLookupSpecBase + +- (void)getIpAddresses:(NSString *)hostname + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-dns-lookup/ios/DnsLookup.mm b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm new file mode 100644 index 00000000..5e13eb04 --- /dev/null +++ b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm @@ -0,0 +1,99 @@ +#import "DnsLookup.h" + +#import +#import +#import +#import +#import + +@implementation DnsLookup + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNDnsLookup"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - getIpAddresses + +- (void)getIpAddresses:(NSString *)hostname + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSError *error = nil; + NSArray *addresses = [self performDnsLookup:hostname error:&error]; + + if (addresses == nil) { + NSString *errorCode = [NSString stringWithFormat:@"%ld", (long)error.code]; + reject(errorCode, error.userInfo[NSDebugDescriptionErrorKey], error); + } else { + resolve(addresses); + } + }); +} + +// MARK: - DNS lookup helper + +- (NSArray *)performDnsLookup:(NSString *)hostname + error:(NSError **)error +{ + if (hostname == nil) { + *error = [NSError errorWithDomain:NSGenericException + code:kCFHostErrorUnknown + userInfo:@{NSDebugDescriptionErrorKey: @"Hostname cannot be null."}]; + return nil; + } + + CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)hostname); + if (hostRef == nil) { + *error = [NSError errorWithDomain:NSGenericException + code:kCFHostErrorUnknown + userInfo:@{NSDebugDescriptionErrorKey: @"Failed to create host."}]; + return nil; + } + + BOOL didStart = CFHostStartInfoResolution(hostRef, kCFHostAddresses, nil); + if (!didStart) { + *error = [NSError errorWithDomain:NSGenericException + code:kCFHostErrorUnknown + userInfo:@{NSDebugDescriptionErrorKey: @"Failed to start."}]; + CFRelease(hostRef); + return nil; + } + + CFArrayRef addressesRef = CFHostGetAddressing(hostRef, nil); + if (addressesRef == nil) { + *error = [NSError errorWithDomain:NSGenericException + code:kCFHostErrorUnknown + userInfo:@{NSDebugDescriptionErrorKey: @"Failed to get addresses."}]; + CFRelease(hostRef); + return nil; + } + + NSMutableArray *addresses = [NSMutableArray array]; + char ipAddress[INET6_ADDRSTRLEN]; + CFIndex numAddresses = CFArrayGetCount(addressesRef); + + for (CFIndex currentIndex = 0; currentIndex < numAddresses; currentIndex++) { + struct sockaddr *address = (struct sockaddr *)CFDataGetBytePtr( + CFArrayGetValueAtIndex(addressesRef, currentIndex)); + getnameinfo(address, address->sa_len, ipAddress, INET6_ADDRSTRLEN, nil, 0, NI_NUMERICHOST); + [addresses addObject:[NSString stringWithCString:ipAddress encoding:NSASCIIStringEncoding]]; + } + + CFRelease(hostRef); + return addresses; +} + +@end diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json new file mode 100644 index 00000000..0a3ae612 --- /dev/null +++ b/native-modules/react-native-dns-lookup/package.json @@ -0,0 +1,162 @@ +{ + "name": "@onekeyfe/react-native-dns-lookup", + "version": "1.1.54", + "description": "react-native-dns-lookup", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "android", + "ios", + "*.podspec", + "!ios/build", + "!android/build", + "!android/gradle", + "!android/gradlew", + "!android/gradlew.bat", + "!android/local.properties", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-dns-lookup.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-dns-lookup/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-dns-lookup#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNDnsLookupSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rnsdnslookup" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/example/node_modules", + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-dns-lookup/src/NativeDnsLookup.ts b/native-modules/react-native-dns-lookup/src/NativeDnsLookup.ts new file mode 100644 index 00000000..48cbaf4a --- /dev/null +++ b/native-modules/react-native-dns-lookup/src/NativeDnsLookup.ts @@ -0,0 +1,8 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + getIpAddresses(hostname: string): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNDnsLookup'); diff --git a/native-modules/react-native-dns-lookup/src/index.tsx b/native-modules/react-native-dns-lookup/src/index.tsx new file mode 100644 index 00000000..c0aadbf3 --- /dev/null +++ b/native-modules/react-native-dns-lookup/src/index.tsx @@ -0,0 +1,4 @@ +import NativeDnsLookup from './NativeDnsLookup'; + +export const DnsLookup = NativeDnsLookup; +export type { Spec as DnsLookupSpec } from './NativeDnsLookup'; diff --git a/native-modules/react-native-dns-lookup/tsconfig.build.json b/native-modules/react-native-dns-lookup/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-dns-lookup/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-dns-lookup/tsconfig.json b/native-modules/react-native-dns-lookup/tsconfig.json new file mode 100644 index 00000000..7359a8bf --- /dev/null +++ b/native-modules/react-native-dns-lookup/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-dns-lookup": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-dns-lookup/turbo.json b/native-modules/react-native-dns-lookup/turbo.json new file mode 100644 index 00000000..8b2bf087 --- /dev/null +++ b/native-modules/react-native-dns-lookup/turbo.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/android", + "!example/android/.gradle", + "!example/android/build", + "!example/android/app/build" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/ios", + "!example/ios/build", + "!example/ios/Pods" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-network-info/NetworkInfo.podspec b/native-modules/react-native-network-info/NetworkInfo.podspec new file mode 100644 index 00000000..7b525800 --- /dev/null +++ b/native-modules/react-native-network-info/NetworkInfo.podspec @@ -0,0 +1,20 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "NetworkInfo" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-network-info.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift,c}" + s.frameworks = 'CoreLocation', 'SystemConfiguration', 'NetworkExtension' + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-network-info/android/build.gradle b/native-modules/react-native-network-info/android/build.gradle new file mode 100644 index 00000000..8433aae7 --- /dev/null +++ b/native-modules/react-native-network-info/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['NetworkInfo_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NetworkInfo_" + name]).toInteger() +} + +android { + namespace "com.rnnetworkinfo" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt new file mode 100644 index 00000000..699eea23 --- /dev/null +++ b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt @@ -0,0 +1,265 @@ +package com.rnnetworkinfo + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.net.wifi.WifiInfo +import android.net.wifi.WifiManager +import android.os.Build +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import java.net.Inet4Address +import java.net.Inet6Address +import java.net.InetAddress +import java.net.NetworkInterface + +@ReactModule(name = NetworkInfoModule.NAME) +class NetworkInfoModule(reactContext: ReactApplicationContext) : + NativeRNNetworkInfoSpec(reactContext) { + + companion object { + const val NAME = "RNNetworkInfo" + } + + override fun getName(): String = NAME + + // MARK: - getSSID + + override fun getSSID(promise: Promise) { + Thread { + try { + val ssid = getWifiSSID() + promise.resolve(ssid) + } catch (e: Exception) { + promise.resolve(null) + } + }.start() + } + + private fun getWifiSSID(): String? { + val context = reactApplicationContext + val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager + ?: return null + @Suppress("DEPRECATION") + val wifiInfo: WifiInfo = wifiManager.connectionInfo ?: return null + @Suppress("DEPRECATION") + val ssid = wifiInfo.ssid + if (ssid == null || ssid == "") return null + return if (ssid.startsWith("\"") && ssid.endsWith("\"")) { + ssid.substring(1, ssid.length - 1) + } else { + ssid + } + } + + // MARK: - getBSSID + + override fun getBSSID(promise: Promise) { + Thread { + try { + val context = reactApplicationContext + val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager + @Suppress("DEPRECATION") + val bssid = wifiManager?.connectionInfo?.bssid + promise.resolve(bssid) + } catch (e: Exception) { + promise.resolve(null) + } + }.start() + } + + // MARK: - getBroadcast + + override fun getBroadcast(promise: Promise) { + Thread { + try { + var broadcast: String? = null + val interfaces = NetworkInterface.getNetworkInterfaces() + while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (iface.name == "wlan0" || iface.name == "eth0") { + for (ia in iface.interfaceAddresses) { + val broadcastAddr = ia.broadcast + if (broadcastAddr != null) { + broadcast = broadcastAddr.hostAddress + break + } + } + } + if (broadcast != null) break + } + promise.resolve(broadcast) + } catch (e: Exception) { + promise.resolve(null) + } + }.start() + } + + // MARK: - getIPAddress + + override fun getIPAddress(promise: Promise) { + Thread { + try { + val address = getIPv4Address() + promise.resolve(address ?: "") + } catch (e: Exception) { + promise.resolve("") + } + }.start() + } + + // MARK: - getIPV6Address + + override fun getIPV6Address(promise: Promise) { + Thread { + try { + var address: String? = null + val interfaces = NetworkInterface.getNetworkInterfaces() + loop@ while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (!iface.isUp || iface.isLoopback) continue + val addrs = iface.inetAddresses + while (addrs.hasMoreElements()) { + val addr = addrs.nextElement() + if (addr is Inet6Address && !addr.isLoopbackAddress && !addr.isLinkLocalAddress) { + address = addr.hostAddress + break@loop + } + } + } + promise.resolve(address ?: "") + } catch (e: Exception) { + promise.resolve("") + } + }.start() + } + + // MARK: - getGatewayIPAddress + + override fun getGatewayIPAddress(promise: Promise) { + Thread { + try { + val context = reactApplicationContext + val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager + @Suppress("DEPRECATION") + val dhcpInfo = wifiManager?.dhcpInfo + val gateway = if (dhcpInfo != null && dhcpInfo.gateway != 0) { + formatIpAddress(dhcpInfo.gateway) + } else { + null + } + promise.resolve(gateway ?: "") + } catch (e: Exception) { + promise.resolve("") + } + }.start() + } + + // MARK: - getIPV4Address + + override fun getIPV4Address(promise: Promise) { + Thread { + try { + val address = getIPv4Address() + promise.resolve(address ?: "0.0.0.0") + } catch (e: Exception) { + promise.resolve("0.0.0.0") + } + }.start() + } + + // MARK: - getWIFIIPV4Address + + override fun getWIFIIPV4Address(promise: Promise) { + Thread { + try { + var address: String? = null + val interfaces = NetworkInterface.getNetworkInterfaces() + loop@ while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (iface.name == "wlan0") { + val addrs = iface.inetAddresses + while (addrs.hasMoreElements()) { + val addr = addrs.nextElement() + if (addr is Inet4Address && !addr.isLoopbackAddress) { + address = addr.hostAddress + break@loop + } + } + } + } + promise.resolve(address ?: "0.0.0.0") + } catch (e: Exception) { + promise.resolve("0.0.0.0") + } + }.start() + } + + // MARK: - getSubnet + + override fun getSubnet(promise: Promise) { + Thread { + try { + var subnet: String? = null + val interfaces = NetworkInterface.getNetworkInterfaces() + loop@ while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (!iface.isUp || iface.isLoopback) continue + for (ia in iface.interfaceAddresses) { + val addr = ia.address + if (addr is Inet4Address && !addr.isLoopbackAddress) { + val prefixLen = ia.networkPrefixLength.toInt() + val mask = prefixLengthToSubnetMask(prefixLen) + subnet = mask + break@loop + } + } + } + promise.resolve(subnet ?: "0.0.0.0") + } catch (e: Exception) { + promise.resolve("0.0.0.0") + } + }.start() + } + + // MARK: - Helpers + + private fun getIPv4Address(): String? { + val interfaces = NetworkInterface.getNetworkInterfaces() + while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (!iface.isUp || iface.isLoopback) continue + val addrs = iface.inetAddresses + while (addrs.hasMoreElements()) { + val addr = addrs.nextElement() + if (addr is Inet4Address && !addr.isLoopbackAddress) { + return addr.hostAddress + } + } + } + return null + } + + @Suppress("DEPRECATION") + private fun formatIpAddress(ip: Int): String { + return String.format( + "%d.%d.%d.%d", + ip and 0xff, + ip shr 8 and 0xff, + ip shr 16 and 0xff, + ip shr 24 and 0xff + ) + } + + private fun prefixLengthToSubnetMask(prefixLength: Int): String { + val mask = if (prefixLength == 0) 0 else (-1 shl (32 - prefixLength)) + return String.format( + "%d.%d.%d.%d", + mask shr 24 and 0xff, + mask shr 16 and 0xff, + mask shr 8 and 0xff, + mask and 0xff + ) + } +} diff --git a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoPackage.kt b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoPackage.kt new file mode 100644 index 00000000..6670828e --- /dev/null +++ b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoPackage.kt @@ -0,0 +1,33 @@ +package com.rnnetworkinfo + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class NetworkInfoPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == NetworkInfoModule.NAME) { + NetworkInfoModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[NetworkInfoModule.NAME] = ReactModuleInfo( + NetworkInfoModule.NAME, + NetworkInfoModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-network-info/babel.config.js b/native-modules/react-native-network-info/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-network-info/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.h b/native-modules/react-native-network-info/ios/NetworkInfo.h new file mode 100644 index 00000000..a71077ff --- /dev/null +++ b/native-modules/react-native-network-info/ios/NetworkInfo.h @@ -0,0 +1,24 @@ +#import + +@interface NetworkInfo : NativeRNNetworkInfoSpecBase + +- (void)getSSID:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getBSSID:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getBroadcast:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getIPAddress:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getIPV6Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getGatewayIPAddress:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getIPV4Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getWIFIIPV4Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getSubnet:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.mm b/native-modules/react-native-network-info/ios/NetworkInfo.mm new file mode 100644 index 00000000..6c374670 --- /dev/null +++ b/native-modules/react-native-network-info/ios/NetworkInfo.mm @@ -0,0 +1,347 @@ +#import "NetworkInfo.h" +#import "getgateway.h" + +#import +#import +#include +#include +#include +#include +#import + +#define IOS_CELLULAR @"pdp_ip0" +#define IOS_WIFI @"en0" +#define IP_ADDR_IPv4 @"ipv4" +#define IP_ADDR_IPv6 @"ipv6" + +@import SystemConfiguration.CaptiveNetwork; + +@implementation NetworkInfo + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNNetworkInfo"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - getSSID + +- (void)getSSID:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ +#if TARGET_OS_IOS + if (@available(iOS 14.0, *)) { + [NEHotspotNetwork fetchCurrentWithCompletionHandler:^(NEHotspotNetwork * _Nullable currentNetwork) { + resolve(currentNetwork.SSID); + }]; + return; + } + + @try { + NSArray *interfaceNames = CFBridgingRelease(CNCopySupportedInterfaces()); + NSDictionary *SSIDInfo; + NSString *SSID = nil; + + for (NSString *interfaceName in interfaceNames) { + SSIDInfo = CFBridgingRelease(CNCopyCurrentNetworkInfo((__bridge CFStringRef)interfaceName)); + if (SSIDInfo.count > 0) { + SSID = SSIDInfo[@"SSID"]; + break; + } + } + resolve(SSID); + } @catch (NSException *exception) { + resolve(nil); + } +#else + resolve(nil); +#endif +} + +// MARK: - getBSSID + +- (void)getBSSID:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ +#if TARGET_OS_IOS + if (@available(iOS 14.0, *)) { + [NEHotspotNetwork fetchCurrentWithCompletionHandler:^(NEHotspotNetwork * _Nullable currentNetwork) { + resolve(currentNetwork.BSSID); + }]; + return; + } + + @try { + NSArray *interfaceNames = CFBridgingRelease(CNCopySupportedInterfaces()); + NSString *BSSID = nil; + + for (NSString *interface in interfaceNames) { + CFDictionaryRef networkDetails = CNCopyCurrentNetworkInfo((CFStringRef)interface); + if (networkDetails) { + BSSID = (NSString *)CFDictionaryGetValue(networkDetails, kCNNetworkInfoKeyBSSID); + CFRelease(networkDetails); + } + } + resolve(BSSID); + } @catch (NSException *exception) { + resolve(nil); + } +#else + resolve(nil); +#endif +} + +// MARK: - getBroadcast + +- (void)getBroadcast:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *address = nil; + + struct ifaddrs *interfaces = NULL; + struct ifaddrs *temp_addr = NULL; + int success = getifaddrs(&interfaces); + + if (success == 0) { + temp_addr = interfaces; + while (temp_addr != NULL) { + if (temp_addr->ifa_addr->sa_family == AF_INET) { + if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { + NSString *localAddr = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; + NSString *netmask = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]; + + struct in_addr local_addr; + struct in_addr netmask_addr; + inet_aton([localAddr UTF8String], &local_addr); + inet_aton([netmask UTF8String], &netmask_addr); + + local_addr.s_addr |= ~(netmask_addr.s_addr); + address = [NSString stringWithUTF8String:inet_ntoa(local_addr)]; + } + } + temp_addr = temp_addr->ifa_next; + } + } + freeifaddrs(interfaces); + resolve(address); + } @catch (NSException *exception) { + resolve(nil); + } + }); +} + +// MARK: - getIPAddress + +- (void)getIPAddress:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *address = nil; + + struct ifaddrs *interfaces = NULL; + struct ifaddrs *temp_addr = NULL; + int success = getifaddrs(&interfaces); + + if (success == 0) { + temp_addr = interfaces; + while (temp_addr != NULL) { + if (temp_addr->ifa_addr->sa_family == AF_INET) { + if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { + address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; + } + } + temp_addr = temp_addr->ifa_next; + } + } + freeifaddrs(interfaces); + resolve(address ?: @""); + } @catch (NSException *exception) { + resolve(@""); + } + }); +} + +// MARK: - getIPV6Address + +- (void)getIPV6Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *address = nil; + + struct ifaddrs *interfaces = NULL; + struct ifaddrs *temp_addr = NULL; + int success = getifaddrs(&interfaces); + + if (success == 0) { + temp_addr = interfaces; + while (temp_addr != NULL) { + if (temp_addr->ifa_addr->sa_family == AF_INET6) { + if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { + char ipAddress[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)temp_addr->ifa_addr; + if (inet_ntop(AF_INET6, &addr6->sin6_addr, ipAddress, INET6_ADDRSTRLEN)) { + address = [NSString stringWithUTF8String:ipAddress]; + } + } + } + temp_addr = temp_addr->ifa_next; + } + } + freeifaddrs(interfaces); + resolve(address ?: @""); + } @catch (NSException *exception) { + resolve(@""); + } + }); +} + +// MARK: - getGatewayIPAddress + +- (void)getGatewayIPAddress:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *ipString = nil; + struct in_addr gatewayaddr; + int r = getdefaultgateway(&(gatewayaddr.s_addr)); + if (r >= 0) { + ipString = [NSString stringWithFormat:@"%s", inet_ntoa(gatewayaddr)]; + } + resolve(ipString ?: @""); + } @catch (NSException *exception) { + resolve(@""); + } + }); +} + +// MARK: - getIPV4Address + +- (void)getIPV4Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSArray *searchArray = @[IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv4]; + NSDictionary *addresses = [self getAllIPAddresses]; + + __block NSString *address = nil; + [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) { + address = addresses[key]; + if (address) *stop = YES; + }]; + resolve(address ?: @"0.0.0.0"); + } @catch (NSException *exception) { + resolve(@"0.0.0.0"); + } + }); +} + +// MARK: - getWIFIIPV4Address + +- (void)getWIFIIPV4Address:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSArray *searchArray = @[IOS_WIFI @"/" IP_ADDR_IPv4]; + NSDictionary *addresses = [self getAllIPAddresses]; + + __block NSString *address = nil; + [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) { + address = addresses[key]; + if (address) *stop = YES; + }]; + resolve(address ?: @"0.0.0.0"); + } @catch (NSException *exception) { + resolve(@"0.0.0.0"); + } + }); +} + +// MARK: - getSubnet + +- (void)getSubnet:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSString *netmask = nil; + struct ifaddrs *interfaces = NULL; + struct ifaddrs *temp_addr = NULL; + + int success = getifaddrs(&interfaces); + if (success == 0) { + temp_addr = interfaces; + while (temp_addr != NULL) { + if (temp_addr->ifa_addr->sa_family == AF_INET) { + if ([@(temp_addr->ifa_name) isEqualToString:@"en0"]) { + netmask = @(inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)); + } + } + temp_addr = temp_addr->ifa_next; + } + } + freeifaddrs(interfaces); + resolve(netmask ?: @"0.0.0.0"); + } @catch (NSException *exception) { + resolve(@"0.0.0.0"); + } + }); +} + +// MARK: - getAllIPAddresses helper + +- (NSDictionary *)getAllIPAddresses +{ + NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8]; + + struct ifaddrs *interfaces; + if (!getifaddrs(&interfaces)) { + struct ifaddrs *interface; + for (interface = interfaces; interface; interface = interface->ifa_next) { + if (!(interface->ifa_flags & IFF_UP)) { + continue; + } + const struct sockaddr_in *addr = (const struct sockaddr_in *)interface->ifa_addr; + char addrBuf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + if (addr && (addr->sin_family == AF_INET || addr->sin_family == AF_INET6)) { + NSString *name = [NSString stringWithUTF8String:interface->ifa_name]; + NSString *type = nil; + if (addr->sin_family == AF_INET) { + if (inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) { + type = IP_ADDR_IPv4; + } + } else { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)interface->ifa_addr; + if (inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) { + type = IP_ADDR_IPv6; + } + } + if (type) { + NSString *key = [NSString stringWithFormat:@"%@/%@", name, type]; + addresses[key] = [NSString stringWithUTF8String:addrBuf]; + } + } + } + freeifaddrs(interfaces); + } + return [addresses count] ? addresses : @{}; +} + +@end diff --git a/native-modules/react-native-network-info/ios/getgateway.c b/native-modules/react-native-network-info/ios/getgateway.c new file mode 100644 index 00000000..6fa9110f --- /dev/null +++ b/native-modules/react-native-network-info/ios/getgateway.c @@ -0,0 +1,83 @@ +// +// getgateway.c +// +// This is pulled directly from https://stackoverflow.com/a/29440193/1120802 +// + +#include +#include +#include +#include +#include "getgateway.h" + +#include "TargetConditionals.h" +#if TARGET_IPHONE_SIMULATOR +#include +#define TypeEN "en1" +#else +#include +#define TypeEN "en0" +#endif + +#include +#include + +#define CTL_NET 4 /* network, see socket.h */ + +#if defined(BSD) || defined(__APPLE__) + +#define ROUNDUP(a) \ +((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +int getdefaultgateway(in_addr_t *addr) +{ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_FLAGS, RTF_GATEWAY}; + size_t l; + char *buf, *p; + struct rt_msghdr *rt; + struct sockaddr *sa; + struct sockaddr *sa_tab[RTAX_MAX]; + int i; + int r = -1; + if (sysctl(mib, sizeof(mib) / sizeof(int), 0, &l, 0, 0) < 0) { + return -1; + } + if (l > 0) { + buf = malloc(l); + if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) { + free(buf); + return -1; + } + for (p = buf; p < buf + l; p += rt->rtm_msglen) { + rt = (struct rt_msghdr *)p; + sa = (struct sockaddr *)(rt + 1); + for (i = 0; i < RTAX_MAX; i++) { + if (rt->rtm_addrs & (1 << i)) { + sa_tab[i] = sa; + sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); + } else { + sa_tab[i] = NULL; + } + } + + if (((rt->rtm_addrs & (RTA_DST | RTA_GATEWAY)) == (RTA_DST | RTA_GATEWAY)) + && sa_tab[RTAX_DST]->sa_family == AF_INET + && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { + + if (((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { + char ifName[128]; + if_indextoname(rt->rtm_index, ifName); + if (strcmp(TypeEN, ifName) == 0) { + *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; + r = 0; + } + } + } + } + free(buf); + } + return r; +} + +#endif diff --git a/native-modules/react-native-network-info/ios/getgateway.h b/native-modules/react-native-network-info/ios/getgateway.h new file mode 100644 index 00000000..6b9c9621 --- /dev/null +++ b/native-modules/react-native-network-info/ios/getgateway.h @@ -0,0 +1,15 @@ +// +// getgateway.h +// +// This is pulled directly from https://stackoverflow.com/a/29440193/1120802 +// + +#ifndef getgateway_h +#define getgateway_h + +#include +#include + +int getdefaultgateway(in_addr_t *addr); + +#endif /* getgateway_h */ diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json new file mode 100644 index 00000000..f7411b45 --- /dev/null +++ b/native-modules/react-native-network-info/package.json @@ -0,0 +1,162 @@ +{ + "name": "@onekeyfe/react-native-network-info", + "version": "1.1.54", + "description": "react-native-network-info", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "android", + "ios", + "*.podspec", + "!ios/build", + "!android/build", + "!android/gradle", + "!android/gradlew", + "!android/gradlew.bat", + "!android/local.properties", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-network-info.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-network-info/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-network-info#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNNetworkInfoSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rnnetworkinfo" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/example/node_modules", + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-network-info/src/NativeNetworkInfo.ts b/native-modules/react-native-network-info/src/NativeNetworkInfo.ts new file mode 100644 index 00000000..5d0d16df --- /dev/null +++ b/native-modules/react-native-network-info/src/NativeNetworkInfo.ts @@ -0,0 +1,16 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + getSSID(): Promise; + getBSSID(): Promise; + getBroadcast(): Promise; + getIPAddress(): Promise; + getIPV6Address(): Promise; + getGatewayIPAddress(): Promise; + getIPV4Address(): Promise; + getWIFIIPV4Address(): Promise; + getSubnet(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNNetworkInfo'); diff --git a/native-modules/react-native-network-info/src/index.tsx b/native-modules/react-native-network-info/src/index.tsx new file mode 100644 index 00000000..d7328bea --- /dev/null +++ b/native-modules/react-native-network-info/src/index.tsx @@ -0,0 +1,4 @@ +import NativeNetworkInfo from './NativeNetworkInfo'; + +export const NetworkInfo = NativeNetworkInfo; +export type { Spec as NetworkInfoSpec } from './NativeNetworkInfo'; diff --git a/native-modules/react-native-network-info/tsconfig.build.json b/native-modules/react-native-network-info/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-network-info/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-network-info/tsconfig.json b/native-modules/react-native-network-info/tsconfig.json new file mode 100644 index 00000000..4d9ef8bb --- /dev/null +++ b/native-modules/react-native-network-info/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-network-info": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-network-info/turbo.json b/native-modules/react-native-network-info/turbo.json new file mode 100644 index 00000000..8b2bf087 --- /dev/null +++ b/native-modules/react-native-network-info/turbo.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/android", + "!example/android/.gradle", + "!example/android/build", + "!example/android/app/build" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/ios", + "!example/ios/build", + "!example/ios/Pods" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-pbkdf2/Pbkdf2.podspec b/native-modules/react-native-pbkdf2/Pbkdf2.podspec new file mode 100644 index 00000000..fa06c778 --- /dev/null +++ b/native-modules/react-native-pbkdf2/Pbkdf2.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "Pbkdf2" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-pbkdf2.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-pbkdf2/babel.config.js b/native-modules/react-native-pbkdf2/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-pbkdf2/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-pbkdf2/ios/Pbkdf2.h b/native-modules/react-native-pbkdf2/ios/Pbkdf2.h new file mode 100644 index 00000000..1c5a0597 --- /dev/null +++ b/native-modules/react-native-pbkdf2/ios/Pbkdf2.h @@ -0,0 +1,13 @@ +#import + +@interface Pbkdf2 : NativePbkdf2SpecBase + +- (void)derive:(NSString *)password + salt:(NSString *)salt + rounds:(double)rounds + keyLength:(double)keyLength + hash:(NSString *)hash + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm b/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm new file mode 100644 index 00000000..0efe8fe6 --- /dev/null +++ b/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm @@ -0,0 +1,62 @@ +#import "Pbkdf2.h" +#import + +@implementation Pbkdf2 + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"Pbkdf2"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - derive + +- (void)derive:(NSString *)password + salt:(NSString *)salt + rounds:(double)rounds + keyLength:(double)keyLength + hash:(NSString *)hash + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @try { + NSData *passwordData = [[NSData alloc] initWithBase64EncodedString:password options:0]; + NSData *saltData = [[NSData alloc] initWithBase64EncodedString:salt options:0]; + + NSUInteger keyLengthBytes = (NSUInteger)keyLength; + NSMutableData *derivedKey = [NSMutableData dataWithLength:keyLengthBytes]; + + CCPseudoRandomAlgorithm prf = kCCPRFHmacAlgSHA1; + if ([hash isEqualToString:@"sha-512"]) { + prf = kCCPRFHmacAlgSHA512; + } else if ([hash isEqualToString:@"sha-256"]) { + prf = kCCPRFHmacAlgSHA256; + } + + CCKeyDerivationPBKDF( + kCCPBKDF2, + passwordData.bytes, passwordData.length, + saltData.bytes, saltData.length, + prf, + (unsigned int)rounds, + derivedKey.mutableBytes, derivedKey.length); + + resolve([derivedKey base64EncodedStringWithOptions:0]); + } @catch (NSException *exception) { + reject(@"derive_fail", exception.reason, nil); + } + }); +} + +@end diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json new file mode 100644 index 00000000..5cb8323d --- /dev/null +++ b/native-modules/react-native-pbkdf2/package.json @@ -0,0 +1,155 @@ +{ + "name": "@onekeyfe/react-native-pbkdf2", + "version": "1.1.54", + "description": "react-native-pbkdf2", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-pbkdf2.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-pbkdf2/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-pbkdf2#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "Pbkdf2Spec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.pbkdf2" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-pbkdf2/src/NativePbkdf2.ts b/native-modules/react-native-pbkdf2/src/NativePbkdf2.ts new file mode 100644 index 00000000..a14902d0 --- /dev/null +++ b/native-modules/react-native-pbkdf2/src/NativePbkdf2.ts @@ -0,0 +1,14 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + derive( + password: string, + salt: string, + rounds: number, + keyLength: number, + hash: string, + ): Promise; +} + +export default TurboModuleRegistry.getEnforcing('Pbkdf2'); diff --git a/native-modules/react-native-pbkdf2/src/index.tsx b/native-modules/react-native-pbkdf2/src/index.tsx new file mode 100644 index 00000000..5799aad8 --- /dev/null +++ b/native-modules/react-native-pbkdf2/src/index.tsx @@ -0,0 +1,4 @@ +import NativePbkdf2 from './NativePbkdf2'; + +export default NativePbkdf2; +export type { Spec as Pbkdf2Spec } from './NativePbkdf2'; diff --git a/native-modules/react-native-pbkdf2/tsconfig.build.json b/native-modules/react-native-pbkdf2/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-pbkdf2/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-pbkdf2/tsconfig.json b/native-modules/react-native-pbkdf2/tsconfig.json new file mode 100644 index 00000000..08b64104 --- /dev/null +++ b/native-modules/react-native-pbkdf2/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-pbkdf2": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-pbkdf2/turbo.json b/native-modules/react-native-pbkdf2/turbo.json new file mode 100644 index 00000000..e094f154 --- /dev/null +++ b/native-modules/react-native-pbkdf2/turbo.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-ping/Ping.podspec b/native-modules/react-native-ping/Ping.podspec new file mode 100644 index 00000000..6604500d --- /dev/null +++ b/native-modules/react-native-ping/Ping.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "Ping" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-ping.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,c}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-ping/babel.config.js b/native-modules/react-native-ping/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-ping/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-ping/ios/GBPing/GBPing.h b/native-modules/react-native-ping/ios/GBPing/GBPing.h new file mode 100755 index 00000000..fd17491c --- /dev/null +++ b/native-modules/react-native-ping/ios/GBPing/GBPing.h @@ -0,0 +1,50 @@ +// +// GBPing.h +// + +#import + +#import "GBPingSummary.h" + +@class GBPingSummary; +@protocol GBPingDelegate; + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^StartupCallback)(BOOL success, NSError *_Nullable error); + +@interface GBPing : NSObject + +@property (weak, nonatomic, nullable) id delegate; + +@property (copy, nonatomic, nullable) NSString *host; +@property (assign, atomic) NSTimeInterval pingPeriod; +@property (assign, atomic) NSTimeInterval timeout; +@property (assign, atomic) NSUInteger payloadSize; +@property (assign, atomic) NSUInteger ttl; +@property (assign, atomic, readonly) BOOL isPinging; +@property (assign, atomic, readonly) BOOL isReady; + +@property (assign, atomic) BOOL debug; + +- (void)setupWithBlock:(StartupCallback)callback; +- (void)startPingingWithBlock:(void (^)(GBPingSummary *))successBlock fail:(void (^)(NSError *))failBlock; +- (void)stop; + +@end + +@protocol GBPingDelegate + +@optional + +- (void)ping:(GBPing *)pinger didFailWithError:(NSError *)error; + +- (void)ping:(GBPing *)pinger didSendPingWithSummary:(GBPingSummary *)summary; +- (void)ping:(GBPing *)pinger didFailToSendPingWithSummary:(GBPingSummary *)summary error:(NSError *)error; +- (void)ping:(GBPing *)pinger didTimeoutWithSummary:(GBPingSummary *)summary; +- (void)ping:(GBPing *)pinger didReceiveReplyWithSummary:(GBPingSummary *)summary; +- (void)ping:(GBPing *)pinger didReceiveUnexpectedReplyWithSummary:(GBPingSummary *)summary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/native-modules/react-native-ping/ios/GBPing/GBPing.m b/native-modules/react-native-ping/ios/GBPing/GBPing.m new file mode 100755 index 00000000..8d1a7d2b --- /dev/null +++ b/native-modules/react-native-ping/ios/GBPing/GBPing.m @@ -0,0 +1,944 @@ +// +// GBPing.m +// + +#import "GBPing.h" +#import "LHDefinition.h" + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR + #import +#else + #import +#endif + +#import "ICMPHeader.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static NSTimeInterval const kPendingPingsCleanupGrace = 1.0; + +static NSUInteger const kDefaultPayloadSize = 56; +static NSUInteger const kDefaultTTL = 49; +static NSTimeInterval const kDefaultPingPeriod = 1.0; +static NSTimeInterval const kDefaultTimeout = 2.0; + +@interface GBPing () + +@property (assign, atomic) int socket; +@property (strong, nonatomic) NSData *hostAddress; +@property (strong, nonatomic) NSString *hostAddressString; +@property (assign, nonatomic) uint16_t identifier; + +@property (assign, atomic, readwrite) BOOL isPinging; +@property (assign, atomic, readwrite) BOOL isReady; +@property (assign, nonatomic) NSUInteger nextSequenceNumber; +@property (strong, atomic) NSMutableDictionary *pendingPings; +@property (strong, nonatomic) NSMutableDictionary *timeoutTimers; + +@property (strong, nonatomic) dispatch_queue_t setupQueue; + +@property (assign, atomic) BOOL isStopped; + +@property (copy, atomic) void (^ successBlock)(GBPingSummary *summary); +@property (copy, atomic) void (^ failBlock)(NSError *summary); + +@end + +@implementation GBPing +{ + NSUInteger _payloadSize; + NSUInteger _ttl; + NSTimeInterval _timeout; + NSTimeInterval _pingPeriod; +} + +#pragma mark - custom acc + +- (void)setTimeout:(NSTimeInterval)timeout +{ + @synchronized(self) { + if (self.isPinging) { + if (self.debug) { + NSLog(@"GBPing: can't set timeout while pinger is running."); + } + } else { + _timeout = timeout; + } + } +} + +- (NSTimeInterval)timeout +{ + @synchronized(self) { + if (!_timeout) { + return kDefaultTimeout; + } else { + return _timeout; + } + } +} + +- (void)setTtl:(NSUInteger)ttl +{ + @synchronized(self) { + if (self.isPinging) { + if (self.debug) { + NSLog(@"GBPing: can't set ttl while pinger is running."); + } + } else { + _ttl = ttl; + } + } +} + +- (NSUInteger)ttl +{ + @synchronized(self) { + if (!_ttl) { + return kDefaultTTL; + } else { + return _ttl; + } + } +} + +- (void)setPayloadSize:(NSUInteger)payloadSize +{ + @synchronized(self) { + if (self.isPinging) { + if (self.debug) { + NSLog(@"GBPing: can't set payload size while pinger is running."); + } + } else { + _payloadSize = payloadSize; + } + } +} + +- (NSUInteger)payloadSize +{ + @synchronized(self) { + if (!_payloadSize) { + return kDefaultPayloadSize; + } else { + return _payloadSize; + } + } +} + +- (void)setPingPeriod:(NSTimeInterval)pingPeriod +{ + @synchronized(self) { + if (self.isPinging) { + if (self.debug) { + NSLog(@"GBPing: can't set pingPeriod while pinger is running."); + } + } else { + _pingPeriod = pingPeriod; + } + } +} + +- (NSTimeInterval)pingPeriod +{ + @synchronized(self) { + if (!_pingPeriod) { + return (NSTimeInterval)kDefaultPingPeriod; + } else { + return _pingPeriod; + } + } +} + +#pragma mark - core pinging methods + +- (void)setupWithBlock:(StartupCallback)callback +{ + //error out of its already setup + if (self.isReady) { + if (self.debug) { + NSLog(@"GBPing: Can't setup, already setup."); + } + + //notify about error and return + dispatch_async(dispatch_get_main_queue(), ^{ + DEFINE_NSError(runningError, PingUtil_Message_PreviousPingIsStillRunning) + callback(NO, runningError); + }); + return; + } + + //error out if no host is set + if (!self.host) { + if (self.debug) { + NSLog(@"GBPing: set host before attempting to start."); + } + + //notify about error and return + dispatch_async(dispatch_get_main_queue(), ^{ + DEFINE_NSError(hostError, PingUtil_Message_HostErrorNotSetHost) + callback(NO, hostError); + }); + return; + } + + //set up data structs + self.nextSequenceNumber = 0; + self.pendingPings = [[NSMutableDictionary alloc] init]; + self.timeoutTimers = [[NSMutableDictionary alloc] init]; + + dispatch_async(self.setupQueue, ^{ + CFStreamError streamError; + BOOL success; + + CFHostRef hostRef = CFHostCreateWithName(NULL, (__bridge CFStringRef)self.host); + + /* + * CFHostCreateWithName will return a null result in certain cases. + * CFHostStartInfoResolution will return YES if _hostRef is null. + */ + if (hostRef) { + success = CFHostStartInfoResolution(hostRef, kCFHostAddresses, &streamError); + } else { + success = NO; + } + + if (!success) { + //construct an error + NSDictionary *userInfo; + NSError *error; + + if (hostRef && streamError.domain == kCFStreamErrorDomainNetDB) { + userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInteger:streamError.error], kCFGetAddrInfoFailureKey, + nil + ]; + } else { + userInfo = nil; + } + error = [NSError errorWithDomain:(NSString *)kCFErrorDomainCFNetwork code:kCFHostErrorUnknown userInfo:userInfo]; + + //clean up so far + [self stop]; + + //notify about error and return + dispatch_async(dispatch_get_main_queue(), ^{ + DEFINE_NSError(hostUnknowError, PingUtil_Message_HostErrorUnknown) + callback(NO, hostUnknowError); + }); + + //just incase + if (hostRef) { + CFRelease(hostRef); + } + return; + } + + //get the first IPv4 or IPv6 address + Boolean resolved; + NSArray *addresses = (__bridge NSArray *)CFHostGetAddressing(hostRef, &resolved); + if (resolved && (addresses != nil)) { + resolved = false; + for (NSData *address in addresses) { + const struct sockaddr *anAddrPtr = (const struct sockaddr *)[address bytes]; + + if ([address length] >= sizeof(struct sockaddr) && + (anAddrPtr->sa_family == AF_INET || anAddrPtr->sa_family == AF_INET6)) { + resolved = true; + self.hostAddress = address; + struct sockaddr_in *sin = (struct sockaddr_in *)anAddrPtr; + char str[INET6_ADDRSTRLEN]; + inet_ntop(anAddrPtr->sa_family, &(sin->sin_addr), str, INET6_ADDRSTRLEN); + self.hostAddressString = [[NSString alloc] initWithUTF8String:str]; + break; + } + } + } + + //we can stop host resolution now + if (hostRef) { + CFRelease(hostRef); + } + + //if an error occurred during resolution + if (!resolved) { + //stop + [self stop]; + + //notify about error and return + dispatch_async(dispatch_get_main_queue(), ^{ + DEFINE_NSError(hostError, PingUtil_Message_HostErrorHostNotFound) + callback(NO, hostError); + }); + return; + } + + //set up socket + int err = 0; + switch (self.hostAddressFamily) { + case AF_INET: { + self.socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + if (self.socket < 0) { + err = errno; + } + } break; + case AF_INET6: { + self.socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + if (self.socket < 0) { + err = errno; + } + } break; + default: { + err = EPROTONOSUPPORT; + } break; + } + + //couldnt setup socket + if (err) { + //clean up so far + [self stop]; + + //notify about error and close + dispatch_async(dispatch_get_main_queue(), ^{ + DEFINE_NSError(unknownError, PingUtil_Message_Unknown) + callback(NO, unknownError); + }); + return; + } + + //set ttl on the socket + if (self.ttl) { + u_char ttlForSockOpt = (u_char)self.ttl; + setsockopt(self.socket, IPPROTO_IP, IP_TTL, &ttlForSockOpt, sizeof(NSUInteger)); + } + + //we are ready now + self.isReady = YES; + + //notify that we are ready + dispatch_async(dispatch_get_main_queue(), ^{ + callback(YES, nil); + }); + }); + + self.isStopped = NO; +} + +- (void)startPingingWithBlock:(void (^)(GBPingSummary *))successBlock fail:(void (^)(NSError *))failBlock +{ + if (self.isReady && !self.isPinging) { + self.successBlock = [successBlock copy]; + self.failBlock = [failBlock copy]; + //go into infinite listenloop on a new thread (listenThread) + NSThread *listenThread = [[NSThread alloc] initWithTarget:self selector:@selector(listenLoop) object:nil]; + listenThread.name = @"listenThread"; + + //set up loop that sends packets on a new thread (sendThread) + NSThread *sendThread = [[NSThread alloc] initWithTarget:self selector:@selector(sendLoop) object:nil]; + sendThread.name = @"sendThread"; + + //we're pinging now + self.isPinging = YES; + [listenThread start]; + [sendThread start]; + } +} + +- (void)listenLoop +{ + @autoreleasepool { + while (self.isPinging) + [self listenOnce]; + } +} + +- (void)listenOnce +{ + int err; + struct sockaddr_storage addr; + socklen_t addrLen; + ssize_t bytesRead; + void *buffer; + enum { kBufferSize = 65535 }; + + buffer = malloc(kBufferSize); + assert(buffer); + + //set socket timeout + struct timeval tv; + tv.tv_sec = self.timeout / 1000; + tv.tv_usec = 0; + if (setsockopt(self.socket, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) { + NSLog(@"Set Timeput Error"); + } + + //read the data. + addrLen = sizeof(addr); + bytesRead = recvfrom(self.socket, buffer, kBufferSize, 0, (struct sockaddr *)&addr, &addrLen); + err = 0; + if (bytesRead < 0) { + err = errno; + } + + //process the data we read. + if (bytesRead > 0) { + char hoststr[INET6_ADDRSTRLEN]; + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + inet_ntop(sin->sin_family, &(sin->sin_addr), hoststr, INET6_ADDRSTRLEN); + NSString *host = [[NSString alloc] initWithUTF8String:hoststr]; + + if ([host isEqualToString:self.hostAddressString]) { // only make sense where received packet comes from expected source + NSDate *receiveDate = [NSDate date]; + NSMutableData *packet; + + packet = [NSMutableData dataWithBytes:buffer length:(NSUInteger)bytesRead]; + assert(packet); + + //complete the ping summary + const struct ICMPHeader *headerPointer; + + if (sin->sin_family == AF_INET) { + headerPointer = [[self class] icmp4InPacket:packet]; + } else { + headerPointer = (const struct ICMPHeader *)[packet bytes]; + } + + NSUInteger seqNo = (NSUInteger)OSSwapBigToHostInt16(headerPointer->sequenceNumber); + NSNumber *key = @(seqNo); + GBPingSummary *pingSummary = [(GBPingSummary *)self.pendingPings[key] copy]; + + if (pingSummary) { + if ([self isValidPingResponsePacket:packet]) { + //override the source address (we might have sent to google.com and 172.123.213.192 replied) + pingSummary.receiveDate = receiveDate; + // IP can't be read from header for ICMPv6 + if (sin->sin_family == AF_INET) { + pingSummary.host = [[self class] sourceAddressInPacket:packet]; + + //set ttl from response (different servers may respond with different ttls) + const struct IPHeader *ipPtr; + if ([packet length] >= sizeof(IPHeader)) { + ipPtr = (const IPHeader *)[packet bytes]; + pingSummary.ttl = ipPtr->timeToLive; + } + } + + pingSummary.status = GBPingStatusSuccess; + + //invalidate the timeouttimer + NSTimer *timer = self.timeoutTimers[key]; + [timer invalidate]; + [self.timeoutTimers removeObjectForKey:key]; + + if (self.successBlock) { + self.successBlock([pingSummary copy]); + } + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didReceiveReplyWithSummary:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + //notify delegate + [self.delegate ping:self didReceiveReplyWithSummary:[pingSummary copy]]; + }); + } + } else { + pingSummary.status = GBPingStatusFail; + + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didReceiveUnexpectedReplyWithSummary:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate ping:self didReceiveUnexpectedReplyWithSummary:[pingSummary copy]]; + }); + } + } + } + } + } else { + //we failed to read the data, so shut everything down. + if (err == 0) { + err = EPIPE; + } + + @synchronized(self) { + if (!self.isStopped) { + if (self.failBlock) { + DEFINE_NSError(unknownError, PingUtil_Message_Unknown) + _failBlock(unknownError); + } + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didFailWithError:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate ping:self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]]; + }); + } + } + } + + //stop the whole thing + [self stop]; + } + + free(buffer); +} + +- (void)sendLoop +{ + @autoreleasepool { + while (self.isPinging) { + [self sendPing]; + + NSTimeInterval runUntil = CFAbsoluteTimeGetCurrent() + self.pingPeriod; + NSTimeInterval time = 0; + while (runUntil > time) { + NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceReferenceDate:runUntil]; + [[NSRunLoop currentRunLoop] runUntilDate:runUntilDate]; + + time = CFAbsoluteTimeGetCurrent(); + } + } + } +} + +- (void)sendPing +{ + if (self.isPinging) { + int err; + NSData *packet; + ssize_t bytesSent; + + // Construct the ping packet. + NSData *payload = [self generateDataWithLength:(self.payloadSize)]; + + switch (self.hostAddressFamily) { + case AF_INET: { + packet = [self pingPacketWithType:kICMPv4TypeEchoRequest payload:payload requiresChecksum:YES]; + } break; + case AF_INET6: { + packet = [self pingPacketWithType:kICMPv6TypeEchoRequest payload:payload requiresChecksum:NO]; + } break; + default: { + assert(NO); + } break; + } + + // this is our ping summary + GBPingSummary *newPingSummary = [GBPingSummary new]; + + // Send the packet. + if (self.socket == 0) { + bytesSent = -1; + err = EBADF; + } else { + //record the send date + NSDate *sendDate = [NSDate date]; + + //construct ping summary, as much as it can + newPingSummary.sequenceNumber = self.nextSequenceNumber; + newPingSummary.host = self.host; + newPingSummary.sendDate = sendDate; + newPingSummary.ttl = self.ttl; + newPingSummary.payloadSize = self.payloadSize; + newPingSummary.status = GBPingStatusPending; + + //add it to pending pings + NSNumber *key = @(self.nextSequenceNumber); + self.pendingPings[key] = newPingSummary; + + //increment sequence number + self.nextSequenceNumber += 1; + + //we create a copy, this one will be passed out to other threads + GBPingSummary *pingSummaryCopy = [newPingSummary copy]; + + //we need to clean up our list of pending pings, and we do that after the timeout has elapsed (+ some grace period) + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((self.timeout + kPendingPingsCleanupGrace) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + //remove the ping from the pending list + [self.pendingPings removeObjectForKey:key]; + }); + + //add a timeout timer + //add a timeout timer + NSTimer *timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:self.timeout + target:[NSBlockOperation blockOperationWithBlock:^{ + newPingSummary.status = GBPingStatusFail; + + //notify about the failure + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didTimeoutWithSummary:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate ping:self didTimeoutWithSummary:pingSummaryCopy]; + }); + } + + //remove the timer itself from the timers list + //lm make sure that the timer list doesnt grow and these removals actually work... try logging the count of the timeoutTimers when stopping the pinger + [self.timeoutTimers removeObjectForKey:key]; + }] + selector:@selector(main) + userInfo:nil + repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:timeoutTimer forMode:NSRunLoopCommonModes]; + + //keep a local ref to it + if (self.timeoutTimers) { + self.timeoutTimers[key] = timeoutTimer; + } + + //notify delegate about this + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didSendPingWithSummary:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate ping:self didSendPingWithSummary:pingSummaryCopy]; + }); + } + + bytesSent = sendto( + self.socket, + [packet bytes], + [packet length], + 0, + (struct sockaddr *)[self.hostAddress bytes], + (socklen_t)[self.hostAddress length] + ); + err = 0; + if (bytesSent < 0) { + err = errno; + } + } + + // This is after the sending + + //successfully sent + if ((bytesSent > 0) && (((NSUInteger)bytesSent) == [packet length])) { + //noop, we already notified delegate about sending of the ping + } + //failed to send + else { + //complete the error + if (err == 0) { + err = ENOBUFS; // This is not a hugely descriptor error, alas. + } + + //little log + if (self.debug) { + NSLog(@"GBPing: failed to send packet with error code: %d", err); + } + + //change status + newPingSummary.status = GBPingStatusFail; + + GBPingSummary *pingSummaryCopyAfterFailure = [newPingSummary copy]; + + if (self.failBlock) { + DEFINE_NSError(unknownError, PingUtil_Message_Unknown) + self.failBlock(unknownError); + } + //notify delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(ping:didFailToSendPingWithSummary:error:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate ping:self didFailToSendPingWithSummary:pingSummaryCopyAfterFailure error:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]]; + }); + } + } + } +} + +- (void)stop +{ + @synchronized(self) { + if (!self.isStopped) { + self.isPinging = NO; + + self.isReady = NO; + + //destroy listenThread by closing socket (listenThread) + if (self.socket) { + close(self.socket); + self.socket = 0; + } + + //destroy host + self.hostAddress = nil; + + //clean up pendingpings + [self.pendingPings removeAllObjects]; + self.pendingPings = nil; + for (NSNumber *key in [self.timeoutTimers copy]) { + NSTimer *timer = self.timeoutTimers[key]; + [timer invalidate]; + } + + //clean up timeouttimers + [self.timeoutTimers removeAllObjects]; + self.timeoutTimers = nil; + + //reset seq number + self.nextSequenceNumber = 0; + + self.isStopped = YES; + } + } +} + +#pragma mark - util + +static uint16_t in_cksum(const void *buffer, size_t bufferLen) +// This is the standard BSD checksum code, modified to use modern types. +{ + size_t bytesLeft; + int32_t sum; + const uint16_t *cursor; + union { + uint16_t us; + uint8_t uc[2]; + } last; + uint16_t answer; + + bytesLeft = bufferLen; + sum = 0; + cursor = buffer; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), we add + * sequential 16 bit words to it, and at the end, fold back all the + * carry bits from the top 16 bits into the lower 16 bits. + */ + while (bytesLeft > 1) { + sum += *cursor; + cursor += 1; + bytesLeft -= 2; + } + + /* mop up an odd byte, if necessary */ + if (bytesLeft == 1) { + last.uc[0] = *(const uint8_t *)cursor; + last.uc[1] = 0; + sum += last.us; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = (uint16_t) ~sum; /* truncate to 16 bits */ + + return answer; +} + ++ (NSString *)sourceAddressInPacket:(NSData *)packet +{ + // Returns the source address of the IP packet + + const struct IPHeader *ipPtr; + const uint8_t *sourceAddress; + + if ([packet length] >= sizeof(IPHeader)) { + ipPtr = (const IPHeader *)[packet bytes]; + + sourceAddress = ipPtr->sourceAddress;//dont need to swap byte order those cuz theyre the smallest atomic unit (1 byte) + NSString *ipString = [NSString stringWithFormat:@"%d.%d.%d.%d", sourceAddress[0], sourceAddress[1], sourceAddress[2], sourceAddress[3]]; + + return ipString; + } else return nil; +} + ++ (NSUInteger)icmp4HeaderOffsetInPacket:(NSData *)packet +// Returns the offset of the ICMPHeader within an IP packet. +{ + NSUInteger result; + const struct IPHeader *ipPtr; + size_t ipHeaderLength; + + result = NSNotFound; + if ([packet length] >= (sizeof(IPHeader) + sizeof(ICMPHeader))) { + ipPtr = (const IPHeader *)[packet bytes]; + assert((ipPtr->versionAndHeaderLength & 0xF0) == 0x40); // IPv4 + assert(ipPtr->protocol == 1); // ICMP + ipHeaderLength = (ipPtr->versionAndHeaderLength & 0x0F) * sizeof(uint32_t); + if ([packet length] >= (ipHeaderLength + sizeof(ICMPHeader))) { + result = ipHeaderLength; + } + } + return result; +} + ++ (const struct ICMPHeader *)icmp4InPacket:(NSData *)packet +// See comment in header. +{ + const struct ICMPHeader *result; + NSUInteger icmpHeaderOffset; + + result = nil; + icmpHeaderOffset = [self icmp4HeaderOffsetInPacket:packet]; + if (icmpHeaderOffset != NSNotFound) { + result = (const struct ICMPHeader *)(((const uint8_t *)[packet bytes]) + icmpHeaderOffset); + } + return result; +} + +- (BOOL)isValidPingResponsePacket:(NSMutableData *)packet +{ + BOOL result; + + switch (self.hostAddressFamily) { + case AF_INET: { + result = [self isValidPing4ResponsePacket:packet]; + } break; + case AF_INET6: { + result = [self isValidPing6ResponsePacket:packet]; + } break; + default: { + assert(NO); + result = NO; + } break; + } + return result; +} + +- (BOOL)isValidPing4ResponsePacket:(NSMutableData *)packet +// Returns true if the packet looks like a valid ping response packet destined +// for us. +{ + BOOL result; + NSUInteger icmpHeaderOffset; + ICMPHeader *icmpPtr; + uint16_t receivedChecksum; + uint16_t calculatedChecksum; + + result = NO; + + icmpHeaderOffset = [[self class] icmp4HeaderOffsetInPacket:packet]; + if (icmpHeaderOffset != NSNotFound) { + icmpPtr = (struct ICMPHeader *)(((uint8_t *)[packet mutableBytes]) + icmpHeaderOffset); + + receivedChecksum = icmpPtr->checksum; + icmpPtr->checksum = 0; + calculatedChecksum = in_cksum(icmpPtr, [packet length] - icmpHeaderOffset); + icmpPtr->checksum = receivedChecksum; + + if (receivedChecksum == calculatedChecksum) { + if ( (icmpPtr->type == kICMPv4TypeEchoReply) && (icmpPtr->code == 0) ) { + if (OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier) { + if (OSSwapBigToHostInt16(icmpPtr->sequenceNumber) < self.nextSequenceNumber) { + result = YES; + } + } + } + } + } + + // NSLog(@"valid: %@, type: %d", _b(result), icmpPtr->type); + + return result; +} + +- (BOOL)isValidPing6ResponsePacket:(NSMutableData *)packet +// Returns true if the IPv6 packet looks like a valid ping response packet destined +// for us. +{ + BOOL result; + const ICMPHeader *icmpPtr; + + result = NO; + + if (packet.length >= sizeof(*icmpPtr)) { + icmpPtr = packet.bytes; + + if ( (icmpPtr->type == kICMPv6TypeEchoReply) && (icmpPtr->code == 0) ) { + if (OSSwapBigToHostInt16(icmpPtr->identifier) == self.identifier) { + if (OSSwapBigToHostInt16(icmpPtr->sequenceNumber) < self.nextSequenceNumber) { + result = YES; + } + } + } + } + + return result; +} + +- (NSData *)generateDataWithLength:(NSUInteger)length +{ + //create a buffer full of 7's of specified length + char tempBuffer[length]; + memset(tempBuffer, 7, length); + + return [[NSData alloc] initWithBytes:tempBuffer length:length]; +} + +- (void)_invokeTimeoutCallback:(NSTimer *)timer +{ + dispatch_block_t callback = timer.userInfo; + if (callback) { + callback(); + } +} + +- (NSData *)pingPacketWithType:(uint8_t)type payload:(NSData *)payload requiresChecksum:(BOOL)requiresChecksum +{ + NSMutableData *packet; + ICMPHeader *icmpPtr; + + packet = [NSMutableData dataWithLength:sizeof(*icmpPtr) + payload.length]; + assert(packet != nil); + + icmpPtr = packet.mutableBytes; + icmpPtr->type = type; + icmpPtr->code = 0; + icmpPtr->checksum = 0; + icmpPtr->identifier = OSSwapHostToBigInt16(self.identifier); + icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber); + memcpy(&icmpPtr[1], [payload bytes], [payload length]); + + if (requiresChecksum) { + // The IP checksum routine returns a 16-bit number that's already in correct byte order + // (due to wacky 1's complement maths), so we just put it into the packet as a 16-bit unit. + + icmpPtr->checksum = in_cksum(packet.bytes, packet.length); + } + + return packet; +} + +- (sa_family_t)hostAddressFamily +{ + sa_family_t result; + + result = AF_UNSPEC; + if ( (self.hostAddress != nil) && (self.hostAddress.length >= sizeof(struct sockaddr)) ) { + result = ((const struct sockaddr *)self.hostAddress.bytes)->sa_family; + } + return result; +} + +#pragma mark - memory + +- (id)init +{ + if (self = [super init]) { + self.setupQueue = dispatch_queue_create("GBPing setup queue", 0); + self.isStopped = YES; + self.identifier = arc4random(); + } + + return self; +} + +- (void)dealloc +{ + self.delegate = nil; + self.host = nil; + self.timeoutTimers = nil; + self.pendingPings = nil; + self.hostAddress = nil; + + //clean up socket to be sure + if (self.socket) { + close(self.socket); + self.socket = 0; + } +} + +@end diff --git a/native-modules/react-native-ping/ios/GBPing/GBPingSummary.h b/native-modules/react-native-ping/ios/GBPing/GBPingSummary.h new file mode 100755 index 00000000..40c1d8f3 --- /dev/null +++ b/native-modules/react-native-ping/ios/GBPing/GBPingSummary.h @@ -0,0 +1,24 @@ +// +// GBPingSummary.h +// + +#import + +@interface GBPingSummary : NSObject + +typedef enum { + GBPingStatusPending, + GBPingStatusSuccess, + GBPingStatusFail, +} GBPingStatus; + +@property (assign, nonatomic) NSUInteger sequenceNumber; +@property (assign, nonatomic) NSUInteger payloadSize; +@property (assign, nonatomic) NSUInteger ttl; +@property (strong, nonatomic, nullable) NSString *host; +@property (strong, nonatomic, nullable) NSDate *sendDate; +@property (strong, nonatomic, nullable) NSDate *receiveDate; +@property (assign, nonatomic) NSTimeInterval rtt; +@property (assign, nonatomic) GBPingStatus status; + +@end diff --git a/native-modules/react-native-ping/ios/GBPing/GBPingSummary.m b/native-modules/react-native-ping/ios/GBPing/GBPingSummary.m new file mode 100755 index 00000000..27d06f67 --- /dev/null +++ b/native-modules/react-native-ping/ios/GBPing/GBPingSummary.m @@ -0,0 +1,67 @@ +// +// GBPingSummary.m +// + +#import "GBPingSummary.h" + +@implementation GBPingSummary + +#pragma mark - custom acc + +- (void)setHost:(NSString *)host +{ + _host = host; +} + +- (NSTimeInterval)rtt +{ + if (self.sendDate) { + return [self.receiveDate timeIntervalSinceDate:self.sendDate]; + } else { + return 0; + } +} + +#pragma mark - copying + +- (id)copyWithZone:(NSZone *)zone +{ + GBPingSummary *copy = [[[self class] allocWithZone:zone] init]; + + copy.sequenceNumber = self.sequenceNumber; + copy.payloadSize = self.payloadSize; + copy.ttl = self.ttl; + copy.host = [self.host copy]; + copy.sendDate = [self.sendDate copy]; + copy.receiveDate = [self.receiveDate copy]; + copy.status = self.status; + + return copy; +} + +#pragma mark - memory + +- (id)init +{ + if (self = [super init]) { + self.status = GBPingStatusPending; + } + + return self; +} + +- (void)dealloc +{ + self.host = nil; + self.sendDate = nil; + self.receiveDate = nil; +} + +#pragma mark - description + +- (NSString *)description +{ + return [NSString stringWithFormat:@"host: %@, seq: %lu, status: %d, ttl: %lu, payloadSize: %lu, sendDate: %@, receiveDate: %@, rtt: %f", self.host, (unsigned long)self.sequenceNumber, self.status, (unsigned long)self.ttl, (unsigned long)self.payloadSize, self.sendDate, self.receiveDate, self.rtt]; +} + +@end diff --git a/native-modules/react-native-ping/ios/GBPing/ICMPHeader.h b/native-modules/react-native-ping/ios/GBPing/ICMPHeader.h new file mode 100755 index 00000000..91f1e7bf --- /dev/null +++ b/native-modules/react-native-ping/ios/GBPing/ICMPHeader.h @@ -0,0 +1,79 @@ +// +// ICMPHeader.h +// GBPing +// +// Created by Luka Mirosevic on 15/11/2012. +// Copyright (c) 2012 Goonbee. All rights reserved. +// + +#ifndef GBPing_ICMPHeader_h +#define GBPing_ICMPHeader_h + +#include + +#pragma mark - IP and ICMP On-The-Wire Format + +// The following declarations specify the structure of ping packets on the wire. + +// IP header structure: + +struct IPHeader { + uint8_t versionAndHeaderLength; + uint8_t differentiatedServices; + uint16_t totalLength; + uint16_t identification; + uint16_t flagsAndFragmentOffset; + uint8_t timeToLive; + uint8_t protocol; + uint16_t headerChecksum; + uint8_t sourceAddress[4]; + uint8_t destinationAddress[4]; + // options... + // data... +}; +typedef struct IPHeader IPHeader; + +__Check_Compile_Time(sizeof(IPHeader) == 20); +__Check_Compile_Time(offsetof(IPHeader, versionAndHeaderLength) == 0); +__Check_Compile_Time(offsetof(IPHeader, differentiatedServices) == 1); +__Check_Compile_Time(offsetof(IPHeader, totalLength) == 2); +__Check_Compile_Time(offsetof(IPHeader, identification) == 4); +__Check_Compile_Time(offsetof(IPHeader, flagsAndFragmentOffset) == 6); +__Check_Compile_Time(offsetof(IPHeader, timeToLive) == 8); +__Check_Compile_Time(offsetof(IPHeader, protocol) == 9); +__Check_Compile_Time(offsetof(IPHeader, headerChecksum) == 10); +__Check_Compile_Time(offsetof(IPHeader, sourceAddress) == 12); +__Check_Compile_Time(offsetof(IPHeader, destinationAddress) == 16); + +// ICMP type and code combinations: + +enum { + kICMPv4TypeEchoRequest = 8, + kICMPv4TypeEchoReply = 0 +}; + +enum { + kICMPv6TypeEchoRequest = 128, + kICMPv6TypeEchoReply = 129 +}; + +// ICMP header structure: + +struct ICMPHeader { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequenceNumber; + // data... +}; +typedef struct ICMPHeader ICMPHeader; + +__Check_Compile_Time(sizeof(ICMPHeader) == 8); +__Check_Compile_Time(offsetof(ICMPHeader, type) == 0); +__Check_Compile_Time(offsetof(ICMPHeader, code) == 1); +__Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2); +__Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4); +__Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6); + +#endif diff --git a/native-modules/react-native-ping/ios/LHNetwork/LHDefinition.h b/native-modules/react-native-ping/ios/LHNetwork/LHDefinition.h new file mode 100644 index 00000000..5795e8ec --- /dev/null +++ b/native-modules/react-native-ping/ios/LHNetwork/LHDefinition.h @@ -0,0 +1,24 @@ +// +// LHDefinition.h +// RNReactNativePing +// +// Created by Jerry-Luo on 2019/3/29. +// Copyright © 2019 Pomato. All rights reserved. +// + +#ifndef LHDefinition_h +#define LHDefinition_h + +#define DEFINE_NSError(errorName,description) NSError *errorName = [NSError errorWithDomain:@#description code:description userInfo:@{@"code":@(description),@"message":@#description}]; + +typedef NS_ENUM (NSUInteger, PingErrorCode) { + PingUtil_Message_Timeout, + PingUtil_Message_PreviousPingIsStillRunning, + PingUtil_Message_HostErrorNotSetHost, + PingUtil_Message_HostErrorUnknown, + PingUtil_Message_HostErrorHostNotFound, + PingUtil_Message_Unknown, +}; + + +#endif /* LHDefinition_h */ diff --git a/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.h b/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.h new file mode 100755 index 00000000..25d3d180 --- /dev/null +++ b/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.h @@ -0,0 +1,34 @@ +// +// LHNetwork.h +// + +#import +#import + +@interface LHNetwork : NSObject + +@property (nonatomic, copy, readonly) NSString *receivedNetworkSpeed; + +@property (nonatomic, copy, readonly) NSString *sendNetworkSpeed; + +@property (nonatomic, copy, readonly) NSString *receivedNetworkTotal; + +@property (nonatomic, copy, readonly) NSString *sendNetworkTotal; ++ (instancetype)shareNetworkSpeed; + +- (void)startMonitoringNetwork; + +- (void)stopMonitoringNetwork; + +- (void)checkNetworkflow; +@end + +/** + * @{@"received":@"100kB/s"} + */ +FOUNDATION_EXTERN NSString *const kNetworkReceivedSpeedNotification; + +/** + * @{@"send":@"100kB/s"} + */ +FOUNDATION_EXTERN NSString *const kNetworkSendSpeedNotification; diff --git a/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.m b/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.m new file mode 100755 index 00000000..31d06206 --- /dev/null +++ b/native-modules/react-native-ping/ios/LHNetwork/LHNetwork.m @@ -0,0 +1,223 @@ +// +// LHNetwork.m +// +#import "LHNetwork.h" +#include +#include +#include +#include + +/** + * @{@"received":@"100kB/s"} + */ +NSString *const kNetworkReceivedSpeedNotification = @"kNetworkReceivedSpeedNotification"; + +/** + * @{@"send":@"100kB/s"} + */ +NSString *const kNetworkSendSpeedNotification = @"kNetworkSendSpeedNotification"; + +@interface LHNetwork () +{ + uint32_t _iBytes; + uint32_t _oBytes; + uint32_t _allFlow; + uint32_t _wifiIBytes; + uint32_t _wifiOBytes; + uint32_t _wifiFlow; + uint32_t _wwanIBytes; + uint32_t _wwanOBytes; + uint32_t _wwanFlow; +} + +@property (nonatomic, copy) NSString *receivedNetworkSpeed; + +@property (nonatomic, copy) NSString *sendNetworkSpeed; + +@property (nonatomic, copy) NSString *receivedNetworkTotal; + +@property (nonatomic, copy) NSString *sendNetworkTotal; + +@property (nonatomic, strong) NSTimer *timer; + +@end + +@implementation LHNetwork + +static LHNetwork *instance = nil; + ++ (instancetype)shareNetworkSpeed +{ + if (instance == nil) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + } + return instance; +} + ++ (instancetype)allocWithZone:(struct _NSZone *)zone +{ + if (instance == nil) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [super allocWithZone:zone]; + }); + } + return instance; +} + +- (instancetype)init +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [super init]; + _iBytes = _oBytes = _allFlow = _wifiIBytes = _wifiOBytes = _wifiFlow = _wwanIBytes = _wwanOBytes = _wwanFlow = 0; + }); + return instance; +} + +- (void)startMonitoringNetwork +{ + if (_timer) [self stopMonitoringNetwork]; + + [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]; + _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(netSpeedNotification) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; +} + +- (void)stopMonitoringNetwork +{ + if ([_timer isValid]) { + [_timer invalidate]; + } +} + +- (void)netSpeedNotification +{ + [self checkNetworkflow]; +} + +- (NSString *)bytesToAvaiUnit:(uint32_t)bytes +{ + if (bytes < 1024) { // B + return [NSString stringWithFormat:@"%dB", bytes]; + } else if (bytes >= 1024 && bytes < 1024 * 1024) { // KB + return [NSString stringWithFormat:@"%.1fKB", (double)bytes / 1024]; + } else if (bytes >= 1024 * 1024 && bytes < 1024 * 1024 * 1024) { // MB + return [NSString stringWithFormat:@"%.1fMB", (double)bytes / (1024 * 1024)]; + } else { // GB + return [NSString stringWithFormat:@"%.1fGB", (double)bytes / (1024 * 1024 * 1024)]; + } +} + +- (void)checkNetworkflow +{ + struct ifaddrs *ifa_list = 0, *ifa; + if (getifaddrs(&ifa_list) == -1) { + return; + } + + uint32_t iBytes = 0; + uint32_t oBytes = 0; + uint32_t allFlow = 0; + uint32_t wifiIBytes = 0; + uint32_t wifiOBytes = 0; + uint32_t wifiFlow = 0; + uint32_t wwanIBytes = 0; + uint32_t wwanOBytes = 0; + uint32_t wwanFlow = 0; + // struct timeval32 time; + + for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) { + if (AF_LINK != ifa->ifa_addr->sa_family) continue; + + if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING)) continue; + + if (ifa->ifa_data == 0) continue; + + // network flow + if (strncmp(ifa->ifa_name, "lo", 2)) { + struct if_data *if_data = (struct if_data *)ifa->ifa_data; + + iBytes += if_data->ifi_ibytes; + oBytes += if_data->ifi_obytes; + allFlow = iBytes + oBytes; + // time = if_data->ifi_lastchange; + } + + //wifi flow + if (!strcmp(ifa->ifa_name, "en0")) { + struct if_data *if_data = (struct if_data *)ifa->ifa_data; + + wifiIBytes += if_data->ifi_ibytes; + wifiOBytes += if_data->ifi_obytes; + wifiFlow = wifiIBytes + wifiOBytes; + } + + //3G and gprs flow + if (!strcmp(ifa->ifa_name, "pdp_ip0")) { + struct if_data *if_data = (struct if_data *)ifa->ifa_data; + + wwanIBytes += if_data->ifi_ibytes; + wwanOBytes += if_data->ifi_obytes; + wwanFlow = wwanIBytes + wwanOBytes; + } + } + freeifaddrs(ifa_list); + + if (_iBytes != 0) { + self.receivedNetworkSpeed = [[self bytesToAvaiUnit:iBytes - _iBytes] stringByAppendingString:@"/s"]; + self.receivedNetworkTotal = [self bytesToAvaiUnit:iBytes]; + [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkReceivedSpeedNotification object:@{ @"received": self.receivedNetworkSpeed }]; + } + + _iBytes = iBytes; + + if (_oBytes != 0) { + self.sendNetworkSpeed = [[self bytesToAvaiUnit:oBytes - _oBytes] stringByAppendingString:@"/s"]; + self.sendNetworkTotal = [self bytesToAvaiUnit:oBytes]; + [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkSendSpeedNotification object:@{ @"send": self.sendNetworkSpeed }]; + } + _oBytes = oBytes; + + // // + // // NSLog(@"sentBytes==%@",sentBytes); + // NSString *networkFlow = [self bytesToAvaiUnit:allFlow]; + // // + // NSLog(@"networkFlow==%@", networkFlow); + // // + // NSString *wifiReceived = [self bytesToAvaiUnit:wifiIBytes]; + + // NSLog(@"wifiReceived==%@", wifiReceived); + + // NSString *wifiSent = [self bytesToAvaiUnit:wifiOBytes]; + + // NSLog(@"wifiSent==%@", wifiSent); + + // NSString *wifiBytes = [self bytesToAvaiUnit:wifiFlow]; + // // + // NSLog(@"wifiBytes==%@", wifiBytes); + // NSString *wwanReceived = [self bytesToAvaiUnit:wwanIBytes]; + + // NSLog(@"wwanReceived==%@", wwanReceived); + // NSString *wwanSent = [self bytesToAvaiUnit:wwanOBytes]; + + // NSLog(@"wwanSent==%@", wwanSent); + // NSString *wwanBytes = [self bytesToAvaiUnit:wwanFlow]; + // // + // NSLog(@"wwanBytes==%@", wwanBytes); + + // NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + + // [formatter setDateFormat:@"YYYY-MM-dd hh:mm:ss:SSS"]; + + // NSDate *datenow = [NSDate date]; + + // NSString *nowtimeStr = [formatter stringFromDate:datenow]; + + // NSLog(@"time 2 =  %@", nowtimeStr); +} + +@end diff --git a/native-modules/react-native-ping/ios/Ping.h b/native-modules/react-native-ping/ios/Ping.h new file mode 100644 index 00000000..7f61a0bd --- /dev/null +++ b/native-modules/react-native-ping/ios/Ping.h @@ -0,0 +1,10 @@ +#import + +@interface Ping : NativeRNReactNativePingSpecBase + +- (void)start:(NSString *)ipAddress + option:(JS::NativeRNReactNativePing::SpecStartOption &)option + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end diff --git a/native-modules/react-native-ping/ios/Ping.mm b/native-modules/react-native-ping/ios/Ping.mm new file mode 100644 index 00000000..b8391aa5 --- /dev/null +++ b/native-modules/react-native-ping/ios/Ping.mm @@ -0,0 +1,91 @@ +#import "Ping.h" +#import "GBPing/GBPing.h" +#import "LHNetwork/LHNetwork.h" +#import "LHNetwork/LHDefinition.h" + +@interface Ping () +@property (nonatomic, strong) dispatch_queue_t queue; +@end + +@implementation Ping + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNReactNativePing"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (dispatch_queue_t)methodQueue +{ + if (!_queue) { + _queue = dispatch_queue_create("com.onekey.RNPing", DISPATCH_QUEUE_SERIAL); + } + return _queue; +} + +- (void)start:(NSString *)ipAddress + option:(JS::NativeRNReactNativePing::SpecStartOption &)option + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + __block GBPing *ping = [[GBPing alloc] init]; + ping.timeout = 1.0; + ping.payloadSize = 56; + ping.pingPeriod = 0.9; + ping.host = ipAddress; + + unsigned long long timeout = 1000; + if (option.timeout().has_value()) { + timeout = (unsigned long long)option.timeout().value(); + ping.timeout = (NSTimeInterval)timeout; + } + + if (option.payloadSize().has_value()) { + unsigned long long payloadSize = (unsigned long long)option.payloadSize().value(); + ping.payloadSize = payloadSize; + } + + dispatch_queue_t capturedQueue = _queue; + + [ping setupWithBlock:^(BOOL success, NSError *_Nullable err) { + if (!success) { + reject(@(err.code).stringValue, err.domain, err); + return; + } + [ping startPingingWithBlock:^(GBPingSummary *summary) { + if (!ping) { + return; + } + resolve(@(@(summary.rtt * 1000).intValue)); + [ping stop]; + ping = nil; + } fail:^(NSError *_Nonnull error) { + if (!ping) { + return; + } + reject(@(error.code).stringValue, error.domain, error); + [ping stop]; + ping = nil; + }]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_MSEC)), capturedQueue, ^{ + if (!ping) { + return; + } + ping = nil; + DEFINE_NSError(timeoutError, PingUtil_Message_Timeout) + reject(@(timeoutError.code).stringValue, timeoutError.domain, timeoutError); + }); + }]; +} + +@end diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json new file mode 100644 index 00000000..fa337c5a --- /dev/null +++ b/native-modules/react-native-ping/package.json @@ -0,0 +1,85 @@ +{ + "name": "@onekeyfe/react-native-ping", + "version": "1.1.54", + "description": "react-native-ping TurboModule for OneKey", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "prepare": "bob build", + "typecheck": "tsc" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-ping.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-ping/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-ping#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "devDependencies": { + "@react-native/babel-preset": "0.83.0", + "react": "19.2.0", + "react-native": "0.83.0", + "react-native-builder-bob": "^0.40.17", + "typescript": "^5.9.2" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNPingSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rnping" + } + } +} diff --git a/native-modules/react-native-ping/src/NativePing.ts b/native-modules/react-native-ping/src/NativePing.ts new file mode 100644 index 00000000..7d144160 --- /dev/null +++ b/native-modules/react-native-ping/src/NativePing.ts @@ -0,0 +1,8 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + start(ipAddress: string, option: { timeout?: number; payloadSize?: number }): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNReactNativePing'); diff --git a/native-modules/react-native-ping/src/index.tsx b/native-modules/react-native-ping/src/index.tsx new file mode 100644 index 00000000..c056d27b --- /dev/null +++ b/native-modules/react-native-ping/src/index.tsx @@ -0,0 +1,4 @@ +import NativePing from './NativePing'; + +export const Ping = NativePing; +export type { Spec as PingSpec } from './NativePing'; diff --git a/native-modules/react-native-ping/tsconfig.build.json b/native-modules/react-native-ping/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-ping/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-ping/tsconfig.json b/native-modules/react-native-ping/tsconfig.json new file mode 100644 index 00000000..97c1c7a3 --- /dev/null +++ b/native-modules/react-native-ping/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-ping": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-tcp-socket/TcpSocket.podspec b/native-modules/react-native-tcp-socket/TcpSocket.podspec new file mode 100644 index 00000000..6a8cd071 --- /dev/null +++ b/native-modules/react-native-tcp-socket/TcpSocket.podspec @@ -0,0 +1,19 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "TcpSocket" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-tcp-socket.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-tcp-socket/babel.config.js b/native-modules/react-native-tcp-socket/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-tcp-socket/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-tcp-socket/ios/TcpSocket.h b/native-modules/react-native-tcp-socket/ios/TcpSocket.h new file mode 100644 index 00000000..5f21f084 --- /dev/null +++ b/native-modules/react-native-tcp-socket/ios/TcpSocket.h @@ -0,0 +1,5 @@ +#import + +@interface TcpSocket : NativeRNTcpSocketSpecBase + +@end diff --git a/native-modules/react-native-tcp-socket/ios/TcpSocket.mm b/native-modules/react-native-tcp-socket/ios/TcpSocket.mm new file mode 100644 index 00000000..029ccf0b --- /dev/null +++ b/native-modules/react-native-tcp-socket/ios/TcpSocket.mm @@ -0,0 +1,151 @@ +#import "TcpSocket.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +@implementation TcpSocket + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNTcpSocket"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +// MARK: - connectWithTimeout + +- (void)connectWithTimeout:(NSString *)host + port:(double)port + timeoutMs:(double)timeoutMs + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000.0; + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + reject(@"SOCKET_ERROR", @"Failed to create socket", nil); + return; + } + + // Set non-blocking mode + int flags = fcntl(sockfd, F_GETFL, 0); + if (flags < 0) { + close(sockfd); + reject(@"SOCKET_ERROR", @"Failed to get socket flags", nil); + return; + } + if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(sockfd); + reject(@"SOCKET_ERROR", @"Failed to set non-blocking mode", nil); + return; + } + + // Resolve hostname + struct addrinfo hints; + struct addrinfo *res = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + char portStr[16]; + snprintf(portStr, sizeof(portStr), "%d", (int)port); + + int gaiResult = getaddrinfo([host UTF8String], portStr, &hints, &res); + if (gaiResult != 0) { + close(sockfd); + reject(@"DNS_ERROR", + [NSString stringWithFormat:@"%s", gai_strerror(gaiResult)], + nil); + return; + } + + // Attempt non-blocking connect + int connectResult = connect(sockfd, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + + if (connectResult < 0 && errno != EINPROGRESS) { + close(sockfd); + reject(@"CONNECT_ERROR", + [NSString stringWithUTF8String:strerror(errno)], + nil); + return; + } + + // If already connected (unlikely for non-blocking, but handle it) + if (connectResult == 0) { + close(sockfd); + NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - startTime; + resolve(@((NSInteger)elapsed)); + return; + } + + // Wait for connection with select() and timeout + fd_set writeSet; + FD_ZERO(&writeSet); + FD_SET(sockfd, &writeSet); + + long timeoutLong = (long)timeoutMs; + struct timeval tv; + tv.tv_sec = timeoutLong / 1000; + tv.tv_usec = (int)((timeoutLong % 1000) * 1000); + + int selectResult = select(sockfd + 1, NULL, &writeSet, NULL, &tv); + + if (selectResult == 0) { + // Timeout + close(sockfd); + reject(@"ETIMEDOUT", @"Connection timeout", nil); + return; + } + + if (selectResult < 0) { + close(sockfd); + reject(@"SELECT_ERROR", + [NSString stringWithUTF8String:strerror(errno)], + nil); + return; + } + + // Check for socket-level error via getsockopt + int socketError = 0; + socklen_t optLen = sizeof(socketError); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &socketError, &optLen) < 0) { + close(sockfd); + reject(@"CONNECT_ERROR", @"Failed to get socket error", nil); + return; + } + + close(sockfd); + + if (socketError != 0) { + reject(@"CONNECT_ERROR", + [NSString stringWithUTF8String:strerror(socketError)], + nil); + return; + } + + NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - startTime; + resolve(@((NSInteger)elapsed)); + }); +} + +@end diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json new file mode 100644 index 00000000..ab308722 --- /dev/null +++ b/native-modules/react-native-tcp-socket/package.json @@ -0,0 +1,156 @@ +{ + "name": "@onekeyfe/react-native-tcp-socket", + "version": "1.1.54", + "description": "react-native-tcp-socket", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "clean": "del-cli ios/build lib", + "prepare": "bob build", + "typecheck": "tsc", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "test": "jest", + "release": "yarn prepare && npm whoami && npm publish --access public" + }, + "keywords": [ + "react-native", + "ios", + "tcp", + "socket" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-tcp-socket.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-tcp-socket/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-tcp-socket#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "devDependencies": { + "@commitlint/config-conventional": "^19.8.1", + "@eslint/compat": "^1.3.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.35.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/eslint-config": "0.83.0", + "@release-it/conventional-changelog": "^10.0.1", + "@types/jest": "^29.5.14", + "@types/react": "^19.2.0", + "commitlint": "^19.8.1", + "del-cli": "^6.0.0", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "jest": "^29.7.0", + "lefthook": "^2.0.3", + "prettier": "^2.8.8", + "react": "19.2.0", + "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch", + "react-native-builder-bob": "^0.40.17", + "release-it": "^19.0.4", + "turbo": "^2.5.6", + "typescript": "^5.9.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNTcpSocketSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rntcpsocket" + } + }, + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": { + "name": "angular" + } + } + } + }, + "create-react-native-library": { + "type": "turbo-module", + "languages": "kotlin-objc", + "tools": [ + "eslint", + "jest", + "lefthook", + "release-it" + ], + "version": "0.56.0" + } +} diff --git a/native-modules/react-native-tcp-socket/src/NativeTcpSocket.ts b/native-modules/react-native-tcp-socket/src/NativeTcpSocket.ts new file mode 100644 index 00000000..c346be6e --- /dev/null +++ b/native-modules/react-native-tcp-socket/src/NativeTcpSocket.ts @@ -0,0 +1,17 @@ +import { TurboModuleRegistry } from 'react-native'; + +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + /** + * Attempt a TCP connection to host:port. + * Resolves with connection time in ms, rejects with error message. + */ + connectWithTimeout( + host: string, + port: number, + timeoutMs: number, + ): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNTcpSocket'); diff --git a/native-modules/react-native-tcp-socket/src/index.tsx b/native-modules/react-native-tcp-socket/src/index.tsx new file mode 100644 index 00000000..be33a1ec --- /dev/null +++ b/native-modules/react-native-tcp-socket/src/index.tsx @@ -0,0 +1,57 @@ +import NativeTcpSocket from './NativeTcpSocket'; + +// Compatibility shim that mimics the react-native-tcp-socket createConnection API +// but uses a simple Promise underneath (works in background Hermes runtime) +export interface TcpSocketShim { + on(event: 'error', handler: (err: Error) => void): this; + on(event: 'timeout', handler: () => void): this; + destroy(): void; +} + +function createConnection( + options: { host: string; port: number; timeout?: number }, + connectCallback: () => void, +): TcpSocketShim { + const timeout = options.timeout ?? 5000; + const handlers: { error?: (err: Error) => void; timeout?: () => void } = {}; + + let destroyed = false; + + NativeTcpSocket.connectWithTimeout(options.host, options.port, timeout) + .then(() => { + if (!destroyed) connectCallback(); + }) + .catch((err: unknown) => { + if (!destroyed) { + const errMsg = + err instanceof Error ? err.message : String(err as string); + if ( + errMsg.includes('timeout') || + errMsg.includes('ETIMEDOUT') || + errMsg.includes('Connection timeout') + ) { + handlers.timeout?.(); + } else if (handlers.error) { + handlers.error(err instanceof Error ? err : new Error(errMsg)); + } + } + }); + + const shim: TcpSocketShim = { + on(event: 'error' | 'timeout', handler: (err?: Error) => void) { + if (event === 'error') { + handlers.error = handler as (err: Error) => void; + } else if (event === 'timeout') { + handlers.timeout = handler as () => void; + } + return this; + }, + destroy() { + destroyed = true; + }, + }; + return shim; +} + +export default { createConnection }; +export { NativeTcpSocket }; diff --git a/native-modules/react-native-tcp-socket/tsconfig.build.json b/native-modules/react-native-tcp-socket/tsconfig.build.json new file mode 100644 index 00000000..34699441 --- /dev/null +++ b/native-modules/react-native-tcp-socket/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["lib"] +} diff --git a/native-modules/react-native-tcp-socket/tsconfig.json b/native-modules/react-native-tcp-socket/tsconfig.json new file mode 100644 index 00000000..db0e5b40 --- /dev/null +++ b/native-modules/react-native-tcp-socket/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "@onekeyfe/react-native-tcp-socket": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "customConditions": ["react-native-strict-api"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} diff --git a/native-modules/react-native-tcp-socket/turbo.json b/native-modules/react-native-tcp-socket/turbo.json new file mode 100644 index 00000000..0a2c33d0 --- /dev/null +++ b/native-modules/react-native-tcp-socket/turbo.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".nvmrc", ".yarnrc.yml"], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build:android": { + "env": ["ANDROID_HOME", "ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + }, + "build:ios": { + "env": [ + "RCT_NEW_ARCH_ENABLED", + "RCT_REMOVE_LEGACY_ARCH", + "RCT_USE_RN_DEP", + "RCT_USE_PREBUILT_RNCORE" + ], + "inputs": [ + "package.json", + "*.podspec", + "ios", + "src/*.ts", + "src/*.tsx" + ], + "outputs": [] + } + } +} diff --git a/native-modules/react-native-zip-archive/ZipArchive.podspec b/native-modules/react-native-zip-archive/ZipArchive.podspec new file mode 100644 index 00000000..998b79d6 --- /dev/null +++ b/native-modules/react-native-zip-archive/ZipArchive.podspec @@ -0,0 +1,21 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "ZipArchive" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-zip-archive.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + s.dependency 'SSZipArchive' + + install_modules_dependencies(s) +end diff --git a/native-modules/react-native-zip-archive/babel.config.js b/native-modules/react-native-zip-archive/babel.config.js new file mode 100644 index 00000000..0c05fd69 --- /dev/null +++ b/native-modules/react-native-zip-archive/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/native-modules/react-native-zip-archive/ios/ZipArchive.h b/native-modules/react-native-zip-archive/ios/ZipArchive.h new file mode 100644 index 00000000..62990ae0 --- /dev/null +++ b/native-modules/react-native-zip-archive/ios/ZipArchive.h @@ -0,0 +1,10 @@ +#import +#import + +@interface ZipArchive : NativeRNZipArchiveSpecBase + +@property (nonatomic) NSString *processedFilePath; +@property (nonatomic) float progress; +@property (nonatomic, copy) void (^progressHandler)(NSUInteger entryNumber, NSUInteger total); + +@end diff --git a/native-modules/react-native-zip-archive/ios/ZipArchive.mm b/native-modules/react-native-zip-archive/ios/ZipArchive.mm new file mode 100644 index 00000000..633d74a3 --- /dev/null +++ b/native-modules/react-native-zip-archive/ios/ZipArchive.mm @@ -0,0 +1,182 @@ +#import "ZipArchive.h" + +@implementation ZipArchive +{ + bool hasListeners; +} + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + ++ (NSString *)moduleName +{ + return @"RNZipArchive"; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (dispatch_queue_t)methodQueue +{ + return dispatch_queue_create("com.onekey.ZipArchiveQueue", DISPATCH_QUEUE_SERIAL); +} + +// MARK: - isPasswordProtected + +- (void)isPasswordProtected:(NSString *)file + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + BOOL isPasswordProtected = [SSZipArchive isFilePasswordProtectedAtPath:file]; + resolve([NSNumber numberWithBool:isPasswordProtected]); +} + +// MARK: - unzip + +- (void)unzip:(NSString *)from + to:(NSString *)to + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + self.progress = 0.0; + self.processedFilePath = @""; + + NSError *error = nil; + BOOL success = [SSZipArchive unzipFileAtPath:from + toDestination:to + preserveAttributes:NO + overwrite:YES + password:nil + error:&error + delegate:self]; + + self.progress = 1.0; + + if (success) { + resolve(to); + } else { + reject(@"unzip_error", [error localizedDescription], error); + } +} + +// MARK: - unzipWithPassword + +- (void)unzipWithPassword:(NSString *)from + to:(NSString *)to + password:(NSString *)password + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + self.progress = 0.0; + self.processedFilePath = @""; + + NSError *error = nil; + BOOL success = [SSZipArchive unzipFileAtPath:from + toDestination:to + preserveAttributes:NO + overwrite:YES + password:password + error:&error + delegate:self]; + + self.progress = 1.0; + + if (success) { + resolve(to); + } else { + reject(@"unzip_error", @"unable to unzip", error); + } +} + +// MARK: - zipFolder + +- (void)zipFolder:(NSString *)from + to:(NSString *)to + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + self.progress = 0.0; + self.processedFilePath = @""; + [self setProgressHandler]; + + BOOL success = [SSZipArchive createZipFileAtPath:to + withContentsOfDirectory:from + keepParentDirectory:NO + withPassword:nil + andProgressHandler:self.progressHandler]; + + self.progress = 1.0; + + if (success) { + resolve(to); + } else { + reject(@"zip_error", @"unable to zip", nil); + } +} + +// MARK: - zipFiles + +- (void)zipFiles:(NSArray *)files + to:(NSString *)to + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + self.progress = 0.0; + self.processedFilePath = @""; + [self setProgressHandler]; + + BOOL success = [SSZipArchive createZipFileAtPath:to withFilesAtPaths:files]; + + self.progress = 1.0; + + if (success) { + resolve(to); + } else { + reject(@"zip_error", @"unable to zip", nil); + } +} + +// MARK: - getUncompressedSize + +- (void)getUncompressedSize:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + NSError *error = nil; + NSNumber *wantedFileSize = [SSZipArchive payloadSizeForArchiveAtPath:path error:&error]; + + if (error == nil) { + resolve(wantedFileSize); + } else { + resolve(@-1); + } +} + +// MARK: - SSZipArchiveDelegate + +- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex + totalFiles:(NSInteger)totalFiles + archivePath:(NSString *)archivePath + unzippedFilePath:(NSString *)processedFilePath +{ + self.processedFilePath = processedFilePath; +} + +// MARK: - Progress helper + +- (void)setProgressHandler +{ + __weak ZipArchive *weakSelf = self; + self.progressHandler = ^(NSUInteger entryNumber, NSUInteger total) { + if (total > 0) { + weakSelf.progress = (float)entryNumber / (float)total; + } + }; +} + +@end diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json new file mode 100644 index 00000000..80c63b71 --- /dev/null +++ b/native-modules/react-native-zip-archive/package.json @@ -0,0 +1,85 @@ +{ + "name": "@onekeyfe/react-native-zip-archive", + "version": "1.1.54", + "description": "react-native-zip-archive TurboModule for OneKey", + "main": "./lib/module/index.js", + "types": "./lib/typescript/src/index.d.ts", + "exports": { + ".": { + "source": "./src/index.tsx", + "types": "./lib/typescript/src/index.d.ts", + "default": "./lib/module/index.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "src", + "lib", + "ios", + "*.podspec", + "!ios/build", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "prepare": "bob build", + "typecheck": "tsc" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-zip-archive.git" + }, + "author": "@onekeyhq (https://github.com/OneKeyHQ/app-modules)", + "license": "MIT", + "bugs": { + "url": "https://github.com/OneKeyHQ/app-modules/react-native-zip-archive/issues" + }, + "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-zip-archive#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org/" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "devDependencies": { + "@react-native/babel-preset": "0.83.0", + "react": "19.2.0", + "react-native": "0.83.0", + "react-native-builder-bob": "^0.40.17", + "typescript": "^5.9.2" + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "codegenConfig": { + "name": "RNZipArchiveSpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rnziparchive" + } + } +} diff --git a/native-modules/react-native-zip-archive/src/NativeZipArchive.ts b/native-modules/react-native-zip-archive/src/NativeZipArchive.ts new file mode 100644 index 00000000..d2b5ad80 --- /dev/null +++ b/native-modules/react-native-zip-archive/src/NativeZipArchive.ts @@ -0,0 +1,13 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + isPasswordProtected(file: string): Promise; + unzip(from: string, to: string): Promise; + unzipWithPassword(from: string, to: string, password: string): Promise; + zipFolder(from: string, to: string): Promise; + zipFiles(files: string[], to: string): Promise; + getUncompressedSize(path: string): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNZipArchive'); diff --git a/native-modules/react-native-zip-archive/src/index.tsx b/native-modules/react-native-zip-archive/src/index.tsx new file mode 100644 index 00000000..de548b5a --- /dev/null +++ b/native-modules/react-native-zip-archive/src/index.tsx @@ -0,0 +1,4 @@ +import NativeZipArchive from './NativeZipArchive'; + +export const ZipArchive = NativeZipArchive; +export type { Spec as ZipArchiveSpec } from './NativeZipArchive'; diff --git a/native-modules/react-native-zip-archive/tsconfig.build.json b/native-modules/react-native-zip-archive/tsconfig.build.json new file mode 100644 index 00000000..3c0636ad --- /dev/null +++ b/native-modules/react-native-zip-archive/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig", + "exclude": ["example", "lib"] +} diff --git a/native-modules/react-native-zip-archive/tsconfig.json b/native-modules/react-native-zip-archive/tsconfig.json new file mode 100644 index 00000000..f00fb714 --- /dev/null +++ b/native-modules/react-native-zip-archive/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "rootDir": ".", + "paths": { + "react-native-zip-archive": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": ["ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true + } +} From 5c5384b132331f0fd3a0ea958cfcd5afc5464870 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:37:24 +0800 Subject: [PATCH 33/74] chore: bump all packages to 1.1.55 --- native-modules/native-logger/package.json | 2 +- .../react-native-aes-crypto/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../react-native-async-storage/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../react-native-cloud-fs/package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../react-native-dns-lookup/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-network-info/package.json | 2 +- .../react-native-pbkdf2/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-tcp-socket/package.json | 2 +- .../react-native-zip-archive/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- yarn.lock | 243 ++++++++++++++++++ 28 files changed, 270 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index d581ce4f..89507997 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index c8dde6c8..f6b2d616 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 674dbe0a..df7c61aa 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index cf9973d1..a27be877 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 5ddefc15..f9fd33d1 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 9e7f8c33..fc712b43 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index c55b1d09..24218d52 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 01f1b4a2..d33ba59a 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 8bcc9e6d..e47272cd 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 9a3ce935..f5bb2ea4 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 0a3ae612..437977a9 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 9bdec02d..4e097d74 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 90de1103..095d16c0 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 2456898c..a7e66f69 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.54", + "version": "1.1.55", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index f7411b45..e1bcc0f5 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 5cb8323d..550573bf 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index a5272dc8..71ee25ab 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index fa337c5a..6ec7eb44 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index c2807df7..d93b75b9 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 741b8997..ee4b50d6 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index ab308722..f3d955d8 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 80c63b71..87bd75dd 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 2652d8b2..01f00d2a 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.54", + "version": "1.1.55", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 2945bbc5..b5a7342d 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.54", + "version": "1.1.55", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 0480c884..a8abd466 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.54", + "version": "1.1.55", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 7c6c8eec..33c572ae 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.54", + "version": "1.1.55", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 4f5142b4..bbf88526 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.54", + "version": "1.1.55", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/yarn.lock b/yarn.lock index 47788932..e1e0ea6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2826,6 +2826,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-aes-crypto@workspace:native-modules/react-native-aes-crypto": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-aes-crypto@workspace:native-modules/react-native-aes-crypto" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-app-update@workspace:*, @onekeyfe/react-native-app-update@workspace:native-modules/react-native-app-update": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-app-update@workspace:native-modules/react-native-app-update" @@ -2862,6 +2895,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-async-storage@workspace:native-modules/react-native-async-storage": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-async-storage@workspace:native-modules/react-native-async-storage" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-auto-size-input@workspace:*, @onekeyfe/react-native-auto-size-input@workspace:native-views/react-native-auto-size-input": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-auto-size-input@workspace:native-views/react-native-auto-size-input" @@ -3003,6 +3069,21 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-cloud-fs@workspace:native-modules/react-native-cloud-fs": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-cloud-fs@workspace:native-modules/react-native-cloud-fs" + dependencies: + "@react-native/babel-preset": "npm:0.83.0" + react: "npm:19.2.0" + react-native: "npm:0.83.0" + react-native-builder-bob: "npm:^0.40.17" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-cloud-kit-module@workspace:*, @onekeyfe/react-native-cloud-kit-module@workspace:native-modules/react-native-cloud-kit-module": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-cloud-kit-module@workspace:native-modules/react-native-cloud-kit-module" @@ -3075,6 +3156,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-dns-lookup@workspace:native-modules/react-native-dns-lookup": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-dns-lookup@workspace:native-modules/react-native-dns-lookup" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-get-random-values@workspace:*, @onekeyfe/react-native-get-random-values@workspace:native-modules/react-native-get-random-values": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-get-random-values@workspace:native-modules/react-native-get-random-values" @@ -3216,6 +3330,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-network-info@workspace:native-modules/react-native-network-info": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-network-info@workspace:native-modules/react-native-network-info" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-pager-view@workspace:*, @onekeyfe/react-native-pager-view@workspace:native-views/react-native-pager-view": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-pager-view@workspace:native-views/react-native-pager-view" @@ -3231,6 +3378,39 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-pbkdf2@workspace:native-modules/react-native-pbkdf2": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-pbkdf2@workspace:native-modules/react-native-pbkdf2" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-perf-memory@workspace:*, @onekeyfe/react-native-perf-memory@workspace:native-modules/react-native-perf-memory": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-perf-memory@workspace:native-modules/react-native-perf-memory" @@ -3267,6 +3447,21 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-ping@workspace:native-modules/react-native-ping": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-ping@workspace:native-modules/react-native-ping" + dependencies: + "@react-native/babel-preset": "npm:0.83.0" + react: "npm:19.2.0" + react-native: "npm:0.83.0" + react-native-builder-bob: "npm:^0.40.17" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@onekeyfe/react-native-scroll-guard@workspace:*, @onekeyfe/react-native-scroll-guard@workspace:native-views/react-native-scroll-guard": version: 0.0.0-use.local resolution: "@onekeyfe/react-native-scroll-guard@workspace:native-views/react-native-scroll-guard" @@ -3409,6 +3604,54 @@ __metadata: languageName: unknown linkType: soft +"@onekeyfe/react-native-tcp-socket@workspace:native-modules/react-native-tcp-socket": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-tcp-socket@workspace:native-modules/react-native-tcp-socket" + dependencies: + "@commitlint/config-conventional": "npm:^19.8.1" + "@eslint/compat": "npm:^1.3.2" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:^9.35.0" + "@react-native/babel-preset": "npm:0.83.0" + "@react-native/eslint-config": "npm:0.83.0" + "@release-it/conventional-changelog": "npm:^10.0.1" + "@types/jest": "npm:^29.5.14" + "@types/react": "npm:^19.2.0" + commitlint: "npm:^19.8.1" + del-cli: "npm:^6.0.0" + eslint: "npm:^9.35.0" + eslint-config-prettier: "npm:^10.1.8" + eslint-plugin-prettier: "npm:^5.5.4" + jest: "npm:^29.7.0" + lefthook: "npm:^2.0.3" + prettier: "npm:^2.8.8" + react: "npm:19.2.0" + react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" + react-native-builder-bob: "npm:^0.40.17" + release-it: "npm:^19.0.4" + turbo: "npm:^2.5.6" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + +"@onekeyfe/react-native-zip-archive@workspace:native-modules/react-native-zip-archive": + version: 0.0.0-use.local + resolution: "@onekeyfe/react-native-zip-archive@workspace:native-modules/react-native-zip-archive" + dependencies: + "@react-native/babel-preset": "npm:0.83.0" + react: "npm:19.2.0" + react-native: "npm:0.83.0" + react-native-builder-bob: "npm:^0.40.17" + typescript: "npm:^5.9.2" + peerDependencies: + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@phun-ky/typeof@npm:2.0.3": version: 2.0.3 resolution: "@phun-ky/typeof@npm:2.0.3" From bad5ca574b654dd941fea80958ad65c6b282bc37 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:47:23 +0800 Subject: [PATCH 34/74] feat: add Android TurboModule implementations + fix tcp-socket types - Added Android (Kotlin) implementations for all 7 new packages: async-storage, aes-crypto, pbkdf2, ping, zip-archive, cloud-fs, tcp-socket - Fixed TypeScript type error in tcp-socket createConnection shim - Added "android" to files array in package.json for all packages --- .../android/build.gradle | 77 +++++++ .../java/com/aescrypto/AesCryptoModule.kt | 202 ++++++++++++++++++ .../java/com/aescrypto/AesCryptoPackage.kt | 33 +++ .../react-native-aes-crypto/package.json | 3 +- .../android/build.gradle | 77 +++++++ .../com/asyncstorage/RNCAsyncStorageModule.kt | 132 ++++++++++++ .../asyncstorage/RNCAsyncStoragePackage.kt | 33 +++ .../react-native-async-storage/package.json | 3 +- .../android/build.gradle | 77 +++++++ .../java/com/rncloudfs/RNCloudFsModule.kt | 50 +++++ .../java/com/rncloudfs/RNCloudFsPackage.kt | 33 +++ .../react-native-cloud-fs/package.json | 3 +- .../react-native-pbkdf2/android/build.gradle | 77 +++++++ .../src/main/java/com/pbkdf2/Pbkdf2Module.kt | 55 +++++ .../src/main/java/com/pbkdf2/Pbkdf2Package.kt | 33 +++ .../react-native-pbkdf2/package.json | 3 +- .../react-native-ping/android/build.gradle | 77 +++++++ .../com/rnping/RNReactNativePingModule.kt | 37 ++++ .../com/rnping/RNReactNativePingPackage.kt | 33 +++ native-modules/react-native-ping/package.json | 3 +- .../android/build.gradle | 77 +++++++ .../java/com/rntcpsocket/RNTcpSocketModule.kt | 35 +++ .../com/rntcpsocket/RNTcpSocketPackage.kt | 33 +++ .../react-native-tcp-socket/package.json | 3 +- .../react-native-tcp-socket/src/index.tsx | 8 +- .../android/build.gradle | 77 +++++++ .../com/rnziparchive/RNZipArchiveModule.kt | 158 ++++++++++++++ .../com/rnziparchive/RNZipArchivePackage.kt | 33 +++ .../react-native-zip-archive/package.json | 3 +- 29 files changed, 1457 insertions(+), 11 deletions(-) create mode 100644 native-modules/react-native-aes-crypto/android/build.gradle create mode 100644 native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt create mode 100644 native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoPackage.kt create mode 100644 native-modules/react-native-async-storage/android/build.gradle create mode 100644 native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt create mode 100644 native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStoragePackage.kt create mode 100644 native-modules/react-native-cloud-fs/android/build.gradle create mode 100644 native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt create mode 100644 native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsPackage.kt create mode 100644 native-modules/react-native-pbkdf2/android/build.gradle create mode 100644 native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt create mode 100644 native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Package.kt create mode 100644 native-modules/react-native-ping/android/build.gradle create mode 100644 native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt create mode 100644 native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingPackage.kt create mode 100644 native-modules/react-native-tcp-socket/android/build.gradle create mode 100644 native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt create mode 100644 native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketPackage.kt create mode 100644 native-modules/react-native-zip-archive/android/build.gradle create mode 100644 native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt create mode 100644 native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchivePackage.kt diff --git a/native-modules/react-native-aes-crypto/android/build.gradle b/native-modules/react-native-aes-crypto/android/build.gradle new file mode 100644 index 00000000..a2b166a1 --- /dev/null +++ b/native-modules/react-native-aes-crypto/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['AesCrypto_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["AesCrypto_" + name]).toInteger() +} + +android { + namespace "com.aescrypto" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt new file mode 100644 index 00000000..3596533d --- /dev/null +++ b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt @@ -0,0 +1,202 @@ +package com.aescrypto + +import android.util.Base64 +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import java.security.MessageDigest +import java.security.SecureRandom +import java.util.UUID +import javax.crypto.Cipher +import javax.crypto.Mac +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.PBEKeySpec +import javax.crypto.spec.SecretKeySpec + +@ReactModule(name = AesCryptoModule.NAME) +class AesCryptoModule(reactContext: ReactApplicationContext) : + NativeAesCryptoSpec(reactContext) { + + companion object { + const val NAME = "AesCrypto" + } + + override fun getName(): String = NAME + + private fun cipherTransformation(algorithm: String): String { + return when (algorithm.lowercase()) { + "aes-128-cbc", "aes-192-cbc", "aes-256-cbc" -> "AES/CBC/PKCS5Padding" + "aes-128-ecb", "aes-192-ecb", "aes-256-ecb" -> "AES/ECB/PKCS5Padding" + else -> "AES/CBC/PKCS5Padding" + } + } + + override fun encrypt(data: String, key: String, iv: String, algorithm: String, promise: Promise) { + Thread { + try { + val keyBytes = hexToBytes(key) + val ivBytes = hexToBytes(iv) + val transformation = cipherTransformation(algorithm) + val cipher = Cipher.getInstance(transformation) + val secretKey = SecretKeySpec(keyBytes, "AES") + if (transformation.contains("ECB")) { + cipher.init(Cipher.ENCRYPT_MODE, secretKey) + } else { + cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(ivBytes)) + } + val encrypted = cipher.doFinal(data.toByteArray(Charsets.UTF_8)) + promise.resolve(Base64.encodeToString(encrypted, Base64.NO_WRAP)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun decrypt(base64: String, key: String, iv: String, algorithm: String, promise: Promise) { + Thread { + try { + val keyBytes = hexToBytes(key) + val ivBytes = hexToBytes(iv) + val transformation = cipherTransformation(algorithm) + val cipher = Cipher.getInstance(transformation) + val secretKey = SecretKeySpec(keyBytes, "AES") + if (transformation.contains("ECB")) { + cipher.init(Cipher.DECRYPT_MODE, secretKey) + } else { + cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(ivBytes)) + } + val decrypted = cipher.doFinal(Base64.decode(base64, Base64.NO_WRAP)) + promise.resolve(String(decrypted, Charsets.UTF_8)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun pbkdf2(password: String, salt: String, cost: Double, length: Double, algorithm: String, promise: Promise) { + Thread { + try { + val saltBytes = salt.toByteArray(Charsets.UTF_8) + val iterationCount = cost.toInt() + val keyLength = length.toInt() * 8 + val hmacAlgorithm = when (algorithm.uppercase()) { + "SHA256", "SHA-256" -> "PBKDF2WithHmacSHA256" + "SHA512", "SHA-512" -> "PBKDF2WithHmacSHA512" + else -> "PBKDF2WithHmacSHA1" + } + val spec = PBEKeySpec(password.toCharArray(), saltBytes, iterationCount, keyLength) + val factory = SecretKeyFactory.getInstance(hmacAlgorithm) + val keyBytes = factory.generateSecret(spec).encoded + promise.resolve(bytesToHex(keyBytes)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun hmac256(base64: String, key: String, promise: Promise) { + Thread { + try { + val mac = Mac.getInstance("HmacSHA256") + val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA256") + mac.init(secretKey) + val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP)) + promise.resolve(bytesToHex(result)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun hmac512(base64: String, key: String, promise: Promise) { + Thread { + try { + val mac = Mac.getInstance("HmacSHA512") + val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA512") + mac.init(secretKey) + val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP)) + promise.resolve(bytesToHex(result)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun sha1(text: String, promise: Promise) { + Thread { + try { + val digest = MessageDigest.getInstance("SHA-1") + val result = digest.digest(text.toByteArray(Charsets.UTF_8)) + promise.resolve(bytesToHex(result)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun sha256(text: String, promise: Promise) { + Thread { + try { + val digest = MessageDigest.getInstance("SHA-256") + val result = digest.digest(text.toByteArray(Charsets.UTF_8)) + promise.resolve(bytesToHex(result)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun sha512(text: String, promise: Promise) { + Thread { + try { + val digest = MessageDigest.getInstance("SHA-512") + val result = digest.digest(text.toByteArray(Charsets.UTF_8)) + promise.resolve(bytesToHex(result)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun randomUuid(promise: Promise) { + Thread { + try { + promise.resolve(UUID.randomUUID().toString()) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + override fun randomKey(length: Double, promise: Promise) { + Thread { + try { + val bytes = ByteArray(length.toInt()) + SecureRandom().nextBytes(bytes) + promise.resolve(bytesToHex(bytes)) + } catch (e: Exception) { + promise.reject("AES_CRYPTO_ERROR", e.message, e) + } + }.start() + } + + private fun hexToBytes(hex: String): ByteArray { + val len = hex.length + val data = ByteArray(len / 2) + var i = 0 + while (i < len) { + data[i / 2] = ((Character.digit(hex[i], 16) shl 4) + Character.digit(hex[i + 1], 16)).toByte() + i += 2 + } + return data + } + + private fun bytesToHex(bytes: ByteArray): String { + val sb = StringBuilder() + for (b in bytes) { + sb.append(String.format("%02x", b)) + } + return sb.toString() + } +} diff --git a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoPackage.kt b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoPackage.kt new file mode 100644 index 00000000..466ed8dd --- /dev/null +++ b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoPackage.kt @@ -0,0 +1,33 @@ +package com.aescrypto + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class AesCryptoPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == AesCryptoModule.NAME) { + AesCryptoModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[AesCryptoModule.NAME] = ReactModuleInfo( + AesCryptoModule.NAME, + AesCryptoModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index f6b2d616..701a760d 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-async-storage/android/build.gradle b/native-modules/react-native-async-storage/android/build.gradle new file mode 100644 index 00000000..0f6dca54 --- /dev/null +++ b/native-modules/react-native-async-storage/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['AsyncStorage_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["AsyncStorage_" + name]).toInteger() +} + +android { + namespace "com.asyncstorage" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt new file mode 100644 index 00000000..316be4a0 --- /dev/null +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt @@ -0,0 +1,132 @@ +package com.asyncstorage + +import android.content.Context +import android.content.SharedPreferences +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.WritableNativeArray +import com.facebook.react.module.annotations.ReactModule + +@ReactModule(name = RNCAsyncStorageModule.NAME) +class RNCAsyncStorageModule(reactContext: ReactApplicationContext) : + NativeRNCAsyncStorageSpec(reactContext) { + + companion object { + const val NAME = "RNCAsyncStorage" + private const val PREFS_NAME = "RNCAsyncStorage" + } + + private fun getPrefs(): SharedPreferences { + return reactApplicationContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + } + + override fun getName(): String = NAME + + override fun multiGet(keys: ReadableArray, promise: Promise) { + Thread { + try { + val prefs = getPrefs() + val result = WritableNativeArray() + for (i in 0 until keys.size()) { + val key = keys.getString(i) + val pair = WritableNativeArray() + pair.pushString(key) + if (prefs.contains(key)) { + pair.pushString(prefs.getString(key, null)) + } else { + pair.pushNull() + } + result.pushArray(pair) + } + promise.resolve(result) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } + + override fun multiSet(keyValuePairs: ReadableArray, promise: Promise) { + Thread { + try { + val editor = getPrefs().edit() + for (i in 0 until keyValuePairs.size()) { + val pair = keyValuePairs.getArray(i) + if (pair != null && pair.size() >= 2) { + val key = pair.getString(0) + val value = pair.getString(1) + editor.putString(key, value) + } + } + editor.apply() + promise.resolve(null) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } + + override fun multiRemove(keys: ReadableArray, promise: Promise) { + Thread { + try { + val editor = getPrefs().edit() + for (i in 0 until keys.size()) { + editor.remove(keys.getString(i)) + } + editor.apply() + promise.resolve(null) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } + + override fun multiMerge(keyValuePairs: ReadableArray, promise: Promise) { + Thread { + try { + val prefs = getPrefs() + val editor = prefs.edit() + for (i in 0 until keyValuePairs.size()) { + val pair = keyValuePairs.getArray(i) + if (pair != null && pair.size() >= 2) { + val key = pair.getString(0) + val value = pair.getString(1) + // For merge, if key exists and both are JSON objects, deep merge. + // For simplicity, we overwrite (shallow merge by replacing value). + editor.putString(key, value) + } + } + editor.apply() + promise.resolve(null) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } + + override fun getAllKeys(promise: Promise) { + Thread { + try { + val prefs = getPrefs() + val result = WritableNativeArray() + for (key in prefs.all.keys) { + result.pushString(key) + } + promise.resolve(result) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } + + override fun clear(promise: Promise) { + Thread { + try { + getPrefs().edit().clear().apply() + promise.resolve(null) + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + } + }.start() + } +} diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStoragePackage.kt b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStoragePackage.kt new file mode 100644 index 00000000..8ae48eee --- /dev/null +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStoragePackage.kt @@ -0,0 +1,33 @@ +package com.asyncstorage + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class RNCAsyncStoragePackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == RNCAsyncStorageModule.NAME) { + RNCAsyncStorageModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[RNCAsyncStorageModule.NAME] = ReactModuleInfo( + RNCAsyncStorageModule.NAME, + RNCAsyncStorageModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index a27be877..30e1eb8b 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-cloud-fs/android/build.gradle b/native-modules/react-native-cloud-fs/android/build.gradle new file mode 100644 index 00000000..d8d5e4ca --- /dev/null +++ b/native-modules/react-native-cloud-fs/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['RNCloudFs_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNCloudFs_" + name]).toInteger() +} + +android { + namespace "com.rncloudfs" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt new file mode 100644 index 00000000..bd558f93 --- /dev/null +++ b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt @@ -0,0 +1,50 @@ +package com.rncloudfs + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule + +@ReactModule(name = RNCloudFsModule.NAME) +class RNCloudFsModule(reactContext: ReactApplicationContext) : + NativeRNCloudFsSpec(reactContext) { + + companion object { + const val NAME = "RNCloudFs" + private const val NOT_AVAILABLE_ERROR = "iCloud is not available on Android" + } + + override fun getName(): String = NAME + + override fun isAvailable(promise: Promise) { + promise.resolve(false) + } + + override fun createFile(options: ReadableMap, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun fileExists(options: ReadableMap, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun listFiles(options: ReadableMap, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun getIcloudDocument(filename: String, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun deleteFromCloud(item: ReadableMap, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun copyToCloud(options: ReadableMap, promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } + + override fun syncCloud(promise: Promise) { + promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + } +} diff --git a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsPackage.kt b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsPackage.kt new file mode 100644 index 00000000..7b5fe179 --- /dev/null +++ b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsPackage.kt @@ -0,0 +1,33 @@ +package com.rncloudfs + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class RNCloudFsPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == RNCloudFsModule.NAME) { + RNCloudFsModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[RNCloudFsModule.NAME] = ReactModuleInfo( + RNCloudFsModule.NAME, + RNCloudFsModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index d33ba59a..7276bbd5 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "prepare": "bob build", diff --git a/native-modules/react-native-pbkdf2/android/build.gradle b/native-modules/react-native-pbkdf2/android/build.gradle new file mode 100644 index 00000000..e96d7415 --- /dev/null +++ b/native-modules/react-native-pbkdf2/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Pbkdf2_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Pbkdf2_" + name]).toInteger() +} + +android { + namespace "com.pbkdf2" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt new file mode 100644 index 00000000..a19bcb81 --- /dev/null +++ b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt @@ -0,0 +1,55 @@ +package com.pbkdf2 + +import android.util.Base64 +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.PBEKeySpec + +@ReactModule(name = Pbkdf2Module.NAME) +class Pbkdf2Module(reactContext: ReactApplicationContext) : + NativePbkdf2Spec(reactContext) { + + companion object { + const val NAME = "Pbkdf2" + } + + override fun getName(): String = NAME + + override fun derive( + password: String, + salt: String, + rounds: Double, + keyLength: Double, + hash: String, + promise: Promise + ) { + Thread { + try { + val passwordBytes = Base64.decode(password, Base64.DEFAULT) + val saltBytes = Base64.decode(salt, Base64.DEFAULT) + val iterationCount = rounds.toInt() + val keyLengthBits = keyLength.toInt() * 8 + + val algorithm = when (hash.uppercase()) { + "SHA256", "SHA-256" -> "PBKDF2WithHmacSHA256" + "SHA512", "SHA-512" -> "PBKDF2WithHmacSHA512" + else -> "PBKDF2WithHmacSHA256" + } + + val spec = PBEKeySpec( + String(passwordBytes, Charsets.UTF_8).toCharArray(), + saltBytes, + iterationCount, + keyLengthBits + ) + val factory = SecretKeyFactory.getInstance(algorithm) + val derivedKey = factory.generateSecret(spec).encoded + promise.resolve(Base64.encodeToString(derivedKey, Base64.NO_WRAP)) + } catch (e: Exception) { + promise.reject("PBKDF2_ERROR", e.message, e) + } + }.start() + } +} diff --git a/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Package.kt b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Package.kt new file mode 100644 index 00000000..bcaf2030 --- /dev/null +++ b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Package.kt @@ -0,0 +1,33 @@ +package com.pbkdf2 + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class Pbkdf2Package : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == Pbkdf2Module.NAME) { + Pbkdf2Module(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[Pbkdf2Module.NAME] = ReactModuleInfo( + Pbkdf2Module.NAME, + Pbkdf2Module.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 550573bf..000ee7ad 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-ping/android/build.gradle b/native-modules/react-native-ping/android/build.gradle new file mode 100644 index 00000000..56cee1c7 --- /dev/null +++ b/native-modules/react-native-ping/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['RNPing_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNPing_" + name]).toInteger() +} + +android { + namespace "com.rnping" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt new file mode 100644 index 00000000..17f5cdd3 --- /dev/null +++ b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt @@ -0,0 +1,37 @@ +package com.rnping + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule +import java.net.InetAddress + +@ReactModule(name = RNReactNativePingModule.NAME) +class RNReactNativePingModule(reactContext: ReactApplicationContext) : + NativeRNReactNativePingSpec(reactContext) { + + companion object { + const val NAME = "RNReactNativePing" + private const val DEFAULT_TIMEOUT_MS = 3000 + } + + override fun getName(): String = NAME + + override fun start(ipAddress: String, option: ReadableMap, promise: Promise) { + Thread { + try { + val timeout = if (option.hasKey("timeout")) option.getInt("timeout") else DEFAULT_TIMEOUT_MS + val startTime = System.currentTimeMillis() + val reachable = InetAddress.getByName(ipAddress).isReachable(timeout) + val elapsed = System.currentTimeMillis() - startTime + if (reachable) { + promise.resolve(elapsed.toDouble()) + } else { + promise.reject("PING_TIMEOUT", "Host $ipAddress is not reachable within ${timeout}ms") + } + } catch (e: Exception) { + promise.reject("PING_ERROR", e.message, e) + } + }.start() + } +} diff --git a/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingPackage.kt b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingPackage.kt new file mode 100644 index 00000000..353ff3a6 --- /dev/null +++ b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingPackage.kt @@ -0,0 +1,33 @@ +package com.rnping + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class RNReactNativePingPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == RNReactNativePingModule.NAME) { + RNReactNativePingModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[RNReactNativePingModule.NAME] = ReactModuleInfo( + RNReactNativePingModule.NAME, + RNReactNativePingModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 6ec7eb44..848ff63d 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "prepare": "bob build", diff --git a/native-modules/react-native-tcp-socket/android/build.gradle b/native-modules/react-native-tcp-socket/android/build.gradle new file mode 100644 index 00000000..35ef7756 --- /dev/null +++ b/native-modules/react-native-tcp-socket/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['RNTcpSocket_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNTcpSocket_" + name]).toInteger() +} + +android { + namespace "com.rntcpsocket" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt new file mode 100644 index 00000000..1b0a1c0f --- /dev/null +++ b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt @@ -0,0 +1,35 @@ +package com.rntcpsocket + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModule +import java.net.InetSocketAddress +import java.net.Socket + +@ReactModule(name = RNTcpSocketModule.NAME) +class RNTcpSocketModule(reactContext: ReactApplicationContext) : + NativeRNTcpSocketSpec(reactContext) { + + companion object { + const val NAME = "RNTcpSocket" + } + + override fun getName(): String = NAME + + override fun connectWithTimeout(host: String, port: Double, timeoutMs: Double, promise: Promise) { + Thread { + try { + val portInt = port.toInt() + val timeout = timeoutMs.toInt() + val startTime = System.currentTimeMillis() + Socket().use { socket -> + socket.connect(InetSocketAddress(host, portInt), timeout) + } + val elapsed = System.currentTimeMillis() - startTime + promise.resolve(elapsed.toDouble()) + } catch (e: Exception) { + promise.reject("TCP_SOCKET_ERROR", e.message, e) + } + }.start() + } +} diff --git a/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketPackage.kt b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketPackage.kt new file mode 100644 index 00000000..6b144e94 --- /dev/null +++ b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketPackage.kt @@ -0,0 +1,33 @@ +package com.rntcpsocket + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class RNTcpSocketPackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == RNTcpSocketModule.NAME) { + RNTcpSocketModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[RNTcpSocketModule.NAME] = ReactModuleInfo( + RNTcpSocketModule.NAME, + RNTcpSocketModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index f3d955d8..fbcd5a69 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-tcp-socket/src/index.tsx b/native-modules/react-native-tcp-socket/src/index.tsx index be33a1ec..28d670ba 100644 --- a/native-modules/react-native-tcp-socket/src/index.tsx +++ b/native-modules/react-native-tcp-socket/src/index.tsx @@ -37,19 +37,19 @@ function createConnection( } }); - const shim: TcpSocketShim = { - on(event: 'error' | 'timeout', handler: (err?: Error) => void) { + const shim = { + on(event: string, handler: (err?: Error) => void) { if (event === 'error') { handlers.error = handler as (err: Error) => void; } else if (event === 'timeout') { handlers.timeout = handler as () => void; } - return this; + return shim as unknown as TcpSocketShim; }, destroy() { destroyed = true; }, - }; + } as unknown as TcpSocketShim; return shim; } diff --git a/native-modules/react-native-zip-archive/android/build.gradle b/native-modules/react-native-zip-archive/android/build.gradle new file mode 100644 index 00000000..bd91c31c --- /dev/null +++ b/native-modules/react-native-zip-archive/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['RNZipArchive_' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNZipArchive_" + name]).toInteger() +} + +android { + namespace "com.rnziparchive" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt new file mode 100644 index 00000000..d26f37f4 --- /dev/null +++ b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt @@ -0,0 +1,158 @@ +package com.rnziparchive + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.module.annotations.ReactModule +import java.io.BufferedInputStream +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream + +@ReactModule(name = RNZipArchiveModule.NAME) +class RNZipArchiveModule(reactContext: ReactApplicationContext) : + NativeRNZipArchiveSpec(reactContext) { + + companion object { + const val NAME = "RNZipArchive" + private const val BUFFER_SIZE = 8192 + } + + override fun getName(): String = NAME + + override fun isPasswordProtected(file: String, promise: Promise) { + Thread { + try { + // java.util.zip does not support password-protected zips natively + // Return false as a safe default + promise.resolve(false) + } catch (e: Exception) { + promise.reject("ZIP_ERROR", e.message, e) + } + }.start() + } + + override fun unzip(from: String, to: String, promise: Promise) { + Thread { + try { + val destDir = File(to) + if (!destDir.exists()) destDir.mkdirs() + + ZipInputStream(BufferedInputStream(FileInputStream(from))).use { zis -> + var entry: ZipEntry? = zis.nextEntry + while (entry != null) { + val outFile = File(destDir, entry.name) + if (entry.isDirectory) { + outFile.mkdirs() + } else { + outFile.parentFile?.mkdirs() + FileOutputStream(outFile).use { fos -> + val buffer = ByteArray(BUFFER_SIZE) + var len: Int + while (zis.read(buffer).also { len = it } > 0) { + fos.write(buffer, 0, len) + } + } + } + zis.closeEntry() + entry = zis.nextEntry + } + } + promise.resolve(to) + } catch (e: Exception) { + promise.reject("ZIP_ERROR", e.message, e) + } + }.start() + } + + override fun unzipWithPassword(from: String, to: String, password: String, promise: Promise) { + Thread { + // java.util.zip does not support password-protected zip extraction + promise.reject("ZIP_ERROR", "Password-protected zip extraction is not supported on Android") + }.start() + } + + override fun zipFolder(from: String, to: String, promise: Promise) { + Thread { + try { + val sourceDir = File(from) + FileOutputStream(to).use { fos -> + ZipOutputStream(BufferedOutputStream(fos)).use { zos -> + zipDirectory(sourceDir, sourceDir.name, zos) + } + } + promise.resolve(to) + } catch (e: Exception) { + promise.reject("ZIP_ERROR", e.message, e) + } + }.start() + } + + override fun zipFiles(files: ReadableArray, to: String, promise: Promise) { + Thread { + try { + FileOutputStream(to).use { fos -> + ZipOutputStream(BufferedOutputStream(fos)).use { zos -> + for (i in 0 until files.size()) { + val filePath = files.getString(i) + val file = File(filePath) + if (file.exists()) { + addFileToZip(file, file.name, zos) + } + } + } + } + promise.resolve(to) + } catch (e: Exception) { + promise.reject("ZIP_ERROR", e.message, e) + } + }.start() + } + + override fun getUncompressedSize(path: String, promise: Promise) { + Thread { + try { + var totalSize = 0L + ZipFile(path).use { zipFile -> + val entries = zipFile.entries() + while (entries.hasMoreElements()) { + totalSize += entries.nextElement().size + } + } + promise.resolve(totalSize.toDouble()) + } catch (e: Exception) { + promise.reject("ZIP_ERROR", e.message, e) + } + }.start() + } + + private fun zipDirectory(dir: File, baseName: String, zos: ZipOutputStream) { + val files = dir.listFiles() ?: return + for (file in files) { + val entryName = "$baseName/${file.name}" + if (file.isDirectory) { + zipDirectory(file, entryName, zos) + } else { + addFileToZip(file, entryName, zos) + } + } + } + + private fun addFileToZip(file: File, entryName: String, zos: ZipOutputStream) { + val entry = ZipEntry(entryName) + zos.putNextEntry(entry) + FileInputStream(file).use { fis -> + val buffer = ByteArray(BUFFER_SIZE) + var len: Int + while (fis.read(buffer).also { len = it } > 0) { + zos.write(buffer, 0, len) + } + } + zos.closeEntry() + } +} diff --git a/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchivePackage.kt b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchivePackage.kt new file mode 100644 index 00000000..b6349bdd --- /dev/null +++ b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchivePackage.kt @@ -0,0 +1,33 @@ +package com.rnziparchive + +import com.facebook.react.BaseReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import java.util.HashMap + +class RNZipArchivePackage : BaseReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return if (name == RNZipArchiveModule.NAME) { + RNZipArchiveModule(reactContext) + } else { + null + } + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + moduleInfos[RNZipArchiveModule.NAME] = ReactModuleInfo( + RNZipArchiveModule.NAME, + RNZipArchiveModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + moduleInfos + } + } +} diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 87bd75dd..24417715 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -21,7 +21,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "android" ], "scripts": { "prepare": "bob build", From cc57b52965fa6f431baecf18c375a3f8877213f3 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:47:57 +0800 Subject: [PATCH 35/74] chore: bump all packages to 1.1.56 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 89507997..c2aca520 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 701a760d..76784731 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index df7c61aa..43118045 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 30e1eb8b..19c5ca35 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index f9fd33d1..52db50bf 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index fc712b43..a9890442 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 24218d52..412a8d5d 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 7276bbd5..8bfc8b81 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index e47272cd..d579d84a 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index f5bb2ea4..2d967693 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 437977a9..23101c92 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 4e097d74..101cc20c 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 095d16c0..63e332cd 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index a7e66f69..832ffd12 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.55", + "version": "1.1.56", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index e1bcc0f5..14c18d42 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 000ee7ad..35f24d37 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 71ee25ab..fd14d30e 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 848ff63d..0f389cf3 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index d93b75b9..281b4a78 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index ee4b50d6..4b2d15d0 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index fbcd5a69..bc359e3e 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 24417715..3e5586e2 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 01f00d2a..ebff6b6c 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.55", + "version": "1.1.56", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index b5a7342d..d32ad8ae 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.55", + "version": "1.1.56", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index a8abd466..e9097504 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.55", + "version": "1.1.56", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 33c572ae..1a124791 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.55", + "version": "1.1.56", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index bbf88526..0a52b4f5 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.55", + "version": "1.1.56", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 1208b117bf3d15d6961b49278cfc9f9ca306d7e6 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:58:02 +0800 Subject: [PATCH 36/74] fix: add missing release scripts for cloud-fs, ping, zip-archive --- native-modules/react-native-cloud-fs/package.json | 3 ++- native-modules/react-native-ping/package.json | 3 ++- native-modules/react-native-zip-archive/package.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 8bfc8b81..ca0d6271 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -26,7 +26,8 @@ ], "scripts": { "prepare": "bob build", - "typecheck": "tsc" + "typecheck": "tsc", + "release": "yarn prepare && npm whoami && npm publish --access public" }, "keywords": [ "react-native", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 0f389cf3..aeaa094b 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -26,7 +26,8 @@ ], "scripts": { "prepare": "bob build", - "typecheck": "tsc" + "typecheck": "tsc", + "release": "yarn prepare && npm whoami && npm publish --access public" }, "keywords": [ "react-native", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 3e5586e2..a08fea88 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -26,7 +26,8 @@ ], "scripts": { "prepare": "bob build", - "typecheck": "tsc" + "typecheck": "tsc", + "release": "yarn prepare && npm whoami && npm publish --access public" }, "keywords": [ "react-native", From c2f878f646b8d3a55c7df865c53124b5995024dc Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 01:58:24 +0800 Subject: [PATCH 37/74] chore: bump all packages to 1.1.57 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index c2aca520..91eeb86c 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 76784731..2afd7713 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 43118045..044ad61f 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 19c5ca35..c3c549e1 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 52db50bf..fd982d3e 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index a9890442..8d482ea2 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 412a8d5d..c2b5d003 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index ca0d6271..0fd1f0ff 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index d579d84a..b488b704 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 2d967693..67526539 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 23101c92..662bad86 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 101cc20c..5e5752f3 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 63e332cd..c844de33 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 832ffd12..216349a6 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.56", + "version": "1.1.57", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 14c18d42..49f9d8f1 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 35f24d37..3f2a96ac 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index fd14d30e..606ed7d3 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index aeaa094b..4485d667 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 281b4a78..c59a6e94 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 4b2d15d0..08ec26cb 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index bc359e3e..c1d48fe4 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index a08fea88..daea04b4 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index ebff6b6c..8f7a2453 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.56", + "version": "1.1.57", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index d32ad8ae..246a5444 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.56", + "version": "1.1.57", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index e9097504..85628f03 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.56", + "version": "1.1.57", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 1a124791..943cec55 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.56", + "version": "1.1.57", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 0a52b4f5..7bddb5d3 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.56", + "version": "1.1.57", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From dbb0abb8dc2ac187973c6920d29d898d083ee77f Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 02:04:50 +0800 Subject: [PATCH 38/74] fix: set cloud-fs version to 3.0.0 (npm has 2.6.5, can't publish lower) --- native-modules/react-native-cloud-fs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 0fd1f0ff..067ad070 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "1.1.57", + "version": "3.0.0", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", From 69bdab651a7a2b9d373c6e8130fe0f78b46ee2cc Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 02:10:18 +0800 Subject: [PATCH 39/74] chore: bump all packages to 1.1.58 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 91eeb86c..19931691 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 2afd7713..f5c75cb7 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 044ad61f..29e968ea 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index c3c549e1..3e2d8b87 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index fd982d3e..ed32f17b 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 8d482ea2..a2a38516 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index c2b5d003..2c4fc1da 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 067ad070..b7810d2f 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.0", + "version": "3.0.1", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index b488b704..9d4582d4 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 67526539..d129b5ef 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 662bad86..59e08679 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 5e5752f3..c704f05a 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index c844de33..effb8f11 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 216349a6..05b89144 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.57", + "version": "1.1.58", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 49f9d8f1..bc6fcfdd 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 3f2a96ac..cad67d62 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 606ed7d3..06b2eb1d 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 4485d667..decec7c9 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index c59a6e94..02784d39 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 08ec26cb..f7ceac2f 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index c1d48fe4..e27f2637 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index daea04b4..329a3484 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 8f7a2453..c4e82e4b 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.57", + "version": "1.1.58", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 246a5444..4cac6c08 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.57", + "version": "1.1.58", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 85628f03..73ea0334 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.57", + "version": "1.1.58", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 943cec55..005e53b3 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.57", + "version": "1.1.58", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 7bddb5d3..97ddab79 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.57", + "version": "1.1.58", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 369f39e15e0750523fafd3372f8523ed6d9a44d2 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:16:55 +0800 Subject: [PATCH 40/74] fix: correct TcpSocket header import to match codegenConfig name --- .../margelo/nitro/nativelogger/OneKeyLog.kt | 9 +++++---- .../native-logger/ios/OneKeyLog.swift | 9 +++++---- .../android/src/main/cpp/cpp-adapter.cpp | 18 +++++++++++++----- .../cpp/SharedRPC.cpp | 7 +++++++ .../react-native-tcp-socket/ios/TcpSocket.h | 2 +- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt index 70211312..8622fb4b 100644 --- a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt +++ b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt @@ -247,18 +247,19 @@ object OneKeyLog { // Dedup: collapse identical consecutive messages into [N repeat] // ----------------------------------------------------------------------- private val dedupLock = Any() - @Volatile private var prevLogMessage: String? = null + @Volatile private var prevLogKey: String? = null private var repeatCount: Int = 0 private fun log(tag: String, level: String, message: String, androidLogLevel: Int) { - // Dedup identical consecutive messages + // Dedup identical consecutive messages (same level + tag + message) + val logKey = "$level:$tag:$message" synchronized(dedupLock) { - if (message == prevLogMessage) { + if (logKey == prevLogKey) { repeatCount += 1 return } val pendingRepeat = repeatCount - prevLogMessage = message + prevLogKey = logKey repeatCount = 0 if (pendingRepeat > 0) { diff --git a/native-modules/native-logger/ios/OneKeyLog.swift b/native-modules/native-logger/ios/OneKeyLog.swift index 379ad6ff..72ca2b49 100644 --- a/native-modules/native-logger/ios/OneKeyLog.swift +++ b/native-modules/native-logger/ios/OneKeyLog.swift @@ -236,7 +236,7 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { // Dedup: collapse identical consecutive messages into [N repeat] // ----------------------------------------------------------------------- private static let dedupLock = NSLock() - private static var prevLogMessage: String? + private static var prevLogKey: String? private static var repeatCount: Int = 0 private static func log( @@ -247,16 +247,17 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { ) { _ = configured - // Dedup identical consecutive messages + // Dedup identical consecutive messages (same level + tag + message) + let logKey = "\(level):\(tag):\(message)" dedupLock.lock() - let isDuplicate = (message == prevLogMessage) + let isDuplicate = (logKey == prevLogKey) if isDuplicate { repeatCount += 1 dedupLock.unlock() return } let pendingRepeat = repeatCount - prevLogMessage = message + prevLogKey = logKey repeatCount = 0 dedupLock.unlock() diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index 70f40dc1..365d3c72 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -99,14 +99,21 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( SharedStore::install(*rt); - // Create executor that schedules work on this runtime's JS thread via Kotlin - jobject ref = env->NewGlobalRef(thiz); + // Create executor that schedules work on this runtime's JS thread via Kotlin. + // Wrap GlobalRef in shared_ptr so it is automatically released when all + // copies of the executor lambda are destroyed (e.g. on runtime reload). + auto ref = std::shared_ptr<_jobject>(env->NewGlobalRef(thiz), [](jobject r) { + if (r) { + JNIEnv *e = getJNIEnv(); + if (e) e->DeleteGlobalRef(r); + } + }); bool capturedIsMain = static_cast(isMain); RPCRuntimeExecutor executor = [ref, capturedIsMain](std::function work) { JNIEnv *env = getJNIEnv(); if (!env || !ref) { - LOGE("executor: env=%p, ref=%p — aborting", env, ref); + LOGE("executor: env=%p, ref=%p — aborting", env, ref.get()); return; } @@ -117,11 +124,11 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( gPendingWork[workId] = std::move(work); } - jclass cls = env->GetObjectClass(ref); + jclass cls = env->GetObjectClass(ref.get()); jmethodID mid = env->GetMethodID(cls, "scheduleOnJSThread", "(ZJ)V"); if (mid) { LOGI("executor: calling scheduleOnJSThread(isMain=%d, workId=%ld)", capturedIsMain, (long)workId); - env->CallVoidMethod(ref, mid, static_cast(capturedIsMain), static_cast(workId)); + env->CallVoidMethod(ref.get(), mid, static_cast(capturedIsMain), static_cast(workId)); if (env->ExceptionCheck()) { LOGE("executor: JNI exception after scheduleOnJSThread"); env->ExceptionDescribe(); @@ -217,6 +224,7 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeDestroy( JNIEnv *env, jobject thiz) { SharedRPC::reset(); + SharedStore::reset(); LOGI("Native resources cleaned up"); } diff --git a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp index 72cf4da6..d3ee3e65 100644 --- a/native-modules/react-native-background-thread/cpp/SharedRPC.cpp +++ b/native-modules/react-native-background-thread/cpp/SharedRPC.cpp @@ -46,6 +46,13 @@ void SharedRPC::install(jsi::Runtime &rt, RPCRuntimeExecutor executor, void SharedRPC::reset() { std::lock_guard lock(mutex_); slots_.clear(); + // Intentionally leak jsi::Function callbacks to avoid destroying them on the + // wrong thread (same rationale as the leak in install() for reload scenarios). + for (auto &listener : listeners_) { + if (listener.callback) { + new std::shared_ptr(std::move(listener.callback)); + } + } listeners_.clear(); } diff --git a/native-modules/react-native-tcp-socket/ios/TcpSocket.h b/native-modules/react-native-tcp-socket/ios/TcpSocket.h index 5f21f084..f4506593 100644 --- a/native-modules/react-native-tcp-socket/ios/TcpSocket.h +++ b/native-modules/react-native-tcp-socket/ios/TcpSocket.h @@ -1,4 +1,4 @@ -#import +#import @interface TcpSocket : NativeRNTcpSocketSpecBase From d92f0a4e88ca862544714af827d41a17f1eb227e Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:17:19 +0800 Subject: [PATCH 41/74] chore: bump all packages to 1.1.59 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 19931691..74c3488f 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index f5c75cb7..19445c13 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 29e968ea..dd010ae4 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 3e2d8b87..5eb83216 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index ed32f17b..a4dbddfb 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index a2a38516..57534fd8 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 2c4fc1da..fa878594 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index b7810d2f..c37543de 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.1", + "version": "3.0.2", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 9d4582d4..f2ef0ba5 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index d129b5ef..6c94d537 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 59e08679..138744c5 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index c704f05a..2821e0d8 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index effb8f11..0ff45394 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 05b89144..e2768187 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.58", + "version": "1.1.59", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index bc6fcfdd..cb8a47e7 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index cad67d62..682f8fed 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 06b2eb1d..d6f77b3b 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index decec7c9..82eaa4b1 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 02784d39..38338790 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index f7ceac2f..debf373d 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index e27f2637..69673d8b 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 329a3484..f8ee40e0 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index c4e82e4b..2ada087b 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.58", + "version": "1.1.59", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 4cac6c08..e05d825d 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.58", + "version": "1.1.59", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 73ea0334..a92dde98 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.58", + "version": "1.1.59", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 005e53b3..6a7b2cf2 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.58", + "version": "1.1.59", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 97ddab79..31bebd97 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.58", + "version": "1.1.59", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From f7761c24b4feb3be260716d6096e695c8d748a12 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:23:49 +0800 Subject: [PATCH 42/74] fix: correct reflection class name for BundleUpdateStore in SplitBundleLoader The reflection lookup used a stale Expo module path (expo.modules.onekeybundleupdate.BundleUpdateStore) that no longer exists. Updated to the correct class name (com.margelo.nitro.reactnativebundleupdate.BundleUpdateStoreAndroid). --- .../main/java/com/splitbundleloader/SplitBundleLoaderModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt index 58617b16..809df1ac 100644 --- a/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt +++ b/native-modules/react-native-split-bundle-loader/android/src/main/java/com/splitbundleloader/SplitBundleLoaderModule.kt @@ -333,7 +333,7 @@ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) : private fun getOtaBundlePath(): String? { return try { val bundleUpdateStore = Class.forName( - "expo.modules.onekeybundleupdate.BundleUpdateStore" + "com.margelo.nitro.reactnativebundleupdate.BundleUpdateStoreAndroid" ) val method = bundleUpdateStore.getMethod( "getCurrentBundleMainJSBundle", From 31b6be47d93b85c895d638c6158194bf679eb8c0 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:24:52 +0800 Subject: [PATCH 43/74] fix: correct codegen class names to match TS spec file names --- native-modules/react-native-async-storage/ios/AsyncStorage.h | 2 +- native-modules/react-native-async-storage/ios/AsyncStorage.mm | 2 +- native-modules/react-native-cloud-fs/ios/CloudFs.h | 2 +- native-modules/react-native-cloud-fs/ios/CloudFs.mm | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-dns-lookup/ios/DnsLookup.h | 2 +- native-modules/react-native-dns-lookup/ios/DnsLookup.mm | 2 +- native-modules/react-native-network-info/ios/NetworkInfo.h | 2 +- native-modules/react-native-network-info/ios/NetworkInfo.mm | 2 +- native-modules/react-native-ping/ios/Ping.h | 2 +- native-modules/react-native-ping/ios/Ping.mm | 2 +- native-modules/react-native-tcp-socket/ios/TcpSocket.h | 2 +- native-modules/react-native-tcp-socket/ios/TcpSocket.mm | 2 +- native-modules/react-native-zip-archive/ios/ZipArchive.h | 2 +- native-modules/react-native-zip-archive/ios/ZipArchive.mm | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/native-modules/react-native-async-storage/ios/AsyncStorage.h b/native-modules/react-native-async-storage/ios/AsyncStorage.h index 89a04466..60c02827 100644 --- a/native-modules/react-native-async-storage/ios/AsyncStorage.h +++ b/native-modules/react-native-async-storage/ios/AsyncStorage.h @@ -1,6 +1,6 @@ #import -@interface AsyncStorage : NativeRNCAsyncStorageSpecBase +@interface AsyncStorage : NativeAsyncStorageSpecBase - (void)multiGet:(NSArray *)keys resolve:(RCTPromiseResolveBlock)resolve diff --git a/native-modules/react-native-async-storage/ios/AsyncStorage.mm b/native-modules/react-native-async-storage/ios/AsyncStorage.mm index fa5dd526..4154ff0b 100644 --- a/native-modules/react-native-async-storage/ios/AsyncStorage.mm +++ b/native-modules/react-native-async-storage/ios/AsyncStorage.mm @@ -382,7 +382,7 @@ + (BOOL)requiresMainQueueSetup - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } - (instancetype)init diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.h b/native-modules/react-native-cloud-fs/ios/CloudFs.h index b176f25b..159149cb 100644 --- a/native-modules/react-native-cloud-fs/ios/CloudFs.h +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.h @@ -1,6 +1,6 @@ #import -@interface CloudFs : NativeRNCloudFsSpecBase +@interface CloudFs : NativeCloudFsSpecBase @property (nonatomic, strong) NSMetadataQuery *query; diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.mm b/native-modules/react-native-cloud-fs/ios/CloudFs.mm index 43811eb6..b29d2197 100644 --- a/native-modules/react-native-cloud-fs/ios/CloudFs.mm +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.mm @@ -7,7 +7,7 @@ @implementation CloudFs - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index c37543de..8541f24d 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.2", + "version": "3.0.3", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/ios/DnsLookup.h b/native-modules/react-native-dns-lookup/ios/DnsLookup.h index 69dc15bb..d6efb6c6 100644 --- a/native-modules/react-native-dns-lookup/ios/DnsLookup.h +++ b/native-modules/react-native-dns-lookup/ios/DnsLookup.h @@ -1,6 +1,6 @@ #import -@interface DnsLookup : NativeRNDnsLookupSpecBase +@interface DnsLookup : NativeDnsLookupSpecBase - (void)getIpAddresses:(NSString *)hostname resolve:(RCTPromiseResolveBlock)resolve diff --git a/native-modules/react-native-dns-lookup/ios/DnsLookup.mm b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm index 5e13eb04..9e23898e 100644 --- a/native-modules/react-native-dns-lookup/ios/DnsLookup.mm +++ b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm @@ -11,7 +11,7 @@ @implementation DnsLookup - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.h b/native-modules/react-native-network-info/ios/NetworkInfo.h index a71077ff..d819c472 100644 --- a/native-modules/react-native-network-info/ios/NetworkInfo.h +++ b/native-modules/react-native-network-info/ios/NetworkInfo.h @@ -1,6 +1,6 @@ #import -@interface NetworkInfo : NativeRNNetworkInfoSpecBase +@interface NetworkInfo : NativeNetworkInfoSpecBase - (void)getSSID:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.mm b/native-modules/react-native-network-info/ios/NetworkInfo.mm index 6c374670..e08587ea 100644 --- a/native-modules/react-native-network-info/ios/NetworkInfo.mm +++ b/native-modules/react-native-network-info/ios/NetworkInfo.mm @@ -21,7 +21,7 @@ @implementation NetworkInfo - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName diff --git a/native-modules/react-native-ping/ios/Ping.h b/native-modules/react-native-ping/ios/Ping.h index 7f61a0bd..30d5a9f2 100644 --- a/native-modules/react-native-ping/ios/Ping.h +++ b/native-modules/react-native-ping/ios/Ping.h @@ -1,6 +1,6 @@ #import -@interface Ping : NativeRNReactNativePingSpecBase +@interface Ping : NativePingSpecBase - (void)start:(NSString *)ipAddress option:(JS::NativeRNReactNativePing::SpecStartOption &)option diff --git a/native-modules/react-native-ping/ios/Ping.mm b/native-modules/react-native-ping/ios/Ping.mm index b8391aa5..6f44ac2d 100644 --- a/native-modules/react-native-ping/ios/Ping.mm +++ b/native-modules/react-native-ping/ios/Ping.mm @@ -12,7 +12,7 @@ @implementation Ping - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName diff --git a/native-modules/react-native-tcp-socket/ios/TcpSocket.h b/native-modules/react-native-tcp-socket/ios/TcpSocket.h index f4506593..f682676b 100644 --- a/native-modules/react-native-tcp-socket/ios/TcpSocket.h +++ b/native-modules/react-native-tcp-socket/ios/TcpSocket.h @@ -1,5 +1,5 @@ #import -@interface TcpSocket : NativeRNTcpSocketSpecBase +@interface TcpSocket : NativeTcpSocketSpecBase @end diff --git a/native-modules/react-native-tcp-socket/ios/TcpSocket.mm b/native-modules/react-native-tcp-socket/ios/TcpSocket.mm index 029ccf0b..96949c52 100644 --- a/native-modules/react-native-tcp-socket/ios/TcpSocket.mm +++ b/native-modules/react-native-tcp-socket/ios/TcpSocket.mm @@ -16,7 +16,7 @@ @implementation TcpSocket - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName diff --git a/native-modules/react-native-zip-archive/ios/ZipArchive.h b/native-modules/react-native-zip-archive/ios/ZipArchive.h index 62990ae0..b17396b5 100644 --- a/native-modules/react-native-zip-archive/ios/ZipArchive.h +++ b/native-modules/react-native-zip-archive/ios/ZipArchive.h @@ -1,7 +1,7 @@ #import #import -@interface ZipArchive : NativeRNZipArchiveSpecBase +@interface ZipArchive : NativeZipArchiveSpecBase @property (nonatomic) NSString *processedFilePath; @property (nonatomic) float progress; diff --git a/native-modules/react-native-zip-archive/ios/ZipArchive.mm b/native-modules/react-native-zip-archive/ios/ZipArchive.mm index 633d74a3..2786ccbb 100644 --- a/native-modules/react-native-zip-archive/ios/ZipArchive.mm +++ b/native-modules/react-native-zip-archive/ios/ZipArchive.mm @@ -8,7 +8,7 @@ @implementation ZipArchive - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); + return std::make_shared(params); } + (NSString *)moduleName From 8c0aab9b2d6e859bfa8840a6a93d060b4dc984ac Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:25:14 +0800 Subject: [PATCH 44/74] chore: bump all packages to 1.1.60 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 74c3488f..db6d8df2 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 19445c13..0d5808e5 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index dd010ae4..513e0b29 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 5eb83216..2979fc49 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index a4dbddfb..9ed0c6eb 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 57534fd8..c80d9ef2 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index fa878594..a1742075 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 8541f24d..0d717db1 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.3", + "version": "3.0.4", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index f2ef0ba5..59b70f39 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 6c94d537..1d90cee9 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 138744c5..64df54a7 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 2821e0d8..91362f3c 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 0ff45394..defe7d8d 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index e2768187..7791582e 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.59", + "version": "1.1.60", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index cb8a47e7..1d040377 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 682f8fed..f0f94a6f 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index d6f77b3b..9929e72c 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 82eaa4b1..487d115d 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 38338790..5dba66e1 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index debf373d..87e8bb62 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 69673d8b..8904b028 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index f8ee40e0..345152f8 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 2ada087b..80112e80 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.59", + "version": "1.1.60", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index e05d825d..c6723c2f 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.59", + "version": "1.1.60", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index a92dde98..7bbdb45a 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.59", + "version": "1.1.60", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 6a7b2cf2..569654e5 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.59", + "version": "1.1.60", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 31bebd97..565d072e 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.59", + "version": "1.1.60", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 4acfaba023bd81d1ef620778a11549fc4e17dc17 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:30:13 +0800 Subject: [PATCH 45/74] chore: bump all packages to 3.0.4 Align all package versions to the 3.x line to match cloud-fs which cannot use 1.x (npm already has 2.6.5). --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index db6d8df2..074d8d9f 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 0d5808e5..df6b4531 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 513e0b29..3c9c9b16 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 2979fc49..9713bf50 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 9ed0c6eb..4b7e3477 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index c80d9ef2..1e4d2b55 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index a1742075..0764f2a7 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 0d717db1..f7df6b0a 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.4", + "version": "3.0.5", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 59b70f39..7dd1e209 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 1d90cee9..6a1ac237 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 64df54a7..1c59a234 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 91362f3c..1bebf1e9 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index defe7d8d..f2a6017d 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 7791582e..e35c5e07 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "1.1.60", + "version": "3.0.5", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 1d040377..3fb018f8 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index f0f94a6f..9251981d 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 9929e72c..48d25150 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 487d115d..271dff1c 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 5dba66e1..200d2800 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 87e8bb62..1de645ff 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 8904b028..e71d96ed 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 345152f8..7114f349 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 80112e80..d3ebf04c 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "1.1.60", + "version": "3.0.5", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index c6723c2f..50ed8905 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "1.1.60", + "version": "3.0.5", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 7bbdb45a..b16e442a 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "1.1.60", + "version": "3.0.5", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 569654e5..aabe16cc 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "1.1.60", + "version": "3.0.5", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 565d072e..a87ed17f 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "1.1.60", + "version": "3.0.5", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 8f2e592af550a506d8d2b99bd5c1de94dfb259f8 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:35:48 +0800 Subject: [PATCH 46/74] fix: fix compilation errors in ping, pbkdf2, network-info --- CHANGELOG.md | 126 ++++++++++++++++++ .../react-native-async-storage/README.md | 32 +++++ .../ios/NetworkInfo.mm | 2 +- .../ios/getgateway.c | 38 +++++- .../react-native-pbkdf2/ios/Pbkdf2.mm | 6 +- native-modules/react-native-ping/ios/Ping.h | 2 +- native-modules/react-native-ping/ios/Ping.mm | 2 +- 7 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 native-modules/react-native-async-storage/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a6cf4d30..3a06e7e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,132 @@ All notable changes to this project will be documented in this file. +## [3.0.4] - 2026-04-03 + +### Bug Fixes +- **split-bundle-loader**: Fix stale reflection class name for `BundleUpdateStore` in Android `getOtaBundlePath()` — updated from `expo.modules.onekeybundleupdate.BundleUpdateStore` to `com.margelo.nitro.reactnativebundleupdate.BundleUpdateStoreAndroid` +- **native-logger**: Fix dedup logic suppressing error logs — comparison now includes level, tag, and message instead of message-only +- **background-thread**: Fix JNI GlobalRef leak on each `nativeInstallSharedBridge` call — wrap in `shared_ptr` with custom deleter +- **background-thread**: Fix `SharedRPC::reset()` crash from destroying `jsi::Function` on wrong thread — use intentional leak pattern +- **background-thread**: Fix `nativeDestroy` not resetting `SharedStore`, leaving stale data across restarts +- Correct codegen class names to match TS spec file names + +### Chores +- Align all package versions to 3.x line (cloud-fs cannot use 1.x since npm already has 2.6.5) +- Bump all packages to 3.0.4 + +## [1.1.59] - 2026-04-03 + +### Bug Fixes +- **tcp-socket**: Correct header import to match codegenConfig name + +### Chores +- Bump all packages to 1.1.59 + +## [1.1.58] - 2026-04-03 + +### Bug Fixes +- **cloud-fs**: Set version to 3.0.0 (npm already has 2.6.5, cannot publish lower) + +### Chores +- Bump all packages to 1.1.58 + +## [1.1.57] - 2026-04-03 + +### Bug Fixes +- Add missing release scripts for cloud-fs, ping, zip-archive + +### Chores +- Bump all packages to 1.1.57 + +## [1.1.56] - 2026-04-03 + +### Features +- **aes-crypto / async-storage / cloud-fs / dns-lookup / network-info / ping / tcp-socket / zip-archive**: Add Android TurboModule implementations for legacy bridge module replacements +- **tcp-socket**: Fix type definitions + +### Chores +- Bump all packages to 1.1.56 + +## [1.1.55] - 2026-04-03 + +### Features +- **aes-crypto / async-storage / cloud-fs / dns-lookup / network-info / ping / tcp-socket / zip-archive**: Add TurboModule replacements for legacy React Native bridge modules (iOS + JS) + +### Chores +- Bump all packages to 1.1.55 + +## [1.1.54] - 2026-04-02 + +### Chores +- Bump all packages to 1.1.54 + +## [1.1.53] - 2026-04-02 + +### Features +- **split-bundle-loader**: Add split-bundle timing instrumentation and update PGP public key +- **split-bundle-loader**: Add comprehensive timing logs for three-bundle split verification + +### Chores +- Bump all packages to 1.1.53 + +## [1.1.52] - 2026-04-02 + +### Features +- **background-thread**: Add split-bundle common+entry loading strategy for background runtime + +### Chores +- Bump all packages to 1.1.52 + +## [1.1.51] - 2026-04-01 + +### Features +- **split-bundle-loader**: Add `resolveSegmentPath` API and path traversal protection + +### Bug Fixes +- **split-bundle-loader**: Resolve Android `registerSegmentInBackground` race condition +- **split-bundle-loader**: Enhance bridgeless support and robustness improvements + +### Chores +- Bump all packages to 1.1.51 + +## [1.1.49] - 2026-04-01 + +### Features +- **split-bundle-loader**: Add `react-native-split-bundle-loader` TurboModule with `getRuntimeBundleContext` and `loadSegment` APIs +- **split-bundle-loader**: Expose `loadSegmentInBackground` from TurboModule API +- **bundle-update**: Add `registerSegmentInBackground` for late HBC segment loading + +### Chores +- Bump all packages to 1.1.49 + +## [1.1.48] - 2026-03-31 + +### Features +- **bundle-update**: Support background bundle pair bootstrap — add `getBackgroundJsBundlePath`, metadata validation for `requiresBackgroundBundle` and `backgroundProtocolVersion`, and bundle pair compatibility checks + +### Chores +- Bump all packages to 1.1.48 + +## [1.1.47] - 2026-03-31 + +### Features +- **background-thread**: Add SharedBridge JSI HostObject for cross-runtime data transfer between main and background JS runtimes +- **background-thread**: Implement Android background runtime with second ReactHost and SharedBridge +- **background-thread**: Replace SharedBridge with SharedStore + SharedRPC architecture +- **background-thread**: Add onWrite cross-runtime notification, remove legacy messaging +- **native-logger**: Add dedup for identical consecutive log messages + +### Bug Fixes +- **background-thread**: Stabilize background thread runtime initialization +- **background-thread**: Initialize Android shared bridge at app startup +- **shared-rpc**: Rename `RuntimeExecutor` to `RPCRuntimeExecutor` to avoid React Native conflict +- **shared-rpc**: Prevent crash on JS reload by deduplicating listeners with runtimeId +- **shared-rpc**: Leak stale `jsi::Function` callback on reload to prevent crash + +### Chores +- Bump all packages to 1.1.47 + ## [1.1.46] - 2026-03-19 ### Bug Fixes diff --git a/native-modules/react-native-async-storage/README.md b/native-modules/react-native-async-storage/README.md new file mode 100644 index 00000000..c64a6ea8 --- /dev/null +++ b/native-modules/react-native-async-storage/README.md @@ -0,0 +1,32 @@ +# @onekeyfe/react-native-async-storage + +First, a sincere thank-you to Krzysztof Borowy and the +`@react-native-async-storage/async-storage` maintainers for their excellent +work 🙏 + +This package is built on, and inspired by, +[react-native-async-storage/async-storage](https://github.com/react-native-async-storage/async-storage). + +Our original plan was to keep our customizations as patches on top of upstream +`@react-native-async-storage/async-storage`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `async-storage` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [react-native-async-storage/async-storage](https://github.com/react-native-async-storage/async-storage) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to Krzysztof Borowy and everyone who contributes to +`@react-native-async-storage/async-storage` 💙 diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.mm b/native-modules/react-native-network-info/ios/NetworkInfo.mm index e08587ea..c9e5080e 100644 --- a/native-modules/react-native-network-info/ios/NetworkInfo.mm +++ b/native-modules/react-native-network-info/ios/NetworkInfo.mm @@ -14,7 +14,7 @@ #define IP_ADDR_IPv4 @"ipv4" #define IP_ADDR_IPv6 @"ipv6" -@import SystemConfiguration.CaptiveNetwork; +#import @implementation NetworkInfo diff --git a/native-modules/react-native-network-info/ios/getgateway.c b/native-modules/react-native-network-info/ios/getgateway.c index 6fa9110f..22af591d 100644 --- a/native-modules/react-native-network-info/ios/getgateway.c +++ b/native-modules/react-native-network-info/ios/getgateway.c @@ -12,14 +12,48 @@ #include "TargetConditionals.h" #if TARGET_IPHONE_SIMULATOR -#include #define TypeEN "en1" #else -#include #define TypeEN "en0" #endif #include + +// Inline route.h definitions (not available in iOS SDK) +#define RTF_GATEWAY 0x2 +#define NET_RT_FLAGS 2 +#define RTAX_MAX 8 +#define RTAX_DST 0 +#define RTAX_GATEWAY 1 +#define RTA_DST 0x1 +#define RTA_GATEWAY 0x2 + +struct rt_msghdr { + u_short rtm_msglen; + u_char rtm_version; + u_char rtm_type; + u_short rtm_index; + int rtm_flags; + int rtm_addrs; + pid_t rtm_pid; + int rtm_seq; + int rtm_errno; + int rtm_use; + u_long rtm_inits; + struct rt_metrics { + u_long rmx_locks; + u_long rmx_mtu; + u_long rmx_hopcount; + u_long rmx_expire; + u_long rmx_recvpipe; + u_long rmx_sendpipe; + u_long rmx_ssthresh; + u_long rmx_rtt; + u_long rmx_rttvar; + u_long rmx_pksent; + u_long rmx_filler[4]; + } rtm_rmx; +}; #include #define CTL_NET 4 /* network, see socket.h */ diff --git a/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm b/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm index 0efe8fe6..c9ac72e7 100644 --- a/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm +++ b/native-modules/react-native-pbkdf2/ios/Pbkdf2.mm @@ -46,11 +46,11 @@ - (void)derive:(NSString *)password CCKeyDerivationPBKDF( kCCPBKDF2, - passwordData.bytes, passwordData.length, - saltData.bytes, saltData.length, + (const char *)passwordData.bytes, passwordData.length, + (const uint8_t *)saltData.bytes, saltData.length, prf, (unsigned int)rounds, - derivedKey.mutableBytes, derivedKey.length); + (uint8_t *)derivedKey.mutableBytes, derivedKey.length); resolve([derivedKey base64EncodedStringWithOptions:0]); } @catch (NSException *exception) { diff --git a/native-modules/react-native-ping/ios/Ping.h b/native-modules/react-native-ping/ios/Ping.h index 30d5a9f2..17a590e0 100644 --- a/native-modules/react-native-ping/ios/Ping.h +++ b/native-modules/react-native-ping/ios/Ping.h @@ -3,7 +3,7 @@ @interface Ping : NativePingSpecBase - (void)start:(NSString *)ipAddress - option:(JS::NativeRNReactNativePing::SpecStartOption &)option + option:(JS::NativePing::SpecStartOption &)option resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; diff --git a/native-modules/react-native-ping/ios/Ping.mm b/native-modules/react-native-ping/ios/Ping.mm index 6f44ac2d..4ae41b49 100644 --- a/native-modules/react-native-ping/ios/Ping.mm +++ b/native-modules/react-native-ping/ios/Ping.mm @@ -34,7 +34,7 @@ - (dispatch_queue_t)methodQueue } - (void)start:(NSString *)ipAddress - option:(JS::NativeRNReactNativePing::SpecStartOption &)option + option:(JS::NativePing::SpecStartOption &)option resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { From d5c7863d6a7193bb3262ffa8058377e85d233a45 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:36:12 +0800 Subject: [PATCH 47/74] chore: bump all packages to 1.1.61 --- native-modules/native-logger/package.json | 2 +- .../react-native-aes-crypto/README.md | 31 +++++++++++++++++++ .../react-native-aes-crypto/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../react-native-async-storage/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../react-native-cloud-fs/README.md | 31 +++++++++++++++++++ .../react-native-cloud-fs/package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../react-native-dns-lookup/README.md | 31 +++++++++++++++++++ .../react-native-dns-lookup/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-network-info/README.md | 31 +++++++++++++++++++ .../react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/README.md | 31 +++++++++++++++++++ .../react-native-pbkdf2/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/README.md | 31 +++++++++++++++++++ native-modules/react-native-ping/package.json | 2 +- .../react-native-splash-screen/README.md | 31 +++++++++++++++++++ .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-tcp-socket/README.md | 31 +++++++++++++++++++ .../react-native-tcp-socket/package.json | 2 +- .../react-native-zip-archive/README.md | 31 +++++++++++++++++++ .../react-native-zip-archive/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 36 files changed, 306 insertions(+), 27 deletions(-) create mode 100644 native-modules/react-native-aes-crypto/README.md create mode 100644 native-modules/react-native-cloud-fs/README.md create mode 100644 native-modules/react-native-dns-lookup/README.md create mode 100644 native-modules/react-native-network-info/README.md create mode 100644 native-modules/react-native-pbkdf2/README.md create mode 100644 native-modules/react-native-ping/README.md create mode 100644 native-modules/react-native-splash-screen/README.md create mode 100644 native-modules/react-native-tcp-socket/README.md create mode 100644 native-modules/react-native-zip-archive/README.md diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 074d8d9f..0f96619c 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/README.md b/native-modules/react-native-aes-crypto/README.md new file mode 100644 index 00000000..c9c31480 --- /dev/null +++ b/native-modules/react-native-aes-crypto/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-aes-crypto + +First, a sincere thank-you to tectiv3 and the +`react-native-aes-crypto` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[tectiv3/react-native-aes-crypto](https://github.com/tectiv3/react-native-aes-crypto). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-aes-crypto`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-aes-crypto` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [tectiv3/react-native-aes-crypto](https://github.com/tectiv3/react-native-aes-crypto) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to tectiv3 and everyone who contributes to +`react-native-aes-crypto` 💙 diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index df6b4531..01d0b0ec 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 3c9c9b16..a7b675b8 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 9713bf50..4351dc12 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 4b7e3477..c3b1ee0b 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 1e4d2b55..e7c53547 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 0764f2a7..0c3e2e67 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/README.md b/native-modules/react-native-cloud-fs/README.md new file mode 100644 index 00000000..3a47966c --- /dev/null +++ b/native-modules/react-native-cloud-fs/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-cloud-fs + +First, a sincere thank-you to the +`react-native-cloud-fs` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[nicola/react-native-cloud-fs](https://github.com/nicola/react-native-cloud-fs). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-cloud-fs`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-cloud-fs` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [nicola/react-native-cloud-fs](https://github.com/nicola/react-native-cloud-fs) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to everyone who contributes to +`react-native-cloud-fs` 💙 diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index f7df6b0a..9dbb318c 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 7dd1e209..1a7c14e8 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 6a1ac237..888c9aff 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/README.md b/native-modules/react-native-dns-lookup/README.md new file mode 100644 index 00000000..4749a618 --- /dev/null +++ b/native-modules/react-native-dns-lookup/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-dns-lookup + +First, a sincere thank-you to the +`react-native-dns-lookup` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[nicola/react-native-dns-lookup](https://github.com/nicola/react-native-dns-lookup). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-dns-lookup`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-dns-lookup` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [nicola/react-native-dns-lookup](https://github.com/nicola/react-native-dns-lookup) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to everyone who contributes to +`react-native-dns-lookup` 💙 diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 1c59a234..eeddc317 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 1bebf1e9..9c8ec523 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index f2a6017d..db52742e 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index e35c5e07..b36ed9f4 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.5", + "version": "3.0.6", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/README.md b/native-modules/react-native-network-info/README.md new file mode 100644 index 00000000..0304494f --- /dev/null +++ b/native-modules/react-native-network-info/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-network-info + +First, a sincere thank-you to the +`react-native-network-info` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[pusherman/react-native-network-info](https://github.com/pusherman/react-native-network-info). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-network-info`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-network-info` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [pusherman/react-native-network-info](https://github.com/pusherman/react-native-network-info) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to everyone who contributes to +`react-native-network-info` 💙 diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 3fb018f8..1d73f890 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/README.md b/native-modules/react-native-pbkdf2/README.md new file mode 100644 index 00000000..caf9e308 --- /dev/null +++ b/native-modules/react-native-pbkdf2/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-pbkdf2 + +First, a sincere thank-you to the +`react-native-pbkdf2` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[nicola/react-native-pbkdf2](https://github.com/nicola/react-native-pbkdf2). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-pbkdf2`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-pbkdf2` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [nicola/react-native-pbkdf2](https://github.com/nicola/react-native-pbkdf2) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to everyone who contributes to +`react-native-pbkdf2` 💙 diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 9251981d..3a44c42b 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 48d25150..4cab6a26 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/README.md b/native-modules/react-native-ping/README.md new file mode 100644 index 00000000..c761be63 --- /dev/null +++ b/native-modules/react-native-ping/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-ping + +First, a sincere thank-you to the +`react-native-ping` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[nicola/react-native-ping](https://github.com/nicola/react-native-ping). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-ping`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-ping` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [nicola/react-native-ping](https://github.com/nicola/react-native-ping) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to everyone who contributes to +`react-native-ping` 💙 diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 271dff1c..ff8ba90d 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/README.md b/native-modules/react-native-splash-screen/README.md new file mode 100644 index 00000000..3cffe3b5 --- /dev/null +++ b/native-modules/react-native-splash-screen/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-splash-screen + +First, a sincere thank-you to Crazycodeboy and the +`react-native-splash-screen` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[crazycodeboy/react-native-splash-screen](https://github.com/crazycodeboy/react-native-splash-screen). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-splash-screen`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-splash-screen` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [crazycodeboy/react-native-splash-screen](https://github.com/crazycodeboy/react-native-splash-screen) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to Crazycodeboy and everyone who contributes to +`react-native-splash-screen` 💙 diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 200d2800..e2dd2471 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 1de645ff..f1732c54 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/README.md b/native-modules/react-native-tcp-socket/README.md new file mode 100644 index 00000000..1a966fdb --- /dev/null +++ b/native-modules/react-native-tcp-socket/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-tcp-socket + +First, a sincere thank-you to Rapsssito and the +`react-native-tcp-socket` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[Rapsssito/react-native-tcp-socket](https://github.com/Rapsssito/react-native-tcp-socket). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-tcp-socket`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-tcp-socket` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [Rapsssito/react-native-tcp-socket](https://github.com/Rapsssito/react-native-tcp-socket) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to Rapsssito and everyone who contributes to +`react-native-tcp-socket` 💙 diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index e71d96ed..0d68ab5c 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/README.md b/native-modules/react-native-zip-archive/README.md new file mode 100644 index 00000000..5d471e61 --- /dev/null +++ b/native-modules/react-native-zip-archive/README.md @@ -0,0 +1,31 @@ +# @onekeyfe/react-native-zip-archive + +First, a sincere thank-you to Mockingbot and the +`react-native-zip-archive` maintainers for their excellent work 🙏 + +This package is built on, and inspired by, +[mockingbot/react-native-zip-archive](https://github.com/mockingbot/react-native-zip-archive). + +Our original plan was to keep our customizations as patches on top of upstream +`react-native-zip-archive`. + +As our product requirements evolved, the scope of those changes outgrew what we +could reasonably maintain as an upstream patch set. We regret that we were +unable to keep this work in patch form. + +As the gap grew, we ultimately forked `react-native-zip-archive` to keep +development and delivery stable. + +## Upstream Project + +- Repository: [mockingbot/react-native-zip-archive](https://github.com/mockingbot/react-native-zip-archive) +- License: MIT + +## Notes + +- This fork includes OneKey-specific adaptations for our product requirements. +- If you are looking for original behavior and full documentation, please refer + to the upstream repository. + +Thank you again to Mockingbot and everyone who contributes to +`react-native-zip-archive` 💙 diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 7114f349..56c8c3d4 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index d3ebf04c..cccbe2a5 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.5", + "version": "3.0.6", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 50ed8905..79288c9f 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.5", + "version": "3.0.6", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index b16e442a..9c22c085 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.5", + "version": "3.0.6", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index aabe16cc..33195568 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.5", + "version": "3.0.6", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index a87ed17f..6a26ac50 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.5", + "version": "3.0.6", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From da8a769d67dff85bb404b526b9257fb216a84391 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:49:58 +0800 Subject: [PATCH 48/74] feat(async-storage): add AsyncStorageStatic compatibility layer Wrap the TurboModule native interface with single-item convenience methods (getItem, setItem, removeItem, mergeItem) and export the AsyncStorageStatic type to align with the original @react-native-async-storage/async-storage API. --- native-modules/native-logger/package.json | 2 +- .../react-native-aes-crypto/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../react-native-async-storage/package.json | 2 +- .../react-native-async-storage/src/index.tsx | 174 +++++++++++++++++- .../react-native-async-storage/src/types.ts | 54 ++++++ .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../react-native-cloud-fs/package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../react-native-dns-lookup/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-network-info/package.json | 2 +- .../react-native-pbkdf2/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-tcp-socket/package.json | 2 +- .../react-native-zip-archive/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 29 files changed, 252 insertions(+), 30 deletions(-) create mode 100644 native-modules/react-native-async-storage/src/types.ts diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 0f96619c..700a54be 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 01d0b0ec..f46d9efd 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index a7b675b8..1f45c764 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 4351dc12..bbdb523a 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/src/index.tsx b/native-modules/react-native-async-storage/src/index.tsx index d4a6579a..2bba274f 100644 --- a/native-modules/react-native-async-storage/src/index.tsx +++ b/native-modules/react-native-async-storage/src/index.tsx @@ -1,4 +1,172 @@ -import NativeAsyncStorage from './NativeAsyncStorage'; +import NativeModule from './NativeAsyncStorage'; +import type { AsyncStorageStatic } from './types'; -export default NativeAsyncStorage; -export type { Spec as AsyncStorageSpec } from './NativeAsyncStorage'; +function createAsyncStorage(): AsyncStorageStatic { + const getItem: AsyncStorageStatic['getItem'] = async (key, callback) => { + try { + const result = await NativeModule.multiGet([key]); + const value = result?.[0]?.[1] ?? null; + callback?.(null, value); + return value; + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const setItem: AsyncStorageStatic['setItem'] = async ( + key, + value, + callback + ) => { + try { + await NativeModule.multiSet([[key, value]]); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const removeItem: AsyncStorageStatic['removeItem'] = async ( + key, + callback + ) => { + try { + await NativeModule.multiRemove([key]); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const mergeItem: AsyncStorageStatic['mergeItem'] = async ( + key, + value, + callback + ) => { + try { + await NativeModule.multiMerge([[key, value]]); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const clear: AsyncStorageStatic['clear'] = async (callback) => { + try { + await NativeModule.clear(); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const getAllKeys: AsyncStorageStatic['getAllKeys'] = async (callback) => { + try { + const keys = await NativeModule.getAllKeys(); + callback?.(null, keys); + return keys; + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.(error); + throw error; + } + }; + + const flushGetRequests: AsyncStorageStatic['flushGetRequests'] = () => { + // No-op: legacy batching API, not needed with TurboModules + }; + + const multiGet: AsyncStorageStatic['multiGet'] = async (keys, callback) => { + try { + const result = await NativeModule.multiGet([...keys]); + callback?.(null, result); + return result; + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.([error]); + throw error; + } + }; + + const multiSet: AsyncStorageStatic['multiSet'] = async ( + keyValuePairs, + callback + ) => { + try { + const mutablePairs = keyValuePairs.map( + ([k, v]) => [k, v] as [string, string] + ); + await NativeModule.multiSet(mutablePairs); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.([error]); + throw error; + } + }; + + const multiRemove: AsyncStorageStatic['multiRemove'] = async ( + keys, + callback + ) => { + try { + await NativeModule.multiRemove([...keys]); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.([error]); + throw error; + } + }; + + const multiMerge: AsyncStorageStatic['multiMerge'] = async ( + keyValuePairs, + callback + ) => { + try { + await NativeModule.multiMerge(keyValuePairs); + callback?.(null); + } catch (e) { + const error = e instanceof Error ? e : new Error(String(e)); + callback?.([error]); + throw error; + } + }; + + return { + getItem, + setItem, + removeItem, + mergeItem, + clear, + getAllKeys, + flushGetRequests, + multiGet, + multiSet, + multiRemove, + multiMerge, + }; +} + +const AsyncStorage = createAsyncStorage(); + +export default AsyncStorage; + +export type { + AsyncStorageStatic, + Callback, + CallbackWithResult, + KeyValuePair, + MultiCallback, + MultiGetCallback, +} from './types'; diff --git a/native-modules/react-native-async-storage/src/types.ts b/native-modules/react-native-async-storage/src/types.ts new file mode 100644 index 00000000..99bdbc92 --- /dev/null +++ b/native-modules/react-native-async-storage/src/types.ts @@ -0,0 +1,54 @@ +// Types aligned with the original @react-native-async-storage/async-storage + +export type Callback = (error?: Error | null) => void; + +export type CallbackWithResult = ( + error?: Error | null, + result?: T | null +) => void; + +export type KeyValuePair = [string, string | null]; + +export type MultiCallback = ( + errors?: readonly (Error | null)[] | null +) => void; + +export type MultiGetCallback = ( + errors?: readonly (Error | null)[] | null, + result?: readonly KeyValuePair[] +) => void; + +export type AsyncStorageStatic = { + getItem: ( + key: string, + callback?: CallbackWithResult + ) => Promise; + setItem: ( + key: string, + value: string, + callback?: Callback + ) => Promise; + removeItem: (key: string, callback?: Callback) => Promise; + mergeItem: (key: string, value: string, callback?: Callback) => Promise; + clear: (callback?: Callback) => Promise; + getAllKeys: ( + callback?: CallbackWithResult + ) => Promise; + flushGetRequests: () => void; + multiGet: ( + keys: readonly string[], + callback?: MultiGetCallback + ) => Promise; + multiSet: ( + keyValuePairs: ReadonlyArray, + callback?: MultiCallback + ) => Promise; + multiRemove: ( + keys: readonly string[], + callback?: MultiCallback + ) => Promise; + multiMerge: ( + keyValuePairs: [string, string][], + callback?: MultiCallback + ) => Promise; +}; diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index c3b1ee0b..962b6663 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index e7c53547..8a1c91a6 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 0c3e2e67..f0a8d9cc 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 9dbb318c..a6f1cef7 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 1a7c14e8..e953d4e1 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 888c9aff..037894e2 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index eeddc317..8f4b870d 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 9c8ec523..263a9d1a 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index db52742e..87739e56 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index b36ed9f4..a45e00e4 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.6", + "version": "3.0.7", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 1d73f890..ae453eb2 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 3a44c42b..7c8109d3 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 4cab6a26..39e0da6f 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index ff8ba90d..cfa9d023 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index e2dd2471..1f68684b 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index f1732c54..8f597fdd 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 0d68ab5c..af555769 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 56c8c3d4..c79e3b6f 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index cccbe2a5..36b7fe1b 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.6", + "version": "3.0.7", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 79288c9f..2830ea42 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.6", + "version": "3.0.7", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 9c22c085..b55e7444 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.6", + "version": "3.0.7", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 33195568..2c9c82f3 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.6", + "version": "3.0.7", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 6a26ac50..737bc9c5 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.6", + "version": "3.0.7", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 7e100d2fee1d3f7c8d180e0f566d93a6b19eb934 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:57:35 +0800 Subject: [PATCH 49/74] fix: align Android implementations with upstream originals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - async-storage: rewrite from SharedPreferences to SQLite (matching upstream) - Added ReactDatabaseSupplier.java, SerialExecutor.java - Proper transaction handling, MAX_SQL_KEYS batching, deep JSON merge - aes-crypto: fix PKCS5→PKCS7 padding, add spongycastle, match IV handling - pbkdf2: fix default hash SHA256→SHA1, Base64.NO_WRAP→DEFAULT, use spongycastle - network-info: add getFrequency(), DSLITE filtering, SupplicantState check --- .../android/build.gradle | 3 + .../java/com/aescrypto/AesCryptoModule.kt | 298 ++++++++------- .../com/asyncstorage/RNCAsyncStorageModule.kt | 348 +++++++++++++++--- .../asyncstorage/ReactDatabaseSupplier.java | 140 +++++++ .../java/com/asyncstorage/SerialExecutor.java | 38 ++ .../com/rnnetworkinfo/NetworkInfoModule.kt | 275 +++++++------- .../ios/NetworkInfo.h | 2 + .../ios/NetworkInfo.mm | 9 + .../src/NativeNetworkInfo.ts | 1 + .../react-native-pbkdf2/android/build.gradle | 3 + .../src/main/java/com/pbkdf2/Pbkdf2Module.kt | 52 +-- 11 files changed, 813 insertions(+), 356 deletions(-) create mode 100644 native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/ReactDatabaseSupplier.java create mode 100644 native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/SerialExecutor.java diff --git a/native-modules/react-native-aes-crypto/android/build.gradle b/native-modules/react-native-aes-crypto/android/build.gradle index a2b166a1..034e0d6e 100644 --- a/native-modules/react-native-aes-crypto/android/build.gradle +++ b/native-modules/react-native-aes-crypto/android/build.gradle @@ -74,4 +74,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "com.madgag.spongycastle:core:1.58.0.0" + implementation "com.madgag.spongycastle:prov:1.54.0.0" + implementation "com.madgag.spongycastle:pg:1.54.0.0" } diff --git a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt index 3596533d..7f5265d9 100644 --- a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt +++ b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt @@ -9,194 +9,192 @@ import java.security.SecureRandom import java.util.UUID import javax.crypto.Cipher import javax.crypto.Mac -import javax.crypto.SecretKeyFactory import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.SecretKeySpec - +import org.spongycastle.crypto.Digest +import org.spongycastle.crypto.digests.SHA1Digest +import org.spongycastle.crypto.digests.SHA256Digest +import org.spongycastle.crypto.digests.SHA512Digest +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator +import org.spongycastle.crypto.params.KeyParameter +import org.spongycastle.util.encoders.Hex + +/** + * Ported from upstream react-native-aes-crypto Aes.java. + * Adapted to extend NativeAesCryptoSpec (TurboModule). + */ @ReactModule(name = AesCryptoModule.NAME) class AesCryptoModule(reactContext: ReactApplicationContext) : NativeAesCryptoSpec(reactContext) { companion object { const val NAME = "AesCrypto" + private const val CIPHER_CBC_ALGORITHM = "AES/CBC/PKCS7Padding" + private const val CIPHER_CTR_ALGORITHM = "AES/CTR/PKCS5Padding" + private const val HMAC_SHA_256 = "HmacSHA256" + private const val HMAC_SHA_512 = "HmacSHA512" + private const val KEY_ALGORITHM = "AES" + + private val emptyIvSpec = IvParameterSpec(ByteArray(16) { 0x00 }) + + @JvmStatic + fun bytesToHex(bytes: ByteArray): String { + val hexArray = "0123456789abcdef".toCharArray() + val hexChars = CharArray(bytes.size * 2) + for (j in bytes.indices) { + val v = bytes[j].toInt() and 0xFF + hexChars[j * 2] = hexArray[v ushr 4] + hexChars[j * 2 + 1] = hexArray[v and 0x0F] + } + return String(hexChars) + } } override fun getName(): String = NAME - private fun cipherTransformation(algorithm: String): String { - return when (algorithm.lowercase()) { - "aes-128-cbc", "aes-192-cbc", "aes-256-cbc" -> "AES/CBC/PKCS5Padding" - "aes-128-ecb", "aes-192-ecb", "aes-256-ecb" -> "AES/ECB/PKCS5Padding" - else -> "AES/CBC/PKCS5Padding" - } - } - override fun encrypt(data: String, key: String, iv: String, algorithm: String, promise: Promise) { - Thread { - try { - val keyBytes = hexToBytes(key) - val ivBytes = hexToBytes(iv) - val transformation = cipherTransformation(algorithm) - val cipher = Cipher.getInstance(transformation) - val secretKey = SecretKeySpec(keyBytes, "AES") - if (transformation.contains("ECB")) { - cipher.init(Cipher.ENCRYPT_MODE, secretKey) - } else { - cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(ivBytes)) - } - val encrypted = cipher.doFinal(data.toByteArray(Charsets.UTF_8)) - promise.resolve(Base64.encodeToString(encrypted, Base64.NO_WRAP)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val cipherAlgorithm = if (algorithm.lowercase().contains("cbc")) CIPHER_CBC_ALGORITHM else CIPHER_CTR_ALGORITHM + val result = encryptImpl(data, key, iv, cipherAlgorithm) + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun decrypt(base64: String, key: String, iv: String, algorithm: String, promise: Promise) { - Thread { - try { - val keyBytes = hexToBytes(key) - val ivBytes = hexToBytes(iv) - val transformation = cipherTransformation(algorithm) - val cipher = Cipher.getInstance(transformation) - val secretKey = SecretKeySpec(keyBytes, "AES") - if (transformation.contains("ECB")) { - cipher.init(Cipher.DECRYPT_MODE, secretKey) - } else { - cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(ivBytes)) - } - val decrypted = cipher.doFinal(Base64.decode(base64, Base64.NO_WRAP)) - promise.resolve(String(decrypted, Charsets.UTF_8)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val cipherAlgorithm = if (algorithm.lowercase().contains("cbc")) CIPHER_CBC_ALGORITHM else CIPHER_CTR_ALGORITHM + val result = decryptImpl(base64, key, iv, cipherAlgorithm) + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun pbkdf2(password: String, salt: String, cost: Double, length: Double, algorithm: String, promise: Promise) { - Thread { - try { - val saltBytes = salt.toByteArray(Charsets.UTF_8) - val iterationCount = cost.toInt() - val keyLength = length.toInt() * 8 - val hmacAlgorithm = when (algorithm.uppercase()) { - "SHA256", "SHA-256" -> "PBKDF2WithHmacSHA256" - "SHA512", "SHA-512" -> "PBKDF2WithHmacSHA512" - else -> "PBKDF2WithHmacSHA1" - } - val spec = PBEKeySpec(password.toCharArray(), saltBytes, iterationCount, keyLength) - val factory = SecretKeyFactory.getInstance(hmacAlgorithm) - val keyBytes = factory.generateSecret(spec).encoded - promise.resolve(bytesToHex(keyBytes)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() - } - - override fun hmac256(base64: String, key: String, promise: Promise) { - Thread { - try { - val mac = Mac.getInstance("HmacSHA256") - val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA256") - mac.init(secretKey) - val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP)) - promise.resolve(bytesToHex(result)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() - } - - override fun hmac512(base64: String, key: String, promise: Promise) { - Thread { - try { - val mac = Mac.getInstance("HmacSHA512") - val secretKey = SecretKeySpec(hexToBytes(key), "HmacSHA512") - mac.init(secretKey) - val result = mac.doFinal(Base64.decode(base64, Base64.NO_WRAP)) - promise.resolve(bytesToHex(result)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val result = pbkdf2Impl(password, salt, cost.toInt(), length.toInt(), algorithm) + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } + } + + override fun hmac256(data: String, key: String, promise: Promise) { + try { + val result = hmacX(data, key, HMAC_SHA_256) + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } + } + + override fun hmac512(data: String, key: String, promise: Promise) { + try { + val result = hmacX(data, key, HMAC_SHA_512) + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun sha1(text: String, promise: Promise) { - Thread { - try { - val digest = MessageDigest.getInstance("SHA-1") - val result = digest.digest(text.toByteArray(Charsets.UTF_8)) - promise.resolve(bytesToHex(result)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val result = shaX(text, "SHA-1") + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun sha256(text: String, promise: Promise) { - Thread { - try { - val digest = MessageDigest.getInstance("SHA-256") - val result = digest.digest(text.toByteArray(Charsets.UTF_8)) - promise.resolve(bytesToHex(result)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val result = shaX(text, "SHA-256") + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun sha512(text: String, promise: Promise) { - Thread { - try { - val digest = MessageDigest.getInstance("SHA-512") - val result = digest.digest(text.toByteArray(Charsets.UTF_8)) - promise.resolve(bytesToHex(result)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val result = shaX(text, "SHA-512") + promise.resolve(result) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun randomUuid(promise: Promise) { - Thread { - try { - promise.resolve(UUID.randomUUID().toString()) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + promise.resolve(UUID.randomUUID().toString()) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } override fun randomKey(length: Double, promise: Promise) { - Thread { - try { - val bytes = ByteArray(length.toInt()) - SecureRandom().nextBytes(bytes) - promise.resolve(bytesToHex(bytes)) - } catch (e: Exception) { - promise.reject("AES_CRYPTO_ERROR", e.message, e) - } - }.start() + try { + val key = ByteArray(length.toInt()) + SecureRandom().nextBytes(key) + promise.resolve(bytesToHex(key)) + } catch (e: Exception) { + promise.reject("-1", e.message) + } } - private fun hexToBytes(hex: String): ByteArray { - val len = hex.length - val data = ByteArray(len / 2) - var i = 0 - while (i < len) { - data[i / 2] = ((Character.digit(hex[i], 16) shl 4) + Character.digit(hex[i + 1], 16)).toByte() - i += 2 - } - return data + // --- Private helpers (ported from upstream Aes.java) --- + + private fun shaX(data: String, algorithm: String): String { + val md = MessageDigest.getInstance(algorithm) + md.update(data.toByteArray()) + return bytesToHex(md.digest()) } - private fun bytesToHex(bytes: ByteArray): String { - val sb = StringBuilder() - for (b in bytes) { - sb.append(String.format("%02x", b)) + private fun pbkdf2Impl(pwd: String, salt: String, cost: Int, length: Int, algorithm: String): String { + val algorithmDigest: Digest = when { + algorithm.equals("sha1", ignoreCase = true) -> SHA1Digest() + algorithm.equals("sha256", ignoreCase = true) -> SHA256Digest() + algorithm.equals("sha512", ignoreCase = true) -> SHA512Digest() + else -> SHA512Digest() } - return sb.toString() + val gen = PKCS5S2ParametersGenerator(algorithmDigest) + gen.init(pwd.toByteArray(Charsets.UTF_8), salt.toByteArray(Charsets.UTF_8), cost) + val key = (gen.generateDerivedParameters(length) as KeyParameter).key + return bytesToHex(key) + } + + private fun hmacX(text: String, key: String, algorithm: String): String { + val contentData = text.toByteArray(Charsets.UTF_8) + val akHexData = Hex.decode(key) + val mac = Mac.getInstance(algorithm) + val secretKey = SecretKeySpec(akHexData, algorithm) + mac.init(secretKey) + return bytesToHex(mac.doFinal(contentData)) + } + + private fun encryptImpl(text: String, hexKey: String, hexIv: String?, algorithm: String): String? { + if (text.isEmpty()) return null + + val key = Hex.decode(hexKey) + val secretKey = SecretKeySpec(key, KEY_ALGORITHM) + val cipher = Cipher.getInstance(algorithm) + val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv)) + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) + val encrypted = cipher.doFinal(text.toByteArray(Charsets.UTF_8)) + return Base64.encodeToString(encrypted, Base64.NO_WRAP) + } + + private fun decryptImpl(ciphertext: String, hexKey: String, hexIv: String?, algorithm: String): String? { + if (ciphertext.isEmpty()) return null + + val key = Hex.decode(hexKey) + val secretKey = SecretKeySpec(key, KEY_ALGORITHM) + val cipher = Cipher.getInstance(algorithm) + val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv)) + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) + val decrypted = cipher.doFinal(Base64.decode(ciphertext, Base64.NO_WRAP)) + return String(decrypted, Charsets.UTF_8) } } diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt index 316be4a0..903de6ae 100644 --- a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt @@ -1,132 +1,368 @@ package com.asyncstorage -import android.content.Context -import android.content.SharedPreferences +import android.database.Cursor +import android.database.sqlite.SQLiteStatement +import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.WritableNativeArray +import com.facebook.react.bridge.WritableArray import com.facebook.react.module.annotations.ReactModule +import org.json.JSONObject +import java.util.concurrent.Executor +import java.util.concurrent.Executors +/** + * Ported from upstream @react-native-async-storage/async-storage AsyncStorageModule.java + * Adapted to use Promise (TurboModule) instead of Callback. + * Uses SQLite via ReactDatabaseSupplier (same as upstream). + */ @ReactModule(name = RNCAsyncStorageModule.NAME) class RNCAsyncStorageModule(reactContext: ReactApplicationContext) : NativeRNCAsyncStorageSpec(reactContext) { companion object { const val NAME = "RNCAsyncStorage" - private const val PREFS_NAME = "RNCAsyncStorage" + // SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER + private const val MAX_SQL_KEYS = 999 } - private fun getPrefs(): SharedPreferences { - return reactApplicationContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) - } + private val dbSupplier: ReactDatabaseSupplier = ReactDatabaseSupplier.getInstance(reactContext) + private val executor: Executor = SerialExecutor(Executors.newSingleThreadExecutor()) + @Volatile + private var shuttingDown = false override fun getName(): String = NAME + override fun initialize() { + super.initialize() + shuttingDown = false + } + + override fun invalidate() { + shuttingDown = true + dbSupplier.closeDatabase() + } + override fun multiGet(keys: ReadableArray, promise: Promise) { - Thread { + executor.execute { try { - val prefs = getPrefs() - val result = WritableNativeArray() - for (i in 0 until keys.size()) { - val key = keys.getString(i) - val pair = WritableNativeArray() - pair.pushString(key) - if (prefs.contains(key)) { - pair.pushString(prefs.getString(key, null)) - } else { - pair.pushNull() + if (!ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + + val columns = arrayOf(ReactDatabaseSupplier.KEY_COLUMN, ReactDatabaseSupplier.VALUE_COLUMN) + val keysRemaining = HashSet() + val data: WritableArray = Arguments.createArray() + + var keyStart = 0 + while (keyStart < keys.size()) { + val keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS) + val cursor: Cursor = dbSupplier.get().query( + ReactDatabaseSupplier.TABLE_CATALYST, + columns, + buildKeySelection(keyCount), + buildKeySelectionArgs(keys, keyStart, keyCount), + null, null, null + ) + + keysRemaining.clear() + try { + if (cursor.count != keys.size()) { + for (keyIndex in keyStart until keyStart + keyCount) { + keysRemaining.add(keys.getString(keyIndex)) + } + } + if (cursor.moveToFirst()) { + do { + val row = Arguments.createArray() + row.pushString(cursor.getString(0)) + row.pushString(cursor.getString(1)) + data.pushArray(row) + keysRemaining.remove(cursor.getString(0)) + } while (cursor.moveToNext()) + } + } finally { + cursor.close() } - result.pushArray(pair) + + for (key in keysRemaining) { + val row = Arguments.createArray() + row.pushString(key) + row.pushNull() + data.pushArray(row) + } + keysRemaining.clear() + keyStart += MAX_SQL_KEYS } - promise.resolve(result) + + promise.resolve(data) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } } override fun multiSet(keyValuePairs: ReadableArray, promise: Promise) { - Thread { + if (keyValuePairs.size() == 0) { + promise.resolve(null) + return + } + + executor.execute { try { - val editor = getPrefs().edit() - for (i in 0 until keyValuePairs.size()) { - val pair = keyValuePairs.getArray(i) - if (pair != null && pair.size() >= 2) { + if (!ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + + val sql = "INSERT OR REPLACE INTO ${ReactDatabaseSupplier.TABLE_CATALYST} VALUES (?, ?);" + val statement: SQLiteStatement = dbSupplier.get().compileStatement(sql) + try { + dbSupplier.get().beginTransaction() + for (idx in 0 until keyValuePairs.size()) { + val pair = keyValuePairs.getArray(idx) + if (pair == null || pair.size() != 2) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value") + return@execute + } val key = pair.getString(0) val value = pair.getString(1) - editor.putString(key, value) + if (key == null) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid key") + return@execute + } + if (value == null) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value") + return@execute + } + statement.clearBindings() + statement.bindString(1, key) + statement.bindString(2, value) + statement.execute() + } + dbSupplier.get().setTransactionSuccessful() + } finally { + try { + dbSupplier.get().endTransaction() + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + return@execute } } - editor.apply() promise.resolve(null) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } } override fun multiRemove(keys: ReadableArray, promise: Promise) { - Thread { + if (keys.size() == 0) { + promise.resolve(null) + return + } + + executor.execute { try { - val editor = getPrefs().edit() - for (i in 0 until keys.size()) { - editor.remove(keys.getString(i)) + if (!ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + + try { + dbSupplier.get().beginTransaction() + var keyStart = 0 + while (keyStart < keys.size()) { + val keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS) + dbSupplier.get().delete( + ReactDatabaseSupplier.TABLE_CATALYST, + buildKeySelection(keyCount), + buildKeySelectionArgs(keys, keyStart, keyCount) + ) + keyStart += MAX_SQL_KEYS + } + dbSupplier.get().setTransactionSuccessful() + } finally { + try { + dbSupplier.get().endTransaction() + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + return@execute + } } - editor.apply() promise.resolve(null) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } } override fun multiMerge(keyValuePairs: ReadableArray, promise: Promise) { - Thread { + executor.execute { try { - val prefs = getPrefs() - val editor = prefs.edit() - for (i in 0 until keyValuePairs.size()) { - val pair = keyValuePairs.getArray(i) - if (pair != null && pair.size() >= 2) { + if (!ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + + try { + dbSupplier.get().beginTransaction() + for (idx in 0 until keyValuePairs.size()) { + val pair = keyValuePairs.getArray(idx) + if (pair == null || pair.size() != 2) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value") + return@execute + } val key = pair.getString(0) val value = pair.getString(1) - // For merge, if key exists and both are JSON objects, deep merge. - // For simplicity, we overwrite (shallow merge by replacing value). - editor.putString(key, value) + if (key == null) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid key") + return@execute + } + if (value == null) { + promise.reject("ASYNC_STORAGE_ERROR", "Invalid Value") + return@execute + } + if (!mergeImpl(key, value)) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + } + dbSupplier.get().setTransactionSuccessful() + } finally { + try { + dbSupplier.get().endTransaction() + } catch (e: Exception) { + promise.reject("ASYNC_STORAGE_ERROR", e.message, e) + return@execute } } - editor.apply() promise.resolve(null) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } } override fun getAllKeys(promise: Promise) { - Thread { + executor.execute { try { - val prefs = getPrefs() - val result = WritableNativeArray() - for (key in prefs.all.keys) { - result.pushString(key) + if (!ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + + val columns = arrayOf(ReactDatabaseSupplier.KEY_COLUMN) + val cursor: Cursor = dbSupplier.get().query( + ReactDatabaseSupplier.TABLE_CATALYST, + columns, null, null, null, null, null + ) + + val data: WritableArray = Arguments.createArray() + try { + if (cursor.moveToFirst()) { + do { + data.pushString(cursor.getString(0)) + } while (cursor.moveToNext()) + } + } finally { + cursor.close() } - promise.resolve(result) + promise.resolve(data) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } } override fun clear(promise: Promise) { - Thread { + executor.execute { try { - getPrefs().edit().clear().apply() + if (!dbSupplier.ensureDatabase()) { + promise.reject("ASYNC_STORAGE_ERROR", "Database Error") + return@execute + } + dbSupplier.clear() promise.resolve(null) } catch (e: Exception) { promise.reject("ASYNC_STORAGE_ERROR", e.message, e) } - }.start() + } + } + + // --- Private helpers (ported from AsyncLocalStorageUtil.java) --- + + private fun ensureDatabase(): Boolean { + return !shuttingDown && dbSupplier.ensureDatabase() + } + + private fun buildKeySelection(count: Int): String { + val list = Array(count) { "?" } + return "${ReactDatabaseSupplier.KEY_COLUMN} IN (${list.joinToString(", ")})" + } + + private fun buildKeySelectionArgs(keys: ReadableArray, start: Int, count: Int): Array { + return Array(count) { keys.getString(start + it) } + } + + private fun getItemImpl(key: String): String? { + val columns = arrayOf(ReactDatabaseSupplier.VALUE_COLUMN) + val selectionArgs = arrayOf(key) + val cursor = dbSupplier.get().query( + ReactDatabaseSupplier.TABLE_CATALYST, + columns, + "${ReactDatabaseSupplier.KEY_COLUMN}=?", + selectionArgs, + null, null, null + ) + try { + return if (!cursor.moveToFirst()) null else cursor.getString(0) + } finally { + cursor.close() + } + } + + private fun setItemImpl(key: String, value: String): Boolean { + val contentValues = android.content.ContentValues() + contentValues.put(ReactDatabaseSupplier.KEY_COLUMN, key) + contentValues.put(ReactDatabaseSupplier.VALUE_COLUMN, value) + val inserted = dbSupplier.get().insertWithOnConflict( + ReactDatabaseSupplier.TABLE_CATALYST, + null, + contentValues, + android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE + ) + return inserted != -1L + } + + private fun mergeImpl(key: String, value: String): Boolean { + val oldValue = getItemImpl(key) + val newValue: String + if (oldValue == null) { + newValue = value + } else { + val oldJSON = JSONObject(oldValue) + val newJSON = JSONObject(value) + deepMergeInto(oldJSON, newJSON) + newValue = oldJSON.toString() + } + return setItemImpl(key, newValue) + } + + private fun deepMergeInto(oldJSON: JSONObject, newJSON: JSONObject) { + val keys = newJSON.keys() + while (keys.hasNext()) { + val key = keys.next() + val newJSONObject = newJSON.optJSONObject(key) + val oldJSONObject = oldJSON.optJSONObject(key) + if (newJSONObject != null && oldJSONObject != null) { + deepMergeInto(oldJSONObject, newJSONObject) + oldJSON.put(key, oldJSONObject) + } else { + oldJSON.put(key, newJSON.get(key)) + } + } } } diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/ReactDatabaseSupplier.java b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/ReactDatabaseSupplier.java new file mode 100644 index 00000000..6e6032c9 --- /dev/null +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/ReactDatabaseSupplier.java @@ -0,0 +1,140 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.asyncstorage; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; +import javax.annotation.Nullable; + +/** + * Database supplier of the database used by react native async storage. + * Ported from upstream @react-native-async-storage/async-storage ReactDatabaseSupplier.java. + */ +public class ReactDatabaseSupplier extends SQLiteOpenHelper { + + public static final String DATABASE_NAME = "RKStorage"; + + private static final int DATABASE_VERSION = 1; + private static final int SLEEP_TIME_MS = 30; + + static final String TABLE_CATALYST = "catalystLocalStorage"; + static final String KEY_COLUMN = "key"; + static final String VALUE_COLUMN = "value"; + + static final String VERSION_TABLE_CREATE = + "CREATE TABLE " + TABLE_CATALYST + " (" + + KEY_COLUMN + " TEXT PRIMARY KEY, " + + VALUE_COLUMN + " TEXT NOT NULL" + + ")"; + + private static @Nullable ReactDatabaseSupplier sReactDatabaseSupplierInstance; + + private Context mContext; + private @Nullable SQLiteDatabase mDb; + private long mMaximumDatabaseSize = 6L * 1024L * 1024L; + + private ReactDatabaseSupplier(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + mContext = context; + } + + public static ReactDatabaseSupplier getInstance(Context context) { + if (sReactDatabaseSupplierInstance == null) { + sReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context.getApplicationContext()); + } + return sReactDatabaseSupplierInstance; + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(VERSION_TABLE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion != newVersion) { + deleteDatabase(); + onCreate(db); + } + } + + synchronized boolean ensureDatabase() { + if (mDb != null && mDb.isOpen()) { + return true; + } + SQLiteException lastSQLiteException = null; + for (int tries = 0; tries < 2; tries++) { + try { + if (tries > 0) { + deleteDatabase(); + } + mDb = getWritableDatabase(); + break; + } catch (SQLiteException e) { + lastSQLiteException = e; + } + try { + Thread.sleep(SLEEP_TIME_MS); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (mDb == null) { + throw lastSQLiteException; + } + mDb.setMaximumSize(mMaximumDatabaseSize); + return true; + } + + public synchronized SQLiteDatabase get() { + ensureDatabase(); + return mDb; + } + + public synchronized void clearAndCloseDatabase() throws RuntimeException { + try { + clear(); + closeDatabase(); + } catch (Exception e) { + if (deleteDatabase()) { + return; + } + throw new RuntimeException("Clearing and deleting database " + DATABASE_NAME + " failed"); + } + } + + synchronized void clear() { + get().delete(TABLE_CATALYST, null, null); + } + + public synchronized void setMaximumSize(long size) { + mMaximumDatabaseSize = size; + if (mDb != null) { + mDb.setMaximumSize(mMaximumDatabaseSize); + } + } + + private synchronized boolean deleteDatabase() { + closeDatabase(); + return mContext.deleteDatabase(DATABASE_NAME); + } + + public synchronized void closeDatabase() { + if (mDb != null && mDb.isOpen()) { + mDb.close(); + mDb = null; + } + } + + public static void deleteInstance() { + sReactDatabaseSupplierInstance = null; + } +} diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/SerialExecutor.java b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/SerialExecutor.java new file mode 100644 index 00000000..8dec989c --- /dev/null +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/SerialExecutor.java @@ -0,0 +1,38 @@ +package com.asyncstorage; + +import java.util.ArrayDeque; +import java.util.concurrent.Executor; + +/** + * Ported from upstream @react-native-async-storage/async-storage SerialExecutor.java. + */ +public class SerialExecutor implements Executor { + private final ArrayDeque mTasks = new ArrayDeque(); + private Runnable mActive; + private final Executor executor; + + public SerialExecutor(Executor executor) { + this.executor = executor; + } + + public synchronized void execute(final Runnable r) { + mTasks.offer(new Runnable() { + public void run() { + try { + r.run(); + } finally { + scheduleNext(); + } + } + }); + if (mActive == null) { + scheduleNext(); + } + } + + synchronized void scheduleNext() { + if ((mActive = mTasks.poll()) != null) { + executor.execute(mActive); + } + } +} diff --git a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt index 699eea23..bb729690 100644 --- a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt +++ b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt @@ -1,27 +1,38 @@ package com.rnnetworkinfo import android.content.Context -import android.net.ConnectivityManager -import android.net.NetworkCapabilities +import android.net.wifi.SupplicantState import android.net.wifi.WifiInfo import android.net.wifi.WifiManager -import android.os.Build import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.annotations.ReactModule import java.net.Inet4Address import java.net.Inet6Address import java.net.InetAddress +import java.net.InterfaceAddress import java.net.NetworkInterface +/** + * Ported from upstream react-native-network-info RNNetworkInfo.java. + * Adapted to extend NativeRNNetworkInfoSpec (TurboModule). + */ @ReactModule(name = NetworkInfoModule.NAME) class NetworkInfoModule(reactContext: ReactApplicationContext) : NativeRNNetworkInfoSpec(reactContext) { companion object { const val NAME = "RNNetworkInfo" + + val DSLITE_LIST = listOf( + "192.0.0.0", "192.0.0.1", "192.0.0.2", "192.0.0.3", + "192.0.0.4", "192.0.0.5", "192.0.0.6", "192.0.0.7" + ) } + private val wifi: WifiManager = + reactContext.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + override fun getName(): String = NAME // MARK: - getSSID @@ -29,7 +40,16 @@ class NetworkInfoModule(reactContext: ReactApplicationContext) : override fun getSSID(promise: Promise) { Thread { try { - val ssid = getWifiSSID() + @Suppress("DEPRECATION") + val info: WifiInfo = wifi.connectionInfo + var ssid: String? = null + if (info.supplicantState == SupplicantState.COMPLETED) { + @Suppress("DEPRECATION") + ssid = info.ssid + if (ssid != null && ssid.startsWith("\"") && ssid.endsWith("\"")) { + ssid = ssid.substring(1, ssid.length - 1) + } + } promise.resolve(ssid) } catch (e: Exception) { promise.resolve(null) @@ -37,31 +57,18 @@ class NetworkInfoModule(reactContext: ReactApplicationContext) : }.start() } - private fun getWifiSSID(): String? { - val context = reactApplicationContext - val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager - ?: return null - @Suppress("DEPRECATION") - val wifiInfo: WifiInfo = wifiManager.connectionInfo ?: return null - @Suppress("DEPRECATION") - val ssid = wifiInfo.ssid - if (ssid == null || ssid == "") return null - return if (ssid.startsWith("\"") && ssid.endsWith("\"")) { - ssid.substring(1, ssid.length - 1) - } else { - ssid - } - } - // MARK: - getBSSID override fun getBSSID(promise: Promise) { Thread { try { - val context = reactApplicationContext - val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager @Suppress("DEPRECATION") - val bssid = wifiManager?.connectionInfo?.bssid + val info: WifiInfo = wifi.connectionInfo + var bssid: String? = null + if (info.supplicantState == SupplicantState.COMPLETED) { + @Suppress("DEPRECATION") + bssid = wifi.connectionInfo.bssid + } promise.resolve(bssid) } catch (e: Exception) { promise.resolve(null) @@ -74,22 +81,16 @@ class NetworkInfoModule(reactContext: ReactApplicationContext) : override fun getBroadcast(promise: Promise) { Thread { try { - var broadcast: String? = null - val interfaces = NetworkInterface.getNetworkInterfaces() - while (interfaces.hasMoreElements()) { - val iface = interfaces.nextElement() - if (iface.name == "wlan0" || iface.name == "eth0") { - for (ia in iface.interfaceAddresses) { - val broadcastAddr = ia.broadcast - if (broadcastAddr != null) { - broadcast = broadcastAddr.hostAddress - break - } + var ipAddress: String? = null + for (address in getInetAddresses()) { + if (!address.address.isLoopbackAddress) { + val broadCast: InetAddress? = address.broadcast + if (broadCast != null) { + ipAddress = broadCast.toString() } } - if (broadcast != null) break } - promise.resolve(broadcast) + promise.resolve(ipAddress) } catch (e: Exception) { promise.resolve(null) } @@ -101,10 +102,41 @@ class NetworkInfoModule(reactContext: ReactApplicationContext) : override fun getIPAddress(promise: Promise) { Thread { try { - val address = getIPv4Address() - promise.resolve(address ?: "") + var ipAddress: String? = null + var tmp = "0.0.0.0" + for (address in getInetAddresses()) { + if (!address.address.isLoopbackAddress) { + tmp = address.address.hostAddress.toString() + if (!inDSLITERange(tmp)) { + ipAddress = tmp + } + } + } + promise.resolve(ipAddress) } catch (e: Exception) { - promise.resolve("") + promise.resolve(null) + } + }.start() + } + + // MARK: - getIPV4Address + + override fun getIPV4Address(promise: Promise) { + Thread { + try { + var ipAddress: String? = null + var tmp = "0.0.0.0" + for (address in getInetAddresses()) { + if (!address.address.isLoopbackAddress && address.address is Inet4Address) { + tmp = address.address.hostAddress.toString() + if (!inDSLITERange(tmp)) { + ipAddress = tmp + } + } + } + promise.resolve(ipAddress) + } catch (e: Exception) { + promise.resolve(null) } }.start() } @@ -135,131 +167,126 @@ class NetworkInfoModule(reactContext: ReactApplicationContext) : }.start() } - // MARK: - getGatewayIPAddress + // MARK: - getWIFIIPV4Address - override fun getGatewayIPAddress(promise: Promise) { + override fun getWIFIIPV4Address(promise: Promise) { Thread { try { - val context = reactApplicationContext - val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager @Suppress("DEPRECATION") - val dhcpInfo = wifiManager?.dhcpInfo - val gateway = if (dhcpInfo != null && dhcpInfo.gateway != 0) { - formatIpAddress(dhcpInfo.gateway) - } else { - null - } - promise.resolve(gateway ?: "") + val info: WifiInfo = wifi.connectionInfo + val ipAddress = info.ipAddress + val stringIp = String.format( + "%d.%d.%d.%d", + ipAddress and 0xff, + ipAddress shr 8 and 0xff, + ipAddress shr 16 and 0xff, + ipAddress shr 24 and 0xff + ) + promise.resolve(stringIp) } catch (e: Exception) { - promise.resolve("") + promise.resolve(null) } }.start() } - // MARK: - getIPV4Address + // MARK: - getSubnet - override fun getIPV4Address(promise: Promise) { + override fun getSubnet(promise: Promise) { Thread { try { - val address = getIPv4Address() - promise.resolve(address ?: "0.0.0.0") + val interfaces = NetworkInterface.getNetworkInterfaces() + while (interfaces.hasMoreElements()) { + val iface = interfaces.nextElement() + if (iface.isLoopback || !iface.isUp) continue + + val addresses = iface.inetAddresses + for (address in iface.interfaceAddresses) { + val addr = addresses.nextElement() + if (addr is Inet6Address) continue + + promise.resolve(intToIP(address.networkPrefixLength.toInt())) + return@Thread + } + } + promise.resolve("0.0.0.0") } catch (e: Exception) { promise.resolve("0.0.0.0") } }.start() } - // MARK: - getWIFIIPV4Address + // MARK: - getGatewayIPAddress - override fun getWIFIIPV4Address(promise: Promise) { + override fun getGatewayIPAddress(promise: Promise) { Thread { try { - var address: String? = null - val interfaces = NetworkInterface.getNetworkInterfaces() - loop@ while (interfaces.hasMoreElements()) { - val iface = interfaces.nextElement() - if (iface.name == "wlan0") { - val addrs = iface.inetAddresses - while (addrs.hasMoreElements()) { - val addr = addrs.nextElement() - if (addr is Inet4Address && !addr.isLoopbackAddress) { - address = addr.hostAddress - break@loop - } - } - } - } - promise.resolve(address ?: "0.0.0.0") + @Suppress("DEPRECATION") + val dhcpInfo = wifi.dhcpInfo + val gatewayIPInt = dhcpInfo.gateway + val gatewayIP = String.format( + "%d.%d.%d.%d", + gatewayIPInt and 0xFF, + gatewayIPInt shr 8 and 0xFF, + gatewayIPInt shr 16 and 0xFF, + gatewayIPInt shr 24 and 0xFF + ) + promise.resolve(gatewayIP) } catch (e: Exception) { - promise.resolve("0.0.0.0") + promise.resolve(null) } }.start() } - // MARK: - getSubnet + // MARK: - getFrequency - override fun getSubnet(promise: Promise) { + override fun getFrequency(promise: Promise) { Thread { try { - var subnet: String? = null - val interfaces = NetworkInterface.getNetworkInterfaces() - loop@ while (interfaces.hasMoreElements()) { - val iface = interfaces.nextElement() - if (!iface.isUp || iface.isLoopback) continue - for (ia in iface.interfaceAddresses) { - val addr = ia.address - if (addr is Inet4Address && !addr.isLoopbackAddress) { - val prefixLen = ia.networkPrefixLength.toInt() - val mask = prefixLengthToSubnetMask(prefixLen) - subnet = mask - break@loop - } - } - } - promise.resolve(subnet ?: "0.0.0.0") + @Suppress("DEPRECATION") + val info: WifiInfo = wifi.connectionInfo + val frequency = info.frequency.toDouble() + promise.resolve(frequency) } catch (e: Exception) { - promise.resolve("0.0.0.0") + promise.resolve(null) } }.start() } - // MARK: - Helpers - - private fun getIPv4Address(): String? { - val interfaces = NetworkInterface.getNetworkInterfaces() - while (interfaces.hasMoreElements()) { - val iface = interfaces.nextElement() - if (!iface.isUp || iface.isLoopback) continue - val addrs = iface.inetAddresses - while (addrs.hasMoreElements()) { - val addr = addrs.nextElement() - if (addr is Inet4Address && !addr.isLoopbackAddress) { - return addr.hostAddress + // --- Private helpers (ported from upstream RNNetworkInfo.java) --- + + private fun intToIP(ip: Int): String { + val finl = arrayOf("", "", "", "") + var k = 1 + for (i in 0 until 4) { + for (j in 0 until 8) { + if (k <= ip) { + finl[i] += "1" + } else { + finl[i] += "0" } + k++ } } - return null + return "${Integer.parseInt(finl[0], 2)}.${Integer.parseInt(finl[1], 2)}.${Integer.parseInt(finl[2], 2)}.${Integer.parseInt(finl[3], 2)}" } - @Suppress("DEPRECATION") - private fun formatIpAddress(ip: Int): String { - return String.format( - "%d.%d.%d.%d", - ip and 0xff, - ip shr 8 and 0xff, - ip shr 16 and 0xff, - ip shr 24 and 0xff - ) + private fun inDSLITERange(ip: String): Boolean { + return DSLITE_LIST.contains(ip) } - private fun prefixLengthToSubnetMask(prefixLength: Int): String { - val mask = if (prefixLength == 0) 0 else (-1 shl (32 - prefixLength)) - return String.format( - "%d.%d.%d.%d", - mask shr 24 and 0xff, - mask shr 16 and 0xff, - mask shr 8 and 0xff, - mask and 0xff - ) + private fun getInetAddresses(): List { + val addresses = mutableListOf() + try { + val en = NetworkInterface.getNetworkInterfaces() + while (en.hasMoreElements()) { + val intf = en.nextElement() + for (interfaceAddress in intf.interfaceAddresses) { + addresses.add(interfaceAddress) + } + } + } catch (ex: Exception) { + android.util.Log.e(NAME, ex.toString()) + } + return addresses } } diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.h b/native-modules/react-native-network-info/ios/NetworkInfo.h index d819c472..00807ae1 100644 --- a/native-modules/react-native-network-info/ios/NetworkInfo.h +++ b/native-modules/react-native-network-info/ios/NetworkInfo.h @@ -20,5 +20,7 @@ reject:(RCTPromiseRejectBlock)reject; - (void)getSubnet:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getFrequency:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; @end diff --git a/native-modules/react-native-network-info/ios/NetworkInfo.mm b/native-modules/react-native-network-info/ios/NetworkInfo.mm index c9e5080e..de51ae7a 100644 --- a/native-modules/react-native-network-info/ios/NetworkInfo.mm +++ b/native-modules/react-native-network-info/ios/NetworkInfo.mm @@ -305,6 +305,15 @@ - (void)getSubnet:(RCTPromiseResolveBlock)resolve }); } +// MARK: - getFrequency + +- (void)getFrequency:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + // WiFi frequency is not available on iOS + resolve(nil); +} + // MARK: - getAllIPAddresses helper - (NSDictionary *)getAllIPAddresses diff --git a/native-modules/react-native-network-info/src/NativeNetworkInfo.ts b/native-modules/react-native-network-info/src/NativeNetworkInfo.ts index 5d0d16df..fe26a7a0 100644 --- a/native-modules/react-native-network-info/src/NativeNetworkInfo.ts +++ b/native-modules/react-native-network-info/src/NativeNetworkInfo.ts @@ -11,6 +11,7 @@ export interface Spec extends TurboModule { getIPV4Address(): Promise; getWIFIIPV4Address(): Promise; getSubnet(): Promise; + getFrequency(): Promise; } export default TurboModuleRegistry.getEnforcing('RNNetworkInfo'); diff --git a/native-modules/react-native-pbkdf2/android/build.gradle b/native-modules/react-native-pbkdf2/android/build.gradle index e96d7415..64a3b16e 100644 --- a/native-modules/react-native-pbkdf2/android/build.gradle +++ b/native-modules/react-native-pbkdf2/android/build.gradle @@ -74,4 +74,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "com.madgag.spongycastle:core:1.58.0.0" + implementation "com.madgag.spongycastle:prov:1.54.0.0" + implementation "com.madgag.spongycastle:pg:1.54.0.0" } diff --git a/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt index a19bcb81..f2b13472 100644 --- a/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt +++ b/native-modules/react-native-pbkdf2/android/src/main/java/com/pbkdf2/Pbkdf2Module.kt @@ -4,9 +4,17 @@ import android.util.Base64 import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.annotations.ReactModule -import javax.crypto.SecretKeyFactory -import javax.crypto.spec.PBEKeySpec +import org.spongycastle.crypto.Digest +import org.spongycastle.crypto.digests.SHA1Digest +import org.spongycastle.crypto.digests.SHA256Digest +import org.spongycastle.crypto.digests.SHA512Digest +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator +import org.spongycastle.crypto.params.KeyParameter +/** + * Ported from upstream react-native-fast-pbkdf2 Pbkdf2Module.java. + * Adapted to extend NativePbkdf2Spec (TurboModule). + */ @ReactModule(name = Pbkdf2Module.NAME) class Pbkdf2Module(reactContext: ReactApplicationContext) : NativePbkdf2Spec(reactContext) { @@ -25,31 +33,23 @@ class Pbkdf2Module(reactContext: ReactApplicationContext) : hash: String, promise: Promise ) { - Thread { - try { - val passwordBytes = Base64.decode(password, Base64.DEFAULT) - val saltBytes = Base64.decode(salt, Base64.DEFAULT) - val iterationCount = rounds.toInt() - val keyLengthBits = keyLength.toInt() * 8 + try { + val decodedPassword = Base64.decode(password, Base64.DEFAULT) + val decodedSalt = Base64.decode(salt, Base64.DEFAULT) - val algorithm = when (hash.uppercase()) { - "SHA256", "SHA-256" -> "PBKDF2WithHmacSHA256" - "SHA512", "SHA-512" -> "PBKDF2WithHmacSHA512" - else -> "PBKDF2WithHmacSHA256" - } - - val spec = PBEKeySpec( - String(passwordBytes, Charsets.UTF_8).toCharArray(), - saltBytes, - iterationCount, - keyLengthBits - ) - val factory = SecretKeyFactory.getInstance(algorithm) - val derivedKey = factory.generateSecret(spec).encoded - promise.resolve(Base64.encodeToString(derivedKey, Base64.NO_WRAP)) - } catch (e: Exception) { - promise.reject("PBKDF2_ERROR", e.message, e) + // Default to SHA1 (matching upstream original) + val digest: Digest = when (hash) { + "sha-256" -> SHA256Digest() + "sha-512" -> SHA512Digest() + else -> SHA1Digest() } - }.start() + + val gen = PKCS5S2ParametersGenerator(digest) + gen.init(decodedPassword, decodedSalt, rounds.toInt()) + val key = (gen.generateDerivedParameters(keyLength.toInt() * 8) as KeyParameter).key + promise.resolve(Base64.encodeToString(key, Base64.DEFAULT)) + } catch (e: Exception) { + promise.reject("PBKDF2_ERROR", e.message, e) + } } } From 972ff8bf5dae32bcf7d7bdb4d0945fad8d4201c5 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 10:58:00 +0800 Subject: [PATCH 50/74] chore: bump all packages --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 700a54be..d08beed4 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index f46d9efd..ccdbcdca 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 1f45c764..637f45ad 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index bbdb523a..96a794d7 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 962b6663..9dd09699 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 8a1c91a6..de3263bb 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index f0a8d9cc..e41ee867 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index a6f1cef7..8b489e89 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index e953d4e1..d963115e 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 037894e2..0a422740 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 8f4b870d..3f7a21ba 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 263a9d1a..b2247536 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 87739e56..88e6187d 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index a45e00e4..3d3152f0 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.7", + "version": "3.0.8", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index ae453eb2..a519883b 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 7c8109d3..5826402e 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 39e0da6f..929a120f 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index cfa9d023..83f5431d 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 1f68684b..7613e6bf 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 8f597fdd..a406bcb7 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index af555769..4f96da82 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index c79e3b6f..a9d878cb 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 36b7fe1b..ea6c7e30 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.7", + "version": "3.0.8", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 2830ea42..bea06571 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.7", + "version": "3.0.8", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index b55e7444..da5a24d4 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.7", + "version": "3.0.8", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 2c9c82f3..b9a51576 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.7", + "version": "3.0.8", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 737bc9c5..93098902 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.7", + "version": "3.0.8", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From a2b898d847e53a62d04a23a274961ea8d6a71d2f Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:00:06 +0800 Subject: [PATCH 51/74] fix: sync aes-crypto patch changes - use Hex encoding for all I/O Ported from patches/react-native-aes-crypto+3.2.1.patch: - shaX: input from getBytes() to Hex.decode() - pbkdf2: password/salt from UTF-8 to Hex.decode() - hmacX: text from UTF-8 to Hex.decode() - encrypt: input from UTF-8 to Hex.decode(), output from Base64 to hex - decrypt: input from Base64 to Hex.decode(), output from UTF-8 to hex --- .../src/main/java/com/aescrypto/AesCryptoModule.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt index 7f5265d9..f92fa6b8 100644 --- a/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt +++ b/native-modules/react-native-aes-crypto/android/src/main/java/com/aescrypto/AesCryptoModule.kt @@ -148,7 +148,7 @@ class AesCryptoModule(reactContext: ReactApplicationContext) : private fun shaX(data: String, algorithm: String): String { val md = MessageDigest.getInstance(algorithm) - md.update(data.toByteArray()) + md.update(Hex.decode(data)) return bytesToHex(md.digest()) } @@ -160,13 +160,13 @@ class AesCryptoModule(reactContext: ReactApplicationContext) : else -> SHA512Digest() } val gen = PKCS5S2ParametersGenerator(algorithmDigest) - gen.init(pwd.toByteArray(Charsets.UTF_8), salt.toByteArray(Charsets.UTF_8), cost) + gen.init(Hex.decode(pwd), Hex.decode(salt), cost) val key = (gen.generateDerivedParameters(length) as KeyParameter).key return bytesToHex(key) } private fun hmacX(text: String, key: String, algorithm: String): String { - val contentData = text.toByteArray(Charsets.UTF_8) + val contentData = Hex.decode(text) val akHexData = Hex.decode(key) val mac = Mac.getInstance(algorithm) val secretKey = SecretKeySpec(akHexData, algorithm) @@ -182,8 +182,8 @@ class AesCryptoModule(reactContext: ReactApplicationContext) : val cipher = Cipher.getInstance(algorithm) val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv)) cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) - val encrypted = cipher.doFinal(text.toByteArray(Charsets.UTF_8)) - return Base64.encodeToString(encrypted, Base64.NO_WRAP) + val encrypted = cipher.doFinal(Hex.decode(text)) + return bytesToHex(encrypted) } private fun decryptImpl(ciphertext: String, hexKey: String, hexIv: String?, algorithm: String): String? { @@ -194,7 +194,7 @@ class AesCryptoModule(reactContext: ReactApplicationContext) : val cipher = Cipher.getInstance(algorithm) val ivSpec = if (hexIv == null || hexIv.isEmpty()) emptyIvSpec else IvParameterSpec(Hex.decode(hexIv)) cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) - val decrypted = cipher.doFinal(Base64.decode(ciphertext, Base64.NO_WRAP)) - return String(decrypted, Charsets.UTF_8) + val decrypted = cipher.doFinal(Hex.decode(ciphertext)) + return bytesToHex(decrypted) } } From 854ee5b899ea6b68250afa15d655efe12bfd875d Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:00:30 +0800 Subject: [PATCH 52/74] chore: bump all packages --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index d08beed4..de66ce31 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index ccdbcdca..955d12ac 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 637f45ad..4ac3ac58 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 96a794d7..35eb54fa 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 9dd09699..d9b8a736 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index de3263bb..01038aad 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index e41ee867..f6e36e2e 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 8b489e89..d50e3924 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index d963115e..f84312bb 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 0a422740..c4ec5756 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 3f7a21ba..e5b7e860 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index b2247536..d67c2c1b 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 88e6187d..f7c99033 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 3d3152f0..e834c27a 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.8", + "version": "3.0.9", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index a519883b..725353e1 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 5826402e..d7b8a9a9 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 929a120f..02a5bfc9 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 83f5431d..a0688aa4 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 7613e6bf..9208bcd4 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index a406bcb7..95874a99 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 4f96da82..5a46111e 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index a9d878cb..03f40cb4 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index ea6c7e30..53387b52 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.8", + "version": "3.0.9", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index bea06571..44e56692 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.8", + "version": "3.0.9", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index da5a24d4..9ace87b9 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.8", + "version": "3.0.9", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index b9a51576..323574de 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.8", + "version": "3.0.9", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 93098902..d8842ef6 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.8", + "version": "3.0.9", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From a10044379819d01e28acba201ac3c1511bac4fdf Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:17:47 +0800 Subject: [PATCH 53/74] fix: add CFDataRef cast in DnsLookup.mm --- native-modules/react-native-dns-lookup/ios/DnsLookup.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-modules/react-native-dns-lookup/ios/DnsLookup.mm b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm index 9e23898e..3815eff4 100644 --- a/native-modules/react-native-dns-lookup/ios/DnsLookup.mm +++ b/native-modules/react-native-dns-lookup/ios/DnsLookup.mm @@ -87,7 +87,7 @@ - (NSArray *)performDnsLookup:(NSString *)hostname for (CFIndex currentIndex = 0; currentIndex < numAddresses; currentIndex++) { struct sockaddr *address = (struct sockaddr *)CFDataGetBytePtr( - CFArrayGetValueAtIndex(addressesRef, currentIndex)); + (CFDataRef)CFArrayGetValueAtIndex(addressesRef, currentIndex)); getnameinfo(address, address->sa_len, ipAddress, INET6_ADDRSTRLEN, nil, 0, NI_NUMERICHOST); [addresses addObject:[NSString stringWithCString:ipAddress encoding:NSASCIIStringEncoding]]; } From 82cd10a780fe3e26591f7e581982529e065c10a5 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:35:39 +0800 Subject: [PATCH 54/74] fix: iOS compilation fixes verified with local build - native-logger: fix prevLogMessage -> prevLogKey typo - aes-crypto: add type casts for CCKeyDerivationPBKDF and CC_SHA1/256/512 - cloud-fs: remove deprecated ALAssetsLibrary code - network-info: add extern "C" guard in getgateway.h for ObjC++ linking - dns-lookup: add CFDataRef cast in CFDataGetBytePtr call --- .yarn/versions/f13d26c4.yml | 32 +++++++++++++++++++ .../native-logger/ios/OneKeyLog.swift | 2 +- .../react-native-aes-crypto/ios/AesCrypto.mm | 12 +++---- .../lib/module/NativeAesCrypto.js | 5 +++ .../lib/module/NativeAesCrypto.js.map | 1 + .../lib/module/index.js | 15 +++++++++ .../lib/module/index.js.map | 1 + .../lib/module/package.json | 1 + .../lib/typescript/package.json | 1 + .../lib/typescript/src/NativeAesCrypto.d.ts | 16 ++++++++++ .../typescript/src/NativeAesCrypto.d.ts.map | 1 + .../lib/typescript/src/index.d.ts | 14 ++++++++ .../lib/typescript/src/index.d.ts.map | 1 + .../react-native-aes-crypto/src/index.tsx | 11 +++++++ .../react-native-async-storage/package.json | 3 ++ .../react-native-cloud-fs/ios/CloudFs.mm | 21 +----------- .../lib/module/NativeDnsLookup.js | 5 +++ .../lib/module/NativeDnsLookup.js.map | 1 + .../lib/module/index.js | 6 ++++ .../lib/module/index.js.map | 1 + .../lib/module/package.json | 1 + .../lib/typescript/package.json | 1 + .../lib/typescript/src/NativeDnsLookup.d.ts | 7 ++++ .../typescript/src/NativeDnsLookup.d.ts.map | 1 + .../lib/typescript/src/index.d.ts | 4 +++ .../lib/typescript/src/index.d.ts.map | 1 + .../react-native-dns-lookup/src/index.tsx | 3 ++ .../ios/getgateway.h | 8 +++++ .../lib/module/NativeZipArchive.js | 5 +++ .../lib/module/NativeZipArchive.js.map | 1 + .../lib/module/index.js | 6 ++++ .../lib/module/index.js.map | 1 + .../lib/module/package.json | 1 + .../lib/typescript/package.json | 1 + .../lib/typescript/src/NativeZipArchive.d.ts | 12 +++++++ .../typescript/src/NativeZipArchive.d.ts.map | 1 + .../lib/typescript/src/index.d.ts | 4 +++ .../lib/typescript/src/index.d.ts.map | 1 + .../react-native-zip-archive/src/index.tsx | 2 ++ 39 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 .yarn/versions/f13d26c4.yml create mode 100644 native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js create mode 100644 native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map create mode 100644 native-modules/react-native-aes-crypto/lib/module/index.js create mode 100644 native-modules/react-native-aes-crypto/lib/module/index.js.map create mode 100644 native-modules/react-native-aes-crypto/lib/module/package.json create mode 100644 native-modules/react-native-aes-crypto/lib/typescript/package.json create mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts create mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map create mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts create mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map create mode 100644 native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js create mode 100644 native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map create mode 100644 native-modules/react-native-dns-lookup/lib/module/index.js create mode 100644 native-modules/react-native-dns-lookup/lib/module/index.js.map create mode 100644 native-modules/react-native-dns-lookup/lib/module/package.json create mode 100644 native-modules/react-native-dns-lookup/lib/typescript/package.json create mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts create mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map create mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts create mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map create mode 100644 native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js create mode 100644 native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map create mode 100644 native-modules/react-native-zip-archive/lib/module/index.js create mode 100644 native-modules/react-native-zip-archive/lib/module/index.js.map create mode 100644 native-modules/react-native-zip-archive/lib/module/package.json create mode 100644 native-modules/react-native-zip-archive/lib/typescript/package.json create mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts create mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map create mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts create mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map diff --git a/.yarn/versions/f13d26c4.yml b/.yarn/versions/f13d26c4.yml new file mode 100644 index 00000000..6a563611 --- /dev/null +++ b/.yarn/versions/f13d26c4.yml @@ -0,0 +1,32 @@ +releases: + "@onekeyfe/react-native-aes-crypto": patch + "@onekeyfe/react-native-app-update": patch + "@onekeyfe/react-native-async-storage": patch + "@onekeyfe/react-native-background-thread": patch + "@onekeyfe/react-native-bundle-update": patch + "@onekeyfe/react-native-check-biometric-auth-changed": patch + "@onekeyfe/react-native-cloud-fs": patch + "@onekeyfe/react-native-cloud-kit-module": patch + "@onekeyfe/react-native-native-logger": patch + +undecided: + - "@onekeyfe/app-modules" + - "@onekeyfe/app-modules-example" + - "@onekeyfe/react-native-device-utils" + - "@onekeyfe/react-native-dns-lookup" + - "@onekeyfe/react-native-get-random-values" + - "@onekeyfe/react-native-keychain-module" + - "@onekeyfe/react-native-lite-card" + - "@onekeyfe/react-native-network-info" + - "@onekeyfe/react-native-pbkdf2" + - "@onekeyfe/react-native-perf-memory" + - "@onekeyfe/react-native-ping" + - "@onekeyfe/react-native-splash-screen" + - "@onekeyfe/react-native-split-bundle-loader" + - "@onekeyfe/react-native-tcp-socket" + - "@onekeyfe/react-native-zip-archive" + - "@onekeyfe/react-native-auto-size-input" + - "@onekeyfe/react-native-pager-view" + - "@onekeyfe/react-native-scroll-guard" + - "@onekeyfe/react-native-skeleton" + - "@onekeyfe/react-native-tab-view" diff --git a/native-modules/native-logger/ios/OneKeyLog.swift b/native-modules/native-logger/ios/OneKeyLog.swift index 72ca2b49..cdefcc5e 100644 --- a/native-modules/native-logger/ios/OneKeyLog.swift +++ b/native-modules/native-logger/ios/OneKeyLog.swift @@ -326,7 +326,7 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault { dedupLock.lock() let pending = repeatCount repeatCount = 0 - prevLogMessage = nil + prevLogKey = nil dedupLock.unlock() if pending > 0 { diff --git a/native-modules/react-native-aes-crypto/ios/AesCrypto.mm b/native-modules/react-native-aes-crypto/ios/AesCrypto.mm index c16fb2b1..db415274 100644 --- a/native-modules/react-native-aes-crypto/ios/AesCrypto.mm +++ b/native-modules/react-native-aes-crypto/ios/AesCrypto.mm @@ -234,11 +234,11 @@ - (void)pbkdf2:(NSString *)password int status = CCKeyDerivationPBKDF( kCCPBKDF2, - passwordData.bytes, passwordData.length, - saltData.bytes, saltData.length, + (const char *)passwordData.bytes, passwordData.length, + (const uint8_t *)saltData.bytes, saltData.length, prf, (unsigned int)cost, - hashKeyData.mutableBytes, hashKeyData.length); + (uint8_t *)hashKeyData.mutableBytes, hashKeyData.length); if (status == kCCParamError) { reject(@"keygen_fail", @"Key derivation parameter error", nil); @@ -321,7 +321,7 @@ - (void)sha1:(NSString *)text @try { NSData *inputData = fromHex(text); NSMutableData *result = [[NSMutableData alloc] initWithLength:CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(inputData.bytes, (CC_LONG)inputData.length, result.mutableBytes); + CC_SHA1((const void *)inputData.bytes, (CC_LONG)inputData.length, (unsigned char *)result.mutableBytes); resolve(toHex(result)); } @catch (NSException *exception) { reject(@"sha1_fail", exception.reason, nil); @@ -343,7 +343,7 @@ - (void)sha256:(NSString *)text reject(@"sha256_fail", @"Memory allocation error", nil); return; } - CC_SHA256(inputData.bytes, (CC_LONG)inputData.length, buffer); + CC_SHA256((const void *)inputData.bytes, (CC_LONG)inputData.length, buffer); NSData *result = [NSData dataWithBytesNoCopy:buffer length:CC_SHA256_DIGEST_LENGTH freeWhenDone:YES]; @@ -368,7 +368,7 @@ - (void)sha512:(NSString *)text reject(@"sha512_fail", @"Memory allocation error", nil); return; } - CC_SHA512(inputData.bytes, (CC_LONG)inputData.length, buffer); + CC_SHA512((const void *)inputData.bytes, (CC_LONG)inputData.length, buffer); NSData *result = [NSData dataWithBytesNoCopy:buffer length:CC_SHA512_DIGEST_LENGTH freeWhenDone:YES]; diff --git a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js new file mode 100644 index 00000000..e15db6ec --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js @@ -0,0 +1,5 @@ +"use strict"; + +import { TurboModuleRegistry } from 'react-native'; +export default TurboModuleRegistry.getEnforcing('AesCrypto'); +//# sourceMappingURL=NativeAesCrypto.js.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map new file mode 100644 index 00000000..d7706f32 --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map @@ -0,0 +1 @@ +{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAesCrypto.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAgClD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,WAAW,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-aes-crypto/lib/module/index.js b/native-modules/react-native-aes-crypto/lib/module/index.js new file mode 100644 index 00000000..925cbc48 --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/module/index.js @@ -0,0 +1,15 @@ +"use strict"; + +import NativeAesCrypto from "./NativeAesCrypto.js"; +export const encrypt = NativeAesCrypto.encrypt.bind(NativeAesCrypto); +export const decrypt = NativeAesCrypto.decrypt.bind(NativeAesCrypto); +export const pbkdf2 = NativeAesCrypto.pbkdf2.bind(NativeAesCrypto); +export const hmac256 = NativeAesCrypto.hmac256.bind(NativeAesCrypto); +export const hmac512 = NativeAesCrypto.hmac512.bind(NativeAesCrypto); +export const sha1 = NativeAesCrypto.sha1.bind(NativeAesCrypto); +export const sha256 = NativeAesCrypto.sha256.bind(NativeAesCrypto); +export const sha512 = NativeAesCrypto.sha512.bind(NativeAesCrypto); +export const randomUuid = NativeAesCrypto.randomUuid.bind(NativeAesCrypto); +export const randomKey = NativeAesCrypto.randomKey.bind(NativeAesCrypto); +export default NativeAesCrypto; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/module/index.js.map b/native-modules/react-native-aes-crypto/lib/module/index.js.map new file mode 100644 index 00000000..3a43ce3e --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/module/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["NativeAesCrypto","encrypt","bind","decrypt","pbkdf2","hmac256","hmac512","sha1","sha256","sha512","randomUuid","randomKey"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,eAAe,MAAM,sBAAmB;AAE/C,OAAO,MAAMC,OAAO,GAAGD,eAAe,CAACC,OAAO,CAACC,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMG,OAAO,GAAGH,eAAe,CAACG,OAAO,CAACD,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMI,MAAM,GAAGJ,eAAe,CAACI,MAAM,CAACF,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMK,OAAO,GAAGL,eAAe,CAACK,OAAO,CAACH,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMM,OAAO,GAAGN,eAAe,CAACM,OAAO,CAACJ,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMO,IAAI,GAAGP,eAAe,CAACO,IAAI,CAACL,IAAI,CAACF,eAAe,CAAC;AAC9D,OAAO,MAAMQ,MAAM,GAAGR,eAAe,CAACQ,MAAM,CAACN,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMS,MAAM,GAAGT,eAAe,CAACS,MAAM,CAACP,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMU,UAAU,GAAGV,eAAe,CAACU,UAAU,CAACR,IAAI,CAACF,eAAe,CAAC;AAC1E,OAAO,MAAMW,SAAS,GAAGX,eAAe,CAACW,SAAS,CAACT,IAAI,CAACF,eAAe,CAAC;AAExE,eAAeA,eAAe","ignoreList":[]} diff --git a/native-modules/react-native-aes-crypto/lib/module/package.json b/native-modules/react-native-aes-crypto/lib/module/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/module/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-aes-crypto/lib/typescript/package.json b/native-modules/react-native-aes-crypto/lib/typescript/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/typescript/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts new file mode 100644 index 00000000..9092067f --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts @@ -0,0 +1,16 @@ +import type { TurboModule } from 'react-native'; +export interface Spec extends TurboModule { + encrypt(data: string, key: string, iv: string, algorithm: string): Promise; + decrypt(base64: string, key: string, iv: string, algorithm: string): Promise; + pbkdf2(password: string, salt: string, cost: number, length: number, algorithm: string): Promise; + hmac256(base64: string, key: string): Promise; + hmac512(base64: string, key: string): Promise; + sha1(text: string): Promise; + sha256(text: string): Promise; + sha512(text: string): Promise; + randomUuid(): Promise; + randomKey(length: number): Promise; +} +declare const _default: Spec; +export default _default; +//# sourceMappingURL=NativeAesCrypto.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map new file mode 100644 index 00000000..c7e835e7 --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeAesCrypto.d.ts","sourceRoot":"","sources":["../../../src/NativeAesCrypto.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CACL,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C;;AAED,wBAAmE"} \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts new file mode 100644 index 00000000..0cfec6af --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts @@ -0,0 +1,14 @@ +import NativeAesCrypto from './NativeAesCrypto'; +export declare const encrypt: (data: string, key: string, iv: string, algorithm: string) => Promise; +export declare const decrypt: (base64: string, key: string, iv: string, algorithm: string) => Promise; +export declare const pbkdf2: (password: string, salt: string, cost: number, length: number, algorithm: string) => Promise; +export declare const hmac256: (base64: string, key: string) => Promise; +export declare const hmac512: (base64: string, key: string) => Promise; +export declare const sha1: (text: string) => Promise; +export declare const sha256: (text: string) => Promise; +export declare const sha512: (text: string) => Promise; +export declare const randomUuid: () => Promise; +export declare const randomKey: (length: number) => Promise; +export default NativeAesCrypto; +export type { Spec as AesCryptoSpec } from './NativeAesCrypto'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map new file mode 100644 index 00000000..f6687ff2 --- /dev/null +++ b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAEhD,eAAO,MAAM,OAAO,+EAAgD,CAAC;AACrE,eAAO,MAAM,OAAO,iFAAgD,CAAC;AACrE,eAAO,MAAM,MAAM,sGAA+C,CAAC;AACnE,eAAO,MAAM,OAAO,kDAAgD,CAAC;AACrE,eAAO,MAAM,OAAO,kDAAgD,CAAC;AACrE,eAAO,MAAM,IAAI,mCAA6C,CAAC;AAC/D,eAAO,MAAM,MAAM,mCAA+C,CAAC;AACnE,eAAO,MAAM,MAAM,mCAA+C,CAAC;AACnE,eAAO,MAAM,UAAU,uBAAmD,CAAC;AAC3E,eAAO,MAAM,SAAS,qCAAkD,CAAC;AAEzE,eAAe,eAAe,CAAC;AAC/B,YAAY,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/src/index.tsx b/native-modules/react-native-aes-crypto/src/index.tsx index dfb905d9..9c27e533 100644 --- a/native-modules/react-native-aes-crypto/src/index.tsx +++ b/native-modules/react-native-aes-crypto/src/index.tsx @@ -1,4 +1,15 @@ import NativeAesCrypto from './NativeAesCrypto'; +export const encrypt = NativeAesCrypto.encrypt.bind(NativeAesCrypto); +export const decrypt = NativeAesCrypto.decrypt.bind(NativeAesCrypto); +export const pbkdf2 = NativeAesCrypto.pbkdf2.bind(NativeAesCrypto); +export const hmac256 = NativeAesCrypto.hmac256.bind(NativeAesCrypto); +export const hmac512 = NativeAesCrypto.hmac512.bind(NativeAesCrypto); +export const sha1 = NativeAesCrypto.sha1.bind(NativeAesCrypto); +export const sha256 = NativeAesCrypto.sha256.bind(NativeAesCrypto); +export const sha512 = NativeAesCrypto.sha512.bind(NativeAesCrypto); +export const randomUuid = NativeAesCrypto.randomUuid.bind(NativeAesCrypto); +export const randomKey = NativeAesCrypto.randomKey.bind(NativeAesCrypto); + export default NativeAesCrypto; export type { Spec as AesCryptoSpec } from './NativeAesCrypto'; diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 35eb54fa..388e2ab7 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -10,6 +10,9 @@ "types": "./lib/typescript/src/index.d.ts", "default": "./lib/module/index.js" }, + "./lib/typescript/types": { + "types": "./lib/typescript/src/types.d.ts" + }, "./package.json": "./package.json" }, "files": [ diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.mm b/native-modules/react-native-cloud-fs/ios/CloudFs.mm index b29d2197..6cd1a02d 100644 --- a/native-modules/react-native-cloud-fs/ios/CloudFs.mm +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.mm @@ -1,6 +1,5 @@ #import "CloudFs.h" #import -#import @implementation CloudFs @@ -237,25 +236,7 @@ - (void)copyToCloud:(NSDictionary *)options sourceUri = [source objectForKey:@"path"]; } - if ([sourceUri hasPrefix:@"assets-library"]) { - ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; - [library assetForURL:[NSURL URLWithString:sourceUri] resultBlock:^(ALAsset *asset) { - ALAssetRepresentation *rep = [asset defaultRepresentation]; - Byte *buffer = (Byte *)malloc(rep.size); - NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil]; - NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; - if (data) { - NSString *filename = [sourceUri lastPathComponent]; - NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; - [data writeToFile:tempFile atomically:YES]; - [self moveToICloudDirectory:documentsFolder tempFile:tempFile destinationPath:destinationPath resolve:resolve reject:reject]; - } else { - return reject(@"error", [NSString stringWithFormat:@"failed to copy asset '%@'", sourceUri], nil); - } - } failureBlock:^(NSError *error) { - return reject(@"error", error.description, nil); - }]; - } else if ([sourceUri hasPrefix:@"file:/"] || [sourceUri hasPrefix:@"/"]) { + if ([sourceUri hasPrefix:@"file:/"] || [sourceUri hasPrefix:@"/"]) { NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^file:/+" options:NSRegularExpressionCaseInsensitive error:nil]; NSString *modifiedSourceUri = [regex stringByReplacingMatchesInString:sourceUri options:0 range:NSMakeRange(0, [sourceUri length]) withTemplate:@"/"]; diff --git a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js new file mode 100644 index 00000000..20258781 --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js @@ -0,0 +1,5 @@ +"use strict"; + +import { TurboModuleRegistry } from 'react-native'; +export default TurboModuleRegistry.getEnforcing('RNDnsLookup'); +//# sourceMappingURL=NativeDnsLookup.js.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map new file mode 100644 index 00000000..6d7c4e97 --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map @@ -0,0 +1 @@ +{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeDnsLookup.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAOlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,aAAa,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-dns-lookup/lib/module/index.js b/native-modules/react-native-dns-lookup/lib/module/index.js new file mode 100644 index 00000000..b4fb863a --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/module/index.js @@ -0,0 +1,6 @@ +"use strict"; + +import NativeDnsLookup from "./NativeDnsLookup.js"; +export const DnsLookup = NativeDnsLookup; +export const getIpAddressesForHostname = hostname => NativeDnsLookup.getIpAddresses(hostname); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/module/index.js.map b/native-modules/react-native-dns-lookup/lib/module/index.js.map new file mode 100644 index 00000000..6ffc69f5 --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/module/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["NativeDnsLookup","DnsLookup","getIpAddressesForHostname","hostname","getIpAddresses"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,eAAe,MAAM,sBAAmB;AAE/C,OAAO,MAAMC,SAAS,GAAGD,eAAe;AACxC,OAAO,MAAME,yBAAyB,GACpCC,QAAgB,IACMH,eAAe,CAACI,cAAc,CAACD,QAAQ,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-dns-lookup/lib/module/package.json b/native-modules/react-native-dns-lookup/lib/module/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/module/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-dns-lookup/lib/typescript/package.json b/native-modules/react-native-dns-lookup/lib/typescript/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/typescript/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts new file mode 100644 index 00000000..358ed6df --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts @@ -0,0 +1,7 @@ +import type { TurboModule } from 'react-native'; +export interface Spec extends TurboModule { + getIpAddresses(hostname: string): Promise; +} +declare const _default: Spec; +export default _default; +//# sourceMappingURL=NativeDnsLookup.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map new file mode 100644 index 00000000..de338821 --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeDnsLookup.d.ts","sourceRoot":"","sources":["../../../src/NativeDnsLookup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACrD;;AAED,wBAAqE"} \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts new file mode 100644 index 00000000..b8f5fc9b --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts @@ -0,0 +1,4 @@ +export declare const DnsLookup: import("./NativeDnsLookup").Spec; +export declare const getIpAddressesForHostname: (hostname: string) => Promise; +export type { Spec as DnsLookupSpec } from './NativeDnsLookup'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map new file mode 100644 index 00000000..8ac4440d --- /dev/null +++ b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,kCAAkB,CAAC;AACzC,eAAO,MAAM,yBAAyB,GACpC,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,EAAE,CAA6C,CAAC;AACjE,YAAY,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/src/index.tsx b/native-modules/react-native-dns-lookup/src/index.tsx index c0aadbf3..d52f6755 100644 --- a/native-modules/react-native-dns-lookup/src/index.tsx +++ b/native-modules/react-native-dns-lookup/src/index.tsx @@ -1,4 +1,7 @@ import NativeDnsLookup from './NativeDnsLookup'; export const DnsLookup = NativeDnsLookup; +export const getIpAddressesForHostname = ( + hostname: string, +): Promise => NativeDnsLookup.getIpAddresses(hostname); export type { Spec as DnsLookupSpec } from './NativeDnsLookup'; diff --git a/native-modules/react-native-network-info/ios/getgateway.h b/native-modules/react-native-network-info/ios/getgateway.h index 6b9c9621..09fab260 100644 --- a/native-modules/react-native-network-info/ios/getgateway.h +++ b/native-modules/react-native-network-info/ios/getgateway.h @@ -10,6 +10,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + int getdefaultgateway(in_addr_t *addr); +#ifdef __cplusplus +} +#endif + #endif /* getgateway_h */ diff --git a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js new file mode 100644 index 00000000..4a4c6c04 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js @@ -0,0 +1,5 @@ +"use strict"; + +import { TurboModuleRegistry } from 'react-native'; +export default TurboModuleRegistry.getEnforcing('RNZipArchive'); +//# sourceMappingURL=NativeZipArchive.js.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map new file mode 100644 index 00000000..43ee2ae8 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map @@ -0,0 +1 @@ +{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeZipArchive.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAYlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-zip-archive/lib/module/index.js b/native-modules/react-native-zip-archive/lib/module/index.js new file mode 100644 index 00000000..501433b9 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/module/index.js @@ -0,0 +1,6 @@ +"use strict"; + +import NativeZipArchive from "./NativeZipArchive.js"; +export const ZipArchive = NativeZipArchive; +export const zip = (source, target) => NativeZipArchive.zipFolder(source, target); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/module/index.js.map b/native-modules/react-native-zip-archive/lib/module/index.js.map new file mode 100644 index 00000000..72c735ac --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/module/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["NativeZipArchive","ZipArchive","zip","source","target","zipFolder"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,gBAAgB,MAAM,uBAAoB;AAEjD,OAAO,MAAMC,UAAU,GAAGD,gBAAgB;AAC1C,OAAO,MAAME,GAAG,GAAGA,CAACC,MAAc,EAAEC,MAAc,KAChDJ,gBAAgB,CAACK,SAAS,CAACF,MAAM,EAAEC,MAAM,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-zip-archive/lib/module/package.json b/native-modules/react-native-zip-archive/lib/module/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/module/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-zip-archive/lib/typescript/package.json b/native-modules/react-native-zip-archive/lib/typescript/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/typescript/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts new file mode 100644 index 00000000..643bbd19 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts @@ -0,0 +1,12 @@ +import type { TurboModule } from 'react-native'; +export interface Spec extends TurboModule { + isPasswordProtected(file: string): Promise; + unzip(from: string, to: string): Promise; + unzipWithPassword(from: string, to: string, password: string): Promise; + zipFolder(from: string, to: string): Promise; + zipFiles(files: string[], to: string): Promise; + getUncompressedSize(path: string): Promise; +} +declare const _default: Spec; +export default _default; +//# sourceMappingURL=NativeZipArchive.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map new file mode 100644 index 00000000..c5984026 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeZipArchive.d.ts","sourceRoot":"","sources":["../../../src/NativeZipArchive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;;AAED,wBAAsE"} \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts new file mode 100644 index 00000000..61ab0fe9 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts @@ -0,0 +1,4 @@ +export declare const ZipArchive: import("./NativeZipArchive").Spec; +export declare const zip: (source: string, target: string) => Promise; +export type { Spec as ZipArchiveSpec } from './NativeZipArchive'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map new file mode 100644 index 00000000..baba7524 --- /dev/null +++ b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,mCAAmB,CAAC;AAC3C,eAAO,MAAM,GAAG,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CACvB,CAAC;AAC7C,YAAY,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/src/index.tsx b/native-modules/react-native-zip-archive/src/index.tsx index de548b5a..7cc64316 100644 --- a/native-modules/react-native-zip-archive/src/index.tsx +++ b/native-modules/react-native-zip-archive/src/index.tsx @@ -1,4 +1,6 @@ import NativeZipArchive from './NativeZipArchive'; export const ZipArchive = NativeZipArchive; +export const zip = (source: string, target: string): Promise => + NativeZipArchive.zipFolder(source, target); export type { Spec as ZipArchiveSpec } from './NativeZipArchive'; From 7029299bd717c2bf75c15199d44471ad67e8e312 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:36:06 +0800 Subject: [PATCH 55/74] chore: bump all packages --- .yarn/versions/f13d26c4.yml | 32 ------------------- native-modules/native-logger/package.json | 2 +- .../react-native-aes-crypto/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../react-native-async-storage/package.json | 2 +- .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../react-native-cloud-fs/package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../react-native-dns-lookup/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-network-info/package.json | 2 +- .../react-native-pbkdf2/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-tcp-socket/package.json | 2 +- .../react-native-zip-archive/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 28 files changed, 27 insertions(+), 59 deletions(-) delete mode 100644 .yarn/versions/f13d26c4.yml diff --git a/.yarn/versions/f13d26c4.yml b/.yarn/versions/f13d26c4.yml deleted file mode 100644 index 6a563611..00000000 --- a/.yarn/versions/f13d26c4.yml +++ /dev/null @@ -1,32 +0,0 @@ -releases: - "@onekeyfe/react-native-aes-crypto": patch - "@onekeyfe/react-native-app-update": patch - "@onekeyfe/react-native-async-storage": patch - "@onekeyfe/react-native-background-thread": patch - "@onekeyfe/react-native-bundle-update": patch - "@onekeyfe/react-native-check-biometric-auth-changed": patch - "@onekeyfe/react-native-cloud-fs": patch - "@onekeyfe/react-native-cloud-kit-module": patch - "@onekeyfe/react-native-native-logger": patch - -undecided: - - "@onekeyfe/app-modules" - - "@onekeyfe/app-modules-example" - - "@onekeyfe/react-native-device-utils" - - "@onekeyfe/react-native-dns-lookup" - - "@onekeyfe/react-native-get-random-values" - - "@onekeyfe/react-native-keychain-module" - - "@onekeyfe/react-native-lite-card" - - "@onekeyfe/react-native-network-info" - - "@onekeyfe/react-native-pbkdf2" - - "@onekeyfe/react-native-perf-memory" - - "@onekeyfe/react-native-ping" - - "@onekeyfe/react-native-splash-screen" - - "@onekeyfe/react-native-split-bundle-loader" - - "@onekeyfe/react-native-tcp-socket" - - "@onekeyfe/react-native-zip-archive" - - "@onekeyfe/react-native-auto-size-input" - - "@onekeyfe/react-native-pager-view" - - "@onekeyfe/react-native-scroll-guard" - - "@onekeyfe/react-native-skeleton" - - "@onekeyfe/react-native-tab-view" diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index de66ce31..0dd44328 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 955d12ac..de3b64b9 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 4ac3ac58..eca35954 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 388e2ab7..aa893dfa 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index d9b8a736..65a15dd6 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 01038aad..20b5dd94 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index f6e36e2e..91cf77b3 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index d50e3924..add18e0b 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index f84312bb..f862e93e 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index c4ec5756..ccc26c20 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index e5b7e860..46203945 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index d67c2c1b..b11164e1 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index f7c99033..4a3819a5 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index e834c27a..0d6aabc7 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.9", + "version": "3.0.10", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 725353e1..81f18a26 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index d7b8a9a9..9a640478 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 02a5bfc9..a2e85b98 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index a0688aa4..d539f3d7 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 9208bcd4..45154f84 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 95874a99..99f37f4d 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 5a46111e..3f8d50f6 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 03f40cb4..4f0b7512 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 53387b52..ef627abc 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.9", + "version": "3.0.10", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 44e56692..cbbfa338 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.9", + "version": "3.0.10", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 9ace87b9..d0b99f64 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.9", + "version": "3.0.10", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 323574de..bb851972 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.9", + "version": "3.0.10", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index d8842ef6..29960e89 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.9", + "version": "3.0.10", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 128799fa669d7a3609766219b8ae214934bab074 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:41:49 +0800 Subject: [PATCH 56/74] chore: gitignore lib/ build output and exclude .map from npm publish - Add native-modules/*/lib/ and native-views/*/lib/ to .gitignore - Remove tracked lib/ files from aes-crypto, dns-lookup, zip-archive - Add "!**/*.map" to files field in all 27 package.json files - Add ./lib/typescript/types subpath export to async-storage --- .gitignore | 4 ++++ native-modules/native-logger/package.json | 3 ++- .../lib/module/NativeAesCrypto.js | 5 ----- .../lib/module/NativeAesCrypto.js.map | 1 - .../react-native-aes-crypto/lib/module/index.js | 15 --------------- .../lib/module/index.js.map | 1 - .../lib/module/package.json | 1 - .../lib/typescript/package.json | 1 - .../lib/typescript/src/NativeAesCrypto.d.ts | 16 ---------------- .../lib/typescript/src/NativeAesCrypto.d.ts.map | 1 - .../lib/typescript/src/index.d.ts | 14 -------------- .../lib/typescript/src/index.d.ts.map | 1 - .../react-native-aes-crypto/package.json | 3 ++- .../react-native-app-update/package.json | 3 ++- .../react-native-async-storage/package.json | 3 ++- .../react-native-background-thread/package.json | 3 ++- .../react-native-bundle-update/package.json | 3 ++- .../package.json | 3 ++- .../react-native-cloud-fs/package.json | 3 ++- .../react-native-cloud-kit-module/package.json | 3 ++- .../react-native-device-utils/package.json | 3 ++- .../lib/module/NativeDnsLookup.js | 5 ----- .../lib/module/NativeDnsLookup.js.map | 1 - .../react-native-dns-lookup/lib/module/index.js | 6 ------ .../lib/module/index.js.map | 1 - .../lib/module/package.json | 1 - .../lib/typescript/package.json | 1 - .../lib/typescript/src/NativeDnsLookup.d.ts | 7 ------- .../lib/typescript/src/NativeDnsLookup.d.ts.map | 1 - .../lib/typescript/src/index.d.ts | 4 ---- .../lib/typescript/src/index.d.ts.map | 1 - .../react-native-dns-lookup/package.json | 3 ++- .../react-native-get-random-values/package.json | 3 ++- .../react-native-keychain-module/package.json | 3 ++- .../react-native-lite-card/package.json | 3 ++- .../react-native-network-info/package.json | 3 ++- native-modules/react-native-pbkdf2/package.json | 3 ++- .../react-native-perf-memory/package.json | 3 ++- native-modules/react-native-ping/package.json | 3 ++- .../react-native-splash-screen/package.json | 3 ++- .../package.json | 3 ++- .../react-native-tcp-socket/package.json | 3 ++- .../lib/module/NativeZipArchive.js | 5 ----- .../lib/module/NativeZipArchive.js.map | 1 - .../react-native-zip-archive/lib/module/index.js | 6 ------ .../lib/module/index.js.map | 1 - .../lib/module/package.json | 1 - .../lib/typescript/package.json | 1 - .../lib/typescript/src/NativeZipArchive.d.ts | 12 ------------ .../lib/typescript/src/NativeZipArchive.d.ts.map | 1 - .../lib/typescript/src/index.d.ts | 4 ---- .../lib/typescript/src/index.d.ts.map | 1 - .../react-native-zip-archive/package.json | 3 ++- .../react-native-auto-size-input/package.json | 3 ++- .../react-native-pager-view/package.json | 3 ++- .../react-native-scroll-guard/package.json | 3 ++- native-views/react-native-skeleton/package.json | 3 ++- native-views/react-native-tab-view/package.json | 3 ++- 58 files changed, 58 insertions(+), 144 deletions(-) delete mode 100644 native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js delete mode 100644 native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map delete mode 100644 native-modules/react-native-aes-crypto/lib/module/index.js delete mode 100644 native-modules/react-native-aes-crypto/lib/module/index.js.map delete mode 100644 native-modules/react-native-aes-crypto/lib/module/package.json delete mode 100644 native-modules/react-native-aes-crypto/lib/typescript/package.json delete mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts delete mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map delete mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts delete mode 100644 native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map delete mode 100644 native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js delete mode 100644 native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map delete mode 100644 native-modules/react-native-dns-lookup/lib/module/index.js delete mode 100644 native-modules/react-native-dns-lookup/lib/module/index.js.map delete mode 100644 native-modules/react-native-dns-lookup/lib/module/package.json delete mode 100644 native-modules/react-native-dns-lookup/lib/typescript/package.json delete mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts delete mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map delete mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts delete mode 100644 native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map delete mode 100644 native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js delete mode 100644 native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map delete mode 100644 native-modules/react-native-zip-archive/lib/module/index.js delete mode 100644 native-modules/react-native-zip-archive/lib/module/index.js.map delete mode 100644 native-modules/react-native-zip-archive/lib/module/package.json delete mode 100644 native-modules/react-native-zip-archive/lib/typescript/package.json delete mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts delete mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map delete mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts delete mode 100644 native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map diff --git a/.gitignore b/.gitignore index 27771124..8f5b1635 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,7 @@ test-report.html # Ignore tamagui config file .tamagui scripts/nitro-view/template/android/.gradle + +# generated by react-native-builder-bob +native-modules/*/lib/ +native-views/*/lib/ diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 0dd44328..8b3ca2da 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js deleted file mode 100644 index e15db6ec..00000000 --- a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -import { TurboModuleRegistry } from 'react-native'; -export default TurboModuleRegistry.getEnforcing('AesCrypto'); -//# sourceMappingURL=NativeAesCrypto.js.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map b/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map deleted file mode 100644 index d7706f32..00000000 --- a/native-modules/react-native-aes-crypto/lib/module/NativeAesCrypto.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAesCrypto.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAgClD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,WAAW,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-aes-crypto/lib/module/index.js b/native-modules/react-native-aes-crypto/lib/module/index.js deleted file mode 100644 index 925cbc48..00000000 --- a/native-modules/react-native-aes-crypto/lib/module/index.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; - -import NativeAesCrypto from "./NativeAesCrypto.js"; -export const encrypt = NativeAesCrypto.encrypt.bind(NativeAesCrypto); -export const decrypt = NativeAesCrypto.decrypt.bind(NativeAesCrypto); -export const pbkdf2 = NativeAesCrypto.pbkdf2.bind(NativeAesCrypto); -export const hmac256 = NativeAesCrypto.hmac256.bind(NativeAesCrypto); -export const hmac512 = NativeAesCrypto.hmac512.bind(NativeAesCrypto); -export const sha1 = NativeAesCrypto.sha1.bind(NativeAesCrypto); -export const sha256 = NativeAesCrypto.sha256.bind(NativeAesCrypto); -export const sha512 = NativeAesCrypto.sha512.bind(NativeAesCrypto); -export const randomUuid = NativeAesCrypto.randomUuid.bind(NativeAesCrypto); -export const randomKey = NativeAesCrypto.randomKey.bind(NativeAesCrypto); -export default NativeAesCrypto; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/module/index.js.map b/native-modules/react-native-aes-crypto/lib/module/index.js.map deleted file mode 100644 index 3a43ce3e..00000000 --- a/native-modules/react-native-aes-crypto/lib/module/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["NativeAesCrypto","encrypt","bind","decrypt","pbkdf2","hmac256","hmac512","sha1","sha256","sha512","randomUuid","randomKey"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,eAAe,MAAM,sBAAmB;AAE/C,OAAO,MAAMC,OAAO,GAAGD,eAAe,CAACC,OAAO,CAACC,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMG,OAAO,GAAGH,eAAe,CAACG,OAAO,CAACD,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMI,MAAM,GAAGJ,eAAe,CAACI,MAAM,CAACF,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMK,OAAO,GAAGL,eAAe,CAACK,OAAO,CAACH,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMM,OAAO,GAAGN,eAAe,CAACM,OAAO,CAACJ,IAAI,CAACF,eAAe,CAAC;AACpE,OAAO,MAAMO,IAAI,GAAGP,eAAe,CAACO,IAAI,CAACL,IAAI,CAACF,eAAe,CAAC;AAC9D,OAAO,MAAMQ,MAAM,GAAGR,eAAe,CAACQ,MAAM,CAACN,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMS,MAAM,GAAGT,eAAe,CAACS,MAAM,CAACP,IAAI,CAACF,eAAe,CAAC;AAClE,OAAO,MAAMU,UAAU,GAAGV,eAAe,CAACU,UAAU,CAACR,IAAI,CAACF,eAAe,CAAC;AAC1E,OAAO,MAAMW,SAAS,GAAGX,eAAe,CAACW,SAAS,CAACT,IAAI,CAACF,eAAe,CAAC;AAExE,eAAeA,eAAe","ignoreList":[]} diff --git a/native-modules/react-native-aes-crypto/lib/module/package.json b/native-modules/react-native-aes-crypto/lib/module/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-aes-crypto/lib/module/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-aes-crypto/lib/typescript/package.json b/native-modules/react-native-aes-crypto/lib/typescript/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-aes-crypto/lib/typescript/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts deleted file mode 100644 index 9092067f..00000000 --- a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { TurboModule } from 'react-native'; -export interface Spec extends TurboModule { - encrypt(data: string, key: string, iv: string, algorithm: string): Promise; - decrypt(base64: string, key: string, iv: string, algorithm: string): Promise; - pbkdf2(password: string, salt: string, cost: number, length: number, algorithm: string): Promise; - hmac256(base64: string, key: string): Promise; - hmac512(base64: string, key: string): Promise; - sha1(text: string): Promise; - sha256(text: string): Promise; - sha512(text: string): Promise; - randomUuid(): Promise; - randomKey(length: number): Promise; -} -declare const _default: Spec; -export default _default; -//# sourceMappingURL=NativeAesCrypto.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map b/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map deleted file mode 100644 index c7e835e7..00000000 --- a/native-modules/react-native-aes-crypto/lib/typescript/src/NativeAesCrypto.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"NativeAesCrypto.d.ts","sourceRoot":"","sources":["../../../src/NativeAesCrypto.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CACL,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C;;AAED,wBAAmE"} \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts deleted file mode 100644 index 0cfec6af..00000000 --- a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import NativeAesCrypto from './NativeAesCrypto'; -export declare const encrypt: (data: string, key: string, iv: string, algorithm: string) => Promise; -export declare const decrypt: (base64: string, key: string, iv: string, algorithm: string) => Promise; -export declare const pbkdf2: (password: string, salt: string, cost: number, length: number, algorithm: string) => Promise; -export declare const hmac256: (base64: string, key: string) => Promise; -export declare const hmac512: (base64: string, key: string) => Promise; -export declare const sha1: (text: string) => Promise; -export declare const sha256: (text: string) => Promise; -export declare const sha512: (text: string) => Promise; -export declare const randomUuid: () => Promise; -export declare const randomKey: (length: number) => Promise; -export default NativeAesCrypto; -export type { Spec as AesCryptoSpec } from './NativeAesCrypto'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map b/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map deleted file mode 100644 index f6687ff2..00000000 --- a/native-modules/react-native-aes-crypto/lib/typescript/src/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAEhD,eAAO,MAAM,OAAO,+EAAgD,CAAC;AACrE,eAAO,MAAM,OAAO,iFAAgD,CAAC;AACrE,eAAO,MAAM,MAAM,sGAA+C,CAAC;AACnE,eAAO,MAAM,OAAO,kDAAgD,CAAC;AACrE,eAAO,MAAM,OAAO,kDAAgD,CAAC;AACrE,eAAO,MAAM,IAAI,mCAA6C,CAAC;AAC/D,eAAO,MAAM,MAAM,mCAA+C,CAAC;AACnE,eAAO,MAAM,MAAM,mCAA+C,CAAC;AACnE,eAAO,MAAM,UAAU,uBAAmD,CAAC;AAC3E,eAAO,MAAM,SAAS,qCAAkD,CAAC;AAEzE,eAAe,eAAe,CAAC;AAC/B,YAAY,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index de3b64b9..10e2c0bd 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index eca35954..d9008604 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index aa893dfa..e6df00b7 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -25,7 +25,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 65a15dd6..1a5fdbc2 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -29,7 +29,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 20b5dd94..bca63db6 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 91cf77b3..d275847e 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index add18e0b..fd2ebe25 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "prepare": "bob build", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index f862e93e..61de3c1c 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index ccc26c20..98766af3 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js deleted file mode 100644 index 20258781..00000000 --- a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -import { TurboModuleRegistry } from 'react-native'; -export default TurboModuleRegistry.getEnforcing('RNDnsLookup'); -//# sourceMappingURL=NativeDnsLookup.js.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map b/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map deleted file mode 100644 index 6d7c4e97..00000000 --- a/native-modules/react-native-dns-lookup/lib/module/NativeDnsLookup.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeDnsLookup.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAOlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,aAAa,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-dns-lookup/lib/module/index.js b/native-modules/react-native-dns-lookup/lib/module/index.js deleted file mode 100644 index b4fb863a..00000000 --- a/native-modules/react-native-dns-lookup/lib/module/index.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; - -import NativeDnsLookup from "./NativeDnsLookup.js"; -export const DnsLookup = NativeDnsLookup; -export const getIpAddressesForHostname = hostname => NativeDnsLookup.getIpAddresses(hostname); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/module/index.js.map b/native-modules/react-native-dns-lookup/lib/module/index.js.map deleted file mode 100644 index 6ffc69f5..00000000 --- a/native-modules/react-native-dns-lookup/lib/module/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["NativeDnsLookup","DnsLookup","getIpAddressesForHostname","hostname","getIpAddresses"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,eAAe,MAAM,sBAAmB;AAE/C,OAAO,MAAMC,SAAS,GAAGD,eAAe;AACxC,OAAO,MAAME,yBAAyB,GACpCC,QAAgB,IACMH,eAAe,CAACI,cAAc,CAACD,QAAQ,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-dns-lookup/lib/module/package.json b/native-modules/react-native-dns-lookup/lib/module/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-dns-lookup/lib/module/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-dns-lookup/lib/typescript/package.json b/native-modules/react-native-dns-lookup/lib/typescript/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-dns-lookup/lib/typescript/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts deleted file mode 100644 index 358ed6df..00000000 --- a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { TurboModule } from 'react-native'; -export interface Spec extends TurboModule { - getIpAddresses(hostname: string): Promise; -} -declare const _default: Spec; -export default _default; -//# sourceMappingURL=NativeDnsLookup.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map b/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map deleted file mode 100644 index de338821..00000000 --- a/native-modules/react-native-dns-lookup/lib/typescript/src/NativeDnsLookup.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"NativeDnsLookup.d.ts","sourceRoot":"","sources":["../../../src/NativeDnsLookup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACrD;;AAED,wBAAqE"} \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts deleted file mode 100644 index b8f5fc9b..00000000 --- a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export declare const DnsLookup: import("./NativeDnsLookup").Spec; -export declare const getIpAddressesForHostname: (hostname: string) => Promise; -export type { Spec as DnsLookupSpec } from './NativeDnsLookup'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map b/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map deleted file mode 100644 index 8ac4440d..00000000 --- a/native-modules/react-native-dns-lookup/lib/typescript/src/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,kCAAkB,CAAC;AACzC,eAAO,MAAM,yBAAyB,GACpC,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,EAAE,CAA6C,CAAC;AACjE,YAAY,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 46203945..14eb6d02 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -27,7 +27,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index b11164e1..25bb070e 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 4a3819a5..b81f4682 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 0d6aabc7..54ab09de 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 81f18a26..c519b566 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -27,7 +27,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 9a640478..5c88032d 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index a2e85b98..b34801c1 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index d539f3d7..cf74f405 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "prepare": "bob build", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 45154f84..193914d5 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 99f37f4d..5f56f260 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -27,7 +27,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 3f8d50f6..b7dd5711 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "clean": "del-cli ios/build lib", diff --git a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js deleted file mode 100644 index 4a4c6c04..00000000 --- a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -import { TurboModuleRegistry } from 'react-native'; -export default TurboModuleRegistry.getEnforcing('RNZipArchive'); -//# sourceMappingURL=NativeZipArchive.js.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map b/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map deleted file mode 100644 index 43ee2ae8..00000000 --- a/native-modules/react-native-zip-archive/lib/module/NativeZipArchive.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeZipArchive.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAYlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-zip-archive/lib/module/index.js b/native-modules/react-native-zip-archive/lib/module/index.js deleted file mode 100644 index 501433b9..00000000 --- a/native-modules/react-native-zip-archive/lib/module/index.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; - -import NativeZipArchive from "./NativeZipArchive.js"; -export const ZipArchive = NativeZipArchive; -export const zip = (source, target) => NativeZipArchive.zipFolder(source, target); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/module/index.js.map b/native-modules/react-native-zip-archive/lib/module/index.js.map deleted file mode 100644 index 72c735ac..00000000 --- a/native-modules/react-native-zip-archive/lib/module/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["NativeZipArchive","ZipArchive","zip","source","target","zipFolder"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,gBAAgB,MAAM,uBAAoB;AAEjD,OAAO,MAAMC,UAAU,GAAGD,gBAAgB;AAC1C,OAAO,MAAME,GAAG,GAAGA,CAACC,MAAc,EAAEC,MAAc,KAChDJ,gBAAgB,CAACK,SAAS,CAACF,MAAM,EAAEC,MAAM,CAAC","ignoreList":[]} diff --git a/native-modules/react-native-zip-archive/lib/module/package.json b/native-modules/react-native-zip-archive/lib/module/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-zip-archive/lib/module/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-zip-archive/lib/typescript/package.json b/native-modules/react-native-zip-archive/lib/typescript/package.json deleted file mode 100644 index 089153bc..00000000 --- a/native-modules/react-native-zip-archive/lib/typescript/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"module"} diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts deleted file mode 100644 index 643bbd19..00000000 --- a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { TurboModule } from 'react-native'; -export interface Spec extends TurboModule { - isPasswordProtected(file: string): Promise; - unzip(from: string, to: string): Promise; - unzipWithPassword(from: string, to: string, password: string): Promise; - zipFolder(from: string, to: string): Promise; - zipFiles(files: string[], to: string): Promise; - getUncompressedSize(path: string): Promise; -} -declare const _default: Spec; -export default _default; -//# sourceMappingURL=NativeZipArchive.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map b/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map deleted file mode 100644 index c5984026..00000000 --- a/native-modules/react-native-zip-archive/lib/typescript/src/NativeZipArchive.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"NativeZipArchive.d.ts","sourceRoot":"","sources":["../../../src/NativeZipArchive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD;;AAED,wBAAsE"} \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts deleted file mode 100644 index 61ab0fe9..00000000 --- a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export declare const ZipArchive: import("./NativeZipArchive").Spec; -export declare const zip: (source: string, target: string) => Promise; -export type { Spec as ZipArchiveSpec } from './NativeZipArchive'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map b/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map deleted file mode 100644 index baba7524..00000000 --- a/native-modules/react-native-zip-archive/lib/typescript/src/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,mCAAmB,CAAC;AAC3C,eAAO,MAAM,GAAG,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CACvB,CAAC;AAC7C,YAAY,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC"} \ No newline at end of file diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 4f0b7512..a4c89f98 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -22,7 +22,8 @@ "!**/__fixtures__", "!**/__mocks__", "!**/.*", - "android" + "android", + "!**/*.map" ], "scripts": { "prepare": "bob build", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index ef627abc..6e4eee87 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index cbbfa338..039ed80c 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -29,7 +29,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli lib", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index d0b99f64..378f3c37 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build lib", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index bb851972..ed389b64 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 29960e89..317bb541 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -31,7 +31,8 @@ "!**/__tests__", "!**/__fixtures__", "!**/__mocks__", - "!**/.*" + "!**/.*", + "!**/*.map" ], "scripts": { "clean": "del-cli lib", From 66995d83aa9c1497c34397b8c21f4aec6e6b905d Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 11:43:27 +0800 Subject: [PATCH 57/74] 3.0.11 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 8b3ca2da..56d0206a 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 10e2c0bd..2875d395 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index d9008604..a941acfb 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index e6df00b7..0e96c0f6 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 1a5fdbc2..1936c16d 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index bca63db6..1bf7c6c8 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index d275847e..e7c0b674 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index fd2ebe25..8e317906 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 61de3c1c..d2b63308 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 98766af3..8027f892 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 14eb6d02..90605d81 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 25bb070e..4d652ab6 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index b81f4682..bf205b6e 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 54ab09de..c5f75c60 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.10", + "version": "3.0.11", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index c519b566..73df6d24 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 5c88032d..bc519133 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index b34801c1..cc911f54 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index cf74f405..fcaafa34 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 193914d5..023ba30b 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 5f56f260..d1f59cbd 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index b7dd5711..ccfeea65 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index a4c89f98..b966467a 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 6e4eee87..f0c7fb01 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.10", + "version": "3.0.11", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 039ed80c..c92bd979 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.10", + "version": "3.0.11", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 378f3c37..2065f8e8 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.10", + "version": "3.0.11", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index ed389b64..e13488d8 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.10", + "version": "3.0.11", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 317bb541..f3a377e2 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.10", + "version": "3.0.11", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From ff6be4ced90d41a390c1df9464a4768d9d496f39 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 3 Apr 2026 16:09:30 +0800 Subject: [PATCH 58/74] chore: bump all packages to 3.0.12 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 7 ++++++- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 7 ++++++- native-modules/react-native-background-thread/package.json | 7 ++++++- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 7 ++++++- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 7 ++++++- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 7 ++++++- native-modules/react-native-network-info/package.json | 7 ++++++- native-modules/react-native-pbkdf2/package.json | 7 ++++++- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 7 ++++++- native-modules/react-native-splash-screen/package.json | 2 +- .../react-native-split-bundle-loader/package.json | 7 ++++++- native-modules/react-native-tcp-socket/package.json | 7 ++++++- native-modules/react-native-zip-archive/package.json | 7 ++++++- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 87 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 56d0206a..8dc4ab42 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 2875d395..eeef4385 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -104,6 +104,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.aescrypto" + }, + "ios": { + "modulesProvider": { + "AesCrypto": "AesCrypto" + } } }, "prettier": { diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index a941acfb..c40f2f7a 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 0e96c0f6..2f4a344f 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -107,6 +107,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.asyncstorage" + }, + "ios": { + "modulesProvider": { + "RNCAsyncStorage": "AsyncStorage" + } } }, "prettier": { diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 1936c16d..51277f6b 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -111,6 +111,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.backgroundthread" + }, + "ios": { + "modulesProvider": { + "BackgroundThread": "BackgroundThread" + } } }, "prettier": { diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 1bf7c6c8..722d2bd3 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index e7c0b674..7cb28ed2 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 8e317906..f82f739a 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -83,6 +83,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rncloudfs" + }, + "ios": { + "modulesProvider": { + "RNCloudFs": "CloudFs" + } } } } diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index d2b63308..a77d15ee 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 8027f892..905470d3 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 90605d81..2c34bd42 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -109,6 +109,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rnsdnslookup" + }, + "ios": { + "modulesProvider": { + "RNDnsLookup": "DnsLookup" + } } }, "prettier": { diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 4d652ab6..6cf56131 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index bf205b6e..90d5409b 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index c5f75c60..796c0cd4 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.11", + "version": "3.0.12", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -113,6 +113,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.onekeyfe.reactnativelitecard" + }, + "ios": { + "modulesProvider": { + "ReactNativeLiteCard": "ReactNativeLiteCard" + } } }, "prettier": { diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 73df6d24..045bb42c 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -109,6 +109,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rnnetworkinfo" + }, + "ios": { + "modulesProvider": { + "RNNetworkInfo": "NetworkInfo" + } } }, "prettier": { diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index bc519133..cd038274 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -104,6 +104,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.pbkdf2" + }, + "ios": { + "modulesProvider": { + "Pbkdf2": "Pbkdf2" + } } }, "prettier": { diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index cc911f54..c3be1c88 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index fcaafa34..fd063186 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -83,6 +83,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rnping" + }, + "ios": { + "modulesProvider": { + "RNReactNativePing": "Ping" + } } } } diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 023ba30b..e677562a 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index d1f59cbd..5fa5e046 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -109,6 +109,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.splitbundleloader" + }, + "ios": { + "modulesProvider": { + "SplitBundleLoader": "SplitBundleLoader" + } } }, "prettier": { diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index ccfeea65..5d19e8e0 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -105,6 +105,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rntcpsocket" + }, + "ios": { + "modulesProvider": { + "RNTcpSocket": "TcpSocket" + } } }, "prettier": { diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index b966467a..3377ae12 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", @@ -83,6 +83,11 @@ "jsSrcsDir": "src", "android": { "javaPackageName": "com.rnziparchive" + }, + "ios": { + "modulesProvider": { + "RNZipArchive": "ZipArchive" + } } } } diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index f0c7fb01..e2cb2c41 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.11", + "version": "3.0.12", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index c92bd979..0df9cc82 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.11", + "version": "3.0.12", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 2065f8e8..d5f3f3a8 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.11", + "version": "3.0.12", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index e13488d8..e469e1a7 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.11", + "version": "3.0.12", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index f3a377e2..50cabb4c 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.11", + "version": "3.0.12", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 18d93cae0c8db2166667aecc64a060501f7200ee Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 8 Apr 2026 00:08:24 +0800 Subject: [PATCH 59/74] add web NativeAsyncStorage --- .../react-native-async-storage/package.json | 3 + .../src/NativeAsyncStorage.native.ts | 13 ++ .../src/NativeAsyncStorage.ts | 190 +++++++++++++++++- yarn.lock | 17 ++ 4 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 2f4a344f..09ead76f 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -54,6 +54,9 @@ "publishConfig": { "registry": "https://registry.npmjs.org/" }, + "dependencies": { + "merge-options": "^3.0.4" + }, "devDependencies": { "@commitlint/config-conventional": "^19.8.1", "@eslint/compat": "^1.3.2", diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts new file mode 100644 index 00000000..3c43b075 --- /dev/null +++ b/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts @@ -0,0 +1,13 @@ +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + multiGet(keys: string[]): Promise<[string, string | null][]>; + multiSet(keyValuePairs: [string, string][]): Promise; + multiRemove(keys: string[]): Promise; + multiMerge(keyValuePairs: [string, string][]): Promise; + getAllKeys(): Promise; + clear(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage'); diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts index 3c43b075..93d42a9e 100644 --- a/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts +++ b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts @@ -1,13 +1,181 @@ -import { TurboModuleRegistry } from 'react-native'; -import type { TurboModule } from 'react-native'; - -export interface Spec extends TurboModule { - multiGet(keys: string[]): Promise<[string, string | null][]>; - multiSet(keyValuePairs: [string, string][]): Promise; - multiRemove(keys: string[]): Promise; - multiMerge(keyValuePairs: [string, string][]): Promise; - getAllKeys(): Promise; - clear(): Promise; +/** + * Copyright (c) Nicolas Gallagher. + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import mergeOptions from 'merge-options'; +import type { + AsyncStorageStatic, + MultiCallback, + MultiGetCallback, +} from './types'; + +// eslint-disable-next-line @typescript-eslint/ban-types +type OnMultiResult = Function; +// eslint-disable-next-line @typescript-eslint/ban-types +type OnResult = Function; + +const merge = mergeOptions.bind({ + concatArrays: true, + ignoreUndefined: true, +}); + +function mergeLocalStorageItem(key: string, value: string) { + const oldValue = window.localStorage.getItem(key); + if (oldValue) { + const oldObject = JSON.parse(oldValue); + const newObject = JSON.parse(value); + const nextValue = JSON.stringify(merge(oldObject, newObject)); + window.localStorage.setItem(key, nextValue); + } else { + window.localStorage.setItem(key, value); + } +} + +function createPromise( + getValue: () => Result, + callback?: Callback +): Promise { + return new Promise((resolve, reject) => { + try { + const value = getValue(); + callback?.(null, value); + resolve(value); + } catch (err) { + callback?.(err); + reject(err); + } + }); +} + +function createPromiseAll< + ReturnType, + Result, + ResultProcessor extends OnMultiResult +>( + promises: Promise[], + callback?: MultiCallback | MultiGetCallback, + processResult?: ResultProcessor +): Promise { + return Promise.all(promises).then( + (result) => { + const value = processResult?.(result) ?? null; + callback?.(null, value); + return Promise.resolve(value); + }, + (errors) => { + callback?.(errors); + return Promise.reject(errors); + } + ); } -export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage'); +const AsyncStorage: AsyncStorageStatic = { + /** + * Fetches `key` value. + */ + getItem: (key, callback) => { + return createPromise(() => window.localStorage.getItem(key), callback); + }, + + /** + * Sets `value` for `key`. + */ + setItem: (key, value, callback) => { + return createPromise( + () => window.localStorage.setItem(key, value), + callback + ); + }, + + /** + * Removes a `key` + */ + removeItem: (key, callback) => { + return createPromise(() => window.localStorage.removeItem(key), callback); + }, + + /** + * Merges existing value with input value, assuming they are stringified JSON. + */ + mergeItem: (key, value, callback) => { + return createPromise(() => mergeLocalStorageItem(key, value), callback); + }, + + /** + * Erases *all* AsyncStorage for the domain. + */ + clear: (callback) => { + return createPromise(() => window.localStorage.clear(), callback); + }, + + /** + * Gets *all* keys known to the app, for all callers, libraries, etc. + */ + getAllKeys: (callback) => { + return createPromise(() => { + const numberOfKeys = window.localStorage.length; + const keys: string[] = []; + for (let i = 0; i < numberOfKeys; i += 1) { + const key = window.localStorage.key(i) || ''; + keys.push(key); + } + return keys; + }, callback); + }, + + /** + * (stub) Flushes any pending requests using a single batch call to get the data. + */ + flushGetRequests: () => undefined, + + /** + * multiGet resolves to an array of key-value pair arrays that matches the + * input format of multiSet. + * + * multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']] + */ + multiGet: (keys, callback) => { + const promises = keys.map((key) => AsyncStorage.getItem(key)); + const processResult = (result: string[]) => + result.map((value, i) => [keys[i], value]); + return createPromiseAll(promises, callback, processResult); + }, + + /** + * Takes an array of key-value array pairs. + * multiSet([['k1', 'val1'], ['k2', 'val2']]) + */ + multiSet: (keyValuePairs, callback) => { + const promises = keyValuePairs.map((item) => + AsyncStorage.setItem(item[0], item[1]) + ); + return createPromiseAll(promises, callback); + }, + + /** + * Delete all the keys in the `keys` array. + */ + multiRemove: (keys, callback) => { + const promises = keys.map((key) => AsyncStorage.removeItem(key)); + return createPromiseAll(promises, callback); + }, + + /** + * Takes an array of key-value array pairs and merges them with existing + * values, assuming they are stringified JSON. + * + * multiMerge([['k1', 'val1'], ['k2', 'val2']]) + */ + multiMerge: (keyValuePairs, callback) => { + const promises = keyValuePairs.map((item) => + AsyncStorage.mergeItem(item[0], item[1]) + ); + return createPromiseAll(promises, callback); + }, +}; + +export default AsyncStorage; diff --git a/yarn.lock b/yarn.lock index e1e0ea6b..4a98b9b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2915,6 +2915,7 @@ __metadata: eslint-plugin-prettier: "npm:^5.5.4" jest: "npm:^29.7.0" lefthook: "npm:^2.0.3" + merge-options: "npm:^3.0.4" prettier: "npm:^2.8.8" react: "npm:19.2.0" react-native: "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch" @@ -8484,6 +8485,13 @@ __metadata: languageName: node linkType: hard +"is-plain-obj@npm:^2.1.0": + version: 2.1.0 + resolution: "is-plain-obj@npm:2.1.0" + checksum: 10/cec9100678b0a9fe0248a81743041ed990c2d4c99f893d935545cfbc42876cbe86d207f3b895700c690ad2fa520e568c44afc1605044b535a7820c1d40e38daa + languageName: node + linkType: hard + "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -9862,6 +9870,15 @@ __metadata: languageName: node linkType: hard +"merge-options@npm:^3.0.4": + version: 3.0.4 + resolution: "merge-options@npm:3.0.4" + dependencies: + is-plain-obj: "npm:^2.1.0" + checksum: 10/d86ddb3dd6e85d558dbf25dc944f3527b6bacb944db3fdda6e84a3f59c4e4b85231095f58b835758b9a57708342dee0f8de0dffa352974a48221487fe9f4584f + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" From 185c152d85eb1754d0a916e893df84513f8ff2db Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 8 Apr 2026 00:12:26 +0800 Subject: [PATCH 60/74] 3.0.13 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 8dc4ab42..c406e09a 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index eeef4385..f4f2b343 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index c40f2f7a..47267f73 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 09ead76f..58cabfcd 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 51277f6b..c9905a7d 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 722d2bd3..1c97b635 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 7cb28ed2..aedd8c18 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index f82f739a..64cb071e 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index a77d15ee..6e55abab 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 905470d3..4a2c48c8 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 2c34bd42..231bb6cb 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 6cf56131..e10d1e35 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 90d5409b..08be1edb 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 796c0cd4..6e351f19 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.12", + "version": "3.0.13", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 045bb42c..21cb76e6 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index cd038274..4b9fd494 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index c3be1c88..5f9e28e1 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index fd063186..15ca1490 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index e677562a..1e82ef4f 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 5fa5e046..d72e8985 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 5d19e8e0..228583dd 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 3377ae12..578f786a 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index e2cb2c41..ec1fad93 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.12", + "version": "3.0.13", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 0df9cc82..901f8a12 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.12", + "version": "3.0.13", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index d5f3f3a8..28e10617 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.12", + "version": "3.0.13", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index e469e1a7..28aa650b 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.12", + "version": "3.0.13", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 50cabb4c..1d380621 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.12", + "version": "3.0.13", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 69e48c1f497d84dc8b76774ba1882c5bc80ab9ef Mon Sep 17 00:00:00 2001 From: huhuanming Date: Wed, 8 Apr 2026 00:26:57 +0800 Subject: [PATCH 61/74] fix: resolve type errors in web NativeAsyncStorage - Add DOM lib to tsconfig for window/localStorage types - Add merge-options type declaration for bundler moduleResolution --- .../react-native-async-storage/src/merge-options.d.ts | 4 ++++ native-modules/react-native-async-storage/tsconfig.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 native-modules/react-native-async-storage/src/merge-options.d.ts diff --git a/native-modules/react-native-async-storage/src/merge-options.d.ts b/native-modules/react-native-async-storage/src/merge-options.d.ts new file mode 100644 index 00000000..1fd2b366 --- /dev/null +++ b/native-modules/react-native-async-storage/src/merge-options.d.ts @@ -0,0 +1,4 @@ +declare module 'merge-options' { + function mergeOptions(...args: T[]): T; + export default mergeOptions; +} diff --git a/native-modules/react-native-async-storage/tsconfig.json b/native-modules/react-native-async-storage/tsconfig.json index 06c7d88e..098a5013 100644 --- a/native-modules/react-native-async-storage/tsconfig.json +++ b/native-modules/react-native-async-storage/tsconfig.json @@ -10,7 +10,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "jsx": "react-jsx", - "lib": ["ESNext"], + "lib": ["ESNext", "DOM"], "module": "ESNext", "moduleResolution": "bundler", "noEmit": true, From bb6a14d533abe4cab6739452806507f4663df765 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 9 Apr 2026 15:05:26 +0800 Subject: [PATCH 62/74] chore: patch bump workspaces and fix async-storage module files --- native-modules/native-logger/package.json | 2 +- .../react-native-aes-crypto/package.json | 2 +- .../react-native-app-update/package.json | 2 +- .../react-native-async-storage/package.json | 2 +- .../src/NativeAsyncStorage.native.ts | 13 -- .../src/NativeAsyncStorage.ts | 190 +----------------- .../src/NativeAsyncStorage.web.ts | 181 +++++++++++++++++ .../package.json | 2 +- .../react-native-bundle-update/package.json | 2 +- .../package.json | 2 +- .../react-native-cloud-fs/package.json | 2 +- .../package.json | 2 +- .../react-native-device-utils/package.json | 2 +- .../react-native-dns-lookup/package.json | 2 +- .../package.json | 2 +- .../react-native-keychain-module/package.json | 2 +- .../react-native-lite-card/package.json | 2 +- .../react-native-network-info/package.json | 2 +- .../react-native-pbkdf2/package.json | 2 +- .../react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- .../react-native-splash-screen/package.json | 2 +- .../package.json | 2 +- .../react-native-tcp-socket/package.json | 2 +- .../react-native-zip-archive/package.json | 2 +- .../react-native-auto-size-input/package.json | 2 +- .../react-native-pager-view/package.json | 2 +- .../react-native-scroll-guard/package.json | 2 +- .../react-native-skeleton/package.json | 2 +- .../react-native-tab-view/package.json | 2 +- 30 files changed, 219 insertions(+), 219 deletions(-) delete mode 100644 native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts create mode 100644 native-modules/react-native-async-storage/src/NativeAsyncStorage.web.ts diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index c406e09a..c8f27988 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index f4f2b343..a318af8e 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 47267f73..4a951b48 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 58cabfcd..d1595819 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts deleted file mode 100644 index 3c43b075..00000000 --- a/native-modules/react-native-async-storage/src/NativeAsyncStorage.native.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TurboModuleRegistry } from 'react-native'; -import type { TurboModule } from 'react-native'; - -export interface Spec extends TurboModule { - multiGet(keys: string[]): Promise<[string, string | null][]>; - multiSet(keyValuePairs: [string, string][]): Promise; - multiRemove(keys: string[]): Promise; - multiMerge(keyValuePairs: [string, string][]): Promise; - getAllKeys(): Promise; - clear(): Promise; -} - -export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage'); diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts index 93d42a9e..3c43b075 100644 --- a/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts +++ b/native-modules/react-native-async-storage/src/NativeAsyncStorage.ts @@ -1,181 +1,13 @@ -/** - * Copyright (c) Nicolas Gallagher. - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import mergeOptions from 'merge-options'; -import type { - AsyncStorageStatic, - MultiCallback, - MultiGetCallback, -} from './types'; - -// eslint-disable-next-line @typescript-eslint/ban-types -type OnMultiResult = Function; -// eslint-disable-next-line @typescript-eslint/ban-types -type OnResult = Function; - -const merge = mergeOptions.bind({ - concatArrays: true, - ignoreUndefined: true, -}); - -function mergeLocalStorageItem(key: string, value: string) { - const oldValue = window.localStorage.getItem(key); - if (oldValue) { - const oldObject = JSON.parse(oldValue); - const newObject = JSON.parse(value); - const nextValue = JSON.stringify(merge(oldObject, newObject)); - window.localStorage.setItem(key, nextValue); - } else { - window.localStorage.setItem(key, value); - } -} - -function createPromise( - getValue: () => Result, - callback?: Callback -): Promise { - return new Promise((resolve, reject) => { - try { - const value = getValue(); - callback?.(null, value); - resolve(value); - } catch (err) { - callback?.(err); - reject(err); - } - }); -} - -function createPromiseAll< - ReturnType, - Result, - ResultProcessor extends OnMultiResult ->( - promises: Promise[], - callback?: MultiCallback | MultiGetCallback, - processResult?: ResultProcessor -): Promise { - return Promise.all(promises).then( - (result) => { - const value = processResult?.(result) ?? null; - callback?.(null, value); - return Promise.resolve(value); - }, - (errors) => { - callback?.(errors); - return Promise.reject(errors); - } - ); +import { TurboModuleRegistry } from 'react-native'; +import type { TurboModule } from 'react-native'; + +export interface Spec extends TurboModule { + multiGet(keys: string[]): Promise<[string, string | null][]>; + multiSet(keyValuePairs: [string, string][]): Promise; + multiRemove(keys: string[]): Promise; + multiMerge(keyValuePairs: [string, string][]): Promise; + getAllKeys(): Promise; + clear(): Promise; } -const AsyncStorage: AsyncStorageStatic = { - /** - * Fetches `key` value. - */ - getItem: (key, callback) => { - return createPromise(() => window.localStorage.getItem(key), callback); - }, - - /** - * Sets `value` for `key`. - */ - setItem: (key, value, callback) => { - return createPromise( - () => window.localStorage.setItem(key, value), - callback - ); - }, - - /** - * Removes a `key` - */ - removeItem: (key, callback) => { - return createPromise(() => window.localStorage.removeItem(key), callback); - }, - - /** - * Merges existing value with input value, assuming they are stringified JSON. - */ - mergeItem: (key, value, callback) => { - return createPromise(() => mergeLocalStorageItem(key, value), callback); - }, - - /** - * Erases *all* AsyncStorage for the domain. - */ - clear: (callback) => { - return createPromise(() => window.localStorage.clear(), callback); - }, - - /** - * Gets *all* keys known to the app, for all callers, libraries, etc. - */ - getAllKeys: (callback) => { - return createPromise(() => { - const numberOfKeys = window.localStorage.length; - const keys: string[] = []; - for (let i = 0; i < numberOfKeys; i += 1) { - const key = window.localStorage.key(i) || ''; - keys.push(key); - } - return keys; - }, callback); - }, - - /** - * (stub) Flushes any pending requests using a single batch call to get the data. - */ - flushGetRequests: () => undefined, - - /** - * multiGet resolves to an array of key-value pair arrays that matches the - * input format of multiSet. - * - * multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']] - */ - multiGet: (keys, callback) => { - const promises = keys.map((key) => AsyncStorage.getItem(key)); - const processResult = (result: string[]) => - result.map((value, i) => [keys[i], value]); - return createPromiseAll(promises, callback, processResult); - }, - - /** - * Takes an array of key-value array pairs. - * multiSet([['k1', 'val1'], ['k2', 'val2']]) - */ - multiSet: (keyValuePairs, callback) => { - const promises = keyValuePairs.map((item) => - AsyncStorage.setItem(item[0], item[1]) - ); - return createPromiseAll(promises, callback); - }, - - /** - * Delete all the keys in the `keys` array. - */ - multiRemove: (keys, callback) => { - const promises = keys.map((key) => AsyncStorage.removeItem(key)); - return createPromiseAll(promises, callback); - }, - - /** - * Takes an array of key-value array pairs and merges them with existing - * values, assuming they are stringified JSON. - * - * multiMerge([['k1', 'val1'], ['k2', 'val2']]) - */ - multiMerge: (keyValuePairs, callback) => { - const promises = keyValuePairs.map((item) => - AsyncStorage.mergeItem(item[0], item[1]) - ); - return createPromiseAll(promises, callback); - }, -}; - -export default AsyncStorage; +export default TurboModuleRegistry.getEnforcing('RNCAsyncStorage'); diff --git a/native-modules/react-native-async-storage/src/NativeAsyncStorage.web.ts b/native-modules/react-native-async-storage/src/NativeAsyncStorage.web.ts new file mode 100644 index 00000000..93d42a9e --- /dev/null +++ b/native-modules/react-native-async-storage/src/NativeAsyncStorage.web.ts @@ -0,0 +1,181 @@ +/** + * Copyright (c) Nicolas Gallagher. + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import mergeOptions from 'merge-options'; +import type { + AsyncStorageStatic, + MultiCallback, + MultiGetCallback, +} from './types'; + +// eslint-disable-next-line @typescript-eslint/ban-types +type OnMultiResult = Function; +// eslint-disable-next-line @typescript-eslint/ban-types +type OnResult = Function; + +const merge = mergeOptions.bind({ + concatArrays: true, + ignoreUndefined: true, +}); + +function mergeLocalStorageItem(key: string, value: string) { + const oldValue = window.localStorage.getItem(key); + if (oldValue) { + const oldObject = JSON.parse(oldValue); + const newObject = JSON.parse(value); + const nextValue = JSON.stringify(merge(oldObject, newObject)); + window.localStorage.setItem(key, nextValue); + } else { + window.localStorage.setItem(key, value); + } +} + +function createPromise( + getValue: () => Result, + callback?: Callback +): Promise { + return new Promise((resolve, reject) => { + try { + const value = getValue(); + callback?.(null, value); + resolve(value); + } catch (err) { + callback?.(err); + reject(err); + } + }); +} + +function createPromiseAll< + ReturnType, + Result, + ResultProcessor extends OnMultiResult +>( + promises: Promise[], + callback?: MultiCallback | MultiGetCallback, + processResult?: ResultProcessor +): Promise { + return Promise.all(promises).then( + (result) => { + const value = processResult?.(result) ?? null; + callback?.(null, value); + return Promise.resolve(value); + }, + (errors) => { + callback?.(errors); + return Promise.reject(errors); + } + ); +} + +const AsyncStorage: AsyncStorageStatic = { + /** + * Fetches `key` value. + */ + getItem: (key, callback) => { + return createPromise(() => window.localStorage.getItem(key), callback); + }, + + /** + * Sets `value` for `key`. + */ + setItem: (key, value, callback) => { + return createPromise( + () => window.localStorage.setItem(key, value), + callback + ); + }, + + /** + * Removes a `key` + */ + removeItem: (key, callback) => { + return createPromise(() => window.localStorage.removeItem(key), callback); + }, + + /** + * Merges existing value with input value, assuming they are stringified JSON. + */ + mergeItem: (key, value, callback) => { + return createPromise(() => mergeLocalStorageItem(key, value), callback); + }, + + /** + * Erases *all* AsyncStorage for the domain. + */ + clear: (callback) => { + return createPromise(() => window.localStorage.clear(), callback); + }, + + /** + * Gets *all* keys known to the app, for all callers, libraries, etc. + */ + getAllKeys: (callback) => { + return createPromise(() => { + const numberOfKeys = window.localStorage.length; + const keys: string[] = []; + for (let i = 0; i < numberOfKeys; i += 1) { + const key = window.localStorage.key(i) || ''; + keys.push(key); + } + return keys; + }, callback); + }, + + /** + * (stub) Flushes any pending requests using a single batch call to get the data. + */ + flushGetRequests: () => undefined, + + /** + * multiGet resolves to an array of key-value pair arrays that matches the + * input format of multiSet. + * + * multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']] + */ + multiGet: (keys, callback) => { + const promises = keys.map((key) => AsyncStorage.getItem(key)); + const processResult = (result: string[]) => + result.map((value, i) => [keys[i], value]); + return createPromiseAll(promises, callback, processResult); + }, + + /** + * Takes an array of key-value array pairs. + * multiSet([['k1', 'val1'], ['k2', 'val2']]) + */ + multiSet: (keyValuePairs, callback) => { + const promises = keyValuePairs.map((item) => + AsyncStorage.setItem(item[0], item[1]) + ); + return createPromiseAll(promises, callback); + }, + + /** + * Delete all the keys in the `keys` array. + */ + multiRemove: (keys, callback) => { + const promises = keys.map((key) => AsyncStorage.removeItem(key)); + return createPromiseAll(promises, callback); + }, + + /** + * Takes an array of key-value array pairs and merges them with existing + * values, assuming they are stringified JSON. + * + * multiMerge([['k1', 'val1'], ['k2', 'val2']]) + */ + multiMerge: (keyValuePairs, callback) => { + const promises = keyValuePairs.map((item) => + AsyncStorage.mergeItem(item[0], item[1]) + ); + return createPromiseAll(promises, callback); + }, +}; + +export default AsyncStorage; diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index c9905a7d..a135f9d8 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 1c97b635..418280da 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index aedd8c18..442fe8e8 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 64cb071e..4f1cec4a 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 6e55abab..f94fca17 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 4a2c48c8..926f5de6 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 231bb6cb..fc1a7c22 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index e10d1e35..25fda547 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 08be1edb..852920fb 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 6e351f19..5efb7864 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.13", + "version": "3.0.14", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 21cb76e6..deaf2b3f 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 4b9fd494..571161a7 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 5f9e28e1..b8dcb7eb 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 15ca1490..5003f088 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 1e82ef4f..6d00212f 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index d72e8985..f2f6dfac 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 228583dd..d1b3fe1f 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 578f786a..668402e1 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index ec1fad93..4cf89add 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.13", + "version": "3.0.14", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index 901f8a12..efbc342e 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.13", + "version": "3.0.14", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 28e10617..1bd73f8b 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.13", + "version": "3.0.14", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 28aa650b..fe23f647 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.13", + "version": "3.0.14", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 1d380621..175ac439 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.13", + "version": "3.0.14", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 3ef80d2011add94fecccc438df221759d60e03b8 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 9 Apr 2026 20:40:52 +0800 Subject: [PATCH 63/74] feat: align react-native-cloud-fs types and native implementations with source repo - Update TS Spec with proper types for all methods (replace Object params) - Add Android Google Drive methods: loginIfNeeded, logout, getGoogleDriveDocument, getCurrentlySignedInUserData - Port DriveServiceHelper and full RNCloudFsModule from Java to Kotlin TurboModule - Add iOS stubs for Android-only methods - Fix iOS syncCloud to return boolean instead of nil - Add createFile back to Spec - Add default export to index.tsx - Add Google Drive dependencies to Android build.gradle --- .../android/build.gradle | 10 + .../java/com/rncloudfs/DriveServiceHelper.kt | 108 +++++ .../java/com/rncloudfs/RNCloudFsModule.kt | 403 +++++++++++++++++- .../react-native-cloud-fs/ios/CloudFs.mm | 29 +- .../src/NativeCloudFs.ts | 48 ++- .../react-native-cloud-fs/src/index.tsx | 1 + 6 files changed, 578 insertions(+), 21 deletions(-) create mode 100644 native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/DriveServiceHelper.kt diff --git a/native-modules/react-native-cloud-fs/android/build.gradle b/native-modules/react-native-cloud-fs/android/build.gradle index d8d5e4ca..4e515d26 100644 --- a/native-modules/react-native-cloud-fs/android/build.gradle +++ b/native-modules/react-native-cloud-fs/android/build.gradle @@ -74,4 +74,14 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + // Google Drive / Sign-In + implementation "com.google.android.gms:play-services-auth:21.3.0" + implementation "com.google.http-client:google-http-client-gson:1.44.1" + implementation("com.google.api-client:google-api-client-android:2.7.0") { + exclude group: "org.apache.httpcomponents" + } + implementation("com.google.apis:google-api-services-drive:v3-rev20241027-2.0.0") { + exclude group: "org.apache.httpcomponents" + } } diff --git a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/DriveServiceHelper.kt b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/DriveServiceHelper.kt new file mode 100644 index 00000000..f66fcdd2 --- /dev/null +++ b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/DriveServiceHelper.kt @@ -0,0 +1,108 @@ +package com.rncloudfs + +import android.util.Log +import com.google.android.gms.tasks.Task +import com.google.android.gms.tasks.Tasks +import com.google.api.client.http.FileContent +import com.google.api.services.drive.Drive +import com.google.api.services.drive.model.FileList +import java.io.BufferedReader +import java.io.InputStreamReader +import java.util.concurrent.Executors + +class DriveServiceHelper(private val driveService: Drive) { + + private val executor = Executors.newSingleThreadExecutor() + + fun saveFile( + sourcePath: String, + destinationPath: String, + mimeType: String?, + useDocumentsFolder: Boolean + ): Task { + var existingFileId: String? = null + val fileList = Tasks.await(queryFiles(useDocumentsFolder)) + for (file in fileList.files) { + if (file.name.equals(destinationPath, ignoreCase = true)) { + existingFileId = file.id + } + } + return createFile(sourcePath, destinationPath, mimeType, useDocumentsFolder, existingFileId) + } + + fun createFile( + sourcePath: String, + destinationPath: String, + mimeType: String?, + useDocumentsFolder: Boolean, + fileId: String? + ): Task { + return Tasks.call(executor) { + try { + val sourceFile = java.io.File(sourcePath) + val mediaContent = FileContent(mimeType, sourceFile) + val parentFolder = listOf(if (useDocumentsFolder) "root" else "appDataFolder") + val metadata = com.google.api.services.drive.model.File() + .setMimeType(mimeType) + .setName(destinationPath) + if (fileId == null) { + metadata.parents = parentFolder + } + + val googleFile = if (fileId != null) { + driveService.files().update(fileId, metadata, mediaContent).execute() + } else { + driveService.files().create(metadata, mediaContent).execute() + } + + googleFile?.id ?: throw java.io.IOException("Null result when requesting file creation.") + } catch (e: Exception) { + Log.e(TAG, e.toString()) + throw e + } + } + } + + fun checkIfFileExists(fileId: String): Task { + return Tasks.call(executor) { + val metadata = driveService.files().get(fileId).execute() + metadata != null + } + } + + fun deleteFile(fileId: String): Task { + return Tasks.call(executor) { + driveService.files().delete(fileId).execute() + true + } + } + + fun readFile(fileId: String): Task { + return Tasks.call(executor) { + driveService.files().get(fileId).executeMediaAsInputStream().use { inputStream -> + BufferedReader(InputStreamReader(inputStream)).use { reader -> + val sb = StringBuilder() + var line: String? + while (reader.readLine().also { line = it } != null) { + sb.append(line) + } + sb.toString() + } + } + } + } + + fun queryFiles(useDocumentsFolder: Boolean): Task { + return Tasks.call(executor) { + driveService.files().list() + .setSpaces(if (useDocumentsFolder) "drive" else "appDataFolder") + .setFields("nextPageToken, files(id, name, modifiedTime)") + .setPageSize(100) + .execute() + } + } + + companion object { + private const val TAG = "DriveServiceHelper" + } +} diff --git a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt index bd558f93..83b59bcd 100644 --- a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt +++ b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt @@ -1,50 +1,425 @@ package com.rncloudfs +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.util.Log +import android.webkit.MimeTypeMap +import com.facebook.react.bridge.ActivityEventListener +import com.facebook.react.bridge.LifecycleEventListener import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.WritableNativeArray +import com.facebook.react.bridge.WritableNativeMap import com.facebook.react.module.annotations.ReactModule +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Scope +import com.google.api.client.extensions.android.http.AndroidHttp +import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential +import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException +import com.google.api.client.json.gson.GsonFactory +import com.google.api.services.drive.Drive +import com.google.api.services.drive.DriveScopes +import java.util.Collections @ReactModule(name = RNCloudFsModule.NAME) -class RNCloudFsModule(reactContext: ReactApplicationContext) : - NativeRNCloudFsSpec(reactContext) { +class RNCloudFsModule(private val reactContext: ReactApplicationContext) : + NativeRNCloudFsSpec(reactContext), LifecycleEventListener, ActivityEventListener { + + private var mDriveServiceHelper: DriveServiceHelper? = null + private var signInPromise: Promise? = null + private var mPendingPromise: Promise? = null + private var mPendingOptions: ReadableMap? = null + private var mPendingOperation: String? = null + + init { + reactContext.addLifecycleEventListener(this) + reactContext.addActivityEventListener(this) + } companion object { const val NAME = "RNCloudFs" - private const val NOT_AVAILABLE_ERROR = "iCloud is not available on Android" + private const val TAG = "RNCloudFs" + private const val REQUEST_CODE_SIGN_IN = 1 + private const val REQUEST_AUTHORIZATION = 11 + private const val COPY_TO_CLOUD = "CopyToCloud" + private const val LIST_FILES = "ListFiles" } override fun getName(): String = NAME + // region iOS-only stubs + override fun isAvailable(promise: Promise) { promise.resolve(false) } override fun createFile(options: ReadableMap, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + promise.reject("NOT_AVAILABLE", "iCloud is not available on Android") } - override fun fileExists(options: ReadableMap, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + override fun getIcloudDocument(filename: String, promise: Promise) { + promise.reject("NOT_AVAILABLE", "iCloud is not available on Android") } - override fun listFiles(options: ReadableMap, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + override fun syncCloud(promise: Promise) { + promise.reject("NOT_AVAILABLE", "iCloud is not available on Android") } - override fun getIcloudDocument(filename: String, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + // endregion + + // region Google Sign-In + + override fun loginIfNeeded(promise: Promise) { + if (mDriveServiceHelper == null) { + val account = GoogleSignIn.getLastSignedInAccount(reactContext) + if (account == null) { + signInPromise = promise + requestSignIn() + } else { + val credential = GoogleAccountCredential.usingOAuth2( + reactContext, Collections.singleton(DriveScopes.DRIVE_APPDATA) + ) + credential.selectedAccount = account.account + val googleDriveService = Drive.Builder( + AndroidHttp.newCompatibleTransport(), + GsonFactory(), + credential + ).build() + mDriveServiceHelper = DriveServiceHelper(googleDriveService) + promise.resolve(true) + } + } else { + promise.resolve(true) + } + } + + override fun logout(promise: Promise) { + val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(Scope(DriveScopes.DRIVE_FILE)) + .build() + val client: GoogleSignInClient = GoogleSignIn.getClient(reactContext, signInOptions) + mDriveServiceHelper = null + client.signOut() + .addOnSuccessListener { promise.resolve(true) } + .addOnFailureListener { exception -> + Log.e(TAG, "Couldn't log out.", exception) + promise.reject(exception) + } + } + + override fun getCurrentlySignedInUserData(promise: Promise) { + val account = GoogleSignIn.getLastSignedInAccount(reactContext) + if (account == null) { + promise.resolve(null) + } else { + val photoUrl: Uri? = account.photoUrl + val resultData = WritableNativeMap() + resultData.putString("email", account.email) + resultData.putString("name", account.displayName) + resultData.putString("avatarUrl", photoUrl?.toString()) + promise.resolve(resultData) + } + } + + private fun requestSignIn() { + Log.d(TAG, "Requesting sign-in") + val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(Scope(DriveScopes.DRIVE_FILE)) + .build() + val client: GoogleSignInClient = GoogleSignIn.getClient(reactContext, signInOptions) + reactContext.startActivityForResult(client.signInIntent, REQUEST_CODE_SIGN_IN, null) + } + + // endregion + + // region Google Drive operations + + override fun fileExists(options: ReadableMap, promise: Promise) { + val helper = mDriveServiceHelper + if (helper != null) { + val fileId = options.getString("fileId") ?: "" + Log.d(TAG, "Checking file $fileId") + helper.checkIfFileExists(fileId) + .addOnSuccessListener { exists -> promise.resolve(exists) } + .addOnFailureListener { exception -> + try { + val e = exception as UserRecoverableAuthIOException + reactContext.startActivityForResult(e.intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + Log.e(TAG, "Couldn't check file.", exception) + promise.reject(exception) + } + } + } else { + promise.reject("NOT_LOGGED_IN", "Google Drive not initialized. Call loginIfNeeded first.") + } } override fun deleteFromCloud(item: ReadableMap, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + val helper = mDriveServiceHelper + if (helper != null) { + val fileId = item.getString("id") ?: "" + Log.d(TAG, "Deleting file $fileId") + helper.deleteFile(fileId) + .addOnSuccessListener { deleted -> promise.resolve(deleted) } + .addOnFailureListener { exception -> + try { + val e = exception as UserRecoverableAuthIOException + reactContext.startActivityForResult(e.intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + Log.e(TAG, "Couldn't delete file.", exception) + promise.reject(exception) + } + } + } else { + promise.reject("NOT_LOGGED_IN", "Google Drive not initialized. Call loginIfNeeded first.") + } + } + + override fun listFiles(options: ReadableMap, promise: Promise) { + val helper = mDriveServiceHelper + if (helper != null) { + Log.d(TAG, "Querying for files.") + val useDocumentsFolder = if (options.hasKey("scope")) { + options.getString("scope")?.lowercase() == "visible" + } else { + true + } + try { + helper.queryFiles(useDocumentsFolder) + .addOnSuccessListener { fileList -> + val files = WritableNativeArray() + for (file in fileList.files) { + val fileInfo = WritableNativeMap() + fileInfo.putString("name", file.name) + fileInfo.putString("id", file.id) + fileInfo.putString("lastModified", file.modifiedTime.toString()) + files.pushMap(fileInfo) + } + val result = WritableNativeMap() + result.putArray("files", files) + promise.resolve(result) + clearPendingOperations() + } + .addOnFailureListener { exception -> + clearPendingOperations() + try { + Log.e(TAG, "Unable to query files: ${exception.cause?.message}") + val e = exception as UserRecoverableAuthIOException + mPendingPromise = promise + mPendingOptions = options + mPendingOperation = LIST_FILES + reactContext.startActivityForResult(e.intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + promise.reject(e) + } + } + } catch (exception: Exception) { + try { + val e = exception as java.util.concurrent.ExecutionException + mPendingPromise = promise + mPendingOptions = options + mPendingOperation = LIST_FILES + val intent = (e.cause as UserRecoverableAuthIOException).intent + reactContext.startActivityForResult(intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + promise.reject(exception) + Log.e(TAG, "Unable to query files: ${exception.cause?.message}") + } + } + } else { + promise.reject("NOT_LOGGED_IN", "Google Drive not initialized. Call loginIfNeeded first.") + } } override fun copyToCloud(options: ReadableMap, promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + val helper = mDriveServiceHelper + if (helper != null) { + if (!options.hasKey("sourcePath")) { + promise.reject("error", "sourcePath not specified") + return + } + val source = options.getMap("sourcePath") + var uriOrPath = source?.getString("uri") + if (uriOrPath == null) { + uriOrPath = source?.getString("path") + } + if (uriOrPath == null) { + promise.reject("no path", "no source uri or path was specified") + return + } + if (!options.hasKey("targetPath")) { + promise.reject("error", "targetPath not specified") + return + } + val destinationPath = options.getString("targetPath") ?: "" + val mimeType = if (options.hasKey("mimetype")) options.getString("mimetype") else null + val useDocumentsFolder = if (options.hasKey("scope")) { + options.getString("scope")?.lowercase() == "visible" + } else { + true + } + val actualMimeType = if (mimeType == null) guessMimeType(uriOrPath) else null + + try { + helper.saveFile(uriOrPath, destinationPath, actualMimeType, useDocumentsFolder) + .addOnSuccessListener { fileId -> + Log.d(TAG, "Saving $fileId") + promise.resolve(fileId) + clearPendingOperations() + } + .addOnFailureListener { exception -> + clearPendingOperations() + try { + val e = exception as UserRecoverableAuthIOException + reactContext.startActivityForResult(e.intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + Log.e(TAG, "Couldn't create file.", exception) + } + promise.reject(exception) + } + } catch (exception: Exception) { + try { + val e = exception as java.util.concurrent.ExecutionException + mPendingPromise = promise + mPendingOptions = options + mPendingOperation = COPY_TO_CLOUD + val intent = (e.cause as UserRecoverableAuthIOException).intent + reactContext.startActivityForResult(intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + promise.reject(exception) + Log.e(TAG, "Couldn't create file.", exception) + } + } + } else { + promise.reject("NOT_LOGGED_IN", "Google Drive not initialized. Call loginIfNeeded first.") + } } - override fun syncCloud(promise: Promise) { - promise.reject("NOT_AVAILABLE", NOT_AVAILABLE_ERROR) + override fun getGoogleDriveDocument(fileId: String, promise: Promise) { + val helper = mDriveServiceHelper + if (helper != null) { + Log.d(TAG, "Reading file $fileId") + helper.readFile(fileId) + .addOnSuccessListener { content -> promise.resolve(content) } + .addOnFailureListener { exception -> + try { + val e = exception as UserRecoverableAuthIOException + reactContext.startActivityForResult(e.intent, REQUEST_AUTHORIZATION, null) + } catch (e: Exception) { + Log.e(TAG, "Couldn't read file.", exception) + promise.reject(exception) + } + } + } else { + promise.reject("NOT_LOGGED_IN", "Google Drive not initialized. Call loginIfNeeded first.") + } + } + + // endregion + + // region Activity result handling + + private fun clearPendingOperations() { + mPendingOperation = null + mPendingPromise = null + mPendingOptions = null + } + + override fun onActivityResult(activity: Activity?, requestCode: Int, resultCode: Int, data: Intent?) { + when (requestCode) { + REQUEST_CODE_SIGN_IN -> { + val task = GoogleSignIn.getSignedInAccountFromIntent(data) + handleSignInResult(task) + } + REQUEST_AUTHORIZATION -> { + if (resultCode == Activity.RESULT_OK && data != null) { + val copiedPendingOperation = mPendingOperation + if (copiedPendingOperation != null) { + reactContext.runOnNativeModulesQueueThread { + mPendingOperation = null + when (copiedPendingOperation) { + COPY_TO_CLOUD -> { + try { + mPendingOptions?.let { copyToCloud(it, mPendingPromise!!) } + } catch (e: Exception) { + mPendingPromise?.reject(e) + clearPendingOperations() + } + } + LIST_FILES -> { + try { + mPendingOptions?.let { listFiles(it, mPendingPromise!!) } + } catch (e: Exception) { + mPendingPromise?.reject(e) + clearPendingOperations() + } + } + } + } + } + } else if (resultCode == Activity.RESULT_CANCELED && mPendingPromise != null) { + mPendingPromise?.reject("canceled", "User canceled") + } else if (mPendingPromise != null) { + mPendingPromise?.reject( + "unknown error", + "Operation failed: $mPendingOperation result code $resultCode" + ) + } + } + } + } + + private fun handleSignInResult(completedTask: com.google.android.gms.tasks.Task) { + try { + val googleAccount = completedTask.getResult(ApiException::class.java) + Log.d(TAG, "Signed in as ${googleAccount.email}") + + val credential = GoogleAccountCredential.usingOAuth2( + reactContext, Collections.singleton(DriveScopes.DRIVE_APPDATA) + ) + credential.selectedAccount = googleAccount.account + val googleDriveService = Drive.Builder( + AndroidHttp.newCompatibleTransport(), + GsonFactory(), + credential + ).build() + + mDriveServiceHelper = DriveServiceHelper(googleDriveService) + + signInPromise?.resolve(true) + signInPromise = null + } catch (e: ApiException) { + Log.w(TAG, "signInResult:failed code=${e.statusCode}") + signInPromise?.reject("signInResult:${e.statusCode}", e.message) + signInPromise = null + } + } + + // endregion + + // region Lifecycle + + override fun onHostResume() {} + override fun onHostPause() {} + override fun onHostDestroy() {} + override fun onNewIntent(intent: Intent?) {} + + // endregion + + private fun guessMimeType(url: String): String? { + val extension = MimeTypeMap.getFileExtensionFromUrl(url) + return if (extension != null) { + MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) + } else { + null + } } } diff --git a/native-modules/react-native-cloud-fs/ios/CloudFs.mm b/native-modules/react-native-cloud-fs/ios/CloudFs.mm index 6cd1a02d..ab8c7630 100644 --- a/native-modules/react-native-cloud-fs/ios/CloudFs.mm +++ b/native-modules/react-native-cloud-fs/ios/CloudFs.mm @@ -302,10 +302,37 @@ - (void)syncCloud:(RCTPromiseResolveBlock)resolve for (NSMetadataItem *item in query.results) { [self downloadFileIfNotAvailable:item]; } - return resolve(nil); + return resolve(@YES); }]; } +// MARK: - Android-only stubs + +- (void)loginIfNeeded:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + resolve(@NO); +} + +- (void)logout:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + resolve(@NO); +} + +- (void)getGoogleDriveDocument:(NSString *)fileId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + reject(@"NOT_AVAILABLE", @"Google Drive is not available on iOS", nil); +} + +- (void)getCurrentlySignedInUserData:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject +{ + resolve([NSNull null]); +} + // MARK: - Private helpers - (void)moveToICloudDirectory:(bool)documentsFolder diff --git a/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts b/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts index 459d5a84..17c1b94a 100644 --- a/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts +++ b/native-modules/react-native-cloud-fs/src/NativeCloudFs.ts @@ -2,14 +2,50 @@ import { TurboModuleRegistry } from 'react-native'; import type { TurboModule } from 'react-native'; export interface Spec extends TurboModule { + // Shared isAvailable(): Promise; - createFile(options: Object): Promise; - fileExists(options: Object): Promise; - listFiles(options: Object): Promise; + syncCloud(): Promise; + listFiles(options: { + scope: string; + targetPath?: string; + }): Promise<{ + files: Array<{ + id: string; + name: string; + lastModified: string; + isFile?: boolean; + }>; + }>; + deleteFromCloud(item: { id: string; path?: string }): Promise; + fileExists(options: { + fileId?: string; + targetPath?: string; + scope?: string; + }): Promise; + copyToCloud(options: { + mimetype?: string | null; + scope: string; + sourcePath: { path?: string; uri?: string }; + targetPath: string; + }): Promise; + createFile(options: { + targetPath: string; + content: string; + scope?: string; + }): Promise; + + // iOS only getIcloudDocument(filename: string): Promise; - deleteFromCloud(item: Object): Promise; - copyToCloud(options: Object): Promise; - syncCloud(): Promise; + + // Android only + loginIfNeeded(): Promise; + logout(): Promise; + getGoogleDriveDocument(fileId: string): Promise; + getCurrentlySignedInUserData(): Promise<{ + email: string; + name: string; + avatarUrl: string | null; + } | null>; } export default TurboModuleRegistry.getEnforcing('RNCloudFs'); diff --git a/native-modules/react-native-cloud-fs/src/index.tsx b/native-modules/react-native-cloud-fs/src/index.tsx index fbb02bb6..03f75c1c 100644 --- a/native-modules/react-native-cloud-fs/src/index.tsx +++ b/native-modules/react-native-cloud-fs/src/index.tsx @@ -1,4 +1,5 @@ import NativeCloudFs from './NativeCloudFs'; export const CloudFs = NativeCloudFs; +export default NativeCloudFs; export type { Spec as CloudFsSpec } from './NativeCloudFs'; From 81de6e36e9fd5c6b03aa72bcb14bd3f42d0e6aac Mon Sep 17 00:00:00 2001 From: huhuanming Date: Thu, 9 Apr 2026 20:52:05 +0800 Subject: [PATCH 64/74] 3.0.15 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index c8f27988..73609dd8 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index a318af8e..638842dd 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 4a951b48..1953daf8 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index d1595819..c676c9b1 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index a135f9d8..94bd734f 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 418280da..dba84ac4 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index 442fe8e8..bf80ab7d 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 4f1cec4a..6210bc94 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index f94fca17..743d6224 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 926f5de6..194848ef 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index fc1a7c22..d2b1a649 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 25fda547..b0ecdfb4 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 852920fb..aaeb0928 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 5efb7864..c37d625b 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.14", + "version": "3.0.15", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index deaf2b3f..24bc889b 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 571161a7..1d5703d1 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index b8dcb7eb..03c570f8 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 5003f088..ae93c5f6 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 6d00212f..53d380c9 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index f2f6dfac..13bf860e 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index d1b3fe1f..159253fe 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 668402e1..142e4c59 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 4cf89add..9f3514e1 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.14", + "version": "3.0.15", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index efbc342e..b8fd137b 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.14", + "version": "3.0.15", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 1bd73f8b..370425dc 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.14", + "version": "3.0.15", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index fe23f647..bc8e0ad9 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.14", + "version": "3.0.15", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 175ac439..aae2bd28 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.14", + "version": "3.0.15", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 975245e6fd5fa1b008ea38544b0e8bafef5fc4a6 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 00:59:40 +0800 Subject: [PATCH 65/74] Update RNCAsyncStorageModule.kt --- .../src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt index 903de6ae..3ebb9159 100644 --- a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt @@ -19,7 +19,7 @@ import java.util.concurrent.Executors */ @ReactModule(name = RNCAsyncStorageModule.NAME) class RNCAsyncStorageModule(reactContext: ReactApplicationContext) : - NativeRNCAsyncStorageSpec(reactContext) { + NativeAsyncStorageSpec(reactContext) { companion object { const val NAME = "RNCAsyncStorage" From 8b35bed318f4fbd824ecc56b45f864bf23ced6a7 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 01:00:42 +0800 Subject: [PATCH 66/74] 3.0.16 --- .../src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt | 2 +- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt index 8622fb4b..83629623 100644 --- a/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt +++ b/native-modules/native-logger/android/src/main/java/com/margelo/nitro/nativelogger/OneKeyLog.kt @@ -318,7 +318,7 @@ object OneKeyLog { synchronized(dedupLock) { val pending = repeatCount repeatCount = 0 - prevLogMessage = null + prevLogKey = null if (pending > 0) { val repeatMsg = "[$pending repeat]" diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 73609dd8..411680dc 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 638842dd..d8632c34 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 1953daf8..0cdbed41 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index c676c9b1..80dcb420 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 94bd734f..3b0cea3c 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index dba84ac4..e5762b73 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index bf80ab7d..e51ba674 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 6210bc94..76f7f0dc 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 743d6224..204e28bf 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 194848ef..999e77c5 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index d2b1a649..664d8236 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index b0ecdfb4..69b5b316 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index aaeb0928..41ca161c 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index c37d625b..53480549 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.15", + "version": "3.0.16", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 24bc889b..29bd6f04 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index 1d5703d1..c6e12a60 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 03c570f8..69555744 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index ae93c5f6..3e72f67f 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 53d380c9..5268237b 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 13bf860e..3c045809 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 159253fe..0f3ecc06 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 142e4c59..7d2e6c9c 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 9f3514e1..cf04d036 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.15", + "version": "3.0.16", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index b8fd137b..c7280607 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.15", + "version": "3.0.16", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index 370425dc..fa908831 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.15", + "version": "3.0.16", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index bc8e0ad9..469a251b 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.15", + "version": "3.0.16", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index aae2bd28..6b1e6788 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.15", + "version": "3.0.16", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 8cc2257817ea62222f16ae519fec7c81bca83e06 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 01:20:23 +0800 Subject: [PATCH 67/74] fix specs --- .../java/com/asyncstorage/RNCAsyncStorageModule.kt | 4 ++-- .../src/main/java/com/rncloudfs/RNCloudFsModule.kt | 12 ++++++------ .../main/java/com/rnsdnslookup/DnsLookupModule.kt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt index 3ebb9159..a82dd058 100644 --- a/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt +++ b/native-modules/react-native-async-storage/android/src/main/java/com/asyncstorage/RNCAsyncStorageModule.kt @@ -71,7 +71,7 @@ class RNCAsyncStorageModule(reactContext: ReactApplicationContext) : try { if (cursor.count != keys.size()) { for (keyIndex in keyStart until keyStart + keyCount) { - keysRemaining.add(keys.getString(keyIndex)) + keysRemaining.add(keys.getString(keyIndex) ?: "") } } if (cursor.moveToFirst()) { @@ -304,7 +304,7 @@ class RNCAsyncStorageModule(reactContext: ReactApplicationContext) : } private fun buildKeySelectionArgs(keys: ReadableArray, start: Int, count: Int): Array { - return Array(count) { keys.getString(start + it) } + return Array(count) { keys.getString(start + it) ?: "" } } private fun getItemImpl(key: String): String? { diff --git a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt index 83b59bcd..6ecea155 100644 --- a/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt +++ b/native-modules/react-native-cloud-fs/android/src/main/java/com/rncloudfs/RNCloudFsModule.kt @@ -18,7 +18,7 @@ import com.google.android.gms.auth.api.signin.GoogleSignInClient import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.Scope -import com.google.api.client.extensions.android.http.AndroidHttp +import com.google.api.client.http.javanet.NetHttpTransport import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException import com.google.api.client.json.gson.GsonFactory @@ -28,7 +28,7 @@ import java.util.Collections @ReactModule(name = RNCloudFsModule.NAME) class RNCloudFsModule(private val reactContext: ReactApplicationContext) : - NativeRNCloudFsSpec(reactContext), LifecycleEventListener, ActivityEventListener { + NativeCloudFsSpec(reactContext), LifecycleEventListener, ActivityEventListener { private var mDriveServiceHelper: DriveServiceHelper? = null private var signInPromise: Promise? = null @@ -86,7 +86,7 @@ class RNCloudFsModule(private val reactContext: ReactApplicationContext) : ) credential.selectedAccount = account.account val googleDriveService = Drive.Builder( - AndroidHttp.newCompatibleTransport(), + NetHttpTransport(), GsonFactory(), credential ).build() @@ -333,7 +333,7 @@ class RNCloudFsModule(private val reactContext: ReactApplicationContext) : mPendingOptions = null } - override fun onActivityResult(activity: Activity?, requestCode: Int, resultCode: Int, data: Intent?) { + override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { REQUEST_CODE_SIGN_IN -> { val task = GoogleSignIn.getSignedInAccountFromIntent(data) @@ -387,7 +387,7 @@ class RNCloudFsModule(private val reactContext: ReactApplicationContext) : ) credential.selectedAccount = googleAccount.account val googleDriveService = Drive.Builder( - AndroidHttp.newCompatibleTransport(), + NetHttpTransport(), GsonFactory(), credential ).build() @@ -410,7 +410,7 @@ class RNCloudFsModule(private val reactContext: ReactApplicationContext) : override fun onHostResume() {} override fun onHostPause() {} override fun onHostDestroy() {} - override fun onNewIntent(intent: Intent?) {} + override fun onNewIntent(intent: Intent) {} // endregion diff --git a/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt index cf0d529c..fd2a9e08 100644 --- a/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt +++ b/native-modules/react-native-dns-lookup/android/src/main/java/com/rnsdnslookup/DnsLookupModule.kt @@ -8,7 +8,7 @@ import java.net.InetAddress @ReactModule(name = DnsLookupModule.NAME) class DnsLookupModule(reactContext: ReactApplicationContext) : - NativeRNDnsLookupSpec(reactContext) { + NativeDnsLookupSpec(reactContext) { companion object { const val NAME = "RNDnsLookup" From 2bdbdfcea24d67c646947a899a8ddd4d4d4506e5 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 01:22:39 +0800 Subject: [PATCH 68/74] fix specs --- .../src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt | 2 +- .../android/src/main/java/com/rnping/RNReactNativePingModule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt index bb729690..3f39928a 100644 --- a/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt +++ b/native-modules/react-native-network-info/android/src/main/java/com/rnnetworkinfo/NetworkInfoModule.kt @@ -19,7 +19,7 @@ import java.net.NetworkInterface */ @ReactModule(name = NetworkInfoModule.NAME) class NetworkInfoModule(reactContext: ReactApplicationContext) : - NativeRNNetworkInfoSpec(reactContext) { + NativeNetworkInfoSpec(reactContext) { companion object { const val NAME = "RNNetworkInfo" diff --git a/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt index 17f5cdd3..dbea0219 100644 --- a/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt +++ b/native-modules/react-native-ping/android/src/main/java/com/rnping/RNReactNativePingModule.kt @@ -8,7 +8,7 @@ import java.net.InetAddress @ReactModule(name = RNReactNativePingModule.NAME) class RNReactNativePingModule(reactContext: ReactApplicationContext) : - NativeRNReactNativePingSpec(reactContext) { + NativePingSpec(reactContext) { companion object { const val NAME = "RNReactNativePing" From 22fcb2a8bc004d1b163e5da5ef4411e10efd2cb4 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 01:27:57 +0800 Subject: [PATCH 69/74] fix specs --- .../android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt | 2 +- .../src/main/java/com/rnziparchive/RNZipArchiveModule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt index 1b0a1c0f..52474e6f 100644 --- a/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt +++ b/native-modules/react-native-tcp-socket/android/src/main/java/com/rntcpsocket/RNTcpSocketModule.kt @@ -8,7 +8,7 @@ import java.net.Socket @ReactModule(name = RNTcpSocketModule.NAME) class RNTcpSocketModule(reactContext: ReactApplicationContext) : - NativeRNTcpSocketSpec(reactContext) { + NativeTcpSocketSpec(reactContext) { companion object { const val NAME = "RNTcpSocket" diff --git a/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt index d26f37f4..c2f41853 100644 --- a/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt +++ b/native-modules/react-native-zip-archive/android/src/main/java/com/rnziparchive/RNZipArchiveModule.kt @@ -16,7 +16,7 @@ import java.util.zip.ZipOutputStream @ReactModule(name = RNZipArchiveModule.NAME) class RNZipArchiveModule(reactContext: ReactApplicationContext) : - NativeRNZipArchiveSpec(reactContext) { + NativeZipArchiveSpec(reactContext) { companion object { const val NAME = "RNZipArchive" From 40ddd41f0599753266d33296870d1cea288e6f3b Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 01:28:34 +0800 Subject: [PATCH 70/74] 3.0.17 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index 411680dc..e7e97ef1 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index d8632c34..8e779b52 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index 0cdbed41..bfbd4685 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index 80dcb420..d5315d11 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index 3b0cea3c..fd712e80 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index e5762b73..4e4676da 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index e51ba674..b80cb854 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index 76f7f0dc..f440a16d 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 204e28bf..51fce1d8 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 999e77c5..302e6dbd 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 664d8236..3128d0f2 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 69b5b316..61f658bc 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 41ca161c..44268cd4 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 53480549..43f45f32 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.16", + "version": "3.0.17", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 29bd6f04..656647f0 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index c6e12a60..cae52c9b 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 69555744..83e2007f 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 3e72f67f..9a6dbb3e 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 5268237b..310a22f5 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 3c045809..1e8ac99e 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 0f3ecc06..6a82d54d 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 7d2e6c9c..4f13b8ee 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index cf04d036..6473b41e 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.16", + "version": "3.0.17", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index c7280607..b3d3fdaa 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.16", + "version": "3.0.17", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index fa908831..d0846120 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.16", + "version": "3.0.17", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index 469a251b..ae9cf661 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.16", + "version": "3.0.17", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 6b1e6788..4fd09144 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.16", + "version": "3.0.17", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js", From 718498d04d62e952753eaec93a0f7f15db39c870 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 16:59:25 +0800 Subject: [PATCH 71/74] Update cpp-adapter.cpp --- .../android/src/main/cpp/cpp-adapter.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index 365d3c72..a72fab42 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -86,6 +86,19 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeExecuteWork( } catch (const std::exception &e) { LOGE("Error in nativeExecuteWork: %s", e.what()); } + + // CRITICAL: Drain the Hermes microtask queue. React Native 0.74+ configures + // Hermes with an explicit microtask queue, which must be manually drained + // after each JS execution. Without this, Promise.then() / async-await + // continuations (including already-resolved promises) are never executed, + // causing all awaits to hang forever in the background runtime. + try { + rt->drainMicrotasks(); + } catch (const jsi::JSError &e) { + LOGE("JSError draining microtasks: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("Error draining microtasks: %s", e.what()); + } } // ── nativeInstallSharedBridge ─────────────────────────────────────────── From a234170ef4fad823c2e42c72c48dab53dfb21539 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 17:43:37 +0800 Subject: [PATCH 72/74] Update cpp-adapter.cpp --- .../android/src/main/cpp/cpp-adapter.cpp | 334 ++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index a72fab42..62cee619 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -1,10 +1,17 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include #include "SharedStore.h" #include "SharedRPC.h" @@ -101,6 +108,322 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeExecuteWork( } } +// ── Timer support for background runtime ────────────────────────────── +// The background Hermes runtime does NOT have working setTimeout/setInterval +// out of the box (RN's timer module only wires into the main runtime). We +// install our own JSI-level setTimeout/setInterval/clearTimeout/clearInterval +// backed by a single C++ worker thread that dispatches callbacks back to the +// background JS queue via the same executor used by SharedRPC. + +struct TimerEntry { + std::shared_ptr callback; + long long fireAtMs; // Absolute time in ms when the timer should fire. + long long intervalMs; // 0 if one-shot, >0 if setInterval period. + bool cancelled; +}; + +static std::mutex gTimerMutex; +static std::condition_variable gTimerCv; +static std::unordered_map gTimers; +static std::atomic gNextTimerId{1}; +static std::atomic gTimerWorkerStarted{false}; +static std::atomic gTimerWorkerStop{false}; +static RPCRuntimeExecutor gBgTimerExecutor; + +static long long nowMs() { + using namespace std::chrono; + return duration_cast( + steady_clock::now().time_since_epoch()) + .count(); +} + +static void fireTimerOnJsThread(int64_t timerId, jsi::Runtime &rt) { + std::shared_ptr cb; + long long intervalMs = 0; + bool shouldReschedule = false; + { + std::lock_guard lock(gTimerMutex); + auto it = gTimers.find(timerId); + if (it == gTimers.end()) return; + if (it->second.cancelled) { + gTimers.erase(it); + return; + } + cb = it->second.callback; + intervalMs = it->second.intervalMs; + shouldReschedule = intervalMs > 0; + if (shouldReschedule) { + // Schedule next fire + it->second.fireAtMs = nowMs() + intervalMs; + } else { + gTimers.erase(it); + } + } + if (shouldReschedule) { + gTimerCv.notify_all(); + } + try { + if (cb) cb->call(rt); + } catch (const jsi::JSError &e) { + LOGE("Timer callback JSError: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("Timer callback error: %s", e.what()); + } +} + +static void timerWorkerLoop() { + while (!gTimerWorkerStop.load()) { + std::unique_lock lock(gTimerMutex); + if (gTimers.empty()) { + gTimerCv.wait(lock, [] { + return gTimerWorkerStop.load() || !gTimers.empty(); + }); + if (gTimerWorkerStop.load()) return; + continue; + } + + // Find the earliest fireAt among non-cancelled timers. + long long earliest = LLONG_MAX; + for (auto &kv : gTimers) { + if (!kv.second.cancelled && kv.second.fireAtMs < earliest) { + earliest = kv.second.fireAtMs; + } + } + long long now = nowMs(); + if (earliest > now) { + gTimerCv.wait_for(lock, std::chrono::milliseconds(earliest - now)); + continue; + } + + // Collect timers ready to fire. + std::vector toFire; + for (auto &kv : gTimers) { + if (!kv.second.cancelled && kv.second.fireAtMs <= now) { + toFire.push_back(kv.first); + } + } + lock.unlock(); + + RPCRuntimeExecutor executor = gBgTimerExecutor; + if (!executor) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + for (auto id : toFire) { + executor([id](jsi::Runtime &rt) { fireTimerOnJsThread(id, rt); }); + } + } +} + +static void ensureTimerWorkerStarted() { + bool expected = false; + if (gTimerWorkerStarted.compare_exchange_strong(expected, true)) { + std::thread(timerWorkerLoop).detach(); + LOGI("Timer worker thread started"); + } +} + +static int64_t scheduleTimer( + std::shared_ptr cb, + double ms, + bool isInterval) { + int64_t id = gNextTimerId.fetch_add(1); + long long intervalMs = isInterval ? static_cast(ms) : 0; + long long delay = static_cast(ms); + if (delay < 0) delay = 0; + { + std::lock_guard lock(gTimerMutex); + gTimers[id] = TimerEntry{ + std::move(cb), + nowMs() + delay, + intervalMs, + false, + }; + } + gTimerCv.notify_all(); + ensureTimerWorkerStarted(); + return id; +} + +static void cancelTimer(int64_t id) { + { + std::lock_guard lock(gTimerMutex); + auto it = gTimers.find(id); + if (it != gTimers.end()) { + it->second.cancelled = true; + } + } + gTimerCv.notify_all(); +} + +static void installTimersOnRuntime(jsi::Runtime &rt) { + auto makeSetter = [](bool isInterval) { + return [isInterval]( + jsi::Runtime &rt, + const jsi::Value &, + const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isObject() || + !args[0].getObject(rt).isFunction(rt)) { + return jsi::Value::undefined(); + } + auto cb = std::make_shared( + args[0].getObject(rt).getFunction(rt)); + double ms = 0; + if (count >= 2 && args[1].isNumber()) { + ms = args[1].asNumber(); + } + int64_t id = scheduleTimer(std::move(cb), ms, isInterval); + return jsi::Value(static_cast(id)); + }; + }; + auto makeCanceller = []() { + return [](jsi::Runtime &rt, + const jsi::Value &, + const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isNumber()) { + return jsi::Value::undefined(); + } + int64_t id = static_cast(args[0].asNumber()); + cancelTimer(id); + return jsi::Value::undefined(); + }; + }; + + // requestAnimationFrame(cb): fires after ~16ms (60fps) with high-resolution + // timestamp arg, matching the DOM contract. Background runtime has no + // rendering concept, so we just approximate via setTimeout(16ms). + auto rafFn = [](jsi::Runtime &rt, + const jsi::Value &, + const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isObject() || + !args[0].getObject(rt).isFunction(rt)) { + return jsi::Value::undefined(); + } + // Wrap callback so it receives a DOMHighResTimeStamp-like arg. + auto userCb = std::make_shared( + args[0].getObject(rt).getFunction(rt)); + auto wrapper = jsi::Function::createFromHostFunction( + rt, + jsi::PropNameID::forAscii(rt, "rafWrapper"), + 0, + [userCb](jsi::Runtime &rt2, + const jsi::Value &, + const jsi::Value *, + size_t) -> jsi::Value { + try { + userCb->call(rt2, jsi::Value(static_cast(nowMs()))); + } catch (const jsi::JSError &e) { + LOGE("rAF callback JSError: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("rAF callback error: %s", e.what()); + } + return jsi::Value::undefined(); + }); + auto wrappedCb = std::make_shared(std::move(wrapper)); + int64_t id = scheduleTimer(std::move(wrappedCb), 16.0, false); + return jsi::Value(static_cast(id)); + }; + + // requestIdleCallback(cb, {timeout?}): fires "soon" with an IdleDeadline-ish + // object. Background runtime has no render frames to be idle between, so + // we approximate via setTimeout(1ms) and provide a deadline stub whose + // timeRemaining() always returns 50 (reasonable budget). + auto ricFn = [](jsi::Runtime &rt, + const jsi::Value &, + const jsi::Value *args, + size_t count) -> jsi::Value { + if (count < 1 || !args[0].isObject() || + !args[0].getObject(rt).isFunction(rt)) { + return jsi::Value::undefined(); + } + auto userCb = std::make_shared( + args[0].getObject(rt).getFunction(rt)); + auto wrapper = jsi::Function::createFromHostFunction( + rt, + jsi::PropNameID::forAscii(rt, "ricWrapper"), + 0, + [userCb](jsi::Runtime &rt2, + const jsi::Value &, + const jsi::Value *, + size_t) -> jsi::Value { + try { + // Build a minimal IdleDeadline: { didTimeout: false, + // timeRemaining: () => 50 }. + jsi::Object deadline(rt2); + deadline.setProperty(rt2, "didTimeout", jsi::Value(false)); + deadline.setProperty( + rt2, + "timeRemaining", + jsi::Function::createFromHostFunction( + rt2, + jsi::PropNameID::forAscii(rt2, "timeRemaining"), + 0, + [](jsi::Runtime &, + const jsi::Value &, + const jsi::Value *, + size_t) -> jsi::Value { + return jsi::Value(50.0); + })); + userCb->call(rt2, jsi::Value(rt2, std::move(deadline))); + } catch (const jsi::JSError &e) { + LOGE("rIC callback JSError: %s", e.getMessage().c_str()); + } catch (const std::exception &e) { + LOGE("rIC callback error: %s", e.what()); + } + return jsi::Value::undefined(); + }); + auto wrappedCb = std::make_shared(std::move(wrapper)); + int64_t id = scheduleTimer(std::move(wrappedCb), 1.0, false); + return jsi::Value(static_cast(id)); + }; + + auto global = rt.global(); + global.setProperty( + rt, "setTimeout", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "setTimeout"), 2, + makeSetter(false))); + global.setProperty( + rt, "setInterval", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "setInterval"), 2, + makeSetter(true))); + global.setProperty( + rt, "clearTimeout", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "clearTimeout"), 1, + makeCanceller())); + global.setProperty( + rt, "clearInterval", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "clearInterval"), 1, + makeCanceller())); + global.setProperty( + rt, "requestAnimationFrame", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "requestAnimationFrame"), 1, + rafFn)); + global.setProperty( + rt, "cancelAnimationFrame", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "cancelAnimationFrame"), 1, + makeCanceller())); + global.setProperty( + rt, "requestIdleCallback", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "requestIdleCallback"), 1, + ricFn)); + global.setProperty( + rt, "cancelIdleCallback", + jsi::Function::createFromHostFunction( + rt, jsi::PropNameID::forAscii(rt, "cancelIdleCallback"), 1, + makeCanceller())); + LOGI("Timer + rAF + rIC polyfills installed on bg runtime"); +} + // ── nativeInstallSharedBridge ─────────────────────────────────────────── // Install SharedStore and SharedRPC into a runtime. extern "C" JNIEXPORT void JNICALL @@ -158,9 +481,20 @@ Java_com_backgroundthread_BackgroundThreadManager_nativeInstallSharedBridge( }; std::string runtimeId = isMain ? "main" : "background"; + // Save the bg executor so our custom timer worker can dispatch callbacks + // back to the bg JS queue. We must do this BEFORE moving `executor` into + // SharedRPC::install (which will std::move it out). + if (!capturedIsMain) { + gBgTimerExecutor = executor; + } SharedRPC::install(*rt, std::move(executor), runtimeId); LOGI("SharedStore and SharedRPC installed (isMain=%d)", static_cast(isMain)); if (!capturedIsMain) { + // Install setTimeout/setInterval/clearTimeout/clearInterval on the + // background runtime. React Native's built-in timer module only wires + // into the main runtime, so without this, any `await wait(ms)` or + // setTimeout callback in the background thread would never fire. + installTimersOnRuntime(*rt); invokeOptionalGlobalFunction(*rt, "__setupBackgroundRPCHandler"); } } From f56d3f038f9c80c87c4e699ea55ada4fca79f52d Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 18:15:45 +0800 Subject: [PATCH 73/74] Update cpp-adapter.cpp --- .../android/src/main/cpp/cpp-adapter.cpp | 130 ++++++++++-------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp index 62cee619..a750f7ac 100644 --- a/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp +++ b/native-modules/react-native-background-thread/android/src/main/cpp/cpp-adapter.cpp @@ -137,80 +137,100 @@ static long long nowMs() { .count(); } -static void fireTimerOnJsThread(int64_t timerId, jsi::Runtime &rt) { - std::shared_ptr cb; - long long intervalMs = 0; - bool shouldReschedule = false; - { - std::lock_guard lock(gTimerMutex); - auto it = gTimers.find(timerId); - if (it == gTimers.end()) return; - if (it->second.cancelled) { - gTimers.erase(it); - return; - } - cb = it->second.callback; - intervalMs = it->second.intervalMs; - shouldReschedule = intervalMs > 0; - if (shouldReschedule) { - // Schedule next fire - it->second.fireAtMs = nowMs() + intervalMs; - } else { - gTimers.erase(it); - } - } - if (shouldReschedule) { - gTimerCv.notify_all(); - } +// Called on the bg JS thread. Executes the callback only; the worker has +// already erased (one-shot) or rescheduled (interval) the timer under lock. +static void fireTimerOnJsThread( + int64_t timerId, + std::shared_ptr cb, + jsi::Runtime &rt) { + if (!cb) return; try { - if (cb) cb->call(rt); + cb->call(rt); } catch (const jsi::JSError &e) { - LOGE("Timer callback JSError: %s", e.getMessage().c_str()); + LOGE("Timer %lld callback JSError: %s", (long long)timerId, + e.getMessage().c_str()); } catch (const std::exception &e) { - LOGE("Timer callback error: %s", e.what()); + LOGE("Timer %lld callback error: %s", (long long)timerId, e.what()); } } static void timerWorkerLoop() { while (!gTimerWorkerStop.load()) { - std::unique_lock lock(gTimerMutex); - if (gTimers.empty()) { - gTimerCv.wait(lock, [] { - return gTimerWorkerStop.load() || !gTimers.empty(); - }); - if (gTimerWorkerStop.load()) return; - continue; - } + // Snapshot of timers that should be dispatched this iteration and + // their callbacks. Captured under the lock; callbacks are invoked on + // the JS thread (not here). + std::vector>> toFire; + { + std::unique_lock lock(gTimerMutex); + if (gTimers.empty()) { + gTimerCv.wait(lock, [] { + return gTimerWorkerStop.load() || !gTimers.empty(); + }); + if (gTimerWorkerStop.load()) return; + continue; + } - // Find the earliest fireAt among non-cancelled timers. - long long earliest = LLONG_MAX; - for (auto &kv : gTimers) { - if (!kv.second.cancelled && kv.second.fireAtMs < earliest) { - earliest = kv.second.fireAtMs; + // Find the earliest fireAt among non-cancelled timers. + long long earliest = LLONG_MAX; + for (auto &kv : gTimers) { + if (!kv.second.cancelled && kv.second.fireAtMs < earliest) { + earliest = kv.second.fireAtMs; + } + } + long long now = nowMs(); + if (earliest == LLONG_MAX) { + // Only cancelled timers remain; clean them up. + for (auto it = gTimers.begin(); it != gTimers.end();) { + if (it->second.cancelled) it = gTimers.erase(it); + else ++it; + } + continue; + } + if (earliest > now) { + gTimerCv.wait_for( + lock, std::chrono::milliseconds(earliest - now)); + continue; } - } - long long now = nowMs(); - if (earliest > now) { - gTimerCv.wait_for(lock, std::chrono::milliseconds(earliest - now)); - continue; - } - // Collect timers ready to fire. - std::vector toFire; - for (auto &kv : gTimers) { - if (!kv.second.cancelled && kv.second.fireAtMs <= now) { - toFire.push_back(kv.first); + // Collect ready timers AND either erase (one-shot) or reschedule + // (interval) them RIGHT HERE under the lock. This is critical: + // if we wait to erase in fireTimerOnJsThread, the next worker + // iteration would immediately find the same timers still + // in-queue and re-dispatch them, causing an infinite flood of + // `scheduleOnJSThread` calls. + for (auto it = gTimers.begin(); it != gTimers.end();) { + if (it->second.cancelled) { + it = gTimers.erase(it); + continue; + } + if (it->second.fireAtMs <= now) { + toFire.emplace_back(it->first, it->second.callback); + if (it->second.intervalMs > 0) { + // Reschedule interval. Use `now + intervalMs` rather + // than `fireAtMs + intervalMs` so a slow fire path + // cannot produce an infinite backlog. + it->second.fireAtMs = now + it->second.intervalMs; + ++it; + } else { + it = gTimers.erase(it); + } + } else { + ++it; + } } } - lock.unlock(); RPCRuntimeExecutor executor = gBgTimerExecutor; if (!executor) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); continue; } - for (auto id : toFire) { - executor([id](jsi::Runtime &rt) { fireTimerOnJsThread(id, rt); }); + for (auto &pair : toFire) { + int64_t id = pair.first; + std::shared_ptr cb = pair.second; + executor([id, cb](jsi::Runtime &rt) { + fireTimerOnJsThread(id, cb, rt); + }); } } } From 90c98016d3cdef3189bce07b2807e1b76fb17514 Mon Sep 17 00:00:00 2001 From: huhuanming Date: Fri, 10 Apr 2026 18:16:53 +0800 Subject: [PATCH 74/74] 3.0.18 --- native-modules/native-logger/package.json | 2 +- native-modules/react-native-aes-crypto/package.json | 2 +- native-modules/react-native-app-update/package.json | 2 +- native-modules/react-native-async-storage/package.json | 2 +- native-modules/react-native-background-thread/package.json | 2 +- native-modules/react-native-bundle-update/package.json | 2 +- .../react-native-check-biometric-auth-changed/package.json | 2 +- native-modules/react-native-cloud-fs/package.json | 2 +- native-modules/react-native-cloud-kit-module/package.json | 2 +- native-modules/react-native-device-utils/package.json | 2 +- native-modules/react-native-dns-lookup/package.json | 2 +- native-modules/react-native-get-random-values/package.json | 2 +- native-modules/react-native-keychain-module/package.json | 2 +- native-modules/react-native-lite-card/package.json | 2 +- native-modules/react-native-network-info/package.json | 2 +- native-modules/react-native-pbkdf2/package.json | 2 +- native-modules/react-native-perf-memory/package.json | 2 +- native-modules/react-native-ping/package.json | 2 +- native-modules/react-native-splash-screen/package.json | 2 +- native-modules/react-native-split-bundle-loader/package.json | 2 +- native-modules/react-native-tcp-socket/package.json | 2 +- native-modules/react-native-zip-archive/package.json | 2 +- native-views/react-native-auto-size-input/package.json | 2 +- native-views/react-native-pager-view/package.json | 2 +- native-views/react-native-scroll-guard/package.json | 2 +- native-views/react-native-skeleton/package.json | 2 +- native-views/react-native-tab-view/package.json | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/native-modules/native-logger/package.json b/native-modules/native-logger/package.json index e7e97ef1..8ccbb6fb 100644 --- a/native-modules/native-logger/package.json +++ b/native-modules/native-logger/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-native-logger", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-native-logger", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-aes-crypto/package.json b/native-modules/react-native-aes-crypto/package.json index 8e779b52..292615aa 100644 --- a/native-modules/react-native-aes-crypto/package.json +++ b/native-modules/react-native-aes-crypto/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-aes-crypto", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-aes-crypto", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-app-update/package.json b/native-modules/react-native-app-update/package.json index bfbd4685..1d09d144 100644 --- a/native-modules/react-native-app-update/package.json +++ b/native-modules/react-native-app-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-app-update", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-app-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-async-storage/package.json b/native-modules/react-native-async-storage/package.json index d5315d11..8d8193a3 100644 --- a/native-modules/react-native-async-storage/package.json +++ b/native-modules/react-native-async-storage/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-async-storage", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-async-storage", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-background-thread/package.json b/native-modules/react-native-background-thread/package.json index fd712e80..0ecab15f 100644 --- a/native-modules/react-native-background-thread/package.json +++ b/native-modules/react-native-background-thread/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-background-thread", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-background-thread", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-bundle-update/package.json b/native-modules/react-native-bundle-update/package.json index 4e4676da..cba255c9 100644 --- a/native-modules/react-native-bundle-update/package.json +++ b/native-modules/react-native-bundle-update/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-bundle-update", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-bundle-update", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-check-biometric-auth-changed/package.json b/native-modules/react-native-check-biometric-auth-changed/package.json index b80cb854..ba1db1ac 100644 --- a/native-modules/react-native-check-biometric-auth-changed/package.json +++ b/native-modules/react-native-check-biometric-auth-changed/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-check-biometric-auth-changed", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-check-biometric-auth-changed", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-fs/package.json b/native-modules/react-native-cloud-fs/package.json index f440a16d..2b70fe75 100644 --- a/native-modules/react-native-cloud-fs/package.json +++ b/native-modules/react-native-cloud-fs/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-fs", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-cloud-fs TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-cloud-kit-module/package.json b/native-modules/react-native-cloud-kit-module/package.json index 51fce1d8..78df85a0 100644 --- a/native-modules/react-native-cloud-kit-module/package.json +++ b/native-modules/react-native-cloud-kit-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-cloud-kit-module", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-cloud-kit-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-device-utils/package.json b/native-modules/react-native-device-utils/package.json index 302e6dbd..fb7c78ec 100644 --- a/native-modules/react-native-device-utils/package.json +++ b/native-modules/react-native-device-utils/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-device-utils", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-device-utils", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-dns-lookup/package.json b/native-modules/react-native-dns-lookup/package.json index 3128d0f2..0cf96d4b 100644 --- a/native-modules/react-native-dns-lookup/package.json +++ b/native-modules/react-native-dns-lookup/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-dns-lookup", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-dns-lookup", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-get-random-values/package.json b/native-modules/react-native-get-random-values/package.json index 61f658bc..01d9a234 100644 --- a/native-modules/react-native-get-random-values/package.json +++ b/native-modules/react-native-get-random-values/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-get-random-values", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-get-random-values", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-keychain-module/package.json b/native-modules/react-native-keychain-module/package.json index 44268cd4..3dc41fae 100644 --- a/native-modules/react-native-keychain-module/package.json +++ b/native-modules/react-native-keychain-module/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-keychain-module", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-keychain-module", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-lite-card/package.json b/native-modules/react-native-lite-card/package.json index 43f45f32..c73d5fc5 100644 --- a/native-modules/react-native-lite-card/package.json +++ b/native-modules/react-native-lite-card/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-lite-card", - "version": "3.0.17", + "version": "3.0.18", "description": "lite card", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-network-info/package.json b/native-modules/react-native-network-info/package.json index 656647f0..b7acad05 100644 --- a/native-modules/react-native-network-info/package.json +++ b/native-modules/react-native-network-info/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-network-info", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-network-info", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-pbkdf2/package.json b/native-modules/react-native-pbkdf2/package.json index cae52c9b..525ebd94 100644 --- a/native-modules/react-native-pbkdf2/package.json +++ b/native-modules/react-native-pbkdf2/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pbkdf2", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-pbkdf2", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-perf-memory/package.json b/native-modules/react-native-perf-memory/package.json index 83e2007f..0bd9a361 100644 --- a/native-modules/react-native-perf-memory/package.json +++ b/native-modules/react-native-perf-memory/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-perf-memory", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-perf-memory", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-ping/package.json b/native-modules/react-native-ping/package.json index 9a6dbb3e..96be5a6b 100644 --- a/native-modules/react-native-ping/package.json +++ b/native-modules/react-native-ping/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-ping", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-ping TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-splash-screen/package.json b/native-modules/react-native-splash-screen/package.json index 310a22f5..c3ef0b76 100644 --- a/native-modules/react-native-splash-screen/package.json +++ b/native-modules/react-native-splash-screen/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-splash-screen", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-splash-screen", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-split-bundle-loader/package.json b/native-modules/react-native-split-bundle-loader/package.json index 1e8ac99e..ec26f604 100644 --- a/native-modules/react-native-split-bundle-loader/package.json +++ b/native-modules/react-native-split-bundle-loader/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-split-bundle-loader", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-split-bundle-loader", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-tcp-socket/package.json b/native-modules/react-native-tcp-socket/package.json index 6a82d54d..b03f3eb2 100644 --- a/native-modules/react-native-tcp-socket/package.json +++ b/native-modules/react-native-tcp-socket/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tcp-socket", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-tcp-socket", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-modules/react-native-zip-archive/package.json b/native-modules/react-native-zip-archive/package.json index 4f13b8ee..997e2792 100644 --- a/native-modules/react-native-zip-archive/package.json +++ b/native-modules/react-native-zip-archive/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-zip-archive", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-zip-archive TurboModule for OneKey", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-auto-size-input/package.json b/native-views/react-native-auto-size-input/package.json index 6473b41e..2218b8b8 100644 --- a/native-views/react-native-auto-size-input/package.json +++ b/native-views/react-native-auto-size-input/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-auto-size-input", - "version": "3.0.17", + "version": "3.0.18", "description": "Auto-sizing text input with font scaling, prefix and suffix support", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-pager-view/package.json b/native-views/react-native-pager-view/package.json index b3d3fdaa..0df87fa5 100644 --- a/native-views/react-native-pager-view/package.json +++ b/native-views/react-native-pager-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-pager-view", - "version": "3.0.17", + "version": "3.0.18", "description": "React Native wrapper for Android and iOS ViewPager", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/native-views/react-native-scroll-guard/package.json b/native-views/react-native-scroll-guard/package.json index d0846120..51bd5f6a 100644 --- a/native-views/react-native-scroll-guard/package.json +++ b/native-views/react-native-scroll-guard/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-scroll-guard", - "version": "3.0.17", + "version": "3.0.18", "description": "A native view wrapper that prevents parent scrollable containers (PagerView/ViewPager2) from intercepting child scroll gestures", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-skeleton/package.json b/native-views/react-native-skeleton/package.json index ae9cf661..4ca614ff 100644 --- a/native-views/react-native-skeleton/package.json +++ b/native-views/react-native-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-skeleton", - "version": "3.0.17", + "version": "3.0.18", "description": "react-native-skeleton", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", diff --git a/native-views/react-native-tab-view/package.json b/native-views/react-native-tab-view/package.json index 4fd09144..4924ed2b 100644 --- a/native-views/react-native-tab-view/package.json +++ b/native-views/react-native-tab-view/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/react-native-tab-view", - "version": "3.0.17", + "version": "3.0.18", "description": "Native Bottom Tabs for React Native (UIKit implementation)", "source": "./src/index.tsx", "main": "./lib/module/index.js",