Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add downloader plugin system #2041

Open
wants to merge 18 commits into
base: compose-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import kotlin.random.Random
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.devtools)
alias(libs.plugins.about.libraries)
id("kotlin-parcelize")
kotlin("plugin.serialization") version "1.9.23"
alias(libs.plugins.compose.compiler)
}

android {
Expand Down Expand Up @@ -81,17 +82,18 @@ android {
jvmTarget = "17"
}

buildFeatures.compose = true
buildFeatures.aidl = true
buildFeatures.buildConfig=true
buildFeatures {
compose = true
aidl = true
buildConfig = true
}

android {
androidResources {
generateLocaleConfig = true
}
}

composeOptions.kotlinCompilerExtensionVersion = "1.5.10"
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
Expand All @@ -112,7 +114,6 @@ dependencies {
implementation(libs.runtime.compose)
implementation(libs.splash.screen)
implementation(libs.compose.activity)
implementation(libs.paging.common.ktx)
implementation(libs.work.runtime.ktx)
implementation(libs.preferences.datastore)

Expand Down Expand Up @@ -153,6 +154,9 @@ dependencies {
implementation(libs.revanced.patcher)
implementation(libs.revanced.library)

// Downloader plugins
implementation(project(":downloader-plugin"))

// Native processes
implementation(libs.kotlin.process)

Expand Down
8 changes: 8 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@
-keep class com.android.** {
*;
}
# These two are used by downloader plugins
-keep class app.revanced.manager.plugin.** {
*;
}
-keep class androidx.paging.** {
*;
}

-dontwarn com.google.auto.value.**
-dontwarn java.awt.**
-dontwarn javax.**
Expand Down
30 changes: 28 additions & 2 deletions app/schemas/app.revanced.manager.data.room.AppDatabase/1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "1dd9d5c0201fdf3cfef3ae669fd65e46",
"identityHash": "393045599eb516fc7ef99f142485e9a2",
"entities": [
{
"tableName": "patch_bundles",
Expand Down Expand Up @@ -392,12 +392,38 @@
]
}
]
},
{
"tableName": "trusted_downloader_plugins",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `signature` BLOB NOT NULL, PRIMARY KEY(`package_name`))",
"fields": [
{
"fieldPath": "packageName",
"columnName": "package_name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"package_name"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dd9d5c0201fdf3cfef3ae669fd65e46')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '393045599eb516fc7ef99f142485e9a2')"
]
}
}
17 changes: 9 additions & 8 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="ReservedSystemPermission" />
<permission
android:name="app.revanced.manager.permission.PLUGIN_HOST"
android:protectionLevel="signature"
android:label="@string/plugin_host_permission_label"
android:description="@string/plugin_host_permission_description"
/>

<uses-permission android:name="app.revanced.manager.permission.PLUGIN_HOST" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Expand All @@ -17,12 +24,6 @@
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>

<application
android:name=".ManagerApplication"
android:allowBackup="true"
Expand Down
39 changes: 14 additions & 25 deletions app/src/main/java/app/revanced/manager/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.getValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import app.revanced.manager.ui.destination.Destination
import app.revanced.manager.ui.destination.SettingsDestination
import app.revanced.manager.ui.screen.AppSelectorScreen
Expand All @@ -15,7 +16,6 @@ import app.revanced.manager.ui.screen.InstalledAppInfoScreen
import app.revanced.manager.ui.screen.PatcherScreen
import app.revanced.manager.ui.screen.SelectedAppInfoScreen
import app.revanced.manager.ui.screen.SettingsScreen
import app.revanced.manager.ui.screen.VersionSelectorScreen
import app.revanced.manager.ui.theme.ReVancedManagerTheme
import app.revanced.manager.ui.theme.Theme
import app.revanced.manager.ui.viewmodel.MainViewModel
Expand All @@ -35,6 +35,8 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)

installSplashScreen()

val vm: MainViewModel = getAndroidViewModel()
Expand All @@ -59,9 +61,12 @@ class MainActivity : ComponentActivity() {
is Destination.Dashboard -> DashboardScreen(
onSettingsClick = { navController.navigate(Destination.Settings()) },
onAppSelectorClick = { navController.navigate(Destination.AppSelector) },
onUpdateClick = { navController.navigate(
Destination.Settings(SettingsDestination.Update())
) },
onUpdateClick = {
navController.navigate(Destination.Settings(SettingsDestination.Update()))
},
onDownloaderPluginClick = {
navController.navigate(Destination.Settings(SettingsDestination.Downloads))
},
onAppClick = { installedApp ->
navController.navigate(
Destination.InstalledApplicationInfo(
Expand All @@ -73,12 +78,13 @@ class MainActivity : ComponentActivity() {

is Destination.InstalledApplicationInfo -> InstalledAppInfoScreen(
onPatchClick = { packageName, patchSelection ->
/*
navController.navigate(
Destination.VersionSelector(
packageName,
patchSelection
)
)
)*/
},
onBackClick = { navController.pop() },
viewModel = getComposeViewModel { parametersOf(destination.installedApp) }
Expand All @@ -90,8 +96,9 @@ class MainActivity : ComponentActivity() {
)

is Destination.AppSelector -> AppSelectorScreen(
onAppClick = { navController.navigate(Destination.VersionSelector(it)) },
onStorageClick = {
// onAppClick = { navController.navigate(Destination.VersionSelector(it)) },
// TODO: complete this feature
onSelect = {
navController.navigate(
Destination.SelectedApplicationInfo(
it
Expand All @@ -101,24 +108,6 @@ class MainActivity : ComponentActivity() {
onBackClick = { navController.pop() }
)

is Destination.VersionSelector -> VersionSelectorScreen(
onBackClick = { navController.pop() },
onAppClick = { selectedApp ->
navController.navigate(
Destination.SelectedApplicationInfo(
selectedApp,
destination.patchSelection,
)
)
},
viewModel = getComposeViewModel {
parametersOf(
destination.packageName,
destination.patchSelection
)
}
)

is Destination.SelectedApplicationInfo -> SelectedAppInfoScreen(
onPatchClick = { app, patches, options ->
navController.navigate(
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/app/revanced/manager/ManagerApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app.revanced.manager
import android.app.Application
import app.revanced.manager.di.*
import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.DownloaderPluginRepository
import app.revanced.manager.domain.repository.PatchBundleRepository
import kotlinx.coroutines.Dispatchers
import coil.Coil
Expand All @@ -23,6 +24,8 @@ class ManagerApplication : Application() {
private val scope = MainScope()
private val prefs: PreferencesManager by inject()
private val patchBundleRepository: PatchBundleRepository by inject()
private val downloaderPluginRepository: DownloaderPluginRepository by inject()

override fun onCreate() {
super.onCreate()

Expand Down Expand Up @@ -59,6 +62,9 @@ class ManagerApplication : Application() {
scope.launch {
prefs.preload()
}
scope.launch(Dispatchers.Default) {
downloaderPluginRepository.reload()
}
scope.launch(Dispatchers.Default) {
with(patchBundleRepository) {
reload()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@ import app.revanced.manager.data.room.bundles.PatchBundleEntity
import app.revanced.manager.data.room.options.Option
import app.revanced.manager.data.room.options.OptionDao
import app.revanced.manager.data.room.options.OptionGroup
import app.revanced.manager.data.room.plugins.TrustedDownloaderPlugin
import app.revanced.manager.data.room.plugins.TrustedDownloaderPluginDao
import kotlin.random.Random

@Database(entities = [PatchBundleEntity::class, PatchSelection::class, SelectedPatch::class, DownloadedApp::class, InstalledApp::class, AppliedPatch::class, OptionGroup::class, Option::class], version = 1)
@Database(
entities = [PatchBundleEntity::class, PatchSelection::class, SelectedPatch::class, DownloadedApp::class, InstalledApp::class, AppliedPatch::class, OptionGroup::class, Option::class, TrustedDownloaderPlugin::class],
version = 1
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun patchBundleDao(): PatchBundleDao
abstract fun selectionDao(): SelectionDao
abstract fun downloadedAppDao(): DownloadedAppDao
abstract fun installedAppDao(): InstalledAppDao
abstract fun optionDao(): OptionDao
abstract fun trustedDownloaderPluginDao(): TrustedDownloaderPluginDao

companion object {
fun generateUid() = Random.Default.nextInt()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app.revanced.manager.data.room.plugins

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "trusted_downloader_plugins")
class TrustedDownloaderPlugin(
@PrimaryKey @ColumnInfo(name = "package_name") val packageName: String,
@ColumnInfo(name = "signature") val signature: ByteArray
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package app.revanced.manager.data.room.plugins

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert

@Dao
interface TrustedDownloaderPluginDao {
@Query("SELECT signature FROM trusted_downloader_plugins WHERE package_name = :packageName")
suspend fun getTrustedSignature(packageName: String): ByteArray?

@Upsert
suspend fun upsertTrust(plugin: TrustedDownloaderPlugin)

@Query("DELETE FROM trusted_downloader_plugins WHERE package_name = :packageName")
suspend fun remove(packageName: String)

@Transaction
@Query("DELETE FROM trusted_downloader_plugins WHERE package_name IN (:packageNames)")
suspend fun removeAll(packageNames: Set<String>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ val repositoryModule = module {
// It is best to load patch bundles ASAP
createdAtStart()
}
singleOf(::DownloaderPluginRepository)
singleOf(::WorkerRepository)
singleOf(::DownloadedAppRepository)
singleOf(::InstalledAppRepository)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ val viewModelModule = module {
viewModelOf(::SettingsViewModel)
viewModelOf(::AdvancedSettingsViewModel)
viewModelOf(::AppSelectorViewModel)
viewModelOf(::VersionSelectorViewModel)
viewModelOf(::PatcherViewModel)
viewModelOf(::UpdateViewModel)
viewModelOf(::ChangelogsViewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ class PreferencesManager(
val keystoreCommonName = stringPreference("keystore_cn", KeystoreManager.DEFAULT)
val keystorePass = stringPreference("keystore_pass", KeystoreManager.DEFAULT)

val preferSplits = booleanPreference("prefer_splits", false)

val firstLaunch = booleanPreference("first_launch", true)
val managerAutoUpdates = booleanPreference("manager_auto_updates", false)
val showManagerUpdateDialogOnLaunch = booleanPreference("show_manager_update_dialog_on_launch", true)
Expand All @@ -29,4 +27,6 @@ class PreferencesManager(
val disableSelectionWarning = booleanPreference("disable_selection_warning", false)
val disableUniversalPatchWarning = booleanPreference("disable_universal_patch_warning", false)
val suggestedVersionSafeguard = booleanPreference("suggested_version_safeguard", true)

val acknowledgedDownloaderPlugins = stringSetPreference("acknowledged_downloader_plugins", emptySet())
}
Loading