diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..097f9f9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,9 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew        text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat           text eol=crlf
+
diff --git a/.releaserc b/.releaserc
index 08537c7..5deb9dd 100644
--- a/.releaserc
+++ b/.releaserc
@@ -7,7 +7,13 @@
     }
   ],
   "plugins": [
-    "@semantic-release/commit-analyzer",
+    [
+      "@semantic-release/commit-analyzer", {
+        "releaseRules": [
+          { "type": "build", "scope": "needs-bump", "release": "patch" }
+        ]
+      }
+    ],
     "@semantic-release/release-notes-generator",
     "@semantic-release/changelog",
     "gradle-semantic-release-plugin",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 902510c..ef75fc1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,28 @@
+# [12.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0-dev.1...v12.0.0-dev.2) (2023-07-28)
+
+
+### Features
+
+* Deprecate `Version` annotation ([400442f](https://github.com/ReVanced/revanced-patcher/commit/400442f70ee56cafd4493b2ce64a294db9836509))
+
+# [12.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v11.0.4...v12.0.0-dev.1) (2023-07-26)
+
+
+### Bug Fixes
+
+* correct access flags of `PackageMetadata` ([416d691](https://github.com/ReVanced/revanced-patcher/commit/416d69142f50dab49c9ea3f027e9d53e4777f257))
+* set resource table via resource decoder ([e0f8e1b](https://github.com/ReVanced/revanced-patcher/commit/e0f8e1b71a295948b610029c89a48f52762396b6))
+
+
+### Features
+
+* remove `Path` option ([#202](https://github.com/ReVanced/revanced-patcher/issues/202)) ([69e4a49](https://github.com/ReVanced/revanced-patcher/commit/69e4a490659ebc4fb4bf46148634f4b064ef1713))
+
+
+### BREAKING CHANGES
+
+* This removes the previously available `Path` option
+
 ## [11.0.4](https://github.com/revanced/revanced-patcher/compare/v11.0.3...v11.0.4) (2023-07-01)
 
 
diff --git a/build.gradle.kts b/build.gradle.kts
index dfe7ee5..8d8561f 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
 plugins {
-    kotlin("jvm") version "1.8.10"
+    kotlin("jvm") version "1.8.20"
     `maven-publish`
 }
 
@@ -23,7 +23,7 @@ dependencies {
     implementation("xpp3:xpp3:1.1.4c")
     implementation("app.revanced:smali:2.5.3-a3836654")
     implementation("app.revanced:multidexlib2:2.5.3-a3836654")
-    implementation("app.revanced:apktool-lib:2.7.0")
+    implementation("app.revanced:apktool-lib:2.8.2")
 
     implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20-RC")
     testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20-RC")
diff --git a/gradle.properties b/gradle.properties
index a1a4388..3199db3 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,4 @@
+org.gradle.parallel = true
+org.gradle.caching = true
 kotlin.code.style = official
-version = 11.0.4
+version = 12.0.0-dev.2
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7454180..033e24c 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1f017e4..62f495d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index c53aefa..fcb6fca 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 #
-# Copyright � 2015-2021 the original authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@
 #       Busybox and similar reduced shells will NOT work, because this script
 #       requires all of these POSIX shell features:
 #         * functions;
-#         * expansions �$var�, �${var}�, �${var:-default}�, �${var+SET}�,
-#           �${var#prefix}�, �${var%suffix}�, and �$( cmd )�;
-#         * compound commands having a testable exit status, especially �case�;
-#         * various built-in commands including �command�, �set�, and �ulimit�.
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
 #
 #   Important for patching:
 #
@@ -55,7 +55,7 @@
 #       Darwin, MinGW, and NonStop.
 #
 #   (3) This script is generated from the Groovy template
-#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 #       within the Gradle project.
 #
 #       You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,10 @@ do
     esac
 done
 
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
 APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD=maximum
@@ -133,22 +130,29 @@ location of your Java installation."
     fi
 else
     JAVACMD=java
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
+    fi
 fi
 
 # Increase the maximum file descriptors if we can.
 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
     case $MAX_FD in #(
       max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045
         MAX_FD=$( ulimit -H -n ) ||
             warn "Could not query maximum file descriptor limit"
     esac
     case $MAX_FD in  #(
       '' | soft) :;; #(
       *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045
         ulimit -n "$MAX_FD" ||
             warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
@@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then
     done
 fi
 
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
 # Collect all arguments for the java command;
 #   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
 #     shell script including quotes and variable substitutions, so put them in
@@ -205,6 +213,12 @@ set -- \
         org.gradle.wrapper.GradleWrapperMain \
         "$@"
 
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
 # Use "xargs" to parse quoted args.
 #
 # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd3..93e3f59 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
 @rem limitations under the License.
 @rem
 
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
 @rem ##########################################################################
 @rem
 @rem  Gradle startup script for Windows
@@ -25,7 +25,8 @@
 if "%OS%"=="Windows_NT" setlocal
 
 set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
 :end
 @rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
 
 :fail
 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
 
 :mainEnd
 if "%OS%"=="Windows_NT" endlocal
diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt
index 0865c62..a0bf713 100644
--- a/src/main/kotlin/app/revanced/patcher/Patcher.kt
+++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt
@@ -7,15 +7,16 @@ import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations
 import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
 import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolveUsingLookupMap
 import app.revanced.patcher.patch.*
-import app.revanced.patcher.util.VersionReader
-import brut.androlib.Androlib
-import brut.androlib.meta.UsesFramework
-import brut.androlib.options.BuildOptions
-import brut.androlib.res.AndrolibResources
-import brut.androlib.res.data.ResPackage
-import brut.androlib.res.decoder.AXmlResourceParser
+import brut.androlib.AaptInvoker
+import brut.androlib.ApkDecoder
+import brut.androlib.Config
+import brut.androlib.res.Framework
+import brut.androlib.res.ResourcesDecoder
+import brut.androlib.res.decoder.AndroidManifestResourceParser
 import brut.androlib.res.decoder.ResAttrDecoder
 import brut.androlib.res.decoder.XmlPullStreamDecoder
+import brut.androlib.res.util.ExtMXSerializer
+import brut.androlib.res.util.ExtXmlSerializer
 import brut.androlib.res.xml.ResXmlPatcher
 import brut.directory.ExtFile
 import lanchon.multidexlib2.BasicDexFileNamer
@@ -42,14 +43,9 @@ class Patcher(private val options: PatcherOptions) {
     private var mergeIntegrations = false
     val context: PatcherContext
 
-    companion object {
-        @JvmStatic
-        val version = VersionReader.read()
-        private fun BuildOptions.setBuildOptions(options: PatcherOptions) {
-            this.aaptPath = options.aaptPath
-            this.useAapt2 = true
-            this.frameworkFolderLocation = options.frameworkFolderLocation
-        }
+    private val config = Config.getDefaultConfig().apply {
+        aaptPath = options.aaptPath
+        frameworkDirectory = options.frameworkDirectory
     }
 
     init {
@@ -86,55 +82,39 @@ class Patcher(private val options: PatcherOptions) {
      * Save the patched dex file.
      */
     fun save(): PatcherResult {
-        val packageMetadata = context.packageMetadata
-        val metaInfo = packageMetadata.metaInfo
         var resourceFile: File? = null
 
         when (resourceDecodingMode) {
             ResourceDecodingMode.FULL -> {
+                logger.info("Compiling resources")
+
                 val cacheDirectory = ExtFile(options.resourceCacheDirectory)
+                val aaptFile = cacheDirectory.resolve("aapt_temp_file").also {
+                    Files.deleteIfExists(it.toPath())
+                }.also { resourceFile = it }
+
                 try {
-                    val androlibResources = AndrolibResources().also { resources ->
-                        resources.buildOptions = BuildOptions().also { buildOptions ->
-                            buildOptions.setBuildOptions(options)
-                            buildOptions.isFramework = metaInfo.isFrameworkApk
-                            buildOptions.resourcesAreCompressed = metaInfo.compressionType
-                            buildOptions.doNotCompress = metaInfo.doNotCompress
+                    AaptInvoker(
+                        config,
+                        context.packageMetadata.apkInfo
+                    ).invokeAapt(
+                        aaptFile,
+                        cacheDirectory.resolve("AndroidManifest.xml").also {
+                            ResXmlPatcher.fixingPublicAttrsInProviderAttributes(it)
+                        },
+                        cacheDirectory.resolve("res"),
+                        null,
+                        null,
+                        context.packageMetadata.apkInfo.usesFramework.let { usesFramework ->
+                            usesFramework.ids.map { id ->
+                                Framework(config).getFrameworkApk(id, usesFramework.tag)
+                            }.toTypedArray()
                         }
-
-                        resources.setSdkInfo(metaInfo.sdkInfo)
-                        resources.setVersionInfo(metaInfo.versionInfo)
-                        resources.setSharedLibrary(metaInfo.sharedLibrary)
-                        resources.setSparseResources(metaInfo.sparseResources)
-                    }
-
-                    val manifestFile = cacheDirectory.resolve("AndroidManifest.xml")
-
-                    ResXmlPatcher.fixingPublicAttrsInProviderAttributes(manifestFile)
-
-                    val aaptFile = cacheDirectory.resolve("aapt_temp_file")
-
-                    // delete if it exists
-                    Files.deleteIfExists(aaptFile.toPath())
-
-                    val resDirectory = cacheDirectory.resolve("res")
-                    val includedFiles = metaInfo.usesFramework.ids.map { id ->
-                        androlibResources.getFrameworkApk(
-                            id, metaInfo.usesFramework.tag
-                        )
-                    }.toTypedArray()
-
-                    logger.info("Compiling resources")
-                    androlibResources.aaptPackage(
-                        aaptFile, manifestFile, resDirectory, null, null, includedFiles
                     )
-
-                    resourceFile = aaptFile
                 } finally {
                     cacheDirectory.close()
                 }
             }
-
             else -> logger.info("Not compiling resources because resource patching is not required")
         }
 
@@ -156,7 +136,7 @@ class Patcher(private val options: PatcherOptions) {
             dexFiles.map {
                 app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
             },
-            metaInfo.doNotCompress?.toList(),
+            context.packageMetadata.apkInfo.doNotCompress?.toList(),
             resourceFile
         )
     }
@@ -200,72 +180,68 @@ class Patcher(private val options: PatcherOptions) {
     private fun decodeResources(mode: ResourceDecodingMode) {
         val extInputFile = ExtFile(options.inputFile)
         try {
-            val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
-            val resourceTable = androlib.getResTable(extInputFile, true)
+            val resourcesDecoder = ResourcesDecoder(config, extInputFile)
+
             when (mode) {
                 ResourceDecodingMode.FULL -> {
                     val outDir = File(options.resourceCacheDirectory)
                     if (outDir.exists()) {
                         logger.info("Deleting existing resource cache directory")
-                        if (!outDir.deleteRecursively()) {
-                            logger.error("Failed to delete existing resource cache directory")
-                        }
+                        if (!outDir.deleteRecursively()) logger.error("Failed to delete existing resource cache directory")
                     }
+
                     outDir.mkdirs()
 
                     logger.info("Decoding resources")
 
-                    // decode resources to cache directory
-                    androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
-                    androlib.decodeResourcesFull(extInputFile, outDir, resourceTable)
-
-                    // read additional metadata from the resource table
-                    context.packageMetadata.let { metadata ->
-                        metadata.metaInfo.usesFramework = UsesFramework().also { framework ->
-                            framework.ids = resourceTable.listFramePackages().map { it.id }.sorted()
-                        }
-
-                        // read files to not compress
-                        metadata.metaInfo.doNotCompress = buildList {
-                            androlib.recordUncompressedFiles(extInputFile, this)
-                        }
-                    }
+                    resourcesDecoder.decodeManifest(outDir)
+                    resourcesDecoder.decodeResources(outDir)
 
+                    context.packageMetadata.also {
+                        it.apkInfo = resourcesDecoder.apkInfo
+                    }.apkInfo.doNotCompress = ApkDecoder(config, extInputFile).recordUncompressedFiles(
+                        context.packageMetadata.apkInfo, resourcesDecoder.resFileMapping
+                    )
                 }
-
                 ResourceDecodingMode.MANIFEST_ONLY -> {
                     logger.info("Decoding AndroidManifest.xml only, because resources are not needed")
 
-                    // create decoder for the resource table
-                    val decoder = ResAttrDecoder()
-                    decoder.currentPackage = ResPackage(resourceTable, 0, null)
-
-                    // create xml parser with the decoder
-                    val axmlParser = AXmlResourceParser()
-                    axmlParser.attrDecoder = decoder
-
-                    // parse package information with the decoder and parser which will set required values in the resource table
-                    // instead of decodeManifest another more low level solution can be created to make it faster/better
-                    XmlPullStreamDecoder(
-                        axmlParser, AndrolibResources().resXmlSerializer
+                    // Instead of using resourceDecoder.decodeManifest which decodes the whole file
+                    // use the XmlPullStreamDecoder in order to get necessary information from the manifest
+                    // used below.
+                    XmlPullStreamDecoder(AndroidManifestResourceParser().apply {
+                        attrDecoder = ResAttrDecoder().apply { this.resTable = resourcesDecoder.resTable }
+                    }, ExtMXSerializer().apply {
+                        setProperty(
+                            ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, "    "
+                        )
+                        setProperty(
+                            ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR,
+                            System.getProperty("line.separator")
+                        )
+                        setProperty(
+                            ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING,
+                                "utf-8"
+                            )
+                            setDisabledAttrEscape(true)
+                        }
                     ).decodeManifest(
                         extInputFile.directory.getFileInput("AndroidManifest.xml"),
                         // Older Android versions do not support OutputStream.nullOutputStream()
-                        object : OutputStream() {
-                            override fun write(b: Int) {
-                                // do nothing
-                            }
-                        }
+                        object : OutputStream() { override fun write(b: Int) { /* do nothing */ } }
                     )
                 }
             }
 
-            // read of the resourceTable which is created by reading the manifest file
+            // Get the package name and version from the manifest using the XmlPullStreamDecoder.
+            // XmlPullStreamDecoder.decodeManifest() sets metadata.apkInfo.
             context.packageMetadata.let { metadata ->
-                metadata.packageName = resourceTable.currentResPackage.name
-                metadata.packageVersion = resourceTable.versionInfo.versionName ?: resourceTable.versionInfo.versionCode
-                metadata.metaInfo.versionInfo = resourceTable.versionInfo
-                metadata.metaInfo.sdkInfo = resourceTable.sdkInfo
+                metadata.apkInfo = resourcesDecoder.apkInfo
+
+                metadata.packageName = resourcesDecoder.resTable.currentResPackage.name
+                resourcesDecoder.apkInfo.versionInfo.let {
+                    metadata.packageVersion = it.versionName ?: it.versionCode
+                }
             }
         } finally {
             extInputFile.close()
diff --git a/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt b/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt
index 4e39733..f6528b7 100644
--- a/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt
+++ b/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt
@@ -9,13 +9,13 @@ import java.io.File
  * @param inputFile The input file (usually an apk file).
  * @param resourceCacheDirectory Directory to cache resources.
  * @param aaptPath Optional path to a custom aapt binary.
- * @param frameworkFolderLocation Optional path to a custom framework folder.
+ * @param frameworkDirectory Optional path to a custom framework directory.
  * @param logger Custom logger implementation for the [Patcher].
  */
 data class PatcherOptions(
     internal val inputFile: File,
     internal val resourceCacheDirectory: String,
     internal val aaptPath: String? = null,
-    internal val frameworkFolderLocation: String? = null,
+    internal val frameworkDirectory: String? = null,
     internal val logger: Logger = NopLogger
 )
diff --git a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt b/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt
index 7095a6d..5c59f2d 100644
--- a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt
+++ b/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt
@@ -26,6 +26,7 @@ annotation class Description(
  * @param version The version of a [Patch].
  */
 @Target(AnnotationTarget.CLASS)
+@Deprecated("This annotation is deprecated and will be removed in a future release.")
 annotation class Version(
     val version: String,
 )
diff --git a/src/main/kotlin/app/revanced/patcher/data/PackageMetadata.kt b/src/main/kotlin/app/revanced/patcher/data/PackageMetadata.kt
index eaa1601..f6c1886 100644
--- a/src/main/kotlin/app/revanced/patcher/data/PackageMetadata.kt
+++ b/src/main/kotlin/app/revanced/patcher/data/PackageMetadata.kt
@@ -1,13 +1,15 @@
 package app.revanced.patcher.data
 
-import brut.androlib.meta.MetaInfo
+import brut.androlib.apk.ApkInfo
 
 /**
  * Metadata about a package.
  */
 class PackageMetadata {
     lateinit var packageName: String
+        internal set
     lateinit var packageVersion: String
+        internal set
 
-    internal val metaInfo: MetaInfo = MetaInfo()
+    internal lateinit var apkInfo: ApkInfo
 }
diff --git a/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt b/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt
index 06f2224..fb25246 100644
--- a/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt
+++ b/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt
@@ -25,6 +25,7 @@ object PatchExtensions {
     /**
      * The version of a [Patch].
      */
+    @Deprecated("This property is deprecated and will be removed in a future release.")
     val Class<out Patch<Context>>.version
         get() = findAnnotationRecursively(Version::class)?.version
 
diff --git a/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt b/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt
index 9636f64..cfb0c1c 100644
--- a/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt
+++ b/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt
@@ -229,20 +229,4 @@ sealed class PatchOption<T>(
     ) : ListOption<Int>(
         key, default, options, title, description, required, validator
     )
-
-    /**
-     * A [PatchOption] representing a [Path], backed by a [String].
-     * The validator passes a [String], if you need a [Path] you will have to convert it yourself.
-     * @see PatchOption
-     */
-    class PathOption(
-        key: String,
-        default: Path?,
-        title: String,
-        description: String,
-        required: Boolean = false,
-        validator: (String?) -> Boolean = { true }
-    ) : PatchOption<String>(
-        key, default?.pathString, title, description, required, validator
-    )
 }
diff --git a/src/main/kotlin/app/revanced/patcher/util/VersionReader.kt b/src/main/kotlin/app/revanced/patcher/util/VersionReader.kt
deleted file mode 100644
index 6fc15a5..0000000
--- a/src/main/kotlin/app/revanced/patcher/util/VersionReader.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package app.revanced.patcher.util
-
-import java.util.*
-
-internal object VersionReader {
-    @JvmStatic
-    private val props = Properties().apply {
-        load(
-            VersionReader::class.java.getResourceAsStream("/revanced-patcher/version.properties")
-                ?: throw IllegalStateException("Could not load version.properties")
-        )
-    }
-
-    @JvmStatic
-    fun read(): String {
-        return props.getProperty("version") ?: throw IllegalStateException("Version not found")
-    }
-}
\ No newline at end of file
diff --git a/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt b/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt
index d83e9d8..125b59b 100644
--- a/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt
+++ b/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt
@@ -3,8 +3,6 @@ package app.revanced.patcher.patch
 import app.revanced.patcher.usage.bytecode.ExampleBytecodePatch
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertThrows
-import kotlin.io.path.Path
-import kotlin.io.path.pathString
 import kotlin.test.assertNotEquals
 
 internal class PatchOptionsTest {
@@ -35,10 +33,6 @@ internal class PatchOptionsTest {
                         println(choice)
                     }
                 }
-
-                is PatchOption.PathOption -> {
-                    option.value = Path("test.txt").pathString
-                }
             }
         }
         val option = options.get<String>("key1")
diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt b/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt
index 0add464..f3bf0fc 100644
--- a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt
+++ b/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt
@@ -5,8 +5,8 @@ import app.revanced.patcher.annotation.Name
 import app.revanced.patcher.annotation.Version
 import app.revanced.patcher.data.BytecodeContext
 import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
-import app.revanced.patcher.extensions.or
 import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
+import app.revanced.patcher.extensions.or
 import app.revanced.patcher.patch.*
 import app.revanced.patcher.patch.annotations.DependsOn
 import app.revanced.patcher.patch.annotations.Patch
@@ -29,7 +29,6 @@ import org.jf.dexlib2.immutable.reference.ImmutableFieldReference
 import org.jf.dexlib2.immutable.reference.ImmutableStringReference
 import org.jf.dexlib2.immutable.value.ImmutableFieldEncodedValue
 import org.jf.dexlib2.util.Preconditions
-import kotlin.io.path.Path
 
 @Patch
 @Name("example-bytecode-patch")
@@ -193,10 +192,5 @@ class ExampleBytecodePatch : BytecodePatch(listOf(ExampleFingerprint)) {
                 "key5", null, "title", "description", true
             )
         )
-        private var key6 by option(
-            PatchOption.PathOption(
-                "key6", Path("test.txt"), "title", "description", true
-            )
-        )
     }
 }