diff --git a/airborne_sdk_android/airborne/src/main/java/in/juspay/airborne/ota/UpdateTask.kt b/airborne_sdk_android/airborne/src/main/java/in/juspay/airborne/ota/UpdateTask.kt index 96f29ba0..5e5808d1 100644 --- a/airborne_sdk_android/airborne/src/main/java/in/juspay/airborne/ota/UpdateTask.kt +++ b/airborne_sdk_android/airborne/src/main/java/in/juspay/airborne/ota/UpdateTask.kt @@ -378,8 +378,9 @@ internal class UpdateTask( val body = fr.v.second val serialized = String(body.bytes(), StandardCharsets.UTF_8) try { - val releaseConfig = ReleaseConfig.deSerialize(serialized).getOrThrow() + var releaseConfig = ReleaseConfig.deSerialize(serialized).getOrThrow() trackReleaseConfigFetchResult(fr, startTime) + releaseConfig = transformReleaseConfig(releaseConfig) releaseConfig } catch (e: Exception) { Log.e( @@ -398,6 +399,27 @@ internal class UpdateTask( } } + private fun transformReleaseConfig(releaseConfig: ReleaseConfig): ReleaseConfig { + val localResources = localReleaseConfig?.resources.orEmpty() + val localPackageImportantRes = localReleaseConfig?.pkg?.important.orEmpty() + val newResources = releaseConfig.resources.filter { it !in localResources && it !in localPackageImportantRes } + + if (newResources.isEmpty()) return releaseConfig + + val updatedResources = ReleaseConfig.ResourceManifest(releaseConfig.resources - newResources.toSet()) + + val updatedPackage = releaseConfig.pkg.copy( + important = releaseConfig.pkg.important + newResources + ) + + Log.d(TAG, "Transformed release config with new resources: $newResources") + + return releaseConfig.copy( + pkg = updatedPackage, + resources = updatedResources + ) + } + fun copyTempPkg(): ReleaseConfig.PackageManifest? { readPersistentState(StateKey.SAVED_PACKAGE_UPDATE)?.let { Log.d(TAG, "Found saved pkg $it.") diff --git a/airborne_sdk_iOS/hyper-ota/Airborne/AirborneObjC/ApplicationManager/AJPApplicationManager.m b/airborne_sdk_iOS/hyper-ota/Airborne/AirborneObjC/ApplicationManager/AJPApplicationManager.m index 582de646..c470d31a 100644 --- a/airborne_sdk_iOS/hyper-ota/Airborne/AirborneObjC/ApplicationManager/AJPApplicationManager.m +++ b/airborne_sdk_iOS/hyper-ota/Airborne/AirborneObjC/ApplicationManager/AJPApplicationManager.m @@ -85,6 +85,9 @@ @interface AJPApplicationManager() { @property (nonatomic, strong) AJPFileUtil* fileUtil; @property (nonatomic, strong) AJPRemoteFileUtil* remoteFileUtil; +// Helper method to check if a resource already exists in package important splits +- (BOOL)isResourceExistingInPackageImportantSplits:(AJPResource *)resource package:(AJPApplicationPackage *)package; + @end @implementation AJPApplicationManager @@ -675,7 +678,8 @@ - (void)startDownload { self.resourceDownloadStatus = DOWNLOADING; [self fetchReleaseConfigWithCompletionHandler:^(AJPApplicationManifest* manifest,NSError* error) { if (error==nil && manifest != nil) { - self.downloadedApplicationManifest = manifest; + AJPApplicationManifest *transformedManifest = [self transformDownloadedManifest:manifest]; + self.downloadedApplicationManifest = transformedManifest ?: manifest; self.releaseConfigDownloadStatus = COMPLETED; [self cleanUpUnwantedFiles]; [self updateConfig:manifest.config]; @@ -950,6 +954,75 @@ - (void)fetchReleaseConfigWithCompletionHandler:(AJPReleaseConfigCompletionHandl [manifestDataTask resume]; } +- (BOOL)isResourceExistingInPackageImportantSplits:(AJPResource *)resource package:(AJPApplicationPackage *)package { + if (!resource || !package) { + return NO; + } + + NSArray *allImportantSplits = [package allImportantSplits]; + for (AJPResource *existingResource in allImportantSplits) { + if ([existingResource.filePath isEqualToString:resource.filePath]) { + return YES; + } + } + + return NO; +} + +- (AJPApplicationManifest *)transformDownloadedManifest:(AJPApplicationManifest *)downloadedManifest { + if (!downloadedManifest) { + return nil; + } + + AJPApplicationManifest *localManifest = [self getCurrentApplicationManifest]; + + AJPApplicationPackage *transformedPackage = [[AJPApplicationPackage alloc] init]; + transformedPackage.version = downloadedManifest.package.version; + transformedPackage.name = downloadedManifest.package.name; + transformedPackage.important = [downloadedManifest.package.important mutableCopy]; + transformedPackage.lazy = [downloadedManifest.package.lazy mutableCopy]; + + AJPApplicationResources *transformedResources = [[AJPApplicationResources alloc] init]; + transformedResources.resources = [downloadedManifest.resources.resources mutableCopy]; + + NSDictionary *localResources = localManifest.resources.resources; + NSMutableDictionary *newResources = [transformedResources.resources mutableCopy]; + + NSMutableArray *resourcesToMoveToImportant = [NSMutableArray array]; + + for (NSString *resourceKey in newResources) { + AJPResource *newResource = newResources[resourceKey]; + AJPResource *localResource = localResources[resourceKey]; + + // Check if resource is new or updated AND not already in local package important splits + if ((!localResource || ![newResource.url.absoluteString isEqualToString:localResource.url.absoluteString]) && + ![self isResourceExistingInPackageImportantSplits:newResource package:localManifest.package]) { + [resourcesToMoveToImportant addObject:newResource]; + } + } + + if (resourcesToMoveToImportant.count > 0) { + NSMutableArray *updatedImportantSplits = [transformedPackage.important mutableCopy]; + [updatedImportantSplits addObjectsFromArray:resourcesToMoveToImportant]; + transformedPackage.important = updatedImportantSplits; + + for (AJPResource *resource in resourcesToMoveToImportant) { + [newResources removeObjectForKey:resource.filePath]; + } + transformedResources.resources = newResources; + + [self.tracker trackInfo:@"manifest_transformation" + value:[@{@"resources_moved_to_important": @(resourcesToMoveToImportant.count)} mutableCopy]]; + } + + AJPApplicationManifest *transformedManifest = [[AJPApplicationManifest alloc] + initWithPackage:transformedPackage + config:downloadedManifest.config + resources:transformedResources]; + + return transformedManifest; +} + # pragma mark - Config - (AJPApplicationConfig *)readApplicationConfig {