mirror of
https://github.com/ReVanced/revanced-library.git
synced 2026-01-18 17:03:57 +00:00
Compare commits
22 Commits
v3.0.1-dev
...
patcher22
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93abadd7d7 | ||
|
|
791c484ff3 | ||
|
|
2cc260d587 | ||
|
|
5df2bb81bf | ||
|
|
be0f6bf247 | ||
|
|
9d060c188f | ||
|
|
254f36d03c | ||
|
|
4065c87d5f | ||
|
|
be8d7bf643 | ||
|
|
2328902b6b | ||
|
|
7ec6504619 | ||
|
|
e7a98b5795 | ||
|
|
649f06b19d | ||
|
|
cace51700a | ||
|
|
91cefc8598 | ||
|
|
735c1e39cd | ||
|
|
84cc315541 | ||
|
|
4fe9304570 | ||
|
|
8bb41be8fc | ||
|
|
4b8ac026c3 | ||
|
|
557b6035f8 | ||
|
|
bfc5394b4e |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -11,8 +11,8 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,3 +1,56 @@
|
|||||||
|
# [3.2.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.1.1-dev.1...v3.2.0-dev.1) (2025-05-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Request the update ownership enforcement ([#71](https://github.com/ReVanced/revanced-library/issues/71)) ([be0f6bf](https://github.com/ReVanced/revanced-library/commit/be0f6bf247461d16fbf649a9f2dc6facbb5b0c93))
|
||||||
|
|
||||||
|
## [3.1.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.1.0...v3.1.1-dev.1) (2025-05-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Interpret package name as a string instead of Regex when using grep ([#68](https://github.com/ReVanced/revanced-library/issues/68)) ([254f36d](https://github.com/ReVanced/revanced-library/commit/254f36d03cc8fd3e2508a5e8f69bb5c8e1eb9775))
|
||||||
|
|
||||||
|
# [3.1.0](https://github.com/ReVanced/revanced-library/compare/v3.0.2...v3.1.0) (2024-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Detect if app is installed by fixing inversion ([649f06b](https://github.com/ReVanced/revanced-library/commit/649f06b19dd4d2a3f3216a0b3ea947b9fe0d475f))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Warn when option could not be set because the option does not exist ([7ec6504](https://github.com/ReVanced/revanced-library/commit/7ec650461935faf2a8fbb667db3cf137157b70b5))
|
||||||
|
|
||||||
|
# [3.1.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.3-dev.1...v3.1.0-dev.1) (2024-11-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Warn when option could not be set because the option does not exist ([7ec6504](https://github.com/ReVanced/revanced-library/commit/7ec650461935faf2a8fbb667db3cf137157b70b5))
|
||||||
|
|
||||||
|
## [3.0.3-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.2...v3.0.3-dev.1) (2024-11-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Detect if app is installed by fixing inversion ([649f06b](https://github.com/ReVanced/revanced-library/commit/649f06b19dd4d2a3f3216a0b3ea947b9fe0d475f))
|
||||||
|
|
||||||
|
## [3.0.2](https://github.com/ReVanced/revanced-library/compare/v3.0.1...v3.0.2) (2024-11-05)
|
||||||
|
|
||||||
|
## [3.0.2-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.1...v3.0.2-dev.1) (2024-11-05)
|
||||||
|
|
||||||
|
## [3.0.1](https://github.com/ReVanced/revanced-library/compare/v3.0.0...v3.0.1) (2024-10-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Serialize compatible packages as a map instead of a set of pairs. ([737e272](https://github.com/ReVanced/revanced-library/commit/737e272481fe3b0b4c89233d139b5e657a0c1de4))
|
||||||
|
|
||||||
|
## [3.0.1-dev.3](https://github.com/ReVanced/revanced-library/compare/v3.0.1-dev.2...v3.0.1-dev.3) (2024-10-06)
|
||||||
|
|
||||||
## [3.0.1-dev.2](https://github.com/ReVanced/revanced-library/compare/v3.0.1-dev.1...v3.0.1-dev.2) (2024-10-01)
|
## [3.0.1-dev.2](https://github.com/ReVanced/revanced-library/compare/v3.0.1-dev.1...v3.0.1-dev.2) (2024-10-01)
|
||||||
|
|
||||||
## [3.0.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.0...v3.0.1-dev.1) (2024-08-16)
|
## [3.0.1-dev.1](https://github.com/ReVanced/revanced-library/compare/v3.0.0...v3.0.1-dev.1) (2024-08-16)
|
||||||
|
|||||||
@@ -47,6 +47,18 @@ public final class app/revanced/library/ApkUtils$PrivateKeyCertificatePairDetail
|
|||||||
public final fun getValidUntil ()Ljava/util/Date;
|
public final fun getValidUntil ()Ljava/util/Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/CryptographyKt {
|
||||||
|
public static final fun getPublicKey (Lorg/bouncycastle/openpgp/PGPPublicKeyRing;)Lorg/bouncycastle/openpgp/PGPPublicKey;
|
||||||
|
public static final fun getPublicKeyRing (Lorg/bouncycastle/openpgp/PGPPublicKeyRingCollection;J)Lorg/bouncycastle/openpgp/PGPPublicKeyRing;
|
||||||
|
public static final fun getPublicKeyRingCollection (Ljava/io/InputStream;)Lorg/bouncycastle/openpgp/PGPPublicKeyRingCollection;
|
||||||
|
public static final fun getSignature (Ljava/io/InputStream;)Lorg/bouncycastle/openpgp/PGPSignature;
|
||||||
|
public static final fun matchGitHub (Ldev/sigstore/fulcio/client/ImmutableFulcioCertificateMatcher$Builder;Ljava/lang/String;)Ldev/sigstore/fulcio/client/ImmutableFulcioCertificateMatcher$Builder;
|
||||||
|
public static final fun verificationOptions (Lkotlin/jvm/functions/Function1;)Ldev/sigstore/VerificationOptions;
|
||||||
|
public static final fun verifySLSA ([BLjava/io/InputStream;Ldev/sigstore/VerificationOptions;)Z
|
||||||
|
public static final fun verifySLSA ([BLjava/io/InputStream;Lkotlin/jvm/functions/Function1;)Z
|
||||||
|
public static final fun verifySignature ([BLorg/bouncycastle/openpgp/PGPSignature;Lorg/bouncycastle/openpgp/PGPPublicKey;)Z
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/OptionsKt {
|
public final class app/revanced/library/OptionsKt {
|
||||||
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
||||||
}
|
}
|
||||||
@@ -97,7 +109,7 @@ public abstract interface class app/revanced/library/installation/command/RunRes
|
|||||||
public abstract fun getError ()Ljava/lang/String;
|
public abstract fun getError ()Ljava/lang/String;
|
||||||
public abstract fun getExitCode ()I
|
public abstract fun getExitCode ()I
|
||||||
public abstract fun getOutput ()Ljava/lang/String;
|
public abstract fun getOutput ()Ljava/lang/String;
|
||||||
public abstract fun waitFor ()V
|
public fun waitFor ()V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
||||||
|
|||||||
@@ -47,6 +47,18 @@ public final class app/revanced/library/ApkUtils$PrivateKeyCertificatePairDetail
|
|||||||
public final fun getValidUntil ()Ljava/util/Date;
|
public final fun getValidUntil ()Ljava/util/Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/library/CryptographyKt {
|
||||||
|
public static final fun getPublicKey (Lorg/bouncycastle/openpgp/PGPPublicKeyRing;)Lorg/bouncycastle/openpgp/PGPPublicKey;
|
||||||
|
public static final fun getPublicKeyRing (Lorg/bouncycastle/openpgp/PGPPublicKeyRingCollection;J)Lorg/bouncycastle/openpgp/PGPPublicKeyRing;
|
||||||
|
public static final fun getPublicKeyRingCollection (Ljava/io/InputStream;)Lorg/bouncycastle/openpgp/PGPPublicKeyRingCollection;
|
||||||
|
public static final fun getSignature (Ljava/io/InputStream;)Lorg/bouncycastle/openpgp/PGPSignature;
|
||||||
|
public static final fun matchGitHub (Ldev/sigstore/fulcio/client/ImmutableFulcioCertificateMatcher$Builder;Ljava/lang/String;)Ldev/sigstore/fulcio/client/ImmutableFulcioCertificateMatcher$Builder;
|
||||||
|
public static final fun verificationOptions (Lkotlin/jvm/functions/Function1;)Ldev/sigstore/VerificationOptions;
|
||||||
|
public static final fun verifySLSA ([BLjava/io/InputStream;Ldev/sigstore/VerificationOptions;)Z
|
||||||
|
public static final fun verifySLSA ([BLjava/io/InputStream;Lkotlin/jvm/functions/Function1;)Z
|
||||||
|
public static final fun verifySignature ([BLorg/bouncycastle/openpgp/PGPSignature;Lorg/bouncycastle/openpgp/PGPPublicKey;)Z
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/OptionsKt {
|
public final class app/revanced/library/OptionsKt {
|
||||||
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
public static final fun setOptions (Ljava/util/Set;Ljava/util/Map;)V
|
||||||
}
|
}
|
||||||
@@ -73,7 +85,7 @@ public abstract interface class app/revanced/library/installation/command/RunRes
|
|||||||
public abstract fun getError ()Ljava/lang/String;
|
public abstract fun getError ()Ljava/lang/String;
|
||||||
public abstract fun getExitCode ()I
|
public abstract fun getExitCode ()I
|
||||||
public abstract fun getOutput ()Ljava/lang/String;
|
public abstract fun getOutput ()Ljava/lang/String;
|
||||||
public abstract fun waitFor ()V
|
public fun waitFor ()V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
public final class app/revanced/library/installation/command/RunResult$DefaultImpls {
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ kotlin {
|
|||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation(libs.apksig)
|
implementation(libs.apksig)
|
||||||
implementation(libs.apkzlib)
|
implementation(libs.apkzlib)
|
||||||
implementation(libs.bcpkix.jdk15on)
|
implementation(libs.bouncycastle.bcpkix)
|
||||||
|
implementation(libs.bouncycastle.pgp)
|
||||||
|
implementation(libs.sigstore.java)
|
||||||
implementation(libs.guava)
|
implementation(libs.guava)
|
||||||
implementation(libs.jadb)
|
implementation(libs.jadb)
|
||||||
implementation(libs.kotlin.reflect)
|
implementation(libs.kotlin.reflect)
|
||||||
@@ -71,7 +73,7 @@ kotlin {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.revanced.library"
|
namespace = "app.revanced.library"
|
||||||
compileSdk = 34
|
compileSdk = 36
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
version = 3.0.1-dev.2
|
version = 3.2.0-dev.2-local
|
||||||
#Gradle
|
#Gradle
|
||||||
org.gradle.jvmargs = -Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options="-Xmx2048M"
|
org.gradle.jvmargs = -Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options="-Xmx2048M"
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
[versions]
|
[versions]
|
||||||
android = "8.5.1"
|
android = "8.12.3"
|
||||||
bcpkix-jdk15on = "1.70"
|
binary-compatibility-validator = "0.18.1"
|
||||||
binary-compatibility-validator = "0.15.1"
|
core-ktx = "1.17.0"
|
||||||
core-ktx = "1.13.1"
|
guava = "33.5.0-jre"
|
||||||
guava = "33.0.0-jre"
|
jadb = "1.2.1.1"
|
||||||
jadb = "1.2.1"
|
kotlin = "2.2.21"
|
||||||
kotlin = "2.0.0"
|
kotlinx-coroutines = "1.10.2"
|
||||||
kotlinx-coroutines = "1.8.1"
|
kotlinx-serialization = "1.9.0"
|
||||||
kotlinx-serialization = "1.7.1"
|
|
||||||
libsu = "5.2.2"
|
libsu = "5.2.2"
|
||||||
revanced-patcher = "20.0.0"
|
revanced-patcher = "22.0.0-local"
|
||||||
|
bouncy-castle = "1.82"
|
||||||
|
sigstore = "2.0.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
apkzlib = { module = "com.android.tools.build:apkzlib", version.ref = "android" }
|
apkzlib = { module = "com.android.tools.build:apkzlib", version.ref = "android" }
|
||||||
apksig = { module = "com.android.tools.build:apksig", version.ref = "android" }
|
apksig = { module = "com.android.tools.build:apksig", version.ref = "android" }
|
||||||
bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bcpkix-jdk15on" }
|
|
||||||
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
|
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
|
||||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||||
jadb = { module = "app.revanced:jadb", version.ref = "jadb" } # Fork with Shell v2 support.
|
jadb = { module = "app.revanced:jadb", version.ref = "jadb" } # Fork with Shell v2 support.
|
||||||
@@ -26,6 +26,9 @@ libsu-core = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu"
|
|||||||
libsu-nio = { module = "com.github.topjohnwu.libsu:nio", version.ref = "libsu" }
|
libsu-nio = { module = "com.github.topjohnwu.libsu:nio", version.ref = "libsu" }
|
||||||
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
||||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||||
|
bouncycastle-bcpkix = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "bouncy-castle" }
|
||||||
|
bouncycastle-pgp = { module = "org.bouncycastle:bcpg-jdk18on", version.ref = "bouncy-castle" }
|
||||||
|
sigstore-java = { module = "dev.sigstore:sigstore-java", version.ref = "sigstore" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-library = { id = "com.android.library", version.ref = "android" }
|
android-library = { id = "com.android.library", version.ref = "android" }
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
12
gradlew
vendored
12
gradlew
vendored
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright © 2015 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -86,8 +86,7 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -115,7 +114,6 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -173,7 +171,6 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -206,15 +203,14 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
3
gradlew.bat
vendored
3
gradlew.bat
vendored
@@ -70,11 +70,10 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
|||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageInstaller
|
import android.content.pm.PackageInstaller
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import app.revanced.library.installation.installer.Installer.Apk
|
import app.revanced.library.installation.installer.Installer.Apk
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
@@ -78,17 +79,20 @@ class LocalInstaller(
|
|||||||
override suspend fun getInstallation(packageName: String) = try {
|
override suspend fun getInstallation(packageName: String) = try {
|
||||||
val packageInfo = context.packageManager.getPackageInfo(packageName, 0)
|
val packageInfo = context.packageManager.getPackageInfo(packageName, 0)
|
||||||
|
|
||||||
Installation(packageInfo.applicationInfo.sourceDir)
|
Installation(packageInfo.applicationInfo!!.sourceDir)
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() = context.unregisterReceiver(broadcastReceiver)
|
override fun close() = context.unregisterReceiver(broadcastReceiver)
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
companion object {
|
companion object {
|
||||||
private val sessionParams = PackageInstaller.SessionParams(
|
private val sessionParams = PackageInstaller.SessionParams(
|
||||||
PackageInstaller.SessionParams.MODE_FULL_INSTALL,
|
PackageInstaller.SessionParams.MODE_FULL_INSTALL,
|
||||||
).apply {
|
).apply {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
|
setRequestUpdateOwnership(true)
|
||||||
setInstallReason(PackageManager.INSTALL_REASON_USER)
|
setInstallReason(PackageManager.INSTALL_REASON_USER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package app.revanced.library
|
package app.revanced.library
|
||||||
|
|
||||||
import com.android.apksig.ApkSigner.SignerConfig
|
import com.android.apksig.ApkSigner.SignerConfig
|
||||||
|
import com.android.apksig.KeyConfig
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||||
import org.bouncycastle.cert.X509v3CertificateBuilder
|
import org.bouncycastle.cert.X509v3CertificateBuilder
|
||||||
@@ -155,12 +156,11 @@ object ApkSigner {
|
|||||||
|
|
||||||
// Read the private key and certificate from the keystore.
|
// Read the private key and certificate from the keystore.
|
||||||
|
|
||||||
val privateKey =
|
val privateKey = try {
|
||||||
try {
|
keyStore.getKey(keyStoreEntryAlias, keyStoreEntryPassword.toCharArray()) as PrivateKey
|
||||||
keyStore.getKey(keyStoreEntryAlias, keyStoreEntryPassword.toCharArray()) as PrivateKey
|
} catch (exception: UnrecoverableKeyException) {
|
||||||
} catch (exception: UnrecoverableKeyException) {
|
throw IllegalArgumentException("Invalid password for keystore entry $keyStoreEntryAlias")
|
||||||
throw IllegalArgumentException("Invalid password for keystore entry $keyStoreEntryAlias")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val certificate = keyStore.getCertificate(keyStoreEntryAlias) as X509Certificate
|
val certificate = keyStore.getCertificate(keyStoreEntryAlias) as X509Certificate
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ object ApkSigner {
|
|||||||
listOf(
|
listOf(
|
||||||
SignerConfig.Builder(
|
SignerConfig.Builder(
|
||||||
signer,
|
signer,
|
||||||
privateKeyCertificatePair.privateKey,
|
KeyConfig.Jca(privateKeyCertificatePair.privateKey),
|
||||||
listOf(privateKeyCertificatePair.certificate),
|
listOf(privateKeyCertificatePair.certificate),
|
||||||
).build(),
|
).build(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ object ApkUtils {
|
|||||||
// Delete resources that were staged for deletion.
|
// Delete resources that were staged for deletion.
|
||||||
if (resources.deleteResources.isNotEmpty()) {
|
if (resources.deleteResources.isNotEmpty()) {
|
||||||
targetApkZFile.entries().filter { entry ->
|
targetApkZFile.entries().filter { entry ->
|
||||||
resources.deleteResources.any { shouldDelete -> shouldDelete(entry.centralDirectoryHeader.name) }
|
entry.centralDirectoryHeader.name in resources.deleteResources
|
||||||
}.forEach(StoredEntry::delete)
|
}.forEach(StoredEntry::delete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
163
src/commonMain/kotlin/app/revanced/library/Cryptography.kt
Normal file
163
src/commonMain/kotlin/app/revanced/library/Cryptography.kt
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package app.revanced.library
|
||||||
|
|
||||||
|
import dev.sigstore.KeylessVerifier
|
||||||
|
import dev.sigstore.VerificationOptions
|
||||||
|
import dev.sigstore.VerificationOptions.CertificateMatcher
|
||||||
|
import dev.sigstore.bundle.Bundle
|
||||||
|
import dev.sigstore.dsse.InTotoPayload
|
||||||
|
import dev.sigstore.fulcio.client.ImmutableFulcioCertificateMatcher.Builder
|
||||||
|
import dev.sigstore.strings.StringMatcher
|
||||||
|
import org.bouncycastle.openpgp.*
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
// region PGP signature verification.
|
||||||
|
|
||||||
|
private val verifierBuilderProvider = BcPGPContentVerifierBuilderProvider()
|
||||||
|
|
||||||
|
private val fingerprintCalculator = BcKeyFingerprintCalculator()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the PGP signature of the provided bytes using the provided signature and public key.
|
||||||
|
*
|
||||||
|
* @param bytes The bytes to verify.
|
||||||
|
* @param signature The PGP signature.
|
||||||
|
* @param publicKey The PGP public key.
|
||||||
|
* @return True if the signature is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
fun verifySignature(
|
||||||
|
bytes: ByteArray, signature: PGPSignature, publicKey: PGPPublicKey
|
||||||
|
) = signature.apply {
|
||||||
|
init(verifierBuilderProvider, publicKey)
|
||||||
|
update(bytes)
|
||||||
|
}.verify()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PGP signature from the provided signature input stream.
|
||||||
|
*
|
||||||
|
* @param signatureInputStream The input stream of the PGP signature.
|
||||||
|
* @return The PGP signature.
|
||||||
|
* @throws IllegalArgumentException if the signature format is invalid.
|
||||||
|
*/
|
||||||
|
fun getSignature(
|
||||||
|
signatureInputStream: InputStream
|
||||||
|
) = when (val pgpObject = PGPObjectFactory(
|
||||||
|
PGPUtil.getDecoderStream(signatureInputStream), fingerprintCalculator
|
||||||
|
).nextObject()) {
|
||||||
|
is PGPSignatureList -> pgpObject
|
||||||
|
is PGPCompressedData -> {
|
||||||
|
val compressedDataFactory = PGPObjectFactory(
|
||||||
|
pgpObject.dataStream, fingerprintCalculator
|
||||||
|
)
|
||||||
|
compressedDataFactory.nextObject() as PGPSignatureList
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Invalid PGP signature format.")
|
||||||
|
}.first()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PGP public key ring collection from the provided public key ring input stream.
|
||||||
|
*
|
||||||
|
* @param publicKeyRingInputStream The input stream of the public key ring.
|
||||||
|
* @return The PGP public key ring collection.
|
||||||
|
*/
|
||||||
|
fun getPublicKeyRingCollection(
|
||||||
|
publicKeyRingInputStream: InputStream
|
||||||
|
) = PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicKeyRingInputStream), fingerprintCalculator)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PGP public key ring with the specified key ID from the provided public key ring collection.
|
||||||
|
*
|
||||||
|
* @param publicKeyRingCollection The PGP public key ring collection.
|
||||||
|
* @param keyId The key ID of the public key ring to retrieve.
|
||||||
|
* @return The PGP public key ring with the specified key ID.
|
||||||
|
* @throws IllegalArgumentException if the public key ring with the specified key ID is not found.
|
||||||
|
*/
|
||||||
|
fun getPublicKeyRing(
|
||||||
|
publicKeyRingCollection: PGPPublicKeyRingCollection, keyId: Long
|
||||||
|
) = publicKeyRingCollection.getPublicKeyRing(keyId)
|
||||||
|
?: throw IllegalArgumentException("Can't find public key ring with ID $keyId.")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PGP public key from the provided public key ring.
|
||||||
|
*/
|
||||||
|
fun getPublicKey(publicKeyRing: PGPPublicKeyRing): PGPPublicKey = publicKeyRing.publicKey
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region SLSA attestation verification.
|
||||||
|
|
||||||
|
private val keylessVerifier: KeylessVerifier = KeylessVerifier.builder().sigstorePublicDefaults().build()
|
||||||
|
|
||||||
|
private const val RUNNER_ENVIRONMENT_OID = "1.3.6.1.4.1.57264.1.11"
|
||||||
|
|
||||||
|
private const val PROVENANCE_PREDICATE_TYPE = "https://slsa.dev/provenance/v1"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the SLSA attestation of the provided digest using the provided attestation input stream and matcher.
|
||||||
|
*
|
||||||
|
* @param digest The digest to verify.
|
||||||
|
* @param attestationInputStream The input stream of the attestation.
|
||||||
|
* @param matcher The matcher to add to the verification options.
|
||||||
|
* @return True if the verification is successful, false otherwise.
|
||||||
|
*/
|
||||||
|
fun verifySLSA(
|
||||||
|
digest: ByteArray,
|
||||||
|
attestationInputStream: InputStream,
|
||||||
|
matcher: Builder.() -> Builder,
|
||||||
|
) = verifySLSA(digest, attestationInputStream, verificationOptions(matcher))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the SLSA attestation of the provided digest using the provided attestation input stream
|
||||||
|
* and verification options.
|
||||||
|
*
|
||||||
|
* @param digest The digest to verify.
|
||||||
|
* @param attestationInputStream The input stream of the attestation.
|
||||||
|
* @param verificationOptions The verification options to use.
|
||||||
|
* @return True if the verification is successful, false otherwise.
|
||||||
|
*/
|
||||||
|
fun verifySLSA(
|
||||||
|
digest: ByteArray,
|
||||||
|
attestationInputStream: InputStream,
|
||||||
|
verificationOptions: VerificationOptions,
|
||||||
|
) = runCatching {
|
||||||
|
val bundle = Bundle.from(attestationInputStream.reader())
|
||||||
|
|
||||||
|
val predicateType = InTotoPayload.from(bundle.dsseEnvelope.get()).predicateType
|
||||||
|
require(predicateType == PROVENANCE_PREDICATE_TYPE)
|
||||||
|
|
||||||
|
keylessVerifier.verify(digest, bundle, verificationOptions)
|
||||||
|
}.isSuccess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates verification options with the provided matcher.
|
||||||
|
*
|
||||||
|
* @param matcher The matcher to add to the verification options.
|
||||||
|
* @return The created verification options.
|
||||||
|
*/
|
||||||
|
fun verificationOptions(
|
||||||
|
matcher: Builder.() -> Builder
|
||||||
|
): VerificationOptions = VerificationOptions.builder().addCertificateMatchers(
|
||||||
|
CertificateMatcher.fulcio().matcher().build()
|
||||||
|
).build()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds GitHub-specific matching to the builder for the specified repository.
|
||||||
|
*
|
||||||
|
* @param repository The GitHub repository in the format "owner/repo".
|
||||||
|
* @return The updated builder with GitHub-specific matching.
|
||||||
|
*/
|
||||||
|
fun Builder.matchGitHub(
|
||||||
|
repository: String
|
||||||
|
): Builder = issuer(
|
||||||
|
StringMatcher.string("https://token.actions.githubusercontent.com")
|
||||||
|
).subjectAlternativeName(
|
||||||
|
StringMatcher.regex("(?i)^https://github.com/$repository")
|
||||||
|
).putOidDerAsn1Strings(RUNNER_ENVIRONMENT_OID, StringMatcher.string("github-hosted"))
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
@@ -19,11 +19,16 @@ private val logger = Logger.getLogger("Options")
|
|||||||
* @param options The options to set. The key is the patch name and the value is a map of option keys to option values.
|
* @param options The options to set. The key is the patch name and the value is a map of option keys to option values.
|
||||||
*/
|
*/
|
||||||
fun Set<Patch<*>>.setOptions(options: PatchesOptions) = filter { it.name != null }.forEach { patch ->
|
fun Set<Patch<*>>.setOptions(options: PatchesOptions) = filter { it.name != null }.forEach { patch ->
|
||||||
val patchOptions = options[patch.name] ?: return@forEach
|
options[patch.name]?.forEach setOption@{ (optionKey, optionValue) ->
|
||||||
|
if (optionKey !in patch.options) {
|
||||||
|
return@setOption logger.warning(
|
||||||
|
"Could not set option for the \"${patch.name}\" patch because " +
|
||||||
|
"option with key \"${optionKey}\" does not exist",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
patch.options.forEach option@{ option ->
|
|
||||||
try {
|
try {
|
||||||
patch.options[option.key] = patchOptions[option.key] ?: return@option
|
patch.options[optionKey] = optionValue
|
||||||
} catch (e: OptionException) {
|
} catch (e: OptionException) {
|
||||||
logger.warning("Could not set option value for the \"${patch.name}\" patch: ${e.message}")
|
logger.warning("Could not set option value for the \"${patch.name}\" patch: ${e.message}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package app.revanced.library.installation.installer
|
package app.revanced.library.installation.installer
|
||||||
|
|
||||||
import app.revanced.library.installation.command.AdbShellCommandRunner
|
import app.revanced.library.installation.command.AdbShellCommandRunner
|
||||||
|
import app.revanced.library.installation.command.ShellCommandRunner
|
||||||
|
import app.revanced.library.installation.installer.Constants.GET_SDK_VERSION
|
||||||
import app.revanced.library.installation.installer.Constants.INSTALLED_APK_PATH
|
import app.revanced.library.installation.installer.Constants.INSTALLED_APK_PATH
|
||||||
import app.revanced.library.installation.installer.Installer.Apk
|
|
||||||
import se.vidstige.jadb.JadbException
|
import se.vidstige.jadb.JadbException
|
||||||
import se.vidstige.jadb.managers.Package
|
import se.vidstige.jadb.managers.Package
|
||||||
import se.vidstige.jadb.managers.PackageManager
|
import se.vidstige.jadb.managers.PackageManager
|
||||||
|
import se.vidstige.jadb.managers.PackageManager.UPDATE_OWNERSHIP
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [AdbInstaller] for installing and uninstalling [Apk] files using ADB.
|
* [AdbInstaller] for installing and uninstalling [Apk] files using ADB.
|
||||||
@@ -17,18 +19,23 @@ import se.vidstige.jadb.managers.PackageManager
|
|||||||
class AdbInstaller(
|
class AdbInstaller(
|
||||||
deviceSerial: String? = null,
|
deviceSerial: String? = null,
|
||||||
) : Installer<AdbInstallerResult, Installation>() {
|
) : Installer<AdbInstallerResult, Installation>() {
|
||||||
private val device = getDevice(deviceSerial, logger)
|
private val shellCommandRunner: ShellCommandRunner
|
||||||
private val adbShellCommandRunner = AdbShellCommandRunner(device)
|
private val packageManager: PackageManager
|
||||||
private val packageManager = PackageManager(device)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
val device = getDevice(deviceSerial, logger)
|
||||||
|
shellCommandRunner = AdbShellCommandRunner(device)
|
||||||
|
packageManager = PackageManager(device)
|
||||||
|
|
||||||
logger.fine("Connected to $deviceSerial")
|
logger.fine("Connected to $deviceSerial")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun install(apk: Apk): AdbInstallerResult {
|
override suspend fun install(apk: Apk): AdbInstallerResult {
|
||||||
logger.info("Installing ${apk.file.name}")
|
return runPackageManager {
|
||||||
|
val sdkVersion = shellCommandRunner(GET_SDK_VERSION).output.toInt()
|
||||||
return runPackageManager { install(apk.file) }
|
if (sdkVersion < 34) install(apk.file)
|
||||||
|
else installWithOptions(apk.file, listOf(UPDATE_OWNERSHIP))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun uninstall(packageName: String): AdbInstallerResult {
|
override suspend fun uninstall(packageName: String): AdbInstallerResult {
|
||||||
@@ -39,7 +46,7 @@ class AdbInstaller(
|
|||||||
|
|
||||||
override suspend fun getInstallation(packageName: String): Installation? = packageManager.packages.find {
|
override suspend fun getInstallation(packageName: String): Installation? = packageManager.packages.find {
|
||||||
it.toString() == packageName
|
it.toString() == packageName
|
||||||
}?.let { Installation(adbShellCommandRunner(INSTALLED_APK_PATH).output) }
|
}?.let { Installation(shellCommandRunner(INSTALLED_APK_PATH).output) }
|
||||||
|
|
||||||
private fun runPackageManager(block: PackageManager.() -> Unit) = try {
|
private fun runPackageManager(block: PackageManager.() -> Unit) = try {
|
||||||
packageManager.run(block)
|
packageManager.run(block)
|
||||||
|
|||||||
@@ -4,26 +4,28 @@ package app.revanced.library.installation.installer
|
|||||||
internal object Constants {
|
internal object Constants {
|
||||||
const val PLACEHOLDER = "PLACEHOLDER"
|
const val PLACEHOLDER = "PLACEHOLDER"
|
||||||
|
|
||||||
|
const val SELINUX_CONTEXT = "u:object_r:apk_data_file:s0"
|
||||||
const val TMP_FILE_PATH = "/data/local/tmp/revanced.tmp"
|
const val TMP_FILE_PATH = "/data/local/tmp/revanced.tmp"
|
||||||
const val MOUNT_PATH = "/data/adb/revanced/"
|
const val MOUNT_PATH = "/data/adb/revanced/"
|
||||||
const val MOUNTED_APK_PATH = "$MOUNT_PATH$PLACEHOLDER.apk"
|
const val MOUNTED_APK_PATH = "$MOUNT_PATH$PLACEHOLDER.apk"
|
||||||
const val MOUNT_SCRIPT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
|
const val MOUNT_SCRIPT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
|
||||||
|
|
||||||
const val EXISTS = "[[ -f $PLACEHOLDER ]] || exit 1"
|
const val EXISTS = "[[ -f $PLACEHOLDER ]] || exit 1"
|
||||||
const val MOUNT_GREP = "grep $PLACEHOLDER /proc/mounts"
|
const val MOUNT_GREP = "grep -F $PLACEHOLDER /proc/mounts"
|
||||||
const val DELETE = "rm -rf $PLACEHOLDER"
|
const val DELETE = "rm -rf $PLACEHOLDER"
|
||||||
const val CREATE_DIR = "mkdir -p"
|
const val CREATE_DIR = "mkdir -p"
|
||||||
const val RESTART = "am start -S $PLACEHOLDER"
|
const val RESTART = "am start -S $PLACEHOLDER"
|
||||||
const val KILL = "am force-stop $PLACEHOLDER"
|
const val KILL = "am force-stop $PLACEHOLDER"
|
||||||
const val INSTALLED_APK_PATH = "pm path $PLACEHOLDER"
|
const val INSTALLED_APK_PATH = "pm path $PLACEHOLDER"
|
||||||
const val CREATE_INSTALLATION_PATH = "$CREATE_DIR $MOUNT_PATH"
|
const val CREATE_INSTALLATION_PATH = "$CREATE_DIR $MOUNT_PATH"
|
||||||
|
const val GET_SDK_VERSION = "getprop ro.build.version.sdk"
|
||||||
|
|
||||||
const val MOUNT_APK =
|
const val MOUNT_APK =
|
||||||
"base_path=\"$MOUNTED_APK_PATH\" && " +
|
"base_path=\"$MOUNTED_APK_PATH\" && " +
|
||||||
"mv $TMP_FILE_PATH \$base_path && " +
|
"mv $TMP_FILE_PATH \$base_path && " +
|
||||||
"chmod 644 \$base_path && " +
|
"chmod 644 \$base_path && " +
|
||||||
"chown system:system \$base_path && " +
|
"chown system:system \$base_path && " +
|
||||||
"chcon u:object_r:apk_data_file:s0 \$base_path"
|
"chcon $SELINUX_CONTEXT \$base_path"
|
||||||
|
|
||||||
const val UMOUNT =
|
const val UMOUNT =
|
||||||
"grep $PLACEHOLDER /proc/mounts | " +
|
"grep $PLACEHOLDER /proc/mounts | " +
|
||||||
@@ -52,7 +54,7 @@ internal object Constants {
|
|||||||
|
|
||||||
base_path="$MOUNTED_APK_PATH"
|
base_path="$MOUNTED_APK_PATH"
|
||||||
|
|
||||||
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
|
chcon $SELINUX_CONTEXT ${'$'}base_path
|
||||||
|
|
||||||
# Use Magisk mirror, if possible.
|
# Use Magisk mirror, if possible.
|
||||||
if command -v magisk &> /dev/null; then
|
if command -v magisk &> /dev/null; then
|
||||||
|
|||||||
@@ -122,13 +122,12 @@ abstract class RootInstaller internal constructor(
|
|||||||
* @throws FailedToFindInstalledPackageException If the package is not installed.
|
* @throws FailedToFindInstalledPackageException If the package is not installed.
|
||||||
*/
|
*/
|
||||||
private fun String.assertInstalled() {
|
private fun String.assertInstalled() {
|
||||||
if (INSTALLED_APK_PATH(this)().output.isNotEmpty()) {
|
if (INSTALLED_APK_PATH(this)().output.isEmpty()) {
|
||||||
throw FailedToFindInstalledPackageException(this)
|
throw FailedToFindInstalledPackageException(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class FailedToFindInstalledPackageException internal constructor(packageName: String) :
|
internal class FailedToFindInstalledPackageException internal constructor(packageName: String) : Exception("Failed to find installed package \"$packageName\" because no activity was found")
|
||||||
Exception("Failed to find installed package \"$packageName\" because no activity was found")
|
|
||||||
|
|
||||||
internal class PackageNameRequiredException internal constructor() : Exception("Package name is required")
|
internal class PackageNameRequiredException internal constructor() : Exception("Package name is required")
|
||||||
internal class NoRootPermissionException internal constructor() : Exception("No root permission")
|
internal class NoRootPermissionException internal constructor() : Exception("No root permission")
|
||||||
|
|||||||
Reference in New Issue
Block a user