feat: Update to account for API changes

This commit is contained in:
Ax333l
2025-01-11 22:29:24 +01:00
parent 8a94f909bd
commit 2aa975ab5a
10 changed files with 76 additions and 171 deletions

6
.gitignore vendored
View File

@@ -123,4 +123,8 @@ gradle-app.setting
node_modules/
# Ignore IDEA files
.idea/
.idea/
.kotlin/
local.properties

View File

@@ -63,13 +63,11 @@
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-manager-downloader-template/release.yml)
![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-yellow.svg)
Template repository for ReVanced Manager downloader.
Template repository for ReVanced Manager downloader plugins.
## ❓ About
This is a template to create a new ReVanced Manager downloader repository.
For an example repository, see [TODO](https://github.com/revanced/revanced-manager).
This is a template to create a new ReVanced Manager downloader repository. An example implementation is included.
## 🚀 Get started
@@ -108,7 +106,7 @@ To develop and release ReVanced Manager downloader using this template, some thi
- Commits on the `dev` branch and `main` branch are automatically released
via the [release.yml](.github/workflows/release.yml) workflow, which is also responsible for generating the changelog
and updating the version of ReVanced Manager downloader. It is triggered by pushing to the `dev` or `main` branch.
The workflow uses the `publish` task to publish the release of ReVanced Patches
The workflow uses the `publish` task to publish the release.
- The `publish` task depends on the `assembleRelease` task, so it will be run automatically when publishing a release.
## 📚 Everything else
@@ -126,6 +124,17 @@ Follow the steps below to build ReVanced Manager downloader template:
1. Run `git clone git@github.com:ReVanced/revanced-manager-downloader-template.git` to clone the repository
2. Run `gradlew assembleRelease` to build the project
> [!NOTE]
> If the build fails due to authentication, you may need to authenticate to GitHub Packages.
> Create a PAT with the scope `read:packages` [here](https://github.com/settings/tokens/new?scopes=read:packages&description=ReVanced) and add your token to ~/.gradle/gradle.properties.
>
> Example `gradle.properties` file:
>
> ```properties
> gpr.user = user
> gpr.key = key
> ```
## 📜 Licence
ReVanced Manager downloader template is licensed under the GPLv3 licence.

View File

@@ -1,36 +1,26 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.parcelize)
publishing
signing
}
dependencies {
implementation(libs.compose.activity)
implementation(platform(libs.compose.bom))
implementation(libs.compose.material3)
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling)
compileOnly(project(":downloader-plugin"))
compileOnly(libs.plugin.api)
}
android {
val packageName = "app.revanced.manager.plugin.downloader.example"
namespace = packageName
compileSdk = 34
compileSdk = 35
defaultConfig {
applicationId = packageName
minSdk = 26
targetSdk = 34
targetSdk = 35
versionName = version.toString()
versionCode = versionName!!.filter { it.isDigit() }.toInt()
buildConfigField("String", "PLUGIN_PACKAGE_NAME", "\"$packageName\"")
}
buildTypes {
@@ -64,11 +54,6 @@ android {
jvmTarget = "17"
}
buildFeatures {
compose = true
buildConfig = true
}
applicationVariants.all {
outputs.all {
this as com.android.build.gradle.internal.api.ApkVariantOutputImpl

View File

@@ -4,3 +4,5 @@ android.nonFinalResIds=false
kotlin.code.style = official
org.gradle.parallel = true
org.gradle.caching = true
version = 1.0.0

View File

@@ -1,20 +1,11 @@
[versions]
android = "8.5.2"
compose-activity = "1.9.1"
compose-bom = "2024.08.00"
kotlin = "2.0.20"
material3 = "1.3.0-rc01"
ui-tooling = "1.6.8"
plugin-api = "1.0.0"
android-gradle-plugin = "8.7.3"
kotlin = "2.1.0"
[libraries]
compose-activity = { group = "androidx.activity", name = "activity-compose", version.ref = "compose-activity" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3"}
compose-ui = { group = "androidx.compose.ui", name = "ui" }
compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "ui-tooling" }
plugin-api = { group = "app.revanced", name = "revanced-manager-downloader-api", version.ref = "plugin-api" }
[plugins]
android-application = { id = "com.android.application", version.ref = "android" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -7,14 +7,12 @@
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
tools:targetApi="34">
<activity
android:name=".InteractionActivity"
android:exported="true"
android:permission="app.revanced.manager.permission.PLUGIN_HOST"
android:theme="@android:style/Theme.DeviceDefault" />
tools:targetApi="35">
<!--
ReVanced Manager will look for a plugin definition in this class.
CHeck the file for more information.
-->
<meta-data
android:name="app.revanced.manager.plugin.downloader.class"
android:value="app.revanced.manager.plugin.downloader.example.ExampleDownloaderKt" />

View File

@@ -1,61 +0,0 @@
@file:Suppress("Unused")
package app.revanced.manager.plugin.downloader.example
import android.content.Intent
import android.content.pm.PackageManager
import app.revanced.manager.plugin.downloader.App
import app.revanced.manager.plugin.downloader.example.BuildConfig.PLUGIN_PACKAGE_NAME
import app.revanced.manager.plugin.downloader.DownloaderContext
import app.revanced.manager.plugin.downloader.downloader
import kotlinx.coroutines.delay
import kotlinx.parcelize.Parcelize
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import kotlin.io.path.Path
// TODO: document API, change dispatcher.
@Parcelize
class InstalledApp(
override val packageName: String,
override val version: String,
internal val apkPath: String
) : App(packageName, version)
fun installedAppDownloader(context: DownloaderContext) = downloader<InstalledApp> {
val pm = context.androidContext.packageManager
get { packageName, version ->
val packageInfo = try {
pm.getPackageInfo(packageName, 0)
} catch (_: PackageManager.NameNotFoundException) {
return@get null
}
requestUserInteraction().launch(Intent().apply {
setClassName(
PLUGIN_PACKAGE_NAME,
InteractionActivity::class.java.canonicalName!!
)
})
InstalledApp(
packageName,
packageInfo.versionName,
packageInfo.applicationInfo.sourceDir
).takeIf { version == null || it.version == version }
}
download {
// Simulate download progress
for (i in 0..5) {
reportProgress(i.megaBytes, 5.megaBytes)
delay(1000L)
}
Files.copy(Path(it.apkPath), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
private val Int.megaBytes get() = times(1_000_000).toLong()

View File

@@ -1,65 +0,0 @@
package app.revanced.manager.plugin.downloader.example
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.Modifier
class InteractionActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val isDarkTheme = isSystemInDarkTheme()
val colorScheme = if (isDarkTheme) darkColorScheme() else lightColorScheme()
MaterialTheme(colorScheme) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("User interaction example") }
)
}
) { paddingValues ->
Column(modifier = Modifier.padding(paddingValues)) {
Text("This is an example interaction.")
Row {
TextButton(
onClick = {
setResult(RESULT_CANCELED)
finish()
}
) {
Text("Cancel")
}
TextButton(
onClick = {
setResult(RESULT_OK)
finish()
}
) {
Text("Continue")
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
@file:Suppress("Unused")
package app.revanced.manager.plugin.downloader.example
import android.annotation.SuppressLint
import android.app.Application
import android.content.Intent
import android.content.res.AssetFileDescriptor
import app.revanced.manager.plugin.downloader.*
// This file contains an example downloader implementation using the system file picker.
// Remember to update the Android manifest if you move the definition file.
val exampleDownloader = Downloader {
get { packageName, version ->
// Use the requestStartActivity API to open the system file picker and get the resulting content URI.
val uri = requestStartActivity(
Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("application/vnd.android.package-archive")
)?.data ?: return@get null
println("Package name: $packageName, version: $version")
// We assume the user has selected the correct version, but this might not be the case.
// Real plugins should verify the version and package name if possible.
uri to version
}
// Get an Android context. This is only used for reading the file that the user selected.
// This hack should not be necessary in a real plugin.
@SuppressLint("PrivateApi")
val application = with(Class.forName("android.app.ActivityThread")) {
val activityThread = getMethod("currentActivityThread")(null)
getMethod("getApplication")(activityThread) as Application
}
download { uri ->
// Open the file and return an InputStream to it along with the size.
val fd = application.contentResolver.openAssetFileDescriptor(uri, "r")!!
AssetFileDescriptor.AutoCloseInputStream(fd) to fd.length.takeIf { it > 0L }
}
}