@onekeyfe/react-native-split-bundle-loader 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "SplitBundleLoader"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
17
+ s.public_header_files = "ios/SBLLogger.h"
18
+
19
+ s.dependency 'ReactNativeNativeLogger'
20
+
21
+ install_modules_dependencies(s)
22
+ end
@@ -0,0 +1,77 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['SplitBundleLoader_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.2"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ }
16
+ }
17
+
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+
22
+ apply plugin: "com.facebook.react"
23
+
24
+ def getExtOrIntegerDefault(name) {
25
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["SplitBundleLoader_" + name]).toInteger()
26
+ }
27
+
28
+ android {
29
+ namespace "com.splitbundleloader"
30
+
31
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
32
+
33
+ defaultConfig {
34
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
35
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
36
+ }
37
+
38
+ buildFeatures {
39
+ buildConfig true
40
+ }
41
+
42
+ buildTypes {
43
+ release {
44
+ minifyEnabled false
45
+ }
46
+ }
47
+
48
+ lintOptions {
49
+ disable "GradleCompatible"
50
+ }
51
+
52
+ compileOptions {
53
+ sourceCompatibility JavaVersion.VERSION_1_8
54
+ targetCompatibility JavaVersion.VERSION_1_8
55
+ }
56
+
57
+ sourceSets {
58
+ main {
59
+ java.srcDirs += [
60
+ "generated/java",
61
+ "generated/jni"
62
+ ]
63
+ }
64
+ }
65
+ }
66
+
67
+ repositories {
68
+ mavenCentral()
69
+ google()
70
+ }
71
+
72
+ def kotlin_version = getExtOrDefault("kotlinVersion")
73
+
74
+ dependencies {
75
+ implementation "com.facebook.react:react-android"
76
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
77
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,55 @@
1
+ package com.splitbundleloader
2
+
3
+ /**
4
+ * Lightweight logging wrapper that dynamically dispatches to OneKeyLog.
5
+ * Uses reflection to avoid a hard dependency on the native-logger module.
6
+ * Falls back to android.util.Log when OneKeyLog is not available.
7
+ *
8
+ * Mirrors iOS SBLLogger.
9
+ */
10
+ object SBLLogger {
11
+ private const val TAG = "SplitBundleLoader"
12
+
13
+ private val logClass: Class<*>? by lazy {
14
+ try {
15
+ Class.forName("com.margelo.nitro.nativelogger.OneKeyLog")
16
+ } catch (_: ClassNotFoundException) {
17
+ null
18
+ }
19
+ }
20
+
21
+ private val methods by lazy {
22
+ val cls = logClass ?: return@lazy null
23
+ mapOf(
24
+ "debug" to cls.getMethod("debug", String::class.java, String::class.java),
25
+ "info" to cls.getMethod("info", String::class.java, String::class.java),
26
+ "warn" to cls.getMethod("warn", String::class.java, String::class.java),
27
+ "error" to cls.getMethod("error", String::class.java, String::class.java),
28
+ )
29
+ }
30
+
31
+ @JvmStatic
32
+ fun debug(message: String) = log("debug", message, android.util.Log.DEBUG)
33
+
34
+ @JvmStatic
35
+ fun info(message: String) = log("info", message, android.util.Log.INFO)
36
+
37
+ @JvmStatic
38
+ fun warn(message: String) = log("warn", message, android.util.Log.WARN)
39
+
40
+ @JvmStatic
41
+ fun error(message: String) = log("error", message, android.util.Log.ERROR)
42
+
43
+ private fun log(level: String, message: String, androidLogLevel: Int) {
44
+ val method = methods?.get(level)
45
+ if (method != null) {
46
+ try {
47
+ method.invoke(null, TAG, message)
48
+ return
49
+ } catch (_: Exception) {
50
+ // Fall through to android.util.Log
51
+ }
52
+ }
53
+ android.util.Log.println(androidLogLevel, TAG, message)
54
+ }
55
+ }
@@ -0,0 +1,199 @@
1
+ package com.splitbundleloader
2
+
3
+ import android.content.Context
4
+ import android.content.res.AssetManager
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.module.annotations.ReactModule
9
+ import java.io.File
10
+ import java.io.FileOutputStream
11
+ import java.io.IOException
12
+
13
+ /**
14
+ * TurboModule entry point for SplitBundleLoader.
15
+ *
16
+ * Provides two methods to JS:
17
+ * 1. getRuntimeBundleContext() — Returns current runtime's bundle paths and source kind
18
+ * 2. loadSegment(params) — Registers a HBC segment with the current Hermes runtime
19
+ *
20
+ * Mirrors iOS SplitBundleLoader.mm.
21
+ */
22
+ @ReactModule(name = SplitBundleLoaderModule.NAME)
23
+ class SplitBundleLoaderModule(reactContext: ReactApplicationContext) :
24
+ NativeSplitBundleLoaderSpec(reactContext) {
25
+
26
+ companion object {
27
+ const val NAME = "SplitBundleLoader"
28
+ private const val BUILTIN_EXTRACT_DIR = "onekey-builtin-segments"
29
+ }
30
+
31
+ override fun getName(): String = NAME
32
+
33
+ // -----------------------------------------------------------------------
34
+ // getRuntimeBundleContext
35
+ // -----------------------------------------------------------------------
36
+
37
+ override fun getRuntimeBundleContext(promise: Promise) {
38
+ try {
39
+ val context = reactApplicationContext
40
+ val runtimeKind = "main"
41
+ var sourceKind = "builtin"
42
+ var bundleRoot = ""
43
+ var nativeVersion = ""
44
+ val bundleVersion = ""
45
+
46
+ try {
47
+ nativeVersion = context.packageManager
48
+ .getPackageInfo(context.packageName, 0).versionName ?: ""
49
+ } catch (_: Exception) {
50
+ }
51
+
52
+ // Check OTA bundle path
53
+ val otaBundlePath = getOtaBundlePath()
54
+ if (!otaBundlePath.isNullOrEmpty()) {
55
+ val otaFile = File(otaBundlePath)
56
+ if (otaFile.exists()) {
57
+ sourceKind = "ota"
58
+ bundleRoot = otaFile.parent ?: ""
59
+ }
60
+ }
61
+
62
+ val builtinExtractRoot = File(
63
+ context.filesDir,
64
+ "$BUILTIN_EXTRACT_DIR/$nativeVersion"
65
+ ).absolutePath
66
+
67
+ val result = Arguments.createMap()
68
+ result.putString("runtimeKind", runtimeKind)
69
+ result.putString("sourceKind", sourceKind)
70
+ result.putString("bundleRoot", bundleRoot)
71
+ result.putString("builtinExtractRoot", builtinExtractRoot)
72
+ result.putString("nativeVersion", nativeVersion)
73
+ result.putString("bundleVersion", bundleVersion)
74
+
75
+ promise.resolve(result)
76
+ } catch (e: Exception) {
77
+ promise.reject("SPLIT_BUNDLE_CONTEXT_ERROR", e.message, e)
78
+ }
79
+ }
80
+
81
+ // -----------------------------------------------------------------------
82
+ // loadSegment
83
+ // -----------------------------------------------------------------------
84
+
85
+ override fun loadSegment(
86
+ segmentId: Double,
87
+ segmentKey: String,
88
+ relativePath: String,
89
+ sha256: String,
90
+ promise: Promise
91
+ ) {
92
+ try {
93
+ val segId = segmentId.toInt()
94
+
95
+ val absolutePath = resolveSegmentPath(relativePath)
96
+ if (absolutePath == null) {
97
+ promise.reject(
98
+ "SPLIT_BUNDLE_NOT_FOUND",
99
+ "Segment file not found: $relativePath (key=$segmentKey)"
100
+ )
101
+ return
102
+ }
103
+
104
+ // Register segment via CatalystInstance
105
+ val reactContext = reactApplicationContext
106
+ if (reactContext.hasCatalystInstance()) {
107
+ reactContext.catalystInstance.registerSegment(segId, absolutePath)
108
+ SBLLogger.info("Loaded segment $segmentKey (id=$segId)")
109
+ promise.resolve(null)
110
+ } else {
111
+ promise.reject(
112
+ "SPLIT_BUNDLE_NO_INSTANCE",
113
+ "CatalystInstance not available"
114
+ )
115
+ }
116
+ } catch (e: Exception) {
117
+ promise.reject("SPLIT_BUNDLE_LOAD_ERROR", e.message, e)
118
+ }
119
+ }
120
+
121
+ // -----------------------------------------------------------------------
122
+ // Path resolution helpers
123
+ // -----------------------------------------------------------------------
124
+
125
+ private fun resolveSegmentPath(relativePath: String): String? {
126
+ // 1. Try OTA bundle directory first
127
+ val otaBundlePath = getOtaBundlePath()
128
+ if (!otaBundlePath.isNullOrEmpty()) {
129
+ val otaRoot = File(otaBundlePath).parentFile
130
+ if (otaRoot != null) {
131
+ val candidate = File(otaRoot, relativePath)
132
+ if (candidate.exists()) {
133
+ return candidate.absolutePath
134
+ }
135
+ }
136
+ }
137
+
138
+ // 2. Try builtin: extract from assets if needed
139
+ return extractBuiltinSegmentIfNeeded(relativePath)
140
+ }
141
+
142
+ /**
143
+ * For Android builtin segments, APK assets can't be passed directly as file paths.
144
+ * Extract the asset to the extract cache directory on first access.
145
+ */
146
+ private fun extractBuiltinSegmentIfNeeded(relativePath: String): String? {
147
+ val context = reactApplicationContext
148
+ val nativeVersion = try {
149
+ context.packageManager
150
+ .getPackageInfo(context.packageName, 0).versionName ?: "unknown"
151
+ } catch (_: Exception) {
152
+ "unknown"
153
+ }
154
+
155
+ val extractDir = File(context.filesDir, "$BUILTIN_EXTRACT_DIR/$nativeVersion")
156
+ val extractedFile = File(extractDir, relativePath)
157
+
158
+ // Already extracted
159
+ if (extractedFile.exists()) {
160
+ return extractedFile.absolutePath
161
+ }
162
+
163
+ // Extract from assets
164
+ val assets: AssetManager = context.assets
165
+ return try {
166
+ assets.open(relativePath).use { input ->
167
+ extractedFile.parentFile?.let { parent ->
168
+ if (!parent.exists()) parent.mkdirs()
169
+ }
170
+ FileOutputStream(extractedFile).use { output ->
171
+ val buffer = ByteArray(8192)
172
+ var len: Int
173
+ while (input.read(buffer).also { len = it } != -1) {
174
+ output.write(buffer, 0, len)
175
+ }
176
+ }
177
+ }
178
+ extractedFile.absolutePath
179
+ } catch (_: IOException) {
180
+ null
181
+ }
182
+ }
183
+
184
+ private fun getOtaBundlePath(): String? {
185
+ return try {
186
+ val bundleUpdateStore = Class.forName(
187
+ "expo.modules.onekeybundleupdate.BundleUpdateStore"
188
+ )
189
+ val method = bundleUpdateStore.getMethod(
190
+ "getCurrentBundleMainJSBundle",
191
+ Context::class.java
192
+ )
193
+ val result = method.invoke(null, reactApplicationContext)
194
+ result?.toString()
195
+ } catch (_: Exception) {
196
+ null
197
+ }
198
+ }
199
+ }
@@ -0,0 +1,33 @@
1
+ package com.splitbundleloader
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class SplitBundleLoaderPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == SplitBundleLoaderModule.NAME) {
13
+ SplitBundleLoaderModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
20
+ return ReactModuleInfoProvider {
21
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
22
+ moduleInfos[SplitBundleLoaderModule.NAME] = ReactModuleInfo(
23
+ SplitBundleLoaderModule.NAME,
24
+ SplitBundleLoaderModule.NAME,
25
+ false, // canOverrideExistingModule
26
+ false, // needsEagerInit
27
+ false, // isCxxModule
28
+ true // isTurboModule
29
+ )
30
+ moduleInfos
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,16 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ /// Lightweight logging wrapper that dynamically dispatches to OneKeyLog.
6
+ /// Avoids `@import ReactNativeNativeLogger` which fails in .mm (Objective-C++) files.
7
+ @interface SBLLogger : NSObject
8
+
9
+ + (void)debug:(NSString *)message;
10
+ + (void)info:(NSString *)message;
11
+ + (void)warn:(NSString *)message;
12
+ + (void)error:(NSString *)message;
13
+
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,42 @@
1
+ #import "SBLLogger.h"
2
+
3
+ static NSString *const kTag = @"SplitBundleLoader";
4
+
5
+ @implementation SBLLogger
6
+
7
+ + (void)debug:(NSString *)message {
8
+ [self _log:@"debug::" message:message];
9
+ }
10
+
11
+ + (void)info:(NSString *)message {
12
+ [self _log:@"info::" message:message];
13
+ }
14
+
15
+ + (void)warn:(NSString *)message {
16
+ [self _log:@"warn::" message:message];
17
+ }
18
+
19
+ + (void)error:(NSString *)message {
20
+ [self _log:@"error::" message:message];
21
+ }
22
+
23
+ #pragma mark - Private
24
+
25
+ + (void)_log:(NSString *)selectorName message:(NSString *)message {
26
+ Class logClass = NSClassFromString(@"ReactNativeNativeLogger.OneKeyLog");
27
+ if (!logClass) {
28
+ logClass = NSClassFromString(@"OneKeyLog");
29
+ }
30
+ if (!logClass) {
31
+ return;
32
+ }
33
+ SEL sel = NSSelectorFromString(selectorName);
34
+ if (![logClass respondsToSelector:sel]) {
35
+ return;
36
+ }
37
+ typedef void (*LogFunc)(id, SEL, NSString *, NSString *);
38
+ LogFunc func = (LogFunc)[logClass methodForSelector:sel];
39
+ func(logClass, sel, kTag, message);
40
+ }
41
+
42
+ @end
@@ -0,0 +1,14 @@
1
+ #import <SplitBundleLoaderSpec/SplitBundleLoaderSpec.h>
2
+
3
+ @interface SplitBundleLoader : NativeSplitBundleLoaderSpecBase <NativeSplitBundleLoaderSpec>
4
+
5
+ - (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve
6
+ reject:(RCTPromiseRejectBlock)reject;
7
+ - (void)loadSegment:(double)segmentId
8
+ segmentKey:(NSString *)segmentKey
9
+ relativePath:(NSString *)relativePath
10
+ sha256:(NSString *)sha256
11
+ resolve:(RCTPromiseResolveBlock)resolve
12
+ reject:(RCTPromiseRejectBlock)reject;
13
+
14
+ @end
@@ -0,0 +1,149 @@
1
+ #import "SplitBundleLoader.h"
2
+ #import "SBLLogger.h"
3
+ #import <React/RCTBridge.h>
4
+
5
+ @implementation SplitBundleLoader
6
+
7
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
8
+ (const facebook::react::ObjCTurboModule::InitParams &)params
9
+ {
10
+ [SBLLogger info:@"SplitBundleLoader module initialized"];
11
+ return std::make_shared<facebook::react::NativeSplitBundleLoaderSpecJSI>(params);
12
+ }
13
+
14
+ + (NSString *)moduleName
15
+ {
16
+ return @"SplitBundleLoader";
17
+ }
18
+
19
+ + (BOOL)requiresMainQueueSetup
20
+ {
21
+ return NO;
22
+ }
23
+
24
+ // MARK: - getRuntimeBundleContext
25
+
26
+ - (void)getRuntimeBundleContext:(RCTPromiseResolveBlock)resolve
27
+ reject:(RCTPromiseRejectBlock)reject
28
+ {
29
+ @try {
30
+ NSString *runtimeKind = @"main";
31
+ NSString *sourceKind = @"builtin";
32
+ NSString *bundleRoot = @"";
33
+ NSString *nativeVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] ?: @"";
34
+ NSString *bundleVersion = @"";
35
+
36
+ // Check if OTA bundle is active via BundleUpdateStore
37
+ Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore");
38
+ if (bundleUpdateStoreClass) {
39
+ NSString *otaBundlePath = nil;
40
+ SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle");
41
+ if ([bundleUpdateStoreClass respondsToSelector:sel]) {
42
+ #pragma clang diagnostic push
43
+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
44
+ id result = [bundleUpdateStoreClass performSelector:sel];
45
+ #pragma clang diagnostic pop
46
+ otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil;
47
+ }
48
+ if (otaBundlePath && otaBundlePath.length > 0) {
49
+ NSString *filePath = otaBundlePath;
50
+ if ([otaBundlePath hasPrefix:@"file://"]) {
51
+ filePath = [[NSURL URLWithString:otaBundlePath] path];
52
+ }
53
+ if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
54
+ sourceKind = @"ota";
55
+ bundleRoot = [filePath stringByDeletingLastPathComponent];
56
+ }
57
+ }
58
+ }
59
+
60
+ // Builtin: use main bundle resource path
61
+ if ([sourceKind isEqualToString:@"builtin"]) {
62
+ bundleRoot = [[NSBundle mainBundle] resourcePath] ?: @"";
63
+ }
64
+
65
+ resolve(@{
66
+ @"runtimeKind": runtimeKind,
67
+ @"sourceKind": sourceKind,
68
+ @"bundleRoot": bundleRoot,
69
+ @"nativeVersion": nativeVersion,
70
+ @"bundleVersion": bundleVersion,
71
+ });
72
+ } @catch (NSException *exception) {
73
+ reject(@"SPLIT_BUNDLE_CONTEXT_ERROR", exception.reason, nil);
74
+ }
75
+ }
76
+
77
+ // MARK: - loadSegment
78
+
79
+ - (void)loadSegment:(double)segmentId
80
+ segmentKey:(NSString *)segmentKey
81
+ relativePath:(NSString *)relativePath
82
+ sha256:(NSString *)sha256
83
+ resolve:(RCTPromiseResolveBlock)resolve
84
+ reject:(RCTPromiseRejectBlock)reject
85
+ {
86
+ @try {
87
+ int segId = (int)segmentId;
88
+
89
+ // Resolve absolute path
90
+ NSString *absolutePath = nil;
91
+
92
+ // 1. Try OTA bundle root first
93
+ Class bundleUpdateStoreClass = NSClassFromString(@"ReactNativeBundleUpdate.BundleUpdateStore");
94
+ if (bundleUpdateStoreClass) {
95
+ NSString *otaBundlePath = nil;
96
+ SEL sel = NSSelectorFromString(@"currentBundleMainJSBundle");
97
+ if ([bundleUpdateStoreClass respondsToSelector:sel]) {
98
+ #pragma clang diagnostic push
99
+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
100
+ id result = [bundleUpdateStoreClass performSelector:sel];
101
+ #pragma clang diagnostic pop
102
+ otaBundlePath = [result isKindOfClass:[NSString class]] ? (NSString *)result : nil;
103
+ }
104
+ if (otaBundlePath && otaBundlePath.length > 0) {
105
+ NSString *filePath = otaBundlePath;
106
+ if ([otaBundlePath hasPrefix:@"file://"]) {
107
+ filePath = [[NSURL URLWithString:otaBundlePath] path];
108
+ }
109
+ NSString *otaRoot = [filePath stringByDeletingLastPathComponent];
110
+ NSString *candidate = [otaRoot stringByAppendingPathComponent:relativePath];
111
+ if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) {
112
+ absolutePath = candidate;
113
+ }
114
+ }
115
+ }
116
+
117
+ // 2. Fallback to builtin resource path
118
+ if (!absolutePath) {
119
+ NSString *builtinRoot = [[NSBundle mainBundle] resourcePath];
120
+ NSString *candidate = [builtinRoot stringByAppendingPathComponent:relativePath];
121
+ if ([[NSFileManager defaultManager] fileExistsAtPath:candidate]) {
122
+ absolutePath = candidate;
123
+ }
124
+ }
125
+
126
+ if (!absolutePath) {
127
+ reject(@"SPLIT_BUNDLE_NOT_FOUND",
128
+ [NSString stringWithFormat:@"Segment file not found: %@ (key=%@)", relativePath, segmentKey],
129
+ nil);
130
+ return;
131
+ }
132
+
133
+ // Register segment via RCTBridge
134
+ RCTBridge *bridge = [RCTBridge currentBridge];
135
+ if (bridge) {
136
+ [bridge registerSegmentWithId:@(segId) path:absolutePath];
137
+ [SBLLogger info:[NSString stringWithFormat:@"Loaded segment %@ (id=%d)", segmentKey, segId]];
138
+ resolve(nil);
139
+ } else {
140
+ reject(@"SPLIT_BUNDLE_NO_BRIDGE", @"RCTBridge not available", nil);
141
+ }
142
+ } @catch (NSException *exception) {
143
+ reject(@"SPLIT_BUNDLE_LOAD_ERROR",
144
+ [NSString stringWithFormat:@"Failed to load segment %@: %@", segmentKey, exception.reason],
145
+ nil);
146
+ }
147
+ }
148
+
149
+ @end
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.getEnforcing('SplitBundleLoader');
5
+ //# sourceMappingURL=NativeSplitBundleLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeSplitBundleLoader.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAqBlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,mBAAmB,CAAC","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import NativeSplitBundleLoader from "./NativeSplitBundleLoader.js";
4
+ export const SplitBundleLoader = NativeSplitBundleLoader;
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeSplitBundleLoader","SplitBundleLoader"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,uBAAuB,MAAM,8BAA2B;AAE/D,OAAO,MAAMC,iBAAiB,GAAGD,uBAAuB","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,15 @@
1
+ import type { TurboModule } from 'react-native';
2
+ export interface Spec extends TurboModule {
3
+ getRuntimeBundleContext(): Promise<{
4
+ runtimeKind: string;
5
+ sourceKind: string;
6
+ bundleRoot: string;
7
+ builtinExtractRoot?: string;
8
+ nativeVersion: string;
9
+ bundleVersion?: string;
10
+ }>;
11
+ loadSegment(segmentId: number, segmentKey: string, relativePath: string, sha256: string): Promise<void>;
12
+ }
13
+ declare const _default: Spec;
14
+ export default _default;
15
+ //# sourceMappingURL=NativeSplitBundleLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeSplitBundleLoader.d.ts","sourceRoot":"","sources":["../../../src/NativeSplitBundleLoader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,uBAAuB,IAAI,OAAO,CAAC;QACjC,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC,CAAC;IACH,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;;AAED,wBAA2E"}
@@ -0,0 +1,3 @@
1
+ export declare const SplitBundleLoader: import("./NativeSplitBundleLoader").Spec;
2
+ export type { Spec as SplitBundleLoaderSpec } from './NativeSplitBundleLoader';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,0CAA0B,CAAC;AACzD,YAAY,EAAE,IAAI,IAAI,qBAAqB,EAAE,MAAM,2BAA2B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,162 @@
1
+ {
2
+ "name": "@onekeyfe/react-native-split-bundle-loader",
3
+ "version": "0.1.1",
4
+ "description": "react-native-split-bundle-loader",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "src",
17
+ "lib",
18
+ "android",
19
+ "ios",
20
+ "*.podspec",
21
+ "!ios/build",
22
+ "!android/build",
23
+ "!android/gradle",
24
+ "!android/gradlew",
25
+ "!android/gradlew.bat",
26
+ "!android/local.properties",
27
+ "!**/__tests__",
28
+ "!**/__fixtures__",
29
+ "!**/__mocks__",
30
+ "!**/.*"
31
+ ],
32
+ "scripts": {
33
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
34
+ "prepare": "bob build",
35
+ "typecheck": "tsc",
36
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
37
+ "test": "jest",
38
+ "release": "yarn prepare && npm whoami && npm publish --access public"
39
+ },
40
+ "keywords": [
41
+ "react-native",
42
+ "ios",
43
+ "android"
44
+ ],
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader.git"
48
+ },
49
+ "author": "@onekeyhq <huanming@onekey.so> (https://github.com/OneKeyHQ/app-modules)",
50
+ "license": "MIT",
51
+ "bugs": {
52
+ "url": "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader/issues"
53
+ },
54
+ "homepage": "https://github.com/OneKeyHQ/app-modules/react-native-split-bundle-loader#readme",
55
+ "publishConfig": {
56
+ "registry": "https://registry.npmjs.org/"
57
+ },
58
+ "devDependencies": {
59
+ "@commitlint/config-conventional": "^19.8.1",
60
+ "@eslint/compat": "^1.3.2",
61
+ "@eslint/eslintrc": "^3.3.1",
62
+ "@eslint/js": "^9.35.0",
63
+ "@react-native/babel-preset": "0.83.0",
64
+ "@react-native/eslint-config": "0.83.0",
65
+ "@release-it/conventional-changelog": "^10.0.1",
66
+ "@types/jest": "^29.5.14",
67
+ "@types/react": "^19.2.0",
68
+ "commitlint": "^19.8.1",
69
+ "del-cli": "^6.0.0",
70
+ "eslint": "^9.35.0",
71
+ "eslint-config-prettier": "^10.1.8",
72
+ "eslint-plugin-prettier": "^5.5.4",
73
+ "jest": "^29.7.0",
74
+ "lefthook": "^2.0.3",
75
+ "prettier": "^2.8.8",
76
+ "react": "19.2.0",
77
+ "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch",
78
+ "react-native-builder-bob": "^0.40.17",
79
+ "release-it": "^19.0.4",
80
+ "turbo": "^2.5.6",
81
+ "typescript": "^5.9.2"
82
+ },
83
+ "peerDependencies": {
84
+ "react": "*",
85
+ "react-native": "*"
86
+ },
87
+ "react-native-builder-bob": {
88
+ "source": "src",
89
+ "output": "lib",
90
+ "targets": [
91
+ [
92
+ "module",
93
+ {
94
+ "esm": true
95
+ }
96
+ ],
97
+ [
98
+ "typescript",
99
+ {
100
+ "project": "tsconfig.build.json"
101
+ }
102
+ ]
103
+ ]
104
+ },
105
+ "codegenConfig": {
106
+ "name": "SplitBundleLoaderSpec",
107
+ "type": "modules",
108
+ "jsSrcsDir": "src",
109
+ "android": {
110
+ "javaPackageName": "com.splitbundleloader"
111
+ }
112
+ },
113
+ "prettier": {
114
+ "quoteProps": "consistent",
115
+ "singleQuote": true,
116
+ "tabWidth": 2,
117
+ "trailingComma": "es5",
118
+ "useTabs": false
119
+ },
120
+ "jest": {
121
+ "preset": "react-native",
122
+ "modulePathIgnorePatterns": [
123
+ "<rootDir>/example/node_modules",
124
+ "<rootDir>/lib/"
125
+ ]
126
+ },
127
+ "commitlint": {
128
+ "extends": [
129
+ "@commitlint/config-conventional"
130
+ ]
131
+ },
132
+ "release-it": {
133
+ "git": {
134
+ "commitMessage": "chore: release ${version}",
135
+ "tagName": "v${version}"
136
+ },
137
+ "npm": {
138
+ "publish": true
139
+ },
140
+ "github": {
141
+ "release": true
142
+ },
143
+ "plugins": {
144
+ "@release-it/conventional-changelog": {
145
+ "preset": {
146
+ "name": "angular"
147
+ }
148
+ }
149
+ }
150
+ },
151
+ "create-react-native-library": {
152
+ "type": "turbo-module",
153
+ "languages": "kotlin-objc",
154
+ "tools": [
155
+ "eslint",
156
+ "jest",
157
+ "lefthook",
158
+ "release-it"
159
+ ],
160
+ "version": "0.56.0"
161
+ }
162
+ }
@@ -0,0 +1,22 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+
3
+ import type { TurboModule } from 'react-native';
4
+
5
+ export interface Spec extends TurboModule {
6
+ getRuntimeBundleContext(): Promise<{
7
+ runtimeKind: string;
8
+ sourceKind: string;
9
+ bundleRoot: string;
10
+ builtinExtractRoot?: string;
11
+ nativeVersion: string;
12
+ bundleVersion?: string;
13
+ }>;
14
+ loadSegment(
15
+ segmentId: number,
16
+ segmentKey: string,
17
+ relativePath: string,
18
+ sha256: string,
19
+ ): Promise<void>;
20
+ }
21
+
22
+ export default TurboModuleRegistry.getEnforcing<Spec>('SplitBundleLoader');
package/src/index.tsx ADDED
@@ -0,0 +1,4 @@
1
+ import NativeSplitBundleLoader from './NativeSplitBundleLoader';
2
+
3
+ export const SplitBundleLoader = NativeSplitBundleLoader;
4
+ export type { Spec as SplitBundleLoaderSpec } from './NativeSplitBundleLoader';