@hot-updater/react-native 1.0.0-rc.3 → 1.0.0-rc.31

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.
Files changed (300) hide show
  1. package/android/proguard-rules.pro +17 -2
  2. package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
  3. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +954 -837
  4. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +15 -11
  5. package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
  6. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +287 -22
  7. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +43 -31
  8. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
  9. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
  10. package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
  11. package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
  12. package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
  13. package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
  14. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +127 -50
  15. package/android/src/main/java/com/hotupdater/PreviousProcessExit.kt +89 -0
  16. package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -0
  17. package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
  18. package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
  19. package/android/src/newarch/HotUpdater.kt +7 -9
  20. package/android/src/newarch/HotUpdaterModule.kt +109 -84
  21. package/android/src/oldarch/HotUpdater.kt +7 -9
  22. package/android/src/oldarch/HotUpdaterModule.kt +98 -74
  23. package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
  24. package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
  25. package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
  26. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +950 -1112
  27. package/ios/HotUpdater/Internal/BundleMetadata.swift +8 -53
  28. package/ios/HotUpdater/Internal/FileManagerService.swift +48 -0
  29. package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
  30. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
  31. package/ios/HotUpdater/Internal/HotUpdater.mm +13 -45
  32. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +190 -73
  33. package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
  34. package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
  35. package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
  36. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +119 -71
  37. package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
  38. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
  39. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
  40. package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
  41. package/lib/commonjs/appReady.js +111 -0
  42. package/lib/commonjs/appReady.js.map +1 -0
  43. package/lib/commonjs/checkForUpdate.js +124 -69
  44. package/lib/commonjs/checkForUpdate.js.map +1 -1
  45. package/lib/commonjs/clientPlugin.js +13 -0
  46. package/lib/commonjs/clientPlugin.js.map +1 -0
  47. package/lib/commonjs/error.js +4 -13
  48. package/lib/commonjs/error.js.map +1 -1
  49. package/lib/commonjs/fetchJSON.js +16 -27
  50. package/lib/commonjs/fetchJSON.js.map +1 -1
  51. package/lib/commonjs/fetchUpdateResponse.js +54 -0
  52. package/lib/commonjs/fetchUpdateResponse.js.map +1 -0
  53. package/lib/commonjs/httpClient.js +63 -94
  54. package/lib/commonjs/httpClient.js.map +1 -1
  55. package/lib/commonjs/index.js +71 -18
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/commonjs/native.js +78 -60
  58. package/lib/commonjs/native.js.map +1 -1
  59. package/lib/commonjs/pluginHost.js +44 -0
  60. package/lib/commonjs/pluginHost.js.map +1 -0
  61. package/lib/commonjs/releaseCatalogCache.js +36 -87
  62. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  63. package/lib/commonjs/sdkVersion.js +1 -1
  64. package/lib/commonjs/sdkVersion.js.map +1 -1
  65. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  66. package/lib/commonjs/store.js +3 -10
  67. package/lib/commonjs/store.js.map +1 -1
  68. package/lib/commonjs/updateError.js +132 -0
  69. package/lib/commonjs/updateError.js.map +1 -0
  70. package/lib/commonjs/wrap.js +43 -26
  71. package/lib/commonjs/wrap.js.map +1 -1
  72. package/lib/module/appReady.js +103 -0
  73. package/lib/module/appReady.js.map +1 -0
  74. package/lib/module/checkForUpdate.js +117 -64
  75. package/lib/module/checkForUpdate.js.map +1 -1
  76. package/lib/module/clientPlugin.js +4 -0
  77. package/lib/module/clientPlugin.js.map +1 -0
  78. package/lib/module/error.js +4 -13
  79. package/lib/module/error.js.map +1 -1
  80. package/lib/module/fetchJSON.js +14 -26
  81. package/lib/module/fetchJSON.js.map +1 -1
  82. package/lib/module/fetchUpdateResponse.js +49 -0
  83. package/lib/module/fetchUpdateResponse.js.map +1 -0
  84. package/lib/module/httpClient.js +62 -93
  85. package/lib/module/httpClient.js.map +1 -1
  86. package/lib/module/index.js +58 -20
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/native.js +71 -53
  89. package/lib/module/native.js.map +1 -1
  90. package/lib/module/pluginHost.js +35 -0
  91. package/lib/module/pluginHost.js.map +1 -0
  92. package/lib/module/releaseCatalogCache.js +32 -82
  93. package/lib/module/releaseCatalogCache.js.map +1 -1
  94. package/lib/module/sdkVersion.js +1 -1
  95. package/lib/module/sdkVersion.js.map +1 -1
  96. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  97. package/lib/module/store.js +3 -10
  98. package/lib/module/store.js.map +1 -1
  99. package/lib/module/updateError.js +126 -0
  100. package/lib/module/updateError.js.map +1 -0
  101. package/lib/module/wrap.js +43 -26
  102. package/lib/module/wrap.js.map +1 -1
  103. package/lib/typescript/commonjs/appReady.d.ts +23 -0
  104. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/checkForUpdate.d.ts +16 -4
  106. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
  108. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/error.d.ts +4 -13
  110. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/fetchJSON.d.ts +5 -5
  112. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
  114. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/httpClient.d.ts +4 -33
  116. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/index.d.ts +4 -8
  118. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/native.d.ts +31 -22
  120. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/pluginHost.d.ts +4 -0
  122. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
  124. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  126. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +42 -47
  128. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/store.d.ts +1 -3
  130. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/types.d.ts +1 -1
  132. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  134. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  136. package/lib/typescript/commonjs/wrap.types.d.ts +6 -7
  137. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  138. package/lib/typescript/module/appReady.d.ts +23 -0
  139. package/lib/typescript/module/appReady.d.ts.map +1 -0
  140. package/lib/typescript/module/checkForUpdate.d.ts +16 -4
  141. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  142. package/lib/typescript/module/clientPlugin.d.ts +2 -0
  143. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  144. package/lib/typescript/module/error.d.ts +4 -13
  145. package/lib/typescript/module/error.d.ts.map +1 -1
  146. package/lib/typescript/module/fetchJSON.d.ts +5 -5
  147. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  148. package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
  149. package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
  150. package/lib/typescript/module/httpClient.d.ts +4 -33
  151. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  152. package/lib/typescript/module/index.d.ts +4 -8
  153. package/lib/typescript/module/index.d.ts.map +1 -1
  154. package/lib/typescript/module/native.d.ts +31 -22
  155. package/lib/typescript/module/native.d.ts.map +1 -1
  156. package/lib/typescript/module/pluginHost.d.ts +4 -0
  157. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  158. package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
  159. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  160. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  161. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  162. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +42 -47
  163. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  164. package/lib/typescript/module/store.d.ts +1 -3
  165. package/lib/typescript/module/store.d.ts.map +1 -1
  166. package/lib/typescript/module/types.d.ts +1 -1
  167. package/lib/typescript/module/types.d.ts.map +1 -1
  168. package/lib/typescript/module/updateError.d.ts +26 -0
  169. package/lib/typescript/module/updateError.d.ts.map +1 -0
  170. package/lib/typescript/module/wrap.d.ts.map +1 -1
  171. package/lib/typescript/module/wrap.types.d.ts +6 -7
  172. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  173. package/package.json +7 -4
  174. package/src/appReady.ts +149 -0
  175. package/src/checkForUpdate.ts +151 -88
  176. package/src/clientPlugin.ts +18 -0
  177. package/src/error.ts +4 -14
  178. package/src/fetchJSON.ts +14 -30
  179. package/src/fetchUpdateResponse.ts +54 -0
  180. package/src/httpClient.ts +88 -159
  181. package/src/index.ts +90 -24
  182. package/src/native.ts +106 -102
  183. package/src/pluginHost.ts +45 -0
  184. package/src/releaseCatalogCache.ts +43 -172
  185. package/src/sdkVersion.ts +1 -1
  186. package/src/specs/NativeHotUpdater.ts +41 -48
  187. package/src/store.ts +2 -23
  188. package/src/types.ts +1 -1
  189. package/src/updateError.ts +153 -0
  190. package/src/wrap.tsx +57 -26
  191. package/src/wrap.types.ts +6 -7
  192. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  193. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  194. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  195. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  196. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  197. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  198. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
  199. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
  200. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  201. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
  202. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  203. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  204. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  205. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  206. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  207. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  208. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  209. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  210. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  211. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  212. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  213. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  214. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  215. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -615
  216. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  217. package/lib/commonjs/httpClient.spec.js +0 -102
  218. package/lib/commonjs/httpClient.spec.js.map +0 -1
  219. package/lib/commonjs/index.spec.js +0 -302
  220. package/lib/commonjs/index.spec.js.map +0 -1
  221. package/lib/commonjs/iosInterop.spec.js +0 -18
  222. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  223. package/lib/commonjs/native.spec.js +0 -883
  224. package/lib/commonjs/native.spec.js.map +0 -1
  225. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
  226. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  227. package/lib/commonjs/notifyAppReadyInsights.js +0 -133
  228. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  229. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
  230. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  231. package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
  232. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  233. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
  234. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  235. package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
  236. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  237. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  238. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  239. package/lib/commonjs/store.notification.spec.js +0 -76
  240. package/lib/commonjs/store.notification.spec.js.map +0 -1
  241. package/lib/commonjs/store.spec.js +0 -316
  242. package/lib/commonjs/store.spec.js.map +0 -1
  243. package/lib/commonjs/wrap.spec.js +0 -329
  244. package/lib/commonjs/wrap.spec.js.map +0 -1
  245. package/lib/module/catalogCacheNative.spec.js +0 -31
  246. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  247. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -614
  248. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  249. package/lib/module/httpClient.spec.js +0 -102
  250. package/lib/module/httpClient.spec.js.map +0 -1
  251. package/lib/module/index.spec.js +0 -301
  252. package/lib/module/index.spec.js.map +0 -1
  253. package/lib/module/iosInterop.spec.js +0 -18
  254. package/lib/module/iosInterop.spec.js.map +0 -1
  255. package/lib/module/native.spec.js +0 -882
  256. package/lib/module/native.spec.js.map +0 -1
  257. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
  258. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  259. package/lib/module/notifyAppReadyInsights.js +0 -128
  260. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  261. package/lib/module/notifyAppReadyInsights.spec.js +0 -245
  262. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  263. package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
  264. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  265. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
  266. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  267. package/lib/module/releaseCatalogCache.spec.js +0 -195
  268. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  269. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  270. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  271. package/lib/module/store.notification.spec.js +0 -77
  272. package/lib/module/store.notification.spec.js.map +0 -1
  273. package/lib/module/store.spec.js +0 -315
  274. package/lib/module/store.spec.js.map +0 -1
  275. package/lib/module/wrap.spec.js +0 -330
  276. package/lib/module/wrap.spec.js.map +0 -1
  277. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
  278. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  279. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  280. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  281. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
  282. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  283. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  284. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  285. package/src/catalogCacheNative.spec.ts +0 -63
  286. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -611
  287. package/src/httpClient.spec.ts +0 -132
  288. package/src/index.spec.ts +0 -337
  289. package/src/iosInterop.spec.ts +0 -30
  290. package/src/native.spec.ts +0 -945
  291. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
  292. package/src/notifyAppReadyInsights.spec.ts +0 -243
  293. package/src/notifyAppReadyInsights.test-utils.ts +0 -31
  294. package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
  295. package/src/notifyAppReadyInsights.ts +0 -194
  296. package/src/releaseCatalogCache.spec.ts +0 -282
  297. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  298. package/src/store.notification.spec.ts +0 -92
  299. package/src/store.spec.ts +0 -372
  300. package/src/wrap.spec.ts +0 -406
@@ -2,9 +2,19 @@
2
2
  # Invoked via reflection, when setting js bundle.
3
3
  -keepclassmembers class com.facebook.react.ReactInstanceManager {
4
4
  private final ** mBundleLoader;
5
+ private final ** mJSExceptionHandler;
5
6
  }
6
7
 
7
8
  # New Architecture
9
+ # Crash recovery discovers these accessors through reflection.
10
+ -keepclassmembers class * implements com.facebook.react.ReactApplication {
11
+ public *** getReactHost();
12
+ }
13
+
14
+ -keepclassmembers class * implements com.facebook.react.ReactHost {
15
+ public *** getCurrentReactContext();
16
+ }
17
+
8
18
  # Keep fields accessed via reflection in ReactHost
9
19
  # Support both Java (mReactHostDelegate) and Kotlin (reactHostDelegate) field names
10
20
  -keepclassmembers class com.facebook.react.runtime.ReactHostImpl {
@@ -14,11 +24,16 @@
14
24
 
15
25
  -keepclassmembers class * implements com.facebook.react.runtime.ReactHostDelegate {
16
26
  ** jsBundleLoader;
27
+ ** exceptionHandler;
28
+ }
29
+
30
+ -keepclassmembers class com.facebook.react.bridge.CatalystInstanceImpl {
31
+ ** mJSExceptionHandler;
17
32
  }
18
33
 
19
34
  # Preserve the Brotli decoder and its embedded static dictionary
20
- # (DictionaryData). R8 otherwise strips the dictionary's static init, causing OTA
21
- # .tar.br extraction to fail at runtime with:
35
+ # (DictionaryData). R8 otherwise strips the dictionary's static init, causing
36
+ # per-file Brotli decompression to fail at runtime with:
22
37
  # java.io.IOException: Brotli stream decoding failed
23
38
  # Caused by: brotli dictionary is not set
24
39
  -keep class com.hotupdater.vendor.brotli.** { *; }
@@ -0,0 +1,286 @@
1
+ package com.hotupdater
2
+
3
+ import android.content.Context
4
+ import android.os.Build
5
+ import android.util.TypedValue
6
+ import org.json.JSONObject
7
+ import java.io.File
8
+ import java.io.InputStream
9
+ import java.security.MessageDigest
10
+ import java.util.zip.ZipFile
11
+
12
+ interface BuiltInAssetResolver {
13
+ fun copyIfMatches(
14
+ assetPath: String,
15
+ expectedHash: String,
16
+ destination: File,
17
+ ): Boolean
18
+ }
19
+
20
+ internal class AndroidBuiltInAssetResolver(
21
+ private val context: Context,
22
+ private val cacheFile: File,
23
+ ) : BuiltInAssetResolver {
24
+ private data class CachedIndex(
25
+ val packageIdentity: String,
26
+ val locators: MutableMap<String, String>,
27
+ )
28
+
29
+ private val lock = Any()
30
+
31
+ override fun copyIfMatches(
32
+ assetPath: String,
33
+ expectedHash: String,
34
+ destination: File,
35
+ ): Boolean =
36
+ synchronized(lock) {
37
+ val normalizedPath = RelativePathResolver.normalizeRelativePath(assetPath) ?: return@synchronized false
38
+ val packageIdentity = packageIdentity() ?: return@synchronized false
39
+ val index = readIndex(packageIdentity)
40
+ val cachedLocator = index.locators[normalizedPath]
41
+ if (cachedLocator != null && copyLocatorIfMatches(cachedLocator, expectedHash, destination)) {
42
+ return@synchronized true
43
+ }
44
+
45
+ val locator = resolveLocator(normalizedPath) ?: return@synchronized false
46
+ if (!copyLocatorIfMatches(locator, expectedHash, destination)) return@synchronized false
47
+
48
+ index.locators[normalizedPath] = locator
49
+ writeIndex(index)
50
+ true
51
+ }
52
+
53
+ private fun resolveLocator(assetPath: String): String? {
54
+ if (assetPath == "index.android.bundle") {
55
+ return try {
56
+ context.assets.open(assetPath).close()
57
+ "asset:$assetPath"
58
+ } catch (_: Exception) {
59
+ null
60
+ }
61
+ }
62
+
63
+ val firstSlash = assetPath.indexOf('/')
64
+ if (firstSlash <= 0 || firstSlash == assetPath.lastIndex) return null
65
+ val directory = assetPath.substring(0, firstSlash)
66
+ val filename = assetPath.substring(firstSlash + 1)
67
+ val resourceType = directory.substringBefore('-')
68
+ if (resourceType != "drawable" && resourceType != "raw" && resourceType != "font") return null
69
+ val resourceName = filename.substringBeforeLast('.')
70
+ if (resourceName.isEmpty() || resourceName.any { !(it == '_' || it.isLowerCase() || it.isDigit()) }) {
71
+ return null
72
+ }
73
+
74
+ return try {
75
+ var resourceId = context.resources.getIdentifier(resourceName, resourceType, context.packageName)
76
+ // Metro emits fonts in raw/, while Re.Pack emits the same bytes in font/.
77
+ if (resourceId == 0 &&
78
+ (resourceType == "raw" || resourceType == "font") &&
79
+ filename.substringAfterLast('.') in setOf("ttf", "otf", "ttc")
80
+ ) {
81
+ val alternateType = if (resourceType == "raw") "font" else "raw"
82
+ resourceId = context.resources.getIdentifier(resourceName, alternateType, context.packageName)
83
+ }
84
+ if (resourceId == 0) return null
85
+ val value = TypedValue()
86
+ val density = densityFor(directory)
87
+ if (density == null) {
88
+ context.resources.getValue(resourceId, value, true)
89
+ } else {
90
+ context.resources.getValueForDensity(resourceId, density, value, true)
91
+ val actualDensity = if (value.density == TypedValue.DENSITY_DEFAULT) 160 else value.density
92
+ if (actualDensity != density) return null
93
+ }
94
+ val entry = value.string?.toString() ?: return null
95
+ installedApks().firstNotNullOfOrNull { apk ->
96
+ try {
97
+ ZipFile(apk).use { zip ->
98
+ if (zip.getEntry(entry) == null) null else "zip:${apk.absolutePath}!$entry"
99
+ }
100
+ } catch (_: Exception) {
101
+ null
102
+ }
103
+ }
104
+ } catch (_: Exception) {
105
+ null
106
+ }
107
+ }
108
+
109
+ private fun densityFor(directory: String): Int? =
110
+ when (directory.substringAfter('-', "")) {
111
+ "ldpi" -> 120
112
+ "mdpi" -> 160
113
+ "tvdpi" -> 213
114
+ "hdpi" -> 240
115
+ "xhdpi" -> 320
116
+ "xxhdpi" -> 480
117
+ "xxxhdpi" -> 640
118
+ "nodpi", "anydpi" -> TypedValue.DENSITY_NONE
119
+ else -> null
120
+ }
121
+
122
+ private fun copyLocatorIfMatches(
123
+ locator: String,
124
+ expectedHash: String,
125
+ destination: File,
126
+ ): Boolean {
127
+ val input = openLocator(locator) ?: return false
128
+ val tempFile = File(destination.parentFile, "${destination.name}.builtin.tmp")
129
+ return try {
130
+ destination.parentFile?.mkdirs()
131
+ val digest = MessageDigest.getInstance("SHA-256")
132
+ input.use { source ->
133
+ tempFile.outputStream().use { output ->
134
+ val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
135
+ while (true) {
136
+ val count = source.read(buffer)
137
+ if (count < 0) break
138
+ digest.update(buffer, 0, count)
139
+ output.write(buffer, 0, count)
140
+ }
141
+ }
142
+ }
143
+ val actualHash = digest.digest().joinToString("") { "%02x".format(it) }
144
+ if (!actualHash.equals(expectedHash, ignoreCase = true)) {
145
+ tempFile.delete()
146
+ false
147
+ } else {
148
+ if (destination.exists()) destination.delete()
149
+ tempFile.renameTo(destination) ||
150
+ run {
151
+ tempFile.copyTo(destination, overwrite = true)
152
+ tempFile.delete()
153
+ true
154
+ }
155
+ }
156
+ } catch (_: Exception) {
157
+ tempFile.delete()
158
+ false
159
+ }
160
+ }
161
+
162
+ private fun openLocator(locator: String): InputStream? {
163
+ return try {
164
+ when {
165
+ locator.startsWith("asset:") -> {
166
+ context.assets.open(locator.removePrefix("asset:"))
167
+ }
168
+
169
+ locator.startsWith("zip:") -> {
170
+ val separator = locator.indexOf('!', startIndex = 4)
171
+ if (separator < 0) return null
172
+ val apk = File(locator.substring(4, separator))
173
+ if (installedApks().none { it.absolutePath == apk.absolutePath }) return null
174
+ val zip = ZipFile(apk)
175
+ val entry =
176
+ zip.getEntry(locator.substring(separator + 1)) ?: run {
177
+ zip.close()
178
+ return null
179
+ }
180
+ val stream = zip.getInputStream(entry)
181
+ object : InputStream() {
182
+ override fun read(): Int = stream.read()
183
+
184
+ override fun read(
185
+ buffer: ByteArray,
186
+ offset: Int,
187
+ length: Int,
188
+ ): Int = stream.read(buffer, offset, length)
189
+
190
+ override fun close() {
191
+ stream.close()
192
+ zip.close()
193
+ }
194
+ }
195
+ }
196
+
197
+ else -> {
198
+ null
199
+ }
200
+ }
201
+ } catch (_: Exception) {
202
+ null
203
+ }
204
+ }
205
+
206
+ private fun installedApks(): List<File> {
207
+ val info = context.applicationInfo
208
+ return (listOf(info.sourceDir) + info.splitSourceDirs.orEmpty())
209
+ .filterNotNull()
210
+ .map(::File)
211
+ .filter(File::isFile)
212
+ }
213
+
214
+ private fun packageIdentity(): String? =
215
+ try {
216
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
217
+ val versionCode =
218
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
219
+ packageInfo.longVersionCode
220
+ } else {
221
+ @Suppress("DEPRECATION")
222
+ packageInfo.versionCode.toLong()
223
+ }
224
+ buildString {
225
+ append(context.packageName)
226
+ append('|')
227
+ append(versionCode)
228
+ append('|')
229
+ append(packageInfo.lastUpdateTime)
230
+ installedApks().sortedBy(File::getAbsolutePath).forEach { apk ->
231
+ append('|')
232
+ append(apk.absolutePath)
233
+ append(':')
234
+ append(apk.length())
235
+ append(':')
236
+ append(apk.lastModified())
237
+ }
238
+ }
239
+ } catch (_: Exception) {
240
+ null
241
+ }
242
+
243
+ private fun readIndex(packageIdentity: String): CachedIndex {
244
+ try {
245
+ if (cacheFile.isFile) {
246
+ val json = JSONObject(cacheFile.readText())
247
+ if (json.optInt("schemaVersion") == SCHEMA_VERSION &&
248
+ json.optString("packageIdentity") == packageIdentity
249
+ ) {
250
+ val locatorsJson = json.optJSONObject("locators") ?: JSONObject()
251
+ val locators = mutableMapOf<String, String>()
252
+ locatorsJson.keys().forEach { path -> locators[path] = locatorsJson.getString(path) }
253
+ return CachedIndex(packageIdentity, locators)
254
+ }
255
+ }
256
+ } catch (_: Exception) {
257
+ // A corrupt cache is only a missed optimization.
258
+ }
259
+ return CachedIndex(packageIdentity, mutableMapOf())
260
+ }
261
+
262
+ private fun writeIndex(index: CachedIndex) {
263
+ try {
264
+ cacheFile.parentFile?.mkdirs()
265
+ val locatorsJson = JSONObject()
266
+ index.locators.toSortedMap().forEach { (path, locator) ->
267
+ locatorsJson.put(path, locator)
268
+ }
269
+ val json =
270
+ JSONObject()
271
+ .put("schemaVersion", SCHEMA_VERSION)
272
+ .put("packageIdentity", index.packageIdentity)
273
+ .put("locators", locatorsJson)
274
+ val tempFile = File(cacheFile.parentFile, "${cacheFile.name}.tmp")
275
+ tempFile.writeText("$json\n")
276
+ if (cacheFile.exists()) cacheFile.delete()
277
+ if (!tempFile.renameTo(cacheFile)) tempFile.delete()
278
+ } catch (_: Exception) {
279
+ // Cache persistence must never block a valid install.
280
+ }
281
+ }
282
+
283
+ companion object {
284
+ private const val SCHEMA_VERSION = 1
285
+ }
286
+ }