public void ComputePatch(ApplicationPackage reference, ApplicationPackage target, string pathOutputPatch) { IDeltaEncodingAlgorithm deltaEncodingAlgorithm = new BSDIFFDeltaEncodingAlgortihm(); deltaEncodingAlgorithm.ComputeDelta(reference.PackagePath, target.PackagePath, pathOutputPatch); }
/// <summary> /// Computes patch file for two versions of application presented as two APK files. /// Step 1 - Validate both APK files /// Step 2 - Change extensions from .apk to .zip and save new files' paths /// Step 3 - Create patch directory /// Step 4 - Decompress both APKs into the patch directory /// Step 5 - Load manifests for both APKs /// Step 6 - Construct sets of marked files (files are marked as DELETE, NEW, SAME, UPDATED) /// Step 7 - Copy files that are marked NEW into the constructed patch main directory /// Step 8 - Delta encode files that are marked UPDATED nad copy .diff files into the patch /// Step 9 - Create PatchManifest.xml /// Step 10 - Compress patch /// Clean up /// </summary> /// <param name="reference"></param> /// <param name="target"></param> /// <param name="pathOutputPatch"></param> public void ComputePatch(ApplicationPackage reference, ApplicationPackage target, string pathOutputPatch) { // Step 1 - Validate both APK files if (!AndroidPackageManager.ValidatePackage(reference) || !AndroidPackageManager.ValidatePackage(target)) { LogManager.Log(LogMessageType.Error, "Bad APK input files", "Patcher"); return; } // Step 2 - Change extensions from .apk to .zip and save new files' paths //pathOldApk = FileManager.ChangeExtension(pathOldApk, ".zip"); //pathNewApk = FileManager.ChangeExtension(pathNewApk, ".zip"); // Step 3 - Create patch directory string pathPatchingWorkDir = Patcher.GetPatchingWorkDir(); ConstructPathingWorkDir(pathPatchingWorkDir); // Step 4 - Decompress both APKs into the temporary directory string pathReferenceDir = Path.Combine(pathPatchingWorkDir, NAME_REFERENCE_DIR); string pathTargetDir = Path.Combine(pathPatchingWorkDir, NAME_TARGET_DIR); CompressionManager.DecompressZIP(reference.PackagePath, pathReferenceDir); CompressionManager.DecompressZIP(target.PackagePath, pathTargetDir); // Step 5 - Load manifests for both APKs AndroidApplicationManifest referenceManifest = AndroidPackageManager.GetApplicationManifest(pathReferenceDir); AndroidApplicationManifest targetManifest = AndroidPackageManager.GetApplicationManifest(pathTargetDir); // Step 6 - Construct sets of marked files (files are marked as DELETE, NEW, SAME, UPDATED) // Mark DELETE files HashSet<AndroidApplicationManifestRecord> filesMarkedDELETE = MarkFilesDELETE(referenceManifest, targetManifest); // Mark NEW files HashSet<AndroidApplicationManifestRecord> filesMarkedNEW = MarkFilesNEW(referenceManifest, targetManifest); // Mark UPDATED files HashSet<AndroidApplicationManifestRecord> filesMarkedUPDATED = MarkFilesUPDATED(referenceManifest, targetManifest); // Step 7 - Copy files that are marked NEW into the constructed patch main directory foreach (AndroidApplicationManifestRecord record in filesMarkedNEW) { CopyFileIntoPatch(record.FileName, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), pathTargetDir); } // Step 8 - Delta encode files that are marked UPDATED nad copy .diff files into the patch var deltaEncodingAlgorithm = new BSDIFFDeltaEncodingAlgortihm(); foreach (AndroidApplicationManifestRecord record in filesMarkedUPDATED) { string pathDiffFile = Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR, record.FileName.Replace('\\', '+')) + ".diff"; deltaEncodingAlgorithm.ComputeDelta(Path.Combine(pathReferenceDir, record.FileName), Path.Combine(pathTargetDir, record.FileName), pathDiffFile); // We don't want to include .diff file into the patch if its size is greater than the new file size. // Instead, we include the new version of file itself. if (FileManager.GetFileSize(pathDiffFile) > FileManager.GetFileSize(Path.Combine(pathTargetDir, record.FileName))) { File.Delete(pathDiffFile); CopyFileIntoPatch(record.FileName, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), pathTargetDir); // Add files to filesMarkedNEW and filesMarkedDELETE // During deployment we will delete old file and copy the new one instead of patching the old file filesMarkedDELETE.Add(record); filesMarkedNEW.Add(record); } } // Remove all files that are in filesMarkedNEW from filesMarkedUPDATED filesMarkedUPDATED.ExceptWith(filesMarkedNEW); // Step 9 - Create PatchManifest.xml string patchName = NamingHelper.GetPatchName(reference, target); PatchManifest manifest = new PatchManifest(patchName, reference, target); // We need only files names in the manifest foreach (AndroidApplicationManifestRecord record in filesMarkedNEW) { manifest.AddFileNEW(record.FileName); } foreach (AndroidApplicationManifestRecord record in filesMarkedDELETE) { manifest.AddFileDELETE(record.FileName); } foreach (AndroidApplicationManifestRecord record in filesMarkedUPDATED) { manifest.AddFileUPDATED(record.FileName); } FileManager.SerializeObjectToXML(manifest, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR, NAME_PATCH_MANIFEST)); // Step 10 - Compress patch CompressionManager.CompressDirToZIP(Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), Path.Combine(pathPatchingWorkDir, patchName)); // Clean up // Delete temp directory FileManager.DeleteDirectory(pathPatchingWorkDir); Console.WriteLine(String.Format("Finished patch creation: {0} -> {1}", reference.PackagePath, target.PackagePath)); }