revanced-manager/lib/services/patcher_api.dart

274 lines
8.3 KiB
Dart
Raw Normal View History

2022-08-06 15:04:18 +02:00
import 'dart:io';
import 'package:app_installer/app_installer.dart';
import 'package:device_apps/device_apps.dart';
2022-08-06 15:04:18 +02:00
import 'package:flutter/services.dart';
2022-08-19 20:13:43 +02:00
import 'package:flutter_archive/flutter_archive.dart';
2022-08-09 01:01:06 +02:00
import 'package:injectable/injectable.dart';
import 'package:path_provider/path_provider.dart';
2022-08-06 23:35:35 +02:00
import 'package:revanced_manager/models/patch.dart';
2022-08-14 20:40:34 +02:00
import 'package:revanced_manager/models/patched_application.dart';
2022-08-18 16:33:33 +02:00
import 'package:revanced_manager/services/manager_api.dart';
2022-08-14 20:40:34 +02:00
import 'package:revanced_manager/services/root_api.dart';
2022-08-06 23:35:35 +02:00
import 'package:revanced_manager/utils/string.dart';
import 'package:share_extend/share_extend.dart';
2022-08-06 15:04:18 +02:00
2022-08-09 01:01:06 +02:00
@lazySingleton
class PatcherAPI {
static const patcherChannel = MethodChannel(
'app.revanced.manager/patcher',
);
2022-08-18 16:33:33 +02:00
final ManagerAPI _managerAPI = ManagerAPI();
final RootAPI _rootAPI = RootAPI();
2022-08-14 20:40:34 +02:00
Directory? _tmpDir;
Directory? _workDir;
Directory? _cacheDir;
2022-08-19 20:13:43 +02:00
File? _zipPatchBundleFile;
File? _integrations;
File? _inputFile;
File? _patchedFile;
File? _outFile;
2022-08-09 01:01:06 +02:00
2022-08-19 20:13:43 +02:00
Future<void> initPatcher() async {
_tmpDir = await getTemporaryDirectory();
_workDir = _tmpDir!.createTempSync('tmp-');
_inputFile = File('${_workDir!.path}/base.apk');
_patchedFile = File('${_workDir!.path}/patched.apk');
_outFile = File('${_workDir!.path}/out.apk');
_cacheDir = Directory('${_workDir!.path}/cache');
_cacheDir!.createSync();
}
2022-08-18 16:33:33 +02:00
Future<void> loadPatches() async {
2022-08-19 20:13:43 +02:00
if (_cacheDir == null) {
await initPatcher();
}
if (_zipPatchBundleFile == null) {
File? patchBundleDexFile = await _managerAPI.downloadPatches('.dex');
File? patchBundleJarFile = await _managerAPI.downloadPatches('.jar');
if (patchBundleDexFile != null && patchBundleJarFile != null) {
await joinPatchBundleFiles(patchBundleDexFile, patchBundleJarFile);
if (_zipPatchBundleFile != null) {
await patcherChannel.invokeMethod<bool>(
'loadPatches',
{
'zipPatchBundlePath': _zipPatchBundleFile!.path,
'cacheDirPath': _cacheDir!.path,
},
);
}
2022-08-06 15:04:18 +02:00
}
}
}
Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async {
2022-08-17 19:44:27 +02:00
List<ApplicationWithIcon> filteredPackages = [];
2022-08-19 20:13:43 +02:00
if (_zipPatchBundleFile != null) {
2022-08-06 15:04:18 +02:00
try {
List<String>? patchesPackages = await patcherChannel
.invokeListMethod<String>('getCompatiblePackages');
2022-08-06 15:04:18 +02:00
if (patchesPackages != null) {
for (String package in patchesPackages) {
try {
ApplicationWithIcon? app = await DeviceApps.getApp(package, true)
as ApplicationWithIcon?;
if (app != null) {
2022-08-17 19:44:27 +02:00
filteredPackages.add(app);
}
} catch (e) {
continue;
2022-08-06 15:04:18 +02:00
}
}
}
} on Exception {
2022-08-06 15:04:18 +02:00
return List.empty();
}
}
2022-08-17 19:44:27 +02:00
return filteredPackages;
2022-08-06 15:04:18 +02:00
}
2022-08-17 19:44:27 +02:00
Future<List<Patch>> getFilteredPatches(
2022-08-14 20:40:34 +02:00
PatchedApplication? selectedApp,
) async {
2022-08-17 19:44:27 +02:00
List<Patch> filteredPatches = [];
2022-08-19 20:13:43 +02:00
if (_zipPatchBundleFile != null && selectedApp != null) {
2022-08-17 19:44:27 +02:00
try {
var patches =
await patcherChannel.invokeListMethod<Map<dynamic, dynamic>>(
'getFilteredPatches',
{
'targetPackage': selectedApp.packageName,
'targetVersion': selectedApp.version,
'ignoreVersion': true,
},
);
if (patches != null) {
for (var patch in patches) {
if (!filteredPatches
.any((element) => element.name == patch['name'])) {
filteredPatches.add(
Patch(
name: patch['name'],
simpleName: (patch['name'] as String)
.replaceAll('-', ' ')
.split('-')
.join(' ')
.toTitleCase(),
version: patch['version'] ?? '?.?.?',
description: patch['description'] ?? 'N/A',
),
);
2022-08-06 15:04:18 +02:00
}
}
}
2022-08-17 19:44:27 +02:00
} on Exception {
return List.empty();
}
}
return filteredPatches;
}
Future<List<Patch>> getAppliedPatches(
PatchedApplication? selectedApp,
) async {
List<Patch> appliedPatches = [];
2022-08-19 20:13:43 +02:00
if (_zipPatchBundleFile != null && selectedApp != null) {
2022-08-17 19:44:27 +02:00
try {
var patches =
await patcherChannel.invokeListMethod<Map<dynamic, dynamic>>(
'getFilteredPatches',
{
'targetPackage': selectedApp.packageName,
'targetVersion': selectedApp.version,
'ignoreVersion': true,
},
);
if (patches != null) {
for (var patch in patches) {
if (selectedApp.appliedPatches.contains(patch['name'])) {
appliedPatches.add(
Patch(
name: patch['name'],
simpleName: (patch['name'] as String)
.replaceAll('-', ' ')
.split('-')
.join(' ')
.toTitleCase(),
version: patch['version'] ?? '?.?.?',
description: patch['description'] ?? 'N/A',
),
);
}
}
}
} on Exception {
return List.empty();
2022-08-06 15:04:18 +02:00
}
}
2022-08-17 19:44:27 +02:00
return appliedPatches;
}
2022-08-19 20:13:43 +02:00
Future<void> mergeIntegrations(bool mergeIntegrations) async {
if (mergeIntegrations) {
2022-08-19 20:13:43 +02:00
_integrations = await _managerAPI.downloadIntegrations('.apk');
} else {
_integrations = null;
}
}
Future<void> runPatcher(
String originalFilePath,
List<Patch> selectedPatches,
bool mergeIntegrations,
bool resourcePatching,
) async {
await patcherChannel.invokeMethod(
'runPatcher',
{
'originalFilePath': originalFilePath,
'inputFilePath': _inputFile!.path,
'patchedFilePath': _patchedFile!.path,
'outFilePath': _outFile!.path,
2022-08-18 16:33:33 +02:00
'integrationsPath': _integrations != null ? _integrations!.path : '',
2022-08-17 19:44:27 +02:00
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
'cacheDirPath': _cacheDir!.path,
'mergeIntegrations': mergeIntegrations,
'resourcePatching': resourcePatching,
},
);
}
2022-08-14 20:40:34 +02:00
Future<bool> installPatchedFile(PatchedApplication patchedApp) async {
if (_outFile != null) {
try {
2022-08-14 20:40:34 +02:00
if (patchedApp.isRooted && !patchedApp.isFromStorage) {
2022-08-18 16:33:33 +02:00
return _rootAPI.installApp(
2022-08-14 20:40:34 +02:00
patchedApp.packageName,
patchedApp.apkFilePath,
_outFile!.path,
);
} else {
await AppInstaller.installApk(_outFile!.path);
2022-08-17 18:07:00 +02:00
return await DeviceApps.isAppInstalled(patchedApp.packageName);
}
} on Exception {
return false;
}
}
return false;
}
void cleanPatcher() {
if (_workDir != null) {
_workDir!.deleteSync(recursive: true);
}
}
bool sharePatchedFile(String appName, String version) {
if (_outFile != null) {
2022-08-14 20:40:34 +02:00
String path = _tmpDir!.path;
String prefix = appName.toLowerCase().replaceAll(' ', '-');
String sharePath = '$path/$prefix-revanced_v$version.apk';
File share = _outFile!.copySync(sharePath);
2022-08-14 20:40:34 +02:00
ShareExtend.share(share.path, 'file');
return true;
} else {
return false;
}
2022-08-06 15:04:18 +02:00
}
Future<bool> checkOldPatch(PatchedApplication patchedApp) async {
if (patchedApp.isRooted) {
2022-08-18 16:33:33 +02:00
return await _rootAPI.checkApp(patchedApp.packageName);
}
return false;
}
Future<void> deleteOldPatch(PatchedApplication patchedApp) async {
if (patchedApp.isRooted) {
2022-08-18 16:33:33 +02:00
await _rootAPI.deleteApp(patchedApp.packageName, patchedApp.apkFilePath);
}
}
2022-08-19 20:13:43 +02:00
Future<void> joinPatchBundleFiles(
File patchBundleDexFile,
File patchBundleJarFile,
) async {
_zipPatchBundleFile = File('${_workDir!.path}/join.zip');
Directory joinDir = Directory('${_cacheDir!.path}/join');
try {
await ZipFile.extractToDirectory(
zipFile: patchBundleJarFile,
destinationDir: joinDir,
);
patchBundleDexFile.copySync('${joinDir.path}/classes.dex');
await ZipFile.createFromDirectory(
sourceDir: joinDir,
zipFile: _zipPatchBundleFile!,
recurseSubDirs: true,
);
} on Exception {
_zipPatchBundleFile = null;
}
}
2022-08-06 15:04:18 +02:00
}