mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2025-05-11 13:05:37 +02:00
feat: Add patch options (#1354)
This commit is contained in:
parent
2abadc73e4
commit
ac636670c3
31 changed files with 1889 additions and 397 deletions
|
@ -18,7 +18,7 @@ import 'package:share_extend/share_extend.dart';
|
|||
@lazySingleton
|
||||
class PatcherAPI {
|
||||
static const patcherChannel =
|
||||
MethodChannel('app.revanced.manager.flutter/patcher');
|
||||
MethodChannel('app.revanced.manager.flutter/patcher');
|
||||
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||
final RootAPI _rootAPI = RootAPI();
|
||||
late Directory _dataDir;
|
||||
|
@ -79,8 +79,7 @@ class PatcherAPI {
|
|||
}
|
||||
|
||||
Future<List<ApplicationWithIcon>> getFilteredInstalledApps(
|
||||
bool showUniversalPatches,
|
||||
) async {
|
||||
bool showUniversalPatches,) async {
|
||||
final List<ApplicationWithIcon> filteredApps = [];
|
||||
final bool allAppsIncluded =
|
||||
_universalPatches.isNotEmpty && showUniversalPatches;
|
||||
|
@ -122,11 +121,11 @@ class PatcherAPI {
|
|||
final List<Patch> patches = _patches
|
||||
.where(
|
||||
(patch) =>
|
||||
patch.compatiblePackages.isEmpty ||
|
||||
!patch.name.contains('settings') &&
|
||||
patch.compatiblePackages
|
||||
.any((pack) => pack.name == packageName),
|
||||
)
|
||||
patch.compatiblePackages.isEmpty ||
|
||||
!patch.name.contains('settings') &&
|
||||
patch.compatiblePackages
|
||||
.any((pack) => pack.name == packageName),
|
||||
)
|
||||
.toList();
|
||||
if (!_managerAPI.areUniversalPatchesEnabled()) {
|
||||
filteredPatches[packageName] = patches
|
||||
|
@ -138,20 +137,29 @@ class PatcherAPI {
|
|||
return filteredPatches[packageName];
|
||||
}
|
||||
|
||||
Future<List<Patch>> getAppliedPatches(
|
||||
List<String> appliedPatches,
|
||||
) async {
|
||||
Future<List<Patch>> getAppliedPatches(List<String> appliedPatches,) async {
|
||||
return _patches
|
||||
.where((patch) => appliedPatches.contains(patch.name))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> runPatcher(
|
||||
String packageName,
|
||||
String apkFilePath,
|
||||
List<Patch> selectedPatches,
|
||||
) async {
|
||||
Future<void> runPatcher(String packageName,
|
||||
String apkFilePath,
|
||||
List<Patch> selectedPatches,) async {
|
||||
final File? integrationsFile = await _managerAPI.downloadIntegrations();
|
||||
final Map<String, Map<String, dynamic>> options = {};
|
||||
for (final patch in selectedPatches) {
|
||||
if (patch.options.isNotEmpty) {
|
||||
final Map<String, dynamic> patchOptions = {};
|
||||
for (final option in patch.options) {
|
||||
final patchOption = _managerAPI.getPatchOption(packageName, patch.name, option.key);
|
||||
if (patchOption != null) {
|
||||
patchOptions[patchOption.key] = patchOption.value;
|
||||
}
|
||||
}
|
||||
options[patch.name] = patchOptions;
|
||||
}
|
||||
}
|
||||
|
||||
if (integrationsFile != null) {
|
||||
_dataDir.createSync();
|
||||
|
@ -163,6 +171,7 @@ class PatcherAPI {
|
|||
final Directory cacheDir = Directory('${workDir.path}/cache');
|
||||
cacheDir.createSync();
|
||||
final String originalFilePath = apkFilePath;
|
||||
|
||||
try {
|
||||
await patcherChannel.invokeMethod(
|
||||
'runPatcher',
|
||||
|
@ -173,6 +182,7 @@ class PatcherAPI {
|
|||
'outFilePath': outFile!.path,
|
||||
'integrationsPath': integrationsFile.path,
|
||||
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
||||
'options': options,
|
||||
'cacheDirPath': cacheDir.path,
|
||||
'keyStoreFilePath': _keyStoreFile.path,
|
||||
'keystorePassword': _managerAPI.getKeystorePassword(),
|
||||
|
@ -184,131 +194,131 @@ class PatcherAPI {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stopPatcher() async {
|
||||
try {
|
||||
await patcherChannel.invokeMethod('stopPatcher');
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
Future<void> stopPatcher() async {
|
||||
try {
|
||||
await patcherChannel.invokeMethod('stopPatcher');
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> installPatchedFile(PatchedApplication patchedApp) async {
|
||||
if (outFile != null) {
|
||||
try {
|
||||
if (patchedApp.isRooted) {
|
||||
final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
||||
if (hasRootPermissions) {
|
||||
return _rootAPI.installApp(
|
||||
patchedApp.packageName,
|
||||
patchedApp.apkFilePath,
|
||||
outFile!.path,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final install = await InstallPlugin.installApk(outFile!.path);
|
||||
return install['isSuccess'];
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void exportPatchedFile(String appName, String version) {
|
||||
try {
|
||||
if (outFile != null) {
|
||||
final String newName = _getFileName(appName, version);
|
||||
CRFileSaver.saveFileWithDialog(
|
||||
SaveFileDialogParams(
|
||||
sourceFilePath: outFile!.path,
|
||||
destinationFileName: newName,
|
||||
),
|
||||
);
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sharePatchedFile(String appName, String version) {
|
||||
try {
|
||||
if (outFile != null) {
|
||||
final String newName = _getFileName(appName, version);
|
||||
final int lastSeparator = outFile!.path.lastIndexOf('/');
|
||||
final String newPath =
|
||||
outFile!.path.substring(0, lastSeparator + 1) + newName;
|
||||
final File shareFile = outFile!.copySync(newPath);
|
||||
ShareExtend.share(shareFile.path, 'file');
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _getFileName(String appName, String version) {
|
||||
final String prefix = appName.toLowerCase().replaceAll(' ', '-');
|
||||
final String newName = '$prefix-revanced_v$version.apk';
|
||||
return newName;
|
||||
}
|
||||
|
||||
Future<void> exportPatcherLog(String logs) async {
|
||||
final Directory appCache = await getTemporaryDirectory();
|
||||
final Directory logDir = Directory('${appCache.path}/logs');
|
||||
logDir.createSync();
|
||||
final String dateTime = DateTime.now()
|
||||
.toIso8601String()
|
||||
.replaceAll('-', '')
|
||||
.replaceAll(':', '')
|
||||
.replaceAll('T', '')
|
||||
.replaceAll('.', '');
|
||||
final String fileName = 'revanced-manager_patcher_$dateTime.txt';
|
||||
final File log = File('${logDir.path}/$fileName');
|
||||
log.writeAsStringSync(logs);
|
||||
CRFileSaver.saveFileWithDialog(
|
||||
SaveFileDialogParams(
|
||||
sourceFilePath: log.path,
|
||||
destinationFileName: fileName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String getSuggestedVersion(String packageName) {
|
||||
final Map<String, int> versions = {};
|
||||
for (final Patch patch in _patches) {
|
||||
final Package? package = patch.compatiblePackages.firstWhereOrNull(
|
||||
(pack) => pack.name == packageName,
|
||||
);
|
||||
if (package != null) {
|
||||
for (final String version in package.versions) {
|
||||
versions.update(
|
||||
version,
|
||||
(value) => versions[version]! + 1,
|
||||
ifAbsent: () => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (versions.isNotEmpty) {
|
||||
final entries = versions.entries.toList()
|
||||
..sort((a, b) => a.value.compareTo(b.value));
|
||||
versions
|
||||
..clear()
|
||||
..addEntries(entries);
|
||||
versions.removeWhere((key, value) => value != versions.values.last);
|
||||
return (versions.keys.toList()..sort()).last;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> installPatchedFile(PatchedApplication patchedApp) async {
|
||||
if (outFile != null) {
|
||||
try {
|
||||
if (patchedApp.isRooted) {
|
||||
final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
||||
if (hasRootPermissions) {
|
||||
return _rootAPI.installApp(
|
||||
patchedApp.packageName,
|
||||
patchedApp.apkFilePath,
|
||||
outFile!.path,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final install = await InstallPlugin.installApk(outFile!.path);
|
||||
return install['isSuccess'];
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void exportPatchedFile(String appName, String version) {
|
||||
try {
|
||||
if (outFile != null) {
|
||||
final String newName = _getFileName(appName, version);
|
||||
CRFileSaver.saveFileWithDialog(
|
||||
SaveFileDialogParams(
|
||||
sourceFilePath: outFile!.path,
|
||||
destinationFileName: newName,
|
||||
),
|
||||
);
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sharePatchedFile(String appName, String version) {
|
||||
try {
|
||||
if (outFile != null) {
|
||||
final String newName = _getFileName(appName, version);
|
||||
final int lastSeparator = outFile!.path.lastIndexOf('/');
|
||||
final String newPath =
|
||||
outFile!.path.substring(0, lastSeparator + 1) + newName;
|
||||
final File shareFile = outFile!.copySync(newPath);
|
||||
ShareExtend.share(shareFile.path, 'file');
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _getFileName(String appName, String version) {
|
||||
final String prefix = appName.toLowerCase().replaceAll(' ', '-');
|
||||
final String newName = '$prefix-revanced_v$version.apk';
|
||||
return newName;
|
||||
}
|
||||
|
||||
Future<void> exportPatcherLog(String logs) async {
|
||||
final Directory appCache = await getTemporaryDirectory();
|
||||
final Directory logDir = Directory('${appCache.path}/logs');
|
||||
logDir.createSync();
|
||||
final String dateTime = DateTime.now()
|
||||
.toIso8601String()
|
||||
.replaceAll('-', '')
|
||||
.replaceAll(':', '')
|
||||
.replaceAll('T', '')
|
||||
.replaceAll('.', '');
|
||||
final String fileName = 'revanced-manager_patcher_$dateTime.txt';
|
||||
final File log = File('${logDir.path}/$fileName');
|
||||
log.writeAsStringSync(logs);
|
||||
CRFileSaver.saveFileWithDialog(
|
||||
SaveFileDialogParams(
|
||||
sourceFilePath: log.path,
|
||||
destinationFileName: fileName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String getSuggestedVersion(String packageName) {
|
||||
final Map<String, int> versions = {};
|
||||
for (final Patch patch in _patches) {
|
||||
final Package? package = patch.compatiblePackages.firstWhereOrNull(
|
||||
(pack) => pack.name == packageName,
|
||||
);
|
||||
if (package != null) {
|
||||
for (final String version in package.versions) {
|
||||
versions.update(
|
||||
version,
|
||||
(value) => versions[version]! + 1,
|
||||
ifAbsent: () => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (versions.isNotEmpty) {
|
||||
final entries = versions.entries.toList()
|
||||
..sort((a, b) => a.value.compareTo(b.value));
|
||||
versions
|
||||
..clear()
|
||||
..addEntries(entries);
|
||||
versions.removeWhere((key, value) => value != versions.values.last);
|
||||
return (versions.keys.toList()
|
||||
..sort()).last;
|
||||
}
|
||||
return '';
|
||||
}}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue