react-native-bspatch 4.0.2 → 4.0.3
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.
- package/README.md +4 -3
- package/android/src/main/java/vn/reactnativebspatch/OtaBundleResolver.kt +16 -1
- package/ios/OtaBundleResolver.swift +17 -1
- package/lib/commonjs/ota/types.js.map +1 -1
- package/lib/module/ota/types.js.map +1 -1
- package/lib/typescript/ota/types.d.ts +2 -0
- package/lib/typescript/ota/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ota/types.ts +2 -0
package/README.md
CHANGED
|
@@ -273,13 +273,14 @@ The native `OtaBundleResolver` runs **before JS boots** on every cold start:
|
|
|
273
273
|
|
|
274
274
|
```
|
|
275
275
|
1. Read metadata.json
|
|
276
|
-
2. If lastLaunchSuccessful == false → rollback to previous version
|
|
276
|
+
2. If lastLaunchSuccessful == false → retry (see 7) or rollback to previous version
|
|
277
277
|
3. If currentVersion == baseAppVersion → use APK/IPA bundle
|
|
278
278
|
4. Otherwise → load OTA bundle from ota/v{version}/index.android.bundle (or main.jsbundle)
|
|
279
279
|
5. Unless this version is already verified: mark lastLaunchSuccessful = false (pending)
|
|
280
280
|
6. JS boots → OtaProvider renders the app → marks the running version healthy + verified
|
|
281
|
-
7. If that never happens (crash on load or first render
|
|
282
|
-
|
|
281
|
+
7. If that never happens (crash on load or first render, or the app is killed first) → next
|
|
282
|
+
boot retries the same version, up to 3 unverified launches in total; after that it rolls
|
|
283
|
+
back and records the version in failedVersions so it is never re-applied
|
|
283
284
|
8. A verified version is never rolled back later (a crash after it rendered is an app bug,
|
|
284
285
|
and killing the app during a download must not discard a good bundle)
|
|
285
286
|
```
|
|
@@ -16,7 +16,8 @@ import java.io.File
|
|
|
16
16
|
*
|
|
17
17
|
* Lifecycle:
|
|
18
18
|
* 1. Read metadata.json
|
|
19
|
-
* 2. If lastLaunchSuccessful == false →
|
|
19
|
+
* 2. If lastLaunchSuccessful == false → retry the same version up to MAX_LAUNCH_ATTEMPTS,
|
|
20
|
+
* then rollback to previous version
|
|
20
21
|
* 3. Mark current launch as pending (lastLaunchSuccessful = false)
|
|
21
22
|
* 4. Return the bundle path (or null for APK default)
|
|
22
23
|
* 5. JS marks healthy after first render → lastLaunchSuccessful = true, verifiedVersion = current
|
|
@@ -35,6 +36,8 @@ object OtaBundleResolver {
|
|
|
35
36
|
private const val METADATA_FILE = "metadata.json"
|
|
36
37
|
private const val DEFAULT_BASE_VERSION = 1
|
|
37
38
|
private const val MAX_ROLLBACK = 3
|
|
39
|
+
/** Unverified launches allowed before rollback: a kill before first render is indistinguishable from a crash */
|
|
40
|
+
private const val MAX_LAUNCH_ATTEMPTS = 3
|
|
38
41
|
|
|
39
42
|
/** Version this process booted (set by resolve), so markAsHealthy verifies only that one */
|
|
40
43
|
@Volatile private var launchedVersion: Int? = null
|
|
@@ -84,6 +87,16 @@ object OtaBundleResolver {
|
|
|
84
87
|
val verifiedVersion = metadata.optInt("verifiedVersion", -1)
|
|
85
88
|
|
|
86
89
|
// ── Step 1: Crash detection & rollback ──────────────────────────
|
|
90
|
+
val launchAttempts = metadata.optInt("launchAttempts", 1)
|
|
91
|
+
val currentBundle = File(File(otaDir, "v${currentVersion}"), "index.android.bundle")
|
|
92
|
+
if (!lastLaunchOk && currentVersion > baseVersion && launchAttempts < MAX_LAUNCH_ATTEMPTS &&
|
|
93
|
+
currentBundle.exists()) {
|
|
94
|
+
metadata.put("launchAttempts", launchAttempts + 1)
|
|
95
|
+
writeMetadata(metadataFile, metadata)
|
|
96
|
+
Log.w(TAG, "Previous launch of V$currentVersion not verified → retry ${launchAttempts + 1}/$MAX_LAUNCH_ATTEMPTS")
|
|
97
|
+
return currentBundle.absolutePath
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
if (!lastLaunchOk && currentVersion > baseVersion) {
|
|
88
101
|
Log.w(TAG, "Previous launch failed! Rolling back from V$currentVersion...")
|
|
89
102
|
// Remember the crashing version so JS never re-applies it
|
|
@@ -113,6 +126,7 @@ object OtaBundleResolver {
|
|
|
113
126
|
// Mark this rollback attempt as pending
|
|
114
127
|
if (newVersion != verifiedVersion) {
|
|
115
128
|
metadata.put("lastLaunchSuccessful", false)
|
|
129
|
+
metadata.put("launchAttempts", 1)
|
|
116
130
|
writeMetadata(metadataFile, metadata)
|
|
117
131
|
}
|
|
118
132
|
|
|
@@ -139,6 +153,7 @@ object OtaBundleResolver {
|
|
|
139
153
|
// the next boot will see false and trigger rollback
|
|
140
154
|
if (currentVersion != verifiedVersion) {
|
|
141
155
|
metadata.put("lastLaunchSuccessful", false)
|
|
156
|
+
metadata.put("launchAttempts", 1)
|
|
142
157
|
writeMetadata(metadataFile, metadata)
|
|
143
158
|
}
|
|
144
159
|
|
|
@@ -10,7 +10,8 @@ import Foundation
|
|
|
10
10
|
*
|
|
11
11
|
* Lifecycle:
|
|
12
12
|
* 1. Read metadata.json
|
|
13
|
-
* 2. If lastLaunchSuccessful == false →
|
|
13
|
+
* 2. If lastLaunchSuccessful == false → retry the same version up to maxLaunchAttempts,
|
|
14
|
+
* then rollback to previous version
|
|
14
15
|
* 3. Mark current launch as pending (lastLaunchSuccessful = false)
|
|
15
16
|
* 4. Return the bundle path (or nil for IPA default)
|
|
16
17
|
* 5. JS marks healthy after first render → lastLaunchSuccessful = true, verifiedVersion = current
|
|
@@ -34,6 +35,9 @@ public class OtaBundleResolver: NSObject {
|
|
|
34
35
|
private static let metadataFile = "metadata.json"
|
|
35
36
|
public static let defaultBaseVersion = 1
|
|
36
37
|
private static let maxRollback = 3
|
|
38
|
+
/// Unverified launches allowed before rollback: a kill before first render (e.g. a
|
|
39
|
+
/// background reload, then swiped away) is indistinguishable from a crash
|
|
40
|
+
private static let maxLaunchAttempts = 3
|
|
37
41
|
private static let maxRollbackIterations = 10 // Safety limit to prevent infinite loops
|
|
38
42
|
|
|
39
43
|
/// Version this process booted (set by resolve), so markAsHealthy verifies only that one
|
|
@@ -90,6 +94,16 @@ public class OtaBundleResolver: NSObject {
|
|
|
90
94
|
let verifiedVersion = metadata["verifiedVersion"] as? Int
|
|
91
95
|
|
|
92
96
|
// ── Step 1: Crash detection & rollback ──────────────────────────
|
|
97
|
+
let launchAttempts = metadata["launchAttempts"] as? Int ?? 1
|
|
98
|
+
let currentBundle = otaDir.appendingPathComponent("v\(currentVersion)/main.jsbundle")
|
|
99
|
+
if !lastLaunchOk && currentVersion > baseVersion && launchAttempts < maxLaunchAttempts
|
|
100
|
+
&& FileManager.default.fileExists(atPath: currentBundle.path) {
|
|
101
|
+
metadata["launchAttempts"] = launchAttempts + 1
|
|
102
|
+
writeMetadata(url: metadataURL, metadata: metadata)
|
|
103
|
+
NSLog("[OtaBundleResolver] Previous launch of V\(currentVersion) not verified → retry \(launchAttempts + 1)/\(maxLaunchAttempts)")
|
|
104
|
+
return currentBundle
|
|
105
|
+
}
|
|
106
|
+
|
|
93
107
|
if !lastLaunchOk && currentVersion > baseVersion {
|
|
94
108
|
NSLog("[OtaBundleResolver] Previous launch failed! Rolling back from V\(currentVersion)...")
|
|
95
109
|
|
|
@@ -118,6 +132,7 @@ public class OtaBundleResolver: NSObject {
|
|
|
118
132
|
// Mark this rollback attempt as pending
|
|
119
133
|
if newVersion != verifiedVersion {
|
|
120
134
|
metadata["lastLaunchSuccessful"] = false
|
|
135
|
+
metadata["launchAttempts"] = 1
|
|
121
136
|
writeMetadata(url: metadataURL, metadata: metadata)
|
|
122
137
|
}
|
|
123
138
|
|
|
@@ -143,6 +158,7 @@ public class OtaBundleResolver: NSObject {
|
|
|
143
158
|
// Mark launch as pending
|
|
144
159
|
if currentVersion != verifiedVersion {
|
|
145
160
|
metadata["lastLaunchSuccessful"] = false
|
|
161
|
+
metadata["launchAttempts"] = 1
|
|
146
162
|
writeMetadata(url: metadataURL, metadata: metadata)
|
|
147
163
|
}
|
|
148
164
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["OtaUpdateMode","exports","OtaStatus"],"sourceRoot":"../../../src","sources":["ota/types.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AAFA,IAuBYA,aAAa,GAAAC,OAAA,CAAAD,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAwCzB;AACA;AACA;AAFA,
|
|
1
|
+
{"version":3,"names":["OtaUpdateMode","exports","OtaStatus"],"sourceRoot":"../../../src","sources":["ota/types.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AAFA,IAuBYA,aAAa,GAAAC,OAAA,CAAAD,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAwCzB;AACA;AACA;AAFA,IA+EYE,SAAS,GAAAD,OAAA,CAAAC,SAAA,0BAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAAA,OAATA,SAAS;AAAA","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["OtaUpdateMode","OtaStatus"],"sourceRoot":"../../../src","sources":["ota/types.ts"],"mappings":";;AAAA;AACA;AACA;;AAqBA,WAAYA,aAAa,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;;AAwCzB;AACA;AACA;;
|
|
1
|
+
{"version":3,"names":["OtaUpdateMode","OtaStatus"],"sourceRoot":"../../../src","sources":["ota/types.ts"],"mappings":";;AAAA;AACA;AACA;;AAqBA,WAAYA,aAAa,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;;AAwCzB;AACA;AACA;;AA6EA,WAAYC,SAAS,0BAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAAA,OAATA,SAAS;AAAA","ignoreList":[]}
|
|
@@ -76,6 +76,8 @@ export type OtaMetadata = {
|
|
|
76
76
|
failedVersions?: number[];
|
|
77
77
|
/** Last version that launched and rendered successfully; the native resolver never rolls it back */
|
|
78
78
|
verifiedVersion?: number;
|
|
79
|
+
/** Unverified launches of currentVersion so far; native rolls back once it reaches the limit (3) */
|
|
80
|
+
launchAttempts?: number;
|
|
79
81
|
};
|
|
80
82
|
export type OtaMetrics = {
|
|
81
83
|
patchSizeKB: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ota/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEtD;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEvE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9E;AAED,oBAAY,aAAa;IACrB,MAAM,WAAW;IACjB,YAAY,iBAAiB;IAC7B,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;CAC9C;AAED,MAAM,MAAM,QAAQ,GAAG;IACnB,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACnB,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ota/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/ota/types.ts
CHANGED
|
@@ -84,6 +84,8 @@ export type OtaMetadata = {
|
|
|
84
84
|
failedVersions?: number[];
|
|
85
85
|
/** Last version that launched and rendered successfully; the native resolver never rolls it back */
|
|
86
86
|
verifiedVersion?: number;
|
|
87
|
+
/** Unverified launches of currentVersion so far; native rolls back once it reaches the limit (3) */
|
|
88
|
+
launchAttempts?: number;
|
|
87
89
|
};
|
|
88
90
|
|
|
89
91
|
export type OtaMetrics = {
|