feat: add Patcher API.

This commit is contained in:
Alberto Ponces
2022-08-06 14:04:18 +01:00
parent 57b932fd23
commit fc06f8d571
13 changed files with 403 additions and 93 deletions

13
lib/models/patch.dart Normal file
View File

@@ -0,0 +1,13 @@
class Patch {
final String name;
final String simpleName;
final String version;
final String description;
Patch({
required this.name,
required this.simpleName,
required this.version,
required this.description,
});
}

View File

@@ -8,7 +8,13 @@ class GithubAPI {
Future<String?> latestRelease(String org, repoName) async {
var latestRelease = await github.repositories
.getLatestRelease(RepositorySlug(org, repoName));
var dlurl = latestRelease.assets?.first.browserDownloadUrl;
var dlurl = latestRelease.assets
?.firstWhere((asset) =>
asset.name != null &&
asset.name!.endsWith('.dex') &&
!asset.name!.contains('-sources') &&
!asset.name!.contains('-javadoc'))
.browserDownloadUrl;
return dlurl;
}

View File

@@ -0,0 +1,100 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:installed_apps/app_info.dart';
import 'package:installed_apps/installed_apps.dart';
import 'package:revanced_manager_flutter/models/patch.dart';
import 'package:revanced_manager_flutter/services/github_api.dart';
import 'package:revanced_manager_flutter/utils/string.dart';
class PatcherService {
File? _patchBundleFile;
final List<AppInfo> _filteredPackages = [];
final Map<String, List<Patch>> _filteredPatches = <String, List<Patch>>{};
final GithubAPI githubAPI = GithubAPI();
static const platform = MethodChannel('app.revanced/patcher');
static final PatcherService _instance = PatcherService.internal();
factory PatcherService() => _instance;
PatcherService.internal();
Future<void> loadPatches() async {
if (_patchBundleFile == null) {
String? dexFileUrl =
await githubAPI.latestRelease('revanced', 'revanced-patches');
if (dexFileUrl != null) {
_patchBundleFile =
await DefaultCacheManager().getSingleFile(dexFileUrl);
try {
await platform.invokeMethod(
'loadPatches',
{
'pathBundlesPaths': <String>[_patchBundleFile!.absolute.path],
},
);
} on PlatformException {
_patchBundleFile = null;
}
}
}
}
Future<List<AppInfo>> getFilteredInstalledApps() async {
if (_patchBundleFile != null && _filteredPackages.isEmpty) {
List<AppInfo> all = await InstalledApps.getInstalledApps(false, true);
try {
List<String>? patchesPackages =
await platform.invokeListMethod<String>('getCompatiblePackages');
if (patchesPackages != null) {
for (AppInfo app in all) {
if (patchesPackages.contains(app.packageName)) {
_filteredPackages.add(app);
}
}
}
} on Exception {
return List.empty();
}
}
return _filteredPackages;
}
Future<List<Patch>?> getFilteredPatches(AppInfo? targetApp) async {
if (_patchBundleFile != null && targetApp != null) {
if (_filteredPatches[targetApp.packageName] == null ||
_filteredPatches[targetApp.packageName]!.isEmpty) {
_filteredPatches[targetApp.packageName!] = [];
try {
var patches = await platform.invokeListMethod<Map<dynamic, dynamic>>(
'getFilteredPatches',
{
'targetPackage': targetApp.packageName,
'targetVersion': targetApp.versionName,
'ignoreVersion': true,
},
);
if (patches != null) {
for (var patch in patches) {
_filteredPatches[targetApp.packageName]!.add(
Patch(
name: patch['name'],
simpleName: (patch['name'] as String)
.replaceAll('-', ' ')
.split('-')
.join(' ')
.toTitleCase(),
version: patch['version'] ?? 'unknown',
description: patch['description'] ?? 'unknown',
),
);
}
}
} on Exception {
return List.empty();
}
}
} else {
return List.empty();
}
return _filteredPatches[targetApp.packageName];
}
}

8
lib/utils/string.dart Normal file
View File

@@ -0,0 +1,8 @@
extension StringCasingExtension on String {
String toCapitalized() =>
length > 0 ? '${this[0].toUpperCase()}${substring(1).toLowerCase()}' : '';
String toTitleCase() => replaceAll(RegExp(' +'), ' ')
.split(' ')
.map((str) => str.toCapitalized())
.join(' ');
}