private void AddModLoaderToApk(string apkFilename) { UpdateStatus("Adding the libmodloader.so file to the APK..."); try { using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { using (var resStream = _context.Resources.OpenRawResource(Resource.Raw.libmodloader)) { using (var resStream64 = _context.Resources.OpenRawResource(Resource.Raw.libmodloader64)) { if (apk.DirectoryExists(LIBMODLOADER_TARGET_FILE.GetDirectoryFwdSlash())) { if (apk.FileExists(LIBMODLOADER_TARGET_FILE)) { apk.Delete(LIBMODLOADER_TARGET_FILE); apk.Save(); } apk.QueueWriteStream(LIBMODLOADER_TARGET_FILE, resStream, true, true); } if (apk.DirectoryExists(LIBMODLOADER64_TARGET_FILE.GetDirectoryFwdSlash())) { if (apk.FileExists(LIBMODLOADER64_TARGET_FILE)) { apk.Delete(LIBMODLOADER64_TARGET_FILE); apk.Save(); } apk.QueueWriteStream(LIBMODLOADER64_TARGET_FILE, resStream64, true, true); } try { apk.Save(); } catch (IOException) { GC.Collect(); System.Threading.Thread.Sleep(1000); apk.Save(); } } } } } catch (Exception ex) { Log.LogErr("Error adding libmodloader.so to APK", ex); UpdateStatus("Error adding modloader to the APK!"); throw new ModException("Error adding libmodloader.so to APK", ex); } }
private void AddAndroidPermissions(string apkFilename, List <string> permissions) { if (permissions == null || permissions.Count < 1) { throw new ArgumentException("At least one permission must be specified to add."); } try { using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { byte[] manifest = apk.Read("AndroidManifest.xml"); AxmlWriter writer = new WritePermissionAxmlWriter(permissions); AxmlReader reader = new AxmlReader(manifest); reader.Accept(writer); var outData = writer.ToByteArray(); apk.Write("AndroidManifest.xml", outData, true); apk.Save(); } } catch (Exception ex) { Log.LogErr("Exception trying to add permissions to AndroidManifest.xml", ex); throw; } }
private void SaveFileToApk(string apkFileName, string toFileName, string sourceFile) { using (var apk = new ZipFileProvider(apkFileName, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { using (var fs = File.OpenRead(sourceFile)) { apk.QueueWriteStream(toFileName, fs, true, true); apk.Save(); } } }
private void AddTagFileToApk(string apkFilename) { using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { if (apk.FileExists(MOD_TAG_FILE)) { Log.LogMsg("APK file already had the mod's tag file."); return; } apk.Write(MOD_TAG_FILE, new byte[1], true, false); apk.Save(); } }
private void AddModLoaderToApk(string apkFilename) { UpdateStatus("Adding the libmodloader.so file to the APK..."); try { using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { using (var resStream = _context.Resources.OpenRawResource(Resource.Raw.libmodloader)) { apk.QueueWriteStream(LIBMODLOADER_TARGET_FILE, resStream, true, true); apk.Save(); } } } catch (Exception ex) { Log.LogErr("Error adding libmodloader.so to APK", ex); UpdateStatus("Error adding modloader to the APK!"); throw new ModException("Error adding libmodloader.so to APK", ex); } }
private void AddManifestModToApk(string apkFilename) { UpdateStatus("Modding the manifest in the APK..."); try { using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { using (var resStream = _context.Resources.OpenRawResource(Resource.Raw.manifestmod)) { apk.QueueWriteStream("AndroidManifest.xml", resStream, true, true); apk.Save(); } } } catch (Exception ex) { Log.LogErr("Error modding the manifest in the APK", ex); UpdateStatus("Error modding the manifest in the APK!"); throw new ModException("Error modding the manifest in the APK", ex); } }
private void ExtractAssetsFromApkToExternalStorage(string apkFilename, List <string> excludePaths = null, bool fromBakFiles = false) { UpdateStatus("Extracting assets files from the APK to external storage..."); using (var apk = new ZipFileProvider(apkFilename, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { foreach (var assetFilename in apk.FindFiles(APK_ASSETS_PATH + "*")) { string relativeFilename = assetFilename.Substring(APK_ASSETS_PATH.Length); if (excludePaths != null) { if (excludePaths.Any(x => relativeFilename.StartsWith(x))) { Log.LogMsg($"The asset file {assetFilename} ({relativeFilename}) is not included in assets that should be extracted, skipping."); continue; } } Log.LogMsg($"Extracting {assetFilename}..."); string targetFile = Path.Combine(Constants.ASSETS_RELOC_PATH, relativeFilename); string dirName = Path.GetDirectoryName(targetFile); try { if (!Directory.Exists(dirName)) { Log.LogMsg($"Assets target directory doesn't exist, creating {dirName}"); Directory.CreateDirectory(dirName); } } catch (Exception ex) { Log.LogErr($"Unable to create directory {dirName}!", ex); UpdateStatus("Failed to create assets directory in external storage!"); throw new ModException($"Unable to create directory {dirName}!", ex); } try { using (var readStream = apk.GetReadStream(assetFilename, true)) { if (targetFile.EndsWith(".bobak")) { targetFile = targetFile.Substring(0, targetFile.Length - 6); } using (var fs = File.Open(targetFile, FileMode.Create, FileAccess.Write)) { readStream.CopyTo(fs); } } if (!assetFilename.EndsWith(".bobak")) { apk.Rename(assetFilename, assetFilename + ".bobak"); } } catch (Exception ex) { Log.LogErr($"Failed to extract {assetFilename} to {targetFile}", ex); UpdateStatus("Failed extracting an asset from the APK to external storage!"); throw new ModException($"Failed to extract {assetFilename} to {targetFile}", ex); } } apk.Save(); } }
/// <summary> /// Checks if the backup exists, or creates a very unideal backup of the modded APK for the sake of uninstalling mods /// </summary> public void CheckCreateModdedBackup() { try { if (File.Exists(Constants.BEATSABER_APK_BACKUP_FILE)) { return; } Log.LogErr("WARNING: backup of original Beat Saber APK does not exist. Will attempt to fall back to a post-mod backup."); if (File.Exists(Constants.BEATSABER_APK_MODDED_BACKUP_FILE)) { return; } Log.LogErr("Post-modded backup of Beat Saber APK does not exist, will attempt to create one."); if (!IsBeatSaberInstalled) { Log.LogErr("Beat saber isn't even installed. Can't make any sort of backup."); return; } var apkPath = FindBeatSaberApk(); if (apkPath == null) { Log.LogErr("Unable to find the installed Beat Saber APK path. Cannot make a post-mod backup."); return; } Log.LogErr("Copying APK for unideal backup..."); try { File.Copy(apkPath, Constants.BEATSABER_APK_MODDED_BACKUP_FILE, true); } catch (Exception ex) { Log.LogErr("Exception trying to copy APK for half assed backup.", ex); return; } try { Log.LogErr("Restoring names of modded APK asset files so they can serve as a backup..."); using (var apk = new ZipFileProvider(Constants.BEATSABER_APK_MODDED_BACKUP_FILE, FileCacheMode.None, false, QuestomAssets.Utils.FileUtils.GetTempDirectory())) { foreach (var assetFilename in apk.FindFiles(APK_ASSETS_PATH + "*")) { if (assetFilename.EndsWith(".bobak")) { apk.Rename(assetFilename, assetFilename.Substring(0, assetFilename.Length - 6)); } } apk.Save(); } } catch (Exception ex) { Log.LogErr("Exception trying to make a half assed, post-mod backup while renaming files within the APK", ex); } } catch (Exception ex) { Log.LogErr($"Exception trying to check/create backups", ex); } }