pulse-updates 1.0.3 → 1.0.5
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.
|
@@ -99,6 +99,13 @@ class PulseController private constructor() {
|
|
|
99
99
|
private var embeddedManifest: EmbeddedManifest? = null
|
|
100
100
|
private val executor = Executors.newSingleThreadExecutor()
|
|
101
101
|
|
|
102
|
+
// Embedded asset hashes set for download optimization
|
|
103
|
+
internal val embeddedAssetHashes: Set<String>
|
|
104
|
+
get() = embeddedManifest?.assets
|
|
105
|
+
?.filter { !it.isLaunchAsset }
|
|
106
|
+
?.map { it.hash.lowercase() }
|
|
107
|
+
?.toSet() ?: emptySet()
|
|
108
|
+
|
|
102
109
|
// Native runtime version (from config, embedded manifest, or app version)
|
|
103
110
|
private val nativeRuntimeVersion: String
|
|
104
111
|
get() {
|
|
@@ -602,13 +609,19 @@ class PulseController private constructor() {
|
|
|
602
609
|
private fun loadEmbeddedManifest() {
|
|
603
610
|
val ctx = context ?: return
|
|
604
611
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
612
|
+
// Try pulse/ subdirectory first, then root
|
|
613
|
+
val paths = listOf("pulse/embedded-manifest.json", "embedded-manifest.json")
|
|
614
|
+
for (path in paths) {
|
|
615
|
+
try {
|
|
616
|
+
val json = ctx.assets.open(path).bufferedReader().use { it.readText() }
|
|
617
|
+
embeddedManifest = EmbeddedManifest.fromJson(json)
|
|
618
|
+
pulseLog(TAG, "Loaded embedded manifest from $path: ${embeddedManifest?.updateId}")
|
|
619
|
+
return
|
|
620
|
+
} catch (e: Exception) {
|
|
621
|
+
// Try next path
|
|
622
|
+
}
|
|
611
623
|
}
|
|
624
|
+
pulseLog(TAG, "No embedded manifest found")
|
|
612
625
|
}
|
|
613
626
|
|
|
614
627
|
private fun seedEmbeddedUpdateIfNeeded() {
|
|
@@ -1251,12 +1264,23 @@ object PulseRemoteLoader {
|
|
|
1251
1264
|
}
|
|
1252
1265
|
|
|
1253
1266
|
// Download assets and link them to the update
|
|
1267
|
+
val embeddedHashes = PulseController.getInstance().embeddedAssetHashes
|
|
1268
|
+
|
|
1254
1269
|
for (asset in manifest.assets) {
|
|
1255
1270
|
val assetHash = asset.hash.lowercase()
|
|
1256
1271
|
val assetDest = File(directory, "assets/sha256/$assetHash")
|
|
1257
1272
|
|
|
1258
|
-
//
|
|
1259
|
-
if (
|
|
1273
|
+
// Skip download if already cached
|
|
1274
|
+
if (assetDest.exists()) {
|
|
1275
|
+
// Asset already in cache, just link it
|
|
1276
|
+
}
|
|
1277
|
+
// Skip download if exists in embedded assets
|
|
1278
|
+
else if (embeddedHashes.contains(assetHash)) {
|
|
1279
|
+
pulseLog(TAG, "Asset ${assetHash.take(16)}... exists in embedded, skipping download")
|
|
1280
|
+
// Don't download - will use embedded fallback at runtime
|
|
1281
|
+
}
|
|
1282
|
+
// Download if not exists anywhere
|
|
1283
|
+
else {
|
|
1260
1284
|
try {
|
|
1261
1285
|
downloadFile(asset.url, assetDest, stagingDir)
|
|
1262
1286
|
|
|
@@ -323,13 +323,18 @@ class PulseAppLauncher(
|
|
|
323
323
|
// MARK: - Embedded Manifest
|
|
324
324
|
|
|
325
325
|
private fun loadEmbeddedManifest(): EmbeddedManifest? {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
326
|
+
// Try pulse/ subdirectory first, then root
|
|
327
|
+
val paths = listOf("pulse/embedded-manifest.json", "embedded-manifest.json")
|
|
328
|
+
for (path in paths) {
|
|
329
|
+
try {
|
|
330
|
+
val json = context.assets.open(path).bufferedReader().use { it.readText() }
|
|
331
|
+
return EmbeddedManifest.fromJson(json)
|
|
332
|
+
} catch (e: Exception) {
|
|
333
|
+
// Try next path
|
|
334
|
+
}
|
|
332
335
|
}
|
|
336
|
+
pulseLogWarn(TAG, "No embedded manifest found")
|
|
337
|
+
return null
|
|
333
338
|
}
|
|
334
339
|
|
|
335
340
|
// MARK: - Crypto
|
|
@@ -62,7 +62,8 @@ public final class PulseController {
|
|
|
62
62
|
|
|
63
63
|
// Embedded manifest cache
|
|
64
64
|
private var embeddedManifest: PulseEmbeddedManifest?
|
|
65
|
-
|
|
65
|
+
/// Embedded asset hashes map (hash -> file URL) - internal for download optimization
|
|
66
|
+
internal var embeddedAssetHashes: [String: URL] = [:]
|
|
66
67
|
private var embeddedBundleHash: String?
|
|
67
68
|
|
|
68
69
|
// MARK: - Native Config (from Info.plist, like expo-updates)
|
|
@@ -560,7 +561,9 @@ public final class PulseController {
|
|
|
560
561
|
}
|
|
561
562
|
|
|
562
563
|
private func loadEmbeddedManifest() {
|
|
563
|
-
|
|
564
|
+
// Try pulse/ subdirectory first, then root
|
|
565
|
+
guard let url = Bundle.main.url(forResource: "embedded-manifest", withExtension: "json", subdirectory: "pulse")
|
|
566
|
+
?? Bundle.main.url(forResource: "embedded-manifest", withExtension: "json"),
|
|
564
567
|
let data = try? Data(contentsOf: url),
|
|
565
568
|
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
|
|
566
569
|
pulseLog("No embedded manifest found")
|
|
@@ -1134,6 +1137,14 @@ final class PulseRemoteLoader {
|
|
|
1134
1137
|
continue
|
|
1135
1138
|
}
|
|
1136
1139
|
|
|
1140
|
+
// Already exists in embedded assets? Skip download and use embedded
|
|
1141
|
+
if PulseController.shared.embeddedAssetHashes[assetHash] != nil {
|
|
1142
|
+
pulseLog("Asset \(assetHash.prefix(16))... exists in embedded, skipping download")
|
|
1143
|
+
storeAssetInDatabase(asset: asset, hash: assetHash, database: database, updateId: updateId)
|
|
1144
|
+
group.leave()
|
|
1145
|
+
continue
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1137
1148
|
guard let url = URL(string: asset.url) else {
|
|
1138
1149
|
group.leave()
|
|
1139
1150
|
continue
|