mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-04-29 13:34:25 +02:00
build(Needs bump): Bump ReVanced Patcher (#2242)
Co-authored-by: aAbed <aabedhkhan@gmail.com>
This commit is contained in:
parent
4db4789a06
commit
8d0d782ab5
@ -9,14 +9,15 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import app.revanced.library.ApkUtils
|
||||
import app.revanced.library.ApkUtils.applyTo
|
||||
import app.revanced.library.installation.installer.LocalInstaller
|
||||
import app.revanced.manager.flutter.utils.Aapt
|
||||
import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver
|
||||
import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherConfig
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.loadPatchesFromDex
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
@ -37,7 +38,7 @@ class MainActivity : FlutterActivity() {
|
||||
private var cancel: Boolean = false
|
||||
private var stopResult: MethodChannel.Result? = null
|
||||
|
||||
private lateinit var patches: PatchSet
|
||||
private lateinit var patches: Set<Patch<*>>
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
@ -70,7 +71,6 @@ class MainActivity : FlutterActivity() {
|
||||
"runPatcher" -> {
|
||||
val inFilePath = call.argument<String>("inFilePath")
|
||||
val outFilePath = call.argument<String>("outFilePath")
|
||||
val integrationsPath = call.argument<String>("integrationsPath")
|
||||
val selectedPatches = call.argument<List<String>>("selectedPatches")
|
||||
val options = call.argument<Map<String, Map<String, Any>>>("options")
|
||||
val tmpDirPath = call.argument<String>("tmpDirPath")
|
||||
@ -80,7 +80,6 @@ class MainActivity : FlutterActivity() {
|
||||
if (
|
||||
inFilePath != null &&
|
||||
outFilePath != null &&
|
||||
integrationsPath != null &&
|
||||
selectedPatches != null &&
|
||||
options != null &&
|
||||
tmpDirPath != null &&
|
||||
@ -92,14 +91,17 @@ class MainActivity : FlutterActivity() {
|
||||
result,
|
||||
inFilePath,
|
||||
outFilePath,
|
||||
integrationsPath,
|
||||
selectedPatches,
|
||||
options,
|
||||
tmpDirPath,
|
||||
keyStoreFilePath,
|
||||
keystorePassword
|
||||
)
|
||||
} else result.notImplemented()
|
||||
} else result.error(
|
||||
"INVALID_ARGUMENTS",
|
||||
"Invalid arguments",
|
||||
"One or more arguments are missing"
|
||||
)
|
||||
}
|
||||
|
||||
"stopPatcher" -> {
|
||||
@ -113,14 +115,16 @@ class MainActivity : FlutterActivity() {
|
||||
try {
|
||||
val patchBundleFile = File(patchBundleFilePath)
|
||||
patchBundleFile.setWritable(false)
|
||||
patches = PatchBundleLoader.Dex(
|
||||
patchBundleFile,
|
||||
patches = loadPatchesFromDex(
|
||||
setOf(patchBundleFile),
|
||||
optimizedDexDirectory = codeCacheDir
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
return@setMethodCallHandler result.notImplemented()
|
||||
} catch (err: Error) {
|
||||
return@setMethodCallHandler result.notImplemented()
|
||||
} catch (t: Throwable) {
|
||||
return@setMethodCallHandler result.error(
|
||||
"PATCH_BUNDLE_ERROR",
|
||||
"Failed to load patch bundle",
|
||||
t.stackTraceToString()
|
||||
)
|
||||
}
|
||||
|
||||
JSONArray().apply {
|
||||
@ -130,13 +134,13 @@ class MainActivity : FlutterActivity() {
|
||||
put("description", it.description)
|
||||
put("excluded", !it.use)
|
||||
put("compatiblePackages", JSONArray().apply {
|
||||
it.compatiblePackages?.forEach { compatiblePackage ->
|
||||
it.compatiblePackages?.forEach { (name, versions) ->
|
||||
val compatiblePackageJson = JSONObject().apply {
|
||||
put("name", compatiblePackage.name)
|
||||
put("name", name)
|
||||
put(
|
||||
"versions",
|
||||
JSONArray().apply {
|
||||
compatiblePackage.versions?.forEach { version ->
|
||||
versions?.forEach { version ->
|
||||
put(version)
|
||||
}
|
||||
})
|
||||
@ -172,7 +176,7 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
})
|
||||
} ?: put("values", null)
|
||||
put("valueType", option.valueType)
|
||||
put("type", option.type)
|
||||
}.let(::put)
|
||||
}
|
||||
})
|
||||
@ -211,7 +215,6 @@ class MainActivity : FlutterActivity() {
|
||||
result: MethodChannel.Result,
|
||||
inFilePath: String,
|
||||
outFilePath: String,
|
||||
integrationsPath: String,
|
||||
selectedPatches: List<String>,
|
||||
options: Map<String, Map<String, Any>>,
|
||||
tmpDirPath: String,
|
||||
@ -223,7 +226,6 @@ class MainActivity : FlutterActivity() {
|
||||
inFile.setWritable(true)
|
||||
inFile.setReadable(true)
|
||||
val outFile = File(outFilePath)
|
||||
val integrations = File(integrationsPath)
|
||||
val keyStoreFile = File(keyStoreFilePath)
|
||||
val tmpDir = File(tmpDirPath)
|
||||
|
||||
@ -289,8 +291,8 @@ class MainActivity : FlutterActivity() {
|
||||
updateProgress(0.02, "Loading patches...", "Loading patches")
|
||||
|
||||
val patches = patches.filter { patch ->
|
||||
val isCompatible = patch.compatiblePackages?.any {
|
||||
it.name == patcher.context.packageMetadata.packageName
|
||||
val isCompatible = patch.compatiblePackages?.any { (name, _) ->
|
||||
name == patcher.context.packageMetadata.packageName
|
||||
} ?: false
|
||||
|
||||
val compatibleOrUniversal =
|
||||
@ -307,10 +309,7 @@ class MainActivity : FlutterActivity() {
|
||||
updateProgress(0.05, "Executing...", "")
|
||||
|
||||
val patcherResult = patcher.use {
|
||||
patcher.apply {
|
||||
acceptIntegrations(setOf(integrations))
|
||||
acceptPatches(patches)
|
||||
}
|
||||
it += patches
|
||||
|
||||
runBlocking {
|
||||
// Update the progress bar every time a patch is executed from 0.15 to 0.7
|
||||
@ -318,7 +317,7 @@ class MainActivity : FlutterActivity() {
|
||||
val progressStep = 0.55 / totalPatchesCount
|
||||
var progress = 0.05
|
||||
|
||||
patcher.apply(false).collect(FlowCollector { patchResult: PatchResult ->
|
||||
patcher().collect(FlowCollector { patchResult: PatchResult ->
|
||||
if (cancel(patcher::close)) return@FlowCollector
|
||||
|
||||
val msg = patchResult.exception?.let {
|
||||
@ -346,10 +345,11 @@ class MainActivity : FlutterActivity() {
|
||||
|
||||
if (cancel(patcher::close)) return@Thread
|
||||
|
||||
ApkUtils.sign(
|
||||
ApkUtils.signApk(
|
||||
inFile,
|
||||
outFile,
|
||||
ApkUtils.SigningOptions(
|
||||
"ReVanced",
|
||||
ApkUtils.KeyStoreDetails(
|
||||
keyStoreFile,
|
||||
keystorePassword,
|
||||
"alias",
|
||||
|
@ -21,7 +21,8 @@ subprojects {
|
||||
afterEvaluate {
|
||||
extensions.findByName("android")?.let {
|
||||
it as CommonExtension<*, *, *, *, *, *>
|
||||
it.compileSdk = 34
|
||||
if (it.compileSdk != null && it.compileSdk!! < 31)
|
||||
it.compileSdk = 34
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
revanced-patcher = "19.3.1" # TODO: Update to non-dev
|
||||
revanced-library = "2.2.1"
|
||||
revanced-patcher = "20.0.2"
|
||||
revanced-library = "3.0.1"
|
||||
desugar_jdk_libs = "2.1.2"
|
||||
|
||||
[libraries]
|
||||
|
@ -17,7 +17,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.7.0" apply false
|
||||
id("com.android.application") version "8.5.0" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.0.20" apply false
|
||||
}
|
||||
|
||||
|
@ -158,20 +158,18 @@
|
||||
"languageLabel": "Language",
|
||||
"languageUpdated": "Language updated",
|
||||
"sourcesLabel": "Alternative sources",
|
||||
"sourcesLabelHint": "Configure the alternative sources for ReVanced Patches and ReVanced Integrations",
|
||||
"sourcesIntegrationsLabel": "Integrations source",
|
||||
"sourcesLabelHint": "Configure the alternative sources for ReVanced Patches",
|
||||
"useAlternativeSources": "Use alternative sources",
|
||||
"useAlternativeSourcesHint": "Use alternative sources for ReVanced Patches and ReVanced Integrations instead of the API",
|
||||
"useAlternativeSourcesHint": "Use alternative sources for ReVanced Patches instead of the API",
|
||||
"sourcesResetDialogTitle": "Reset",
|
||||
"sourcesResetDialogText": "Are you sure you want to reset your sources to their default values?",
|
||||
"apiURLResetDialogText": "Are you sure you want to reset your API URL to its default value?",
|
||||
"sourcesUpdateNote": "Note: This will automatically download ReVanced Patches and ReVanced Integrations from the alternative sources.\n\nThis will connect you to the alternative source.",
|
||||
"sourcesUpdateNote": "Note: This will automatically download ReVanced Patches from the alternative sources.\n\nThis will connect you to the alternative source.",
|
||||
"apiURLLabel": "API URL",
|
||||
"apiURLHint": "Configure the API URL of ReVanced Manager",
|
||||
"selectApiURL": "API URL",
|
||||
"orgPatchesLabel": "Patches organization",
|
||||
"sourcesPatchesLabel": "Patches source",
|
||||
"orgIntegrationsLabel": "Integrations organization",
|
||||
"contributorsLabel": "Contributors",
|
||||
"contributorsHint": "A list of contributors of ReVanced",
|
||||
"logsLabel": "Share logs",
|
||||
|
@ -62,11 +62,12 @@ class Option {
|
||||
required this.value,
|
||||
required this.values,
|
||||
required this.required,
|
||||
required this.valueType,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
factory Option.fromJson(Map<String, dynamic> json) {
|
||||
_migrateV17ToV19(json);
|
||||
_migrateV19ToV20(json);
|
||||
|
||||
return _$OptionFromJson(json);
|
||||
}
|
||||
@ -83,13 +84,25 @@ class Option {
|
||||
}
|
||||
}
|
||||
|
||||
static void _migrateV19ToV20(Map<String, dynamic> json) {
|
||||
if (json['valueType'] != null) {
|
||||
final String type = json['valueType'];
|
||||
|
||||
json['type'] = type.endsWith('Array')
|
||||
? 'kotlin.collections.List<kotlin.${type.replaceAll('Array', '')}>'
|
||||
: 'kotlin.$type';
|
||||
|
||||
json['valueType'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
final String key;
|
||||
final String title;
|
||||
final String description;
|
||||
final dynamic value;
|
||||
final Map<String, dynamic>? values;
|
||||
final bool required;
|
||||
final String valueType;
|
||||
final String type;
|
||||
|
||||
Map toJson() => _$OptionToJson(this);
|
||||
}
|
||||
|
@ -111,11 +111,7 @@ class GithubAPI {
|
||||
);
|
||||
if (asset != null) {
|
||||
final String downloadUrl = asset['browser_download_url'];
|
||||
if (extension == '.apk') {
|
||||
_managerAPI.setIntegrationsDownloadURL(downloadUrl);
|
||||
} else {
|
||||
_managerAPI.setPatchesDownloadURL(downloadUrl);
|
||||
}
|
||||
_managerAPI.setPatchesDownloadURL(downloadUrl);
|
||||
return await _downloadManager.getSingleFile(
|
||||
downloadUrl,
|
||||
);
|
||||
|
@ -44,15 +44,13 @@ class ManagerAPI {
|
||||
String keystoreFile =
|
||||
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore';
|
||||
String defaultKeystorePassword = 's3cur3p@ssw0rd';
|
||||
String defaultApiUrl = 'https://api.revanced.app/';
|
||||
String defaultApiUrl = 'https://api.revanced.app/v3';
|
||||
String defaultRepoUrl = 'https://api.github.com';
|
||||
String defaultPatcherRepo = 'revanced/revanced-patcher';
|
||||
String defaultPatchesRepo = 'revanced/revanced-patches';
|
||||
String defaultIntegrationsRepo = 'revanced/revanced-integrations';
|
||||
String defaultCliRepo = 'revanced/revanced-cli';
|
||||
String defaultManagerRepo = 'revanced/revanced-manager';
|
||||
String? patchesVersion = '';
|
||||
String? integrationsVersion = '';
|
||||
|
||||
Future<void> initialize() async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
@ -69,13 +67,15 @@ class ManagerAPI {
|
||||
}
|
||||
|
||||
// Migrate to new API URL if not done yet as the old one is sunset.
|
||||
final bool hasMigratedToNewApi =
|
||||
_prefs.getBool('migratedToNewApiUrl') ?? false;
|
||||
if (!hasMigratedToNewApi) {
|
||||
final bool hasMigratedToLatestApi =
|
||||
_prefs.getBool('migratedToLatestApiUrl') ?? false;
|
||||
if (!hasMigratedToLatestApi) {
|
||||
final String apiUrl = getApiUrl().toLowerCase();
|
||||
if (apiUrl.contains('releases.revanced.app')) {
|
||||
if (apiUrl.contains('releases.revanced.app') ||
|
||||
(apiUrl.contains('api.revanced.app') &&
|
||||
!apiUrl.contains('v3'))) {
|
||||
await setApiUrl(''); // Reset to default.
|
||||
_prefs.setBool('migratedToNewApiUrl', true);
|
||||
_prefs.setBool('migratedToLatestApiUrl', true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,10 +83,8 @@ class ManagerAPI {
|
||||
_prefs.getBool('migratedToAlternativeSource') ?? false;
|
||||
if (!hasMigratedToAlternativeSource) {
|
||||
final String patchesRepo = getPatchesRepo();
|
||||
final String integrationsRepo = getIntegrationsRepo();
|
||||
final bool usingAlternativeSources =
|
||||
patchesRepo.toLowerCase() != defaultPatchesRepo ||
|
||||
integrationsRepo.toLowerCase() != defaultIntegrationsRepo;
|
||||
patchesRepo.toLowerCase() != defaultPatchesRepo;
|
||||
_prefs.setBool('useAlternativeSources', usingAlternativeSources);
|
||||
_prefs.setBool('migratedToAlternativeSource', true);
|
||||
}
|
||||
@ -200,14 +198,6 @@ class ManagerAPI {
|
||||
await _prefs.setStringList('savedPatches-$packageName', patchesJson);
|
||||
}
|
||||
|
||||
String getIntegrationsDownloadURL() {
|
||||
return _prefs.getString('integrationsDownloadURL') ?? '';
|
||||
}
|
||||
|
||||
Future<void> setIntegrationsDownloadURL(String value) async {
|
||||
await _prefs.setString('integrationsDownloadURL', value);
|
||||
}
|
||||
|
||||
List<Patch> getUsedPatches(String packageName) {
|
||||
final List<String> patchesJson =
|
||||
_prefs.getStringList('usedPatches-$packageName') ?? [];
|
||||
@ -256,17 +246,6 @@ class ManagerAPI {
|
||||
_prefs.remove('patchOption-$packageName-$patchName-$key');
|
||||
}
|
||||
|
||||
String getIntegrationsRepo() {
|
||||
return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo;
|
||||
}
|
||||
|
||||
Future<void> setIntegrationsRepo(String value) async {
|
||||
if (value.isEmpty || value.startsWith('/') || value.endsWith('/')) {
|
||||
value = defaultIntegrationsRepo;
|
||||
}
|
||||
await _prefs.setString('integrationsRepo', value);
|
||||
}
|
||||
|
||||
bool getUseDynamicTheme() {
|
||||
return _prefs.getBool('useDynamicTheme') ?? false;
|
||||
}
|
||||
@ -464,28 +443,7 @@ class ManagerAPI {
|
||||
final String currentVersion = await getCurrentPatchesVersion();
|
||||
final String url = getPatchesDownloadURL();
|
||||
return await _githubAPI.getReleaseFile(
|
||||
'.jar',
|
||||
repoName,
|
||||
currentVersion,
|
||||
url,
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<File?> downloadIntegrations() async {
|
||||
try {
|
||||
final String repoName = !isUsingAlternativeSources()
|
||||
? defaultIntegrationsRepo
|
||||
: getIntegrationsRepo();
|
||||
final String currentVersion = await getCurrentIntegrationsVersion();
|
||||
final String url = getIntegrationsDownloadURL();
|
||||
return await _githubAPI.getReleaseFile(
|
||||
'.apk',
|
||||
'.rvp',
|
||||
repoName,
|
||||
currentVersion,
|
||||
url,
|
||||
@ -499,18 +457,12 @@ class ManagerAPI {
|
||||
}
|
||||
|
||||
Future<File?> downloadManager() async {
|
||||
return await _revancedAPI.getLatestReleaseFile(
|
||||
'.apk',
|
||||
defaultManagerRepo,
|
||||
);
|
||||
return await _revancedAPI.getLatestReleaseFile('manager');
|
||||
}
|
||||
|
||||
Future<String?> getLatestPatchesReleaseTime() async {
|
||||
if (!isUsingAlternativeSources()) {
|
||||
return await _revancedAPI.getLatestReleaseTime(
|
||||
'.json',
|
||||
defaultPatchesRepo,
|
||||
);
|
||||
return await _revancedAPI.getLatestReleaseTime('patches');
|
||||
} else {
|
||||
final release = await _githubAPI.getLatestRelease(getPatchesRepo());
|
||||
if (release != null) {
|
||||
@ -525,39 +477,20 @@ class ManagerAPI {
|
||||
|
||||
Future<String?> getLatestManagerReleaseTime() async {
|
||||
return await _revancedAPI.getLatestReleaseTime(
|
||||
'.apk',
|
||||
defaultManagerRepo,
|
||||
'manager',
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> getLatestManagerVersion() async {
|
||||
return await _revancedAPI.getLatestReleaseVersion(
|
||||
'.apk',
|
||||
defaultManagerRepo,
|
||||
'manager',
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> getLatestIntegrationsVersion() async {
|
||||
if (!isUsingAlternativeSources()) {
|
||||
return await _revancedAPI.getLatestReleaseVersion(
|
||||
'.apk',
|
||||
defaultIntegrationsRepo,
|
||||
);
|
||||
} else {
|
||||
final release = await _githubAPI.getLatestRelease(getIntegrationsRepo());
|
||||
if (release != null) {
|
||||
return release['tag_name'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> getLatestPatchesVersion() async {
|
||||
if (!isUsingAlternativeSources()) {
|
||||
return await _revancedAPI.getLatestReleaseVersion(
|
||||
'.json',
|
||||
defaultPatchesRepo,
|
||||
'patches',
|
||||
);
|
||||
} else {
|
||||
final release = await _githubAPI.getLatestRelease(getPatchesRepo());
|
||||
@ -620,25 +553,6 @@ class ManagerAPI {
|
||||
await downloadPatches();
|
||||
}
|
||||
|
||||
Future<String> getCurrentIntegrationsVersion() async {
|
||||
integrationsVersion = _prefs.getString('integrationsVersion') ?? '0.0.0';
|
||||
if (integrationsVersion == '0.0.0' || isPatchesAutoUpdate()) {
|
||||
final String newIntegrationsVersion =
|
||||
await getLatestIntegrationsVersion() ?? '0.0.0';
|
||||
if (integrationsVersion != newIntegrationsVersion &&
|
||||
newIntegrationsVersion != '0.0.0') {
|
||||
await setCurrentIntegrationsVersion(newIntegrationsVersion);
|
||||
}
|
||||
}
|
||||
return integrationsVersion!;
|
||||
}
|
||||
|
||||
Future<void> setCurrentIntegrationsVersion(String version) async {
|
||||
await _prefs.setString('integrationsVersion', version);
|
||||
await setIntegrationsDownloadURL('');
|
||||
await downloadIntegrations();
|
||||
}
|
||||
|
||||
Future<List<PatchedApplication>> getAppsToRemove(
|
||||
List<PatchedApplication> patchedApps,
|
||||
) async {
|
||||
|
@ -33,7 +33,6 @@ class PatcherAPI {
|
||||
|
||||
Future<void> initialize() async {
|
||||
await loadPatches();
|
||||
await _managerAPI.downloadIntegrations();
|
||||
final Directory appCache = await getApplicationSupportDirectory();
|
||||
_dataDir = await getExternalStorageDirectory() ?? appCache;
|
||||
_tmpDir = Directory('${appCache.path}/patcher');
|
||||
@ -153,7 +152,6 @@ class PatcherAPI {
|
||||
List<Patch> selectedPatches,
|
||||
bool isFromStorage,
|
||||
) async {
|
||||
final File? integrationsFile = await _managerAPI.downloadIntegrations();
|
||||
final Map<String, Map<String, dynamic>> options = {};
|
||||
for (final patch in selectedPatches) {
|
||||
if (patch.options.isNotEmpty) {
|
||||
@ -169,44 +167,41 @@ class PatcherAPI {
|
||||
}
|
||||
}
|
||||
|
||||
if (integrationsFile != null) {
|
||||
_dataDir.createSync();
|
||||
_tmpDir.createSync();
|
||||
final Directory workDir = await _tmpDir.createTemp('tmp-');
|
||||
_dataDir.createSync();
|
||||
_tmpDir.createSync();
|
||||
final Directory workDir = await _tmpDir.createTemp('tmp-');
|
||||
|
||||
final File inApkFile = File('${workDir.path}/in.apk');
|
||||
await File(apkFilePath).copy(inApkFile.path);
|
||||
final File inApkFile = File('${workDir.path}/in.apk');
|
||||
await File(apkFilePath).copy(inApkFile.path);
|
||||
|
||||
if (isFromStorage) {
|
||||
// The selected apk was copied to cacheDir by the file picker, so it's not needed anymore.
|
||||
// rename() can't be used here, as Android system also counts the size of files moved out from cacheDir
|
||||
// as part of the app's cache size.
|
||||
File(apkFilePath).delete();
|
||||
}
|
||||
if (isFromStorage) {
|
||||
// The selected apk was copied to cacheDir by the file picker, so it's not needed anymore.
|
||||
// rename() can't be used here, as Android system also counts the size of files moved out from cacheDir
|
||||
// as part of the app's cache size.
|
||||
File(apkFilePath).delete();
|
||||
}
|
||||
|
||||
outFile = File('${workDir.path}/out.apk');
|
||||
outFile = File('${workDir.path}/out.apk');
|
||||
|
||||
final Directory tmpDir =
|
||||
Directory('${workDir.path}/revanced-temporary-files');
|
||||
final Directory tmpDir =
|
||||
Directory('${workDir.path}/revanced-temporary-files');
|
||||
|
||||
try {
|
||||
await patcherChannel.invokeMethod(
|
||||
'runPatcher',
|
||||
{
|
||||
'inFilePath': inApkFile.path,
|
||||
'outFilePath': outFile!.path,
|
||||
'integrationsPath': integrationsFile.path,
|
||||
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
||||
'options': options,
|
||||
'tmpDirPath': tmpDir.path,
|
||||
'keyStoreFilePath': _keyStoreFile.path,
|
||||
'keystorePassword': _managerAPI.getKeystorePassword(),
|
||||
},
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
try {
|
||||
await patcherChannel.invokeMethod(
|
||||
'runPatcher',
|
||||
{
|
||||
'inFilePath': inApkFile.path,
|
||||
'outFilePath': outFile!.path,
|
||||
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
||||
'options': options,
|
||||
'tmpDirPath': tmpDir.path,
|
||||
'keyStoreFilePath': _keyStoreFile.path,
|
||||
'keystorePassword': _managerAPI.getKeystorePassword(),
|
||||
},
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
@ -31,7 +29,7 @@ class RevancedAPI {
|
||||
final Map<String, List<dynamic>> contributors = {};
|
||||
try {
|
||||
final response = await _dio.get('/contributors');
|
||||
final List<dynamic> repositories = response.data['repositories'];
|
||||
final List<dynamic> repositories = response.data;
|
||||
for (final Map<String, dynamic> repo in repositories) {
|
||||
final String name = repo['name'];
|
||||
contributors[name] = repo['contributors'];
|
||||
@ -46,21 +44,15 @@ class RevancedAPI {
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> _getLatestRelease(
|
||||
String extension,
|
||||
String repoName,
|
||||
String toolName,
|
||||
) {
|
||||
if (!locator<ManagerAPI>().getDownloadConsent()) {
|
||||
return Future(() => null);
|
||||
}
|
||||
return getToolsLock.synchronized(() async {
|
||||
try {
|
||||
final response = await _dio.get('/tools');
|
||||
final List<dynamic> tools = response.data['tools'];
|
||||
return tools.firstWhereOrNull(
|
||||
(t) =>
|
||||
(t['repository'] as String) == repoName &&
|
||||
(t['name'] as String).endsWith(extension),
|
||||
);
|
||||
final response = await _dio.get('/$toolName/latest');
|
||||
return response.data;
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
@ -71,13 +63,11 @@ class RevancedAPI {
|
||||
}
|
||||
|
||||
Future<String?> getLatestReleaseVersion(
|
||||
String extension,
|
||||
String repoName,
|
||||
String toolName,
|
||||
) async {
|
||||
try {
|
||||
final Map<String, dynamic>? release = await _getLatestRelease(
|
||||
extension,
|
||||
repoName,
|
||||
toolName,
|
||||
);
|
||||
if (release != null) {
|
||||
return release['version'];
|
||||
@ -92,16 +82,14 @@ class RevancedAPI {
|
||||
}
|
||||
|
||||
Future<File?> getLatestReleaseFile(
|
||||
String extension,
|
||||
String repoName,
|
||||
String toolName,
|
||||
) async {
|
||||
try {
|
||||
final Map<String, dynamic>? release = await _getLatestRelease(
|
||||
extension,
|
||||
repoName,
|
||||
toolName,
|
||||
);
|
||||
if (release != null) {
|
||||
final String url = release['browser_download_url'];
|
||||
final String url = release['assets'][0]['download_url'];
|
||||
return await _downloadManager.getSingleFile(url);
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
@ -129,13 +117,10 @@ class RevancedAPI {
|
||||
}
|
||||
|
||||
Future<File?> downloadManager() async {
|
||||
final Map<String, dynamic>? release = await _getLatestRelease(
|
||||
'.apk',
|
||||
'revanced/revanced-manager',
|
||||
);
|
||||
final Map<String, dynamic>? release = await _getLatestRelease('manager');
|
||||
File? outputFile;
|
||||
await for (final result in _downloadManager.getFileStream(
|
||||
release!['browser_download_url'] as String,
|
||||
release!['download_url'] as String,
|
||||
)) {
|
||||
if (result is DownloadProgress) {
|
||||
final totalSize = result.totalSize ?? 10000000;
|
||||
@ -152,17 +137,15 @@ class RevancedAPI {
|
||||
}
|
||||
|
||||
Future<String?> getLatestReleaseTime(
|
||||
String extension,
|
||||
String repoName,
|
||||
String toolName,
|
||||
) async {
|
||||
try {
|
||||
final Map<String, dynamic>? release = await _getLatestRelease(
|
||||
extension,
|
||||
repoName,
|
||||
toolName,
|
||||
);
|
||||
if (release != null) {
|
||||
final DateTime timestamp =
|
||||
DateTime.parse(release['timestamp'] as String);
|
||||
DateTime.parse(release['created_at'] as String);
|
||||
return format(timestamp, locale: 'en_short');
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
|
@ -40,11 +40,6 @@ class ContributorsView extends StatelessWidget {
|
||||
contributors: model.patchesContributors,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ContributorsCard(
|
||||
title: 'ReVanced Integrations',
|
||||
contributors: model.integrationsContributors,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ContributorsCard(
|
||||
title: 'ReVanced CLI',
|
||||
contributors: model.cliContributors,
|
||||
|
@ -6,19 +6,18 @@ class ContributorsViewModel extends BaseViewModel {
|
||||
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||
List<dynamic> patcherContributors = [];
|
||||
List<dynamic> patchesContributors = [];
|
||||
List<dynamic> integrationsContributors = [];
|
||||
List<dynamic> cliContributors = [];
|
||||
List<dynamic> managerContributors = [];
|
||||
|
||||
String repoName(String repo) => repo.split('/').last;
|
||||
|
||||
Future<void> getContributors() async {
|
||||
final Map<String, List<dynamic>> contributors =
|
||||
await _managerAPI.getContributors();
|
||||
patcherContributors = contributors[_managerAPI.defaultPatcherRepo] ?? [];
|
||||
patchesContributors = contributors[_managerAPI.defaultPatchesRepo] ?? [];
|
||||
integrationsContributors =
|
||||
contributors[_managerAPI.defaultIntegrationsRepo] ?? [];
|
||||
cliContributors = contributors[_managerAPI.defaultCliRepo] ?? [];
|
||||
managerContributors = contributors[_managerAPI.defaultManagerRepo] ?? [];
|
||||
patcherContributors = contributors[repoName(_managerAPI.defaultPatcherRepo)] ?? [];
|
||||
patchesContributors = contributors[repoName(_managerAPI.defaultPatchesRepo)] ?? [];
|
||||
cliContributors = contributors[repoName(_managerAPI.defaultCliRepo)] ?? [];
|
||||
managerContributors = contributors[repoName(_managerAPI.defaultManagerRepo)] ?? [];
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
@ -311,11 +311,8 @@ class HomeViewModel extends BaseViewModel {
|
||||
_toast.showBottom(t.homeView.downloadingMessage);
|
||||
final String patchesVersion =
|
||||
await _managerAPI.getLatestPatchesVersion() ?? '0.0.0';
|
||||
final String integrationsVersion =
|
||||
await _managerAPI.getLatestIntegrationsVersion() ?? '0.0.0';
|
||||
if (patchesVersion != '0.0.0' && integrationsVersion != '0.0.0') {
|
||||
if (patchesVersion != '0.0.0') {
|
||||
await _managerAPI.setCurrentPatchesVersion(patchesVersion);
|
||||
await _managerAPI.setCurrentIntegrationsVersion(integrationsVersion);
|
||||
_toast.showBottom(t.homeView.downloadedMessage);
|
||||
forceRefresh(context);
|
||||
} else {
|
||||
|
@ -330,7 +330,6 @@ class InstallerViewModel extends BaseViewModel {
|
||||
'Version compatibility check: ${_managerAPI.isVersionCompatibilityCheckEnabled()}',
|
||||
'Show universal patches: ${_managerAPI.areUniversalPatchesEnabled()}',
|
||||
'Patches source: ${_managerAPI.getPatchesRepo()}',
|
||||
'Integration source: ${_managerAPI.getIntegrationsRepo()}', //
|
||||
|
||||
'\n- Logs',
|
||||
logsTrimmed.join('\n'),
|
||||
|
@ -44,20 +44,20 @@ class PatchOptionsView extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
for (final Option option in model.modifiedOptions)
|
||||
if (option.valueType == 'String' ||
|
||||
option.valueType == 'Int')
|
||||
if (option.type == 'kotlin.String' ||
|
||||
option.type == 'kotlin.Int')
|
||||
IntAndStringPatchOption(
|
||||
patchOption: option,
|
||||
model: model,
|
||||
)
|
||||
else if (option.valueType == 'Boolean')
|
||||
else if (option.type == 'kotlin.Boolean')
|
||||
BooleanPatchOption(
|
||||
patchOption: option,
|
||||
model: model,
|
||||
)
|
||||
else if (option.valueType == 'StringArray' ||
|
||||
option.valueType == 'IntArray' ||
|
||||
option.valueType == 'LongArray')
|
||||
else if (option.type == 'kotlin.collections.List<kotlin.String>' ||
|
||||
option.type == 'kotlin.collections.List<kotlin.Int>' ||
|
||||
option.type == 'kotlin.collections.List<kotlin.Long>')
|
||||
IntStringLongListPatchOption(
|
||||
patchOption: option,
|
||||
model: model,
|
||||
|
@ -74,7 +74,7 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
title: option.title,
|
||||
description: option.description,
|
||||
values: option.values,
|
||||
valueType: option.valueType,
|
||||
type: option.type,
|
||||
value: value,
|
||||
required: option.required,
|
||||
key: option.key,
|
||||
@ -90,7 +90,7 @@ class PatchOptionsViewModel extends BaseViewModel {
|
||||
title: option.title,
|
||||
description: option.description,
|
||||
values: option.values,
|
||||
valueType: option.valueType,
|
||||
type: option.type,
|
||||
value: option.value is List ? option.value.toList() : option.value,
|
||||
required: option.required,
|
||||
key: option.key,
|
||||
|
@ -14,16 +14,11 @@ class SManageSources extends BaseViewModel {
|
||||
|
||||
final TextEditingController _orgPatSourceController = TextEditingController();
|
||||
final TextEditingController _patSourceController = TextEditingController();
|
||||
final TextEditingController _orgIntSourceController = TextEditingController();
|
||||
final TextEditingController _intSourceController = TextEditingController();
|
||||
|
||||
Future<void> showSourcesDialog(BuildContext context) async {
|
||||
final String patchesRepo = _managerAPI.getPatchesRepo();
|
||||
final String integrationsRepo = _managerAPI.getIntegrationsRepo();
|
||||
_orgPatSourceController.text = patchesRepo.split('/')[0];
|
||||
_patSourceController.text = patchesRepo.split('/')[1];
|
||||
_orgIntSourceController.text = integrationsRepo.split('/')[0];
|
||||
_intSourceController.text = integrationsRepo.split('/')[1];
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
@ -72,38 +67,6 @@ class SManageSources extends BaseViewModel {
|
||||
hintText: patchesRepo.split('/')[1],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Integrations owner's name
|
||||
TextField(
|
||||
controller: _orgIntSourceController,
|
||||
autocorrect: false,
|
||||
onChanged: (value) => notifyListeners(),
|
||||
decoration: InputDecoration(
|
||||
icon: Icon(
|
||||
Icons.merge_outlined,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: t.settingsView.orgIntegrationsLabel,
|
||||
hintText: integrationsRepo.split('/')[0],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Integrations repository's name
|
||||
TextField(
|
||||
controller: _intSourceController,
|
||||
autocorrect: false,
|
||||
onChanged: (value) => notifyListeners(),
|
||||
decoration: InputDecoration(
|
||||
icon: const Icon(
|
||||
Icons.merge_outlined,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: t.settingsView.sourcesIntegrationsLabel,
|
||||
hintText: integrationsRepo.split('/')[1],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(t.settingsView.sourcesUpdateNote),
|
||||
],
|
||||
@ -113,8 +76,6 @@ class SManageSources extends BaseViewModel {
|
||||
onPressed: () {
|
||||
_orgPatSourceController.clear();
|
||||
_patSourceController.clear();
|
||||
_orgIntSourceController.clear();
|
||||
_intSourceController.clear();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(t.cancelButton),
|
||||
@ -124,11 +85,7 @@ class SManageSources extends BaseViewModel {
|
||||
_managerAPI.setPatchesRepo(
|
||||
'${_orgPatSourceController.text.trim()}/${_patSourceController.text.trim()}',
|
||||
);
|
||||
_managerAPI.setIntegrationsRepo(
|
||||
'${_orgIntSourceController.text.trim()}/${_intSourceController.text.trim()}',
|
||||
);
|
||||
_managerAPI.setCurrentPatchesVersion('0.0.0');
|
||||
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
|
||||
_managerAPI.setLastUsedPatchesVersion();
|
||||
_toast.showBottom(t.settingsView.restartAppForChanges);
|
||||
Navigator.of(context).pop();
|
||||
@ -154,9 +111,7 @@ class SManageSources extends BaseViewModel {
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
_managerAPI.setPatchesRepo('');
|
||||
_managerAPI.setIntegrationsRepo('');
|
||||
_managerAPI.setCurrentPatchesVersion('0.0.0');
|
||||
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
|
||||
_toast.showBottom(t.settingsView.restartAppForChanges);
|
||||
Navigator.of(context)
|
||||
..pop()
|
||||
|
@ -56,7 +56,6 @@ class SettingsViewModel extends BaseViewModel {
|
||||
void useAlternativeSources(bool value) {
|
||||
_managerAPI.useAlternativeSources(value);
|
||||
_managerAPI.setCurrentPatchesVersion('0.0.0');
|
||||
_managerAPI.setCurrentIntegrationsVersion('0.0.0');
|
||||
_managerAPI.setLastUsedPatchesVersion();
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ class IntStringLongListPatchOption extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final List<dynamic> values = List.from(patchOption.value ?? []);
|
||||
final ValueNotifier patchOptionValue = ValueNotifier(values);
|
||||
final String type = patchOption.valueType;
|
||||
final String type = patchOption.type;
|
||||
|
||||
String getKey(dynamic value) {
|
||||
if (value != null && patchOption.values != null) {
|
||||
@ -408,12 +408,12 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool isStringOption = widget.patchOption.valueType.contains('String');
|
||||
final bool isArrayOption = widget.patchOption.valueType.contains('Array');
|
||||
final bool isStringOption = widget.patchOption.type.contains('String');
|
||||
final bool isListOption = widget.patchOption.type.contains('List');
|
||||
selectedKey = selectedKey == '' ? selectedKey : widget.selectedKey;
|
||||
final bool isValueArray = widget.value?.startsWith('[') ?? false;
|
||||
final bool shouldResetValue =
|
||||
!isStringOption && isArrayOption && selectedKey == '' && isValueArray;
|
||||
!isStringOption && isListOption && selectedKey == '' && isValueArray;
|
||||
controller.text = shouldResetValue ? '' : widget.value ?? '';
|
||||
defaultValue ??= controller.text;
|
||||
return Column(
|
||||
@ -479,7 +479,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
} else {
|
||||
controller.text = widget.patchOption.values![value].toString();
|
||||
widget.onChanged(
|
||||
isArrayOption
|
||||
isListOption
|
||||
? widget.patchOption.values![value]
|
||||
: controller.text,
|
||||
);
|
||||
@ -492,9 +492,9 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
if (selectedKey == '')
|
||||
TextFormField(
|
||||
inputFormatters: [
|
||||
if (widget.patchOption.valueType.contains('Int'))
|
||||
if (widget.patchOption.type.contains('Int'))
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
|
||||
if (widget.patchOption.valueType.contains('Long'))
|
||||
if (widget.patchOption.type.contains('Long'))
|
||||
FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*')),
|
||||
],
|
||||
controller: controller,
|
||||
@ -505,7 +505,7 @@ class _TextFieldForPatchOptionState extends State<TextFieldForPatchOption> {
|
||||
tooltip: t.patchOptionsView.tooltip,
|
||||
itemBuilder: (BuildContext context) {
|
||||
return [
|
||||
if (isArrayOption)
|
||||
if (isListOption)
|
||||
PopupMenuItem(
|
||||
value: 'remove',
|
||||
child: Text(t.remove),
|
||||
|
@ -33,7 +33,7 @@ bool hasUnsupportedRequiredOption(List<Option> options, Patch patch) {
|
||||
option.key,
|
||||
) ==
|
||||
null) {
|
||||
requiredOptionsType.add(option.valueType);
|
||||
requiredOptionsType.add(option.type);
|
||||
}
|
||||
}
|
||||
for (final String optionType in requiredOptionsType) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user