Compare commits

...

28 Commits

Author SHA1 Message Date
semantic-release-bot
c664a6eaed chore(release): 1.5.1-dev.2 [skip ci]
## [1.5.1-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.5.1-dev.1...v1.5.1-dev.2) (2024-02-08)

### Bug Fixes

* Use the JVM name instead of the value from `KClass#toString` ([d18e436](d18e436de1))
2024-02-08 02:51:47 +00:00
oSumAtrIX
d18e436de1 fix: Use the JVM name instead of the value from KClass#toString 2024-02-08 03:50:15 +01:00
semantic-release-bot
9ff06a2f1b chore(release): 1.5.1-dev.1 [skip ci]
## [1.5.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.5.0...v1.5.1-dev.1) (2024-02-08)

### Bug Fixes

* Map dependencies from `KClass` into `String` to fix serialization ([57e36ab](57e36ab5c1))
2024-02-08 02:10:11 +00:00
oSumAtrIX
57e36ab5c1 fix: Map dependencies from KClass into String to fix serialization 2024-02-08 03:08:10 +01:00
oSumAtrIX
8d934bde00 ci: Use latest Node.js LTS version to fix builds 2024-01-27 00:47:29 +01:00
oSumAtrIX
d1a7699256 ci: Add dependabot 2024-01-26 01:46:20 +01:00
oSumAtrIX
e08d0ad8f3 build: Bump dependencies 2024-01-26 01:46:20 +01:00
oSumAtrIX
4a14c5ccaa build: Bump dependencies 2024-01-10 09:32:58 +01:00
semantic-release-bot
4bbe2fa150 chore(release): 1.5.0 [skip ci]
# [1.5.0](https://github.com/ReVanced/revanced-library/compare/v1.4.0...v1.5.0) (2023-12-28)

### Features

* Add JSON de- and serialization of patches ([ecff6fe](ecff6fe0d3))
* Improve mount reliability by unmounting existing mounts and killing running apps ([9fda407](9fda407441))
2023-12-28 21:35:25 +00:00
oSumAtrIX
938eac53b1 chore: Merge branch dev to main (#20) 2023-12-28 22:34:05 +01:00
Pun Butrach
ab004b91f0 docs: Update to latest branding changes (#23) 2023-12-10 13:31:20 +01:00
semantic-release-bot
b637e0d7d7 chore(release): 1.5.0-dev.2 [skip ci]
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2023-12-07)

### Features

* Improve mount reliability by unmounting existing mounts and killing running apps ([9fda407](9fda407441))
2023-12-07 15:41:07 +00:00
oSumAtrIX
9fda407441 feat: Improve mount reliability by unmounting existing mounts and killing running apps 2023-12-07 16:39:51 +01:00
semantic-release-bot
44f7c13a77 chore(release): 1.5.0-dev.1 [skip ci]
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.4.0...v1.5.0-dev.1) (2023-12-07)

### Features

* Add JSON de- and serialization of patches ([ecff6fe](ecff6fe0d3))
2023-12-07 14:16:31 +00:00
oSumAtrIX
ecff6fe0d3 feat: Add JSON de- and serialization of patches 2023-12-07 15:14:59 +01:00
oSumAtrIX
3515e331ac refactor: Simplify code 2023-12-07 02:45:49 +01:00
oSumAtrIX
a921c40306 build: Bump dependencies 2023-12-07 02:44:36 +01:00
oSumAtrIX
b6e1de5eaf chore: Use correct variable keyword 2023-12-07 02:38:52 +01:00
oSumAtrIX
bf5780e2f7 chore: Improve wording 2023-12-07 02:29:46 +01:00
oSumAtrIX
99e90c02ed refactor: Remove unused typealias 2023-12-01 23:06:29 +01:00
semantic-release-bot
ac3917fecc chore(release): 1.4.0 [skip ci]
# [1.4.0](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0) (2023-11-27)

### Bug Fixes

* Differentiate no package compatibility to any version compatibility ([762b7e3](762b7e3bc0))
* Sort the version maps by the most common version ([e4be6db](e4be6dbccd))

### Features

* Add `PatchUtils#getMostCommonCompatibleVersions` utility function ([c5f3536](c5f3536cbb))
* Allow getting most common compatible versions for all packages ([96845ba](96845ba265))
2023-11-27 21:50:58 +00:00
oSumAtrIX
98b7b347cb chore: Merge branch dev to main (#19) 2023-11-27 22:49:52 +01:00
semantic-release-bot
cdf94ffeca chore(release): 1.4.0-dev.2 [skip ci]
# [1.4.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2023-11-27)

### Bug Fixes

* Differentiate no package compatibility to any version compatibility ([762b7e3](762b7e3bc0))
* Sort the version maps by the most common version ([e4be6db](e4be6dbccd))

### Features

* Allow getting most common compatible versions for all packages ([96845ba](96845ba265))
2023-11-27 21:43:22 +00:00
oSumAtrIX
37434cf4a4 build: Bump dependencies 2023-11-27 22:40:07 +01:00
oSumAtrIX
73c97abedd chore: Lint code 2023-11-27 22:40:00 +01:00
oSumAtrIX
762b7e3bc0 fix: Differentiate no package compatibility to any version compatibility 2023-11-27 22:30:59 +01:00
oSumAtrIX
e4be6dbccd fix: Sort the version maps by the most common version 2023-11-27 21:21:25 +01:00
oSumAtrIX
96845ba265 feat: Allow getting most common compatible versions for all packages 2023-11-27 21:03:23 +01:00
14 changed files with 843 additions and 4931 deletions

22
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: github-actions
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly
- package-ecosystem: npm
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly
- package-ecosystem: gradle
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly

View File

@@ -1,4 +1,4 @@
name: Publish ReVanced Library
name: Release
on:
workflow_dispatch:
@@ -24,23 +24,21 @@ jobs:
persist-credentials: false
fetch-depth: 0
- name: Cache Node modules
uses: actions/cache@v3
with:
path: |
node_modules
key: npm-${{ hashFiles('package-lock.json') }}
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Cleaning is necessary to avoid uploading two identical artifacts with different versions
run: ./gradlew clean --no-daemon
run: ./gradlew build clean
- name: Setup semantic-release
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Release

View File

@@ -1,3 +1,66 @@
## [1.5.1-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.5.1-dev.1...v1.5.1-dev.2) (2024-02-08)
### Bug Fixes
* Use the JVM name instead of the value from `KClass#toString` ([d18e436](https://github.com/ReVanced/revanced-library/commit/d18e436de1df14452ecaa7d827be5e6596ba8a2d))
## [1.5.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.5.0...v1.5.1-dev.1) (2024-02-08)
### Bug Fixes
* Map dependencies from `KClass` into `String` to fix serialization ([57e36ab](https://github.com/ReVanced/revanced-library/commit/57e36ab5c15a5fa7c50fb689ee43ad4eb9a4a515))
# [1.5.0](https://github.com/ReVanced/revanced-library/compare/v1.4.0...v1.5.0) (2023-12-28)
### Features
* Add JSON de- and serialization of patches ([ecff6fe](https://github.com/ReVanced/revanced-library/commit/ecff6fe0d3889d729a0badcfa28b89610bd27d48))
* Improve mount reliability by unmounting existing mounts and killing running apps ([9fda407](https://github.com/ReVanced/revanced-library/commit/9fda40744173669c84b0c2599ae5ac5d39591798))
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2023-12-07)
### Features
* Improve mount reliability by unmounting existing mounts and killing running apps ([9fda407](https://github.com/ReVanced/revanced-library/commit/9fda40744173669c84b0c2599ae5ac5d39591798))
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.4.0...v1.5.0-dev.1) (2023-12-07)
### Features
* Add JSON de- and serialization of patches ([ecff6fe](https://github.com/ReVanced/revanced-library/commit/ecff6fe0d3889d729a0badcfa28b89610bd27d48))
# [1.4.0](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0) (2023-11-27)
### Bug Fixes
* Differentiate no package compatibility to any version compatibility ([762b7e3](https://github.com/ReVanced/revanced-library/commit/762b7e3bc01e2ca33dfcdbb1b5028d60ef6e0a48))
* Sort the version maps by the most common version ([e4be6db](https://github.com/ReVanced/revanced-library/commit/e4be6dbccd86700ffafe7cd8395e845bbd3d5138))
### Features
* Add `PatchUtils#getMostCommonCompatibleVersions` utility function ([c5f3536](https://github.com/ReVanced/revanced-library/commit/c5f3536cbb6997766076595dc0b2b5d2e861ca73))
* Allow getting most common compatible versions for all packages ([96845ba](https://github.com/ReVanced/revanced-library/commit/96845ba265e6dc208c7ac96f5e58734209cd1720))
# [1.4.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2023-11-27)
### Bug Fixes
* Differentiate no package compatibility to any version compatibility ([762b7e3](https://github.com/ReVanced/revanced-library/commit/762b7e3bc01e2ca33dfcdbb1b5028d60ef6e0a48))
* Sort the version maps by the most common version ([e4be6db](https://github.com/ReVanced/revanced-library/commit/e4be6dbccd86700ffafe7cd8395e845bbd3d5138))
### Features
* Allow getting most common compatible versions for all packages ([96845ba](https://github.com/ReVanced/revanced-library/commit/96845ba265e6dc208c7ac96f5e58734209cd1720))
# [1.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0-dev.1) (2023-11-27)

View File

@@ -6,34 +6,53 @@
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
width="256px"
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" />
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/revanced">
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://twitter.com/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" />
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</a>&nbsp;&nbsp;&nbsp;
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
@@ -54,7 +73,7 @@ This document describes how to contribute to ReVanced Library.
Features can be requested by opening an issue using the
[Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature-request.yml&title=feat%3A+).
> **Note**
> [!NOTE]
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Library.
> Good motivation has to be provided for a request to be accepted.
@@ -76,4 +95,4 @@ If you encounter a bug while using ReVanced Library, open an issue using the
it will be merged into the `dev` branch and will be included in the next release of ReVanced Library
❤️ Thank you for considering contributing to ReVanced Library,
ReVanced
ReVanced

View File

@@ -67,6 +67,47 @@ public final class app/revanced/library/PatchUtils {
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
}
public final class app/revanced/library/PatchUtils$Json {
public static final field INSTANCE Lapp/revanced/library/PatchUtils$Json;
public final fun deserialize (Ljava/io/InputStream;Ljava/lang/Class;)Ljava/util/Set;
public final fun serialize (Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;)V
public static synthetic fun serialize$default (Lapp/revanced/library/PatchUtils$Json;Ljava/util/Set;Lkotlin/jvm/functions/Function1;ZLjava/io/OutputStream;ILjava/lang/Object;)V
}
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch : app/revanced/library/PatchUtils$Json$JsonPatch {
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$Companion;
public final fun getCompatiblePackages ()Ljava/util/Set;
public final fun getDependencies ()Ljava/util/Set;
public final fun getDescription ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getOptions ()Ljava/util/Map;
public final fun getRequiresIntegrations ()Z
public final fun getUse ()Z
public final fun setRequiresIntegrations (Z)V
}
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$Companion {
public final fun fromPatch (Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch;
}
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption {
public static final field Companion Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion;
public final fun getDefault ()Ljava/lang/Object;
public final fun getDescription ()Ljava/lang/String;
public final fun getKey ()Ljava/lang/String;
public final fun getRequired ()Z
public final fun getTitle ()Ljava/lang/String;
public final fun getValueType ()Ljava/lang/String;
public final fun getValues ()Ljava/util/Map;
}
public final class app/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption$Companion {
public final fun fromPatchOption (Lapp/revanced/patcher/patch/options/PatchOption;)Lapp/revanced/library/PatchUtils$Json$FullJsonPatch$FullJsonPatchOption;
}
public abstract interface class app/revanced/library/PatchUtils$Json$JsonPatch {
}
public abstract class app/revanced/library/adb/AdbManager {
public static final field Companion Lapp/revanced/library/adb/AdbManager$Companion;
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 1.4.0-dev.1
version = 1.5.1-dev.2

View File

@@ -3,9 +3,9 @@ apksig = "8.1.4"
bcpkix-jdk18on = "1.76"
jackson-module-kotlin = "2.14.3"
jadb = "1.2.1"
kotlin-reflect = "1.9.10"
kotlin-test = "1.9.10"
revanced-patcher = "19.0.0"
kotlin-reflect = "1.9.20"
kotlin-test = "1.9.20"
revanced-patcher = "19.2.0"
binary-compatibility-validator = "0.13.2"
[libraries]

5227
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
{
"devDependencies": {
"@saithodev/semantic-release-backmerge": "^3.2.1",
"@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.8.0",
"semantic-release": "^22.0.8"
"gradle-semantic-release-plugin": "^1.9.1",
"semantic-release": "^23.0.0"
}
}

View File

@@ -3,24 +3,22 @@
package app.revanced.library
import app.revanced.library.Options.Patch.Option
import app.revanced.patcher.PatchClass
import app.revanced.patcher.PatchSet
import app.revanced.patcher.patch.options.PatchOptionException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.File
import java.util.logging.Logger
private typealias PatchList = List<PatchClass>
@Suppress("unused")
object Options {
private val logger = Logger.getLogger(Options::class.java.name)
private var mapper = jacksonObjectMapper()
private val mapper = jacksonObjectMapper()
/**
* Serializes the options for the patches in the list.
* Serializes the options for a set of patches.
*
* @param patches The list of patches to serialize.
* @param patches The set of patches to serialize.
* @param prettyPrint Whether to pretty print the JSON.
* @return The JSON string containing the options.
*/
@@ -57,17 +55,16 @@ object Options {
}
/**
* Deserializes the options for the patches in the list.
* Deserializes the options to a set of patches.
*
* @param json The JSON string containing the options.
* @return The list of [Patch]s.
* @return A set of [Patch]s.
* @see Patch
* @see PatchList
*/
fun deserialize(json: String): Array<Patch> = mapper.readValue(json, Array<Patch>::class.java)
/**
* Sets the options for the patches in the list.
* Sets the options for a set of patches.
*
* @param json The JSON string containing the options.
*/
@@ -95,7 +92,7 @@ object Options {
}
/**
* Sets the options for the patches in the list.
* Sets the options for a set of patches.
*
* @param file The file containing the JSON string containing the options.
* @see setOptions

View File

@@ -1,14 +1,19 @@
package app.revanced.library
import app.revanced.patcher.PatchSet
import java.util.*
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.options.PatchOption
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.InputStream
import java.io.OutputStream
import kotlin.reflect.jvm.jvmName
private typealias PackageName = String
private typealias Version = String
private typealias Count = Int
typealias PackageName = String
typealias Version = String
typealias Count = Int
private typealias VersionMap = SortedMap<Version, Count>
internal typealias PackageNameMap = Map<PackageName, VersionMap>
typealias VersionMap = LinkedHashMap<Version, Count>
typealias PackageNameMap = Map<PackageName, VersionMap>
/**
* Utility functions for working with patches.
@@ -26,7 +31,7 @@ object PatchUtils {
"Use getMostCommonCompatibleVersions instead.",
ReplaceWith(
"getMostCommonCompatibleVersions(patches, setOf(packageName))" +
".entries.firstOrNull()?.value?.keys?.firstOrNull()",
".entries.firstOrNull()?.value?.keys?.firstOrNull()",
),
)
fun getMostCommonCompatibleVersion(
@@ -48,30 +53,146 @@ object PatchUtils {
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version.
*
* @param patches The set of patches to check.
* @param packageNames The names of the compatible packages.
* @param packageNames The names of the compatible packages to include. If null, all packages will be included.
* @param countUnusedPatches Whether to count patches that are not used.
* @return A map of package names to a map of versions to their count.
*/
fun getMostCommonCompatibleVersions(
patches: PatchSet,
packageNames: Set<String>,
packageNames: Set<String>? = null,
countUnusedPatches: Boolean = false,
): PackageNameMap {
val wantedPackages = packageNames.toHashSet()
return buildMap {
): PackageNameMap =
buildMap {
fun filterWantedPackages(compatiblePackages: Iterable<Patch.CompatiblePackage>): Iterable<Patch.CompatiblePackage> {
val wantedPackages = packageNames?.toHashSet() ?: return compatiblePackages
return compatiblePackages.filter { it.name in wantedPackages }
}
patches
.filter { it.use || countUnusedPatches }
.flatMap { it.compatiblePackages ?: emptyList() }
.filter { it.name in wantedPackages }
.let(::filterWantedPackages)
.forEach { compatiblePackage ->
compatiblePackage.versions?.let { versions ->
val versionMap = getOrPut(compatiblePackage.name) { sortedMapOf() }
if (compatiblePackage.versions?.isEmpty() == true) {
return@forEach
}
val versionMap = getOrPut(compatiblePackage.name) { linkedMapOf() }
compatiblePackage.versions?.let { versions ->
versions.forEach { version ->
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
}
}
}
// Sort the version maps by the most common version.
forEach { (packageName, versionMap) ->
this[packageName] =
versionMap
.asIterable()
.sortedWith(compareByDescending { it.value })
.associate { it.key to it.value } as VersionMap
}
}
object Json {
private val mapper = jacksonObjectMapper()
/**
* Serializes a set of [Patch]es to a JSON string and writes it to an output stream.
*
* @param patches The set of [Patch]es to serialize.
* @param transform A function to transform the [Patch]es to [JsonPatch]es.
* @param prettyPrint Whether to pretty print the JSON.
* @param outputStream The output stream to write the JSON to.
*/
fun serialize(
patches: PatchSet,
transform: (Patch<*>) -> JsonPatch = { patch -> FullJsonPatch.fromPatch(patch) },
prettyPrint: Boolean = false,
outputStream: OutputStream,
) {
patches.map(transform).let { transformed ->
if (prettyPrint) {
mapper.writerWithDefaultPrettyPrinter().writeValue(outputStream, transformed)
} else {
mapper.writeValue(outputStream, transformed)
}
}
}
/**
* Deserializes a JSON string to a set of [FullJsonPatch]es from an input stream.
*
* @param inputStream The input stream to read the JSON from.
* @param jsonPatchElementClass The class of the [JsonPatch]es to deserialize.
* @return A set of [JsonPatch]es.
* @see FullJsonPatch
*/
fun <T : JsonPatch> deserialize(
inputStream: InputStream,
jsonPatchElementClass: Class<T>,
): Set<T> =
mapper.readValue(
inputStream,
mapper.typeFactory.constructCollectionType(Set::class.java, jsonPatchElementClass),
)
interface JsonPatch
/**
* A JSON representation of a [Patch].
* @see Patch
*/
class FullJsonPatch internal constructor(
val name: String?,
val description: String?,
val compatiblePackages: Set<Patch.CompatiblePackage>?,
val dependencies: Set<String>?,
val use: Boolean,
var requiresIntegrations: Boolean,
val options: Map<String, FullJsonPatchOption<*>>,
) : JsonPatch {
companion object {
fun fromPatch(patch: Patch<*>) =
FullJsonPatch(
patch.name,
patch.description,
patch.compatiblePackages,
buildSet { patch.dependencies?.forEach { add(it.jvmName) } },
patch.use,
patch.requiresIntegrations,
patch.options.mapValues { FullJsonPatchOption.fromPatchOption(it.value) },
)
}
/**
* A JSON representation of a [PatchOption].
* @see PatchOption
*/
class FullJsonPatchOption<T> internal constructor(
val key: String,
val default: T?,
val values: Map<String, T?>?,
val title: String?,
val description: String?,
val required: Boolean,
val valueType: String,
) {
companion object {
fun fromPatchOption(option: PatchOption<*>) =
FullJsonPatchOption(
option.key,
option.default,
option.values,
option.title,
option.description,
option.required,
option.valueType,
)
}
}
}
}
}

View File

@@ -5,10 +5,11 @@ import app.revanced.library.adb.Constants.CREATE_DIR
import app.revanced.library.adb.Constants.DELETE
import app.revanced.library.adb.Constants.GET_INSTALLED_PATH
import app.revanced.library.adb.Constants.INSTALLATION_PATH
import app.revanced.library.adb.Constants.INSTALL_MOUNT
import app.revanced.library.adb.Constants.INSTALL_MOUNT_SCRIPT
import app.revanced.library.adb.Constants.INSTALL_PATCHED_APK
import app.revanced.library.adb.Constants.MOUNT_PATH
import app.revanced.library.adb.Constants.KILL
import app.revanced.library.adb.Constants.MOUNT_SCRIPT
import app.revanced.library.adb.Constants.MOUNT_SCRIPT_PATH
import app.revanced.library.adb.Constants.PATCHED_APK_PATH
import app.revanced.library.adb.Constants.PLACEHOLDER
import app.revanced.library.adb.Constants.RESTART
@@ -104,9 +105,8 @@ sealed class AdbManager private constructor(deviceSerial: String?) {
device.createFile(TMP_PATH, MOUNT_SCRIPT.applyReplacement(packageName))
device.run(INSTALL_MOUNT, packageName).waitFor()
device.run(UMOUNT, packageName).waitFor() // Sanity check.
device.run(MOUNT_PATH, packageName).waitFor()
device.run(INSTALL_MOUNT_SCRIPT, packageName).waitFor()
device.run(MOUNT_SCRIPT_PATH, packageName).waitFor()
device.run(RESTART, packageName)
device.run(DELETE, TMP_PATH)
@@ -118,9 +118,9 @@ sealed class AdbManager private constructor(deviceSerial: String?) {
device.run(UMOUNT, packageName)
device.run(DELETE.applyReplacement(PATCHED_APK_PATH), packageName)
device.run(DELETE, MOUNT_PATH.applyReplacement(packageName))
device.run(DELETE, MOUNT_SCRIPT_PATH.applyReplacement(packageName))
device.run(DELETE, TMP_PATH)
device.run(RESTART, packageName)
device.run(KILL, packageName)
super.uninstall(packageName)
}

View File

@@ -6,11 +6,12 @@ internal object Constants {
internal const val TMP_PATH = "/data/local/tmp/revanced.tmp"
internal const val INSTALLATION_PATH = "/data/adb/revanced/"
internal const val PATCHED_APK_PATH = "$INSTALLATION_PATH$PLACEHOLDER.apk"
internal const val MOUNT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
internal const val MOUNT_SCRIPT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
internal const val DELETE = "rm -rf $PLACEHOLDER"
internal const val CREATE_DIR = "mkdir -p"
internal const val RESTART = "am start -S $PLACEHOLDER"
internal const val KILL = "am force-stop $PLACEHOLDER"
internal const val GET_INSTALLED_PATH = "pm path $PLACEHOLDER"
internal const val INSTALL_PATCHED_APK =
@@ -23,7 +24,7 @@ internal object Constants {
internal const val UMOUNT =
"grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d ' ' -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
internal const val INSTALL_MOUNT = "mv $TMP_PATH $MOUNT_PATH && chmod +x $MOUNT_PATH"
internal const val INSTALL_MOUNT_SCRIPT = "mv $TMP_PATH $MOUNT_SCRIPT_PATH && chmod +x $MOUNT_SCRIPT_PATH"
internal val MOUNT_SCRIPT =
"""
@@ -33,11 +34,17 @@ internal object Constants {
until [ "$( getprop sys.boot_completed )" = 1 ]; do sleep 3; done
until [ -d "/sdcard/Android" ]; do sleep 1; done
# Unmount any existing mount as a safety measure
$UMOUNT
base_path="$PATCHED_APK_PATH"
stock_path=$( pm path $PLACEHOLDER | grep base | sed 's/package://g' )
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
# Kill the app to force it to restart the mounted APK in case it's already running
$KILL
""".trimIndent()
}

View File

@@ -4,36 +4,75 @@ import app.revanced.patcher.PatchSet
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intArrayPatchOption
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
import org.junit.jupiter.api.Test
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import kotlin.test.assertEquals
internal object PatchUtilsTest {
private val patches =
arrayOf(
newPatch("some.package", "a"),
newPatch("some.package", "a", "b", use = false),
newPatch("some.package", "a", "b", "c", use = false),
newPatch("some.other.package", "b", use = false),
newPatch("some.other.package", "b", "c"),
newPatch("some.other.package", "b", "c", "d"),
newPatch("some.other.other.package"),
newPatch("some.other.other.package", "a"),
newPatch("some.other.other.package", "b"),
newPatch("some.package", setOf("a")) { stringPatchOption("string", "value") },
newPatch("some.package", setOf("a", "b"), use = false),
newPatch("some.package", setOf("a", "b", "c"), use = false),
newPatch("some.other.package", setOf("b"), use = false),
newPatch("some.other.package", setOf("b", "c")) { booleanPatchOption("bool", true) },
newPatch("some.other.package", setOf("b", "c", "d")),
newPatch("some.other.other.package") { intArrayPatchOption("intArray", arrayOf(1, 2, 3)) },
newPatch("some.other.other.package", setOf("a")),
newPatch("some.other.other.package", setOf("b")),
newPatch("some.other.other.other.package", use = false),
newPatch("some.other.other.other.package", use = false),
).toSet()
@Test
fun `return common versions correctly ordered for each package`() {
fun `empty because package is incompatible with any version`() {
assertEqualsVersions(
expected =
mapOf(
"some.package" to sortedMapOf("a" to 3, "b" to 2, "c" to 1),
"some.other.package" to sortedMapOf("b" to 3, "c" to 2, "d" to 1),
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
"some.other.other.other.package" to sortedMapOf(),
),
expected = emptyMap(),
patches = setOf(newPatch("some.package", emptySet(), use = true)),
compatiblePackageNames = setOf("some.package"),
)
}
@Test
fun `empty list of versions because package is unconstrained to any version`() {
assertEqualsVersions(
expected = mapOf("some.package" to linkedMapOf()),
patches = setOf(newPatch("some.package")),
compatiblePackageNames = setOf("some.package"),
countUnusedPatches = true,
)
}
@Test
fun `empty because no known package was supplied`() {
assertEqualsVersions(
expected = emptyMap(),
patches,
compatiblePackageNames = setOf("unknown.package"),
)
}
@Test
fun `common versions correctly ordered for each package`() {
fun assertEqualsExpected(compatiblePackageNames: Set<String>?) =
assertEqualsVersions(
expected =
mapOf(
"some.package" to linkedMapOf("a" to 3, "b" to 2, "c" to 1),
"some.other.package" to linkedMapOf("b" to 3, "c" to 2, "d" to 1),
"some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
"some.other.other.other.package" to linkedMapOf(),
),
patches,
compatiblePackageNames,
countUnusedPatches = true,
)
assertEqualsExpected(
compatiblePackageNames =
setOf(
"some.package",
@@ -41,18 +80,21 @@ internal object PatchUtilsTest {
"some.other.other.package",
"some.other.other.other.package",
),
countUnusedPatches = true,
)
assertEqualsExpected(
compatiblePackageNames = null,
)
}
@Test
fun `return common versions correctly ordered for each package without counting unused patches`() {
fun `common versions correctly ordered for each package without counting unused patches`() {
assertEqualsVersions(
expected =
mapOf(
"some.package" to sortedMapOf("a" to 1),
"some.other.package" to sortedMapOf("b" to 2, "c" to 2, "d" to 1),
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
"some.package" to linkedMapOf("a" to 1),
"some.other.package" to linkedMapOf("b" to 2, "c" to 2, "d" to 1),
"some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
),
patches,
compatiblePackageNames =
@@ -66,30 +108,11 @@ internal object PatchUtilsTest {
)
}
@Test
fun `return an empty map because no known package was supplied`() {
assertEqualsVersions(
expected = emptyMap(),
patches,
compatiblePackageNames = setOf("unknown.package"),
)
}
@Test
fun `return empty set of versions because no compatible package is constrained to a version`() {
assertEqualsVersions(
expected = mapOf("some.package" to sortedMapOf()),
patches = setOf(newPatch("some.package")),
compatiblePackageNames = setOf("some.package"),
countUnusedPatches = true,
)
}
@Test
fun `return 'a' because it is the most common version`() {
val patches =
arrayOf("a", "a", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d")
.map { version -> newPatch("some.package", version) }
.map { version -> newPatch("some.package", setOf(version)) }
.toSet()
assertEqualsVersion("a", patches, "some.package")
@@ -102,7 +125,7 @@ internal object PatchUtilsTest {
@Test
fun `return null because no patch is compatible with the supplied package name`() {
val patches = setOf(newPatch("some.package", "a"))
val patches = setOf(newPatch("some.package", setOf("a")))
assertEqualsVersion(null, patches, "other.package")
}
@@ -118,10 +141,24 @@ internal object PatchUtilsTest {
assertEqualsVersion(null, patches, "other.package")
}
@Test
fun `serializes to and deserializes from JSON string correctly`() {
val out = ByteArrayOutputStream()
PatchUtils.Json.serialize(patches, outputStream = out)
val deserialized =
PatchUtils.Json.deserialize(
ByteArrayInputStream(out.toByteArray()),
PatchUtils.Json.FullJsonPatch::class.java,
)
assert(patches.size == deserialized.size)
}
private fun assertEqualsVersions(
expected: PackageNameMap,
patches: PatchSet,
compatiblePackageNames: Set<String>,
compatiblePackageNames: Set<String>?,
countUnusedPatches: Boolean = false,
) = assertEquals(
expected,
@@ -135,6 +172,7 @@ internal object PatchUtilsTest {
) {
// Test both the deprecated and the new method.
@Suppress("DEPRECATION")
assertEquals(
expected,
PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName),
@@ -149,21 +187,16 @@ internal object PatchUtilsTest {
private fun newPatch(
packageName: String,
vararg versions: String,
versions: Set<String>? = null,
use: Boolean = true,
) = object : BytecodePatch() {
options: Patch<*>.() -> Unit = {},
) = object : BytecodePatch(
name = "test",
compatiblePackages = setOf(CompatiblePackage(packageName, versions?.toSet())),
use = use,
) {
init {
// Set the compatible packages field to the supplied package name and versions reflectively,
// because the setter is private but needed for testing.
val compatiblePackagesField = Patch::class.java.getDeclaredField("compatiblePackages")
compatiblePackagesField.isAccessible = true
compatiblePackagesField.set(this, setOf(CompatiblePackage(packageName, versions.toSet())))
val useField = Patch::class.java.getDeclaredField("use")
useField.isAccessible = true
useField.set(this, use)
options()
}
override fun execute(context: BytecodeContext) {}