mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2024-11-12 18:04:28 +01:00
feat: sentry integration.
This commit is contained in:
parent
007b518503
commit
f1261398e9
12 changed files with 329 additions and 186 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -136,3 +136,8 @@ app.*.map.json
|
||||||
|
|
||||||
Firebase related
|
Firebase related
|
||||||
.firebase
|
.firebase
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
lib\utils\env_class.g.dart
|
||||||
|
/lib/utils/env_class.dart
|
|
@ -241,7 +241,16 @@ class MainActivity : FlutterActivity() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile)
|
|
||||||
|
// Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile)
|
||||||
|
|
||||||
|
try {
|
||||||
|
Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
//log to console
|
||||||
|
print("Error signing apk: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
handler.post {
|
handler.post {
|
||||||
installerChannel.invokeMethod(
|
installerChannel.invokeMethod(
|
||||||
|
|
|
@ -8,7 +8,9 @@ import 'package:revanced_manager/services/patcher_api.dart';
|
||||||
import 'package:revanced_manager/services/revanced_api.dart';
|
import 'package:revanced_manager/services/revanced_api.dart';
|
||||||
import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart';
|
import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart';
|
||||||
import 'package:revanced_manager/ui/views/navigation/navigation_view.dart';
|
import 'package:revanced_manager/ui/views/navigation/navigation_view.dart';
|
||||||
|
import 'package:revanced_manager/utils/env_class.dart';
|
||||||
import 'package:stacked_themes/stacked_themes.dart';
|
import 'package:stacked_themes/stacked_themes.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:timezone/data/latest.dart' as tz;
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
|
|
||||||
Future main() async {
|
Future main() async {
|
||||||
|
@ -21,7 +23,19 @@ Future main() async {
|
||||||
locator<GithubAPI>().initialize();
|
locator<GithubAPI>().initialize();
|
||||||
await locator<PatcherAPI>().initialize();
|
await locator<PatcherAPI>().initialize();
|
||||||
tz.initializeTimeZones();
|
tz.initializeTimeZones();
|
||||||
runApp(const MyApp());
|
await SentryFlutter.init(
|
||||||
|
(options) {
|
||||||
|
options
|
||||||
|
..dsn = Env.SENTRY_DSN
|
||||||
|
..environment = 'alpha'
|
||||||
|
..release = '0.1'
|
||||||
|
..tracesSampleRate = 1.0
|
||||||
|
..anrEnabled = true
|
||||||
|
..enableOutOfMemoryTracking = true
|
||||||
|
..sampleRate = 1.0;
|
||||||
|
},
|
||||||
|
appRunner: () => runApp(const MyApp()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
|
|
|
@ -8,6 +8,8 @@ import 'package:injectable/injectable.dart';
|
||||||
import 'package:native_dio_client/native_dio_client.dart';
|
import 'package:native_dio_client/native_dio_client.dart';
|
||||||
import 'package:revanced_manager/models/patch.dart';
|
import 'package:revanced_manager/models/patch.dart';
|
||||||
import 'package:revanced_manager/utils/check_for_gms.dart';
|
import 'package:revanced_manager/utils/check_for_gms.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
import 'package:sentry_dio/sentry_dio.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
class GithubAPI {
|
class GithubAPI {
|
||||||
|
@ -29,25 +31,36 @@ class GithubAPI {
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize() async {
|
void initialize() async {
|
||||||
bool isGMSInstalled = await checkForGMS();
|
try {
|
||||||
|
bool isGMSInstalled = await checkForGMS();
|
||||||
|
|
||||||
if (!isGMSInstalled) {
|
if (!isGMSInstalled) {
|
||||||
_dio = Dio(BaseOptions(
|
_dio = Dio(BaseOptions(
|
||||||
baseUrl: 'https://api.github.com',
|
baseUrl: 'https://api.github.com',
|
||||||
));
|
));
|
||||||
print('GitHub API: Using default engine + $isGMSInstalled');
|
print('GitHub API: Using default engine + $isGMSInstalled');
|
||||||
} else {
|
} else {
|
||||||
_dio = Dio(BaseOptions(
|
_dio = Dio(BaseOptions(
|
||||||
baseUrl: 'https://api.github.com',
|
baseUrl: 'https://api.github.com',
|
||||||
))
|
))
|
||||||
..httpClientAdapter = NativeAdapter();
|
..httpClientAdapter = NativeAdapter();
|
||||||
print('ReVanced API: Using CronetEngine + $isGMSInstalled');
|
print('ReVanced API: Using CronetEngine + $isGMSInstalled');
|
||||||
|
}
|
||||||
|
_dio.interceptors.add(_dioCacheManager.interceptor);
|
||||||
|
_dio.addSentry(
|
||||||
|
captureFailedRequests: true,
|
||||||
|
);
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
}
|
}
|
||||||
_dio.interceptors.add(_dioCacheManager.interceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearAllCache() async {
|
Future<void> clearAllCache() async {
|
||||||
await _dioCacheManager.clearAll();
|
try {
|
||||||
|
await _dioCacheManager.clearAll();
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>?> _getLatestRelease(String repoName) async {
|
Future<Map<String, dynamic>?> _getLatestRelease(String repoName) async {
|
||||||
|
@ -57,7 +70,8 @@ class GithubAPI {
|
||||||
options: _cacheOptions,
|
options: _cacheOptions,
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +101,8 @@ class GithubAPI {
|
||||||
'\n' as String,
|
'\n' as String,
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
} catch (e) {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return List.empty();
|
return List.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +121,8 @@ class GithubAPI {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -120,7 +136,8 @@ class GithubAPI {
|
||||||
List<dynamic> list = jsonDecode(f.readAsStringSync());
|
List<dynamic> list = jsonDecode(f.readAsStringSync());
|
||||||
patches = list.map((patch) => Patch.fromJson(patch)).toList();
|
patches = list.map((patch) => Patch.fromJson(patch)).toList();
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return List.empty();
|
return List.empty();
|
||||||
}
|
}
|
||||||
return patches;
|
return patches;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:revanced_manager/models/patched_application.dart';
|
||||||
import 'package:revanced_manager/services/github_api.dart';
|
import 'package:revanced_manager/services/github_api.dart';
|
||||||
import 'package:revanced_manager/services/revanced_api.dart';
|
import 'package:revanced_manager/services/revanced_api.dart';
|
||||||
import 'package:revanced_manager/services/root_api.dart';
|
import 'package:revanced_manager/services/root_api.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
|
@ -116,9 +117,13 @@ class ManagerAPI {
|
||||||
await setPatchedApps(patchedApps);
|
await setPatchedApps(patchedApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearAllData() {
|
void clearAllData() async {
|
||||||
_revancedAPI.clearAllCache();
|
try {
|
||||||
_githubAPI.clearAllCache();
|
_revancedAPI.clearAllCache();
|
||||||
|
_githubAPI.clearAllCache();
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, List<dynamic>>> getContributors() async {
|
Future<Map<String, List<dynamic>>> getContributors() async {
|
||||||
|
@ -126,35 +131,50 @@ class ManagerAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Patch>> getPatches() async {
|
Future<List<Patch>> getPatches() async {
|
||||||
String repoName = getPatchesRepo();
|
try {
|
||||||
if (repoName == defaultPatchesRepo) {
|
String repoName = getPatchesRepo();
|
||||||
return await _revancedAPI.getPatches();
|
if (repoName == defaultPatchesRepo) {
|
||||||
} else {
|
return await _revancedAPI.getPatches();
|
||||||
return await _githubAPI.getPatches(repoName);
|
} else {
|
||||||
|
return await _githubAPI.getPatches(repoName);
|
||||||
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File?> downloadPatches() async {
|
Future<File?> downloadPatches() async {
|
||||||
String repoName = getPatchesRepo();
|
try {
|
||||||
if (repoName == defaultPatchesRepo) {
|
String repoName = getPatchesRepo();
|
||||||
return await _revancedAPI.getLatestReleaseFile(
|
if (repoName == defaultPatchesRepo) {
|
||||||
'.jar',
|
return await _revancedAPI.getLatestReleaseFile(
|
||||||
defaultPatchesRepo,
|
'.jar',
|
||||||
);
|
defaultPatchesRepo,
|
||||||
} else {
|
);
|
||||||
return await _githubAPI.getLatestReleaseFile('.jar', repoName);
|
} else {
|
||||||
|
return await _githubAPI.getLatestReleaseFile('.jar', repoName);
|
||||||
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<File?> downloadIntegrations() async {
|
Future<File?> downloadIntegrations() async {
|
||||||
String repoName = getIntegrationsRepo();
|
try {
|
||||||
if (repoName == defaultIntegrationsRepo) {
|
String repoName = getIntegrationsRepo();
|
||||||
return await _revancedAPI.getLatestReleaseFile(
|
if (repoName == defaultIntegrationsRepo) {
|
||||||
'.apk',
|
return await _revancedAPI.getLatestReleaseFile(
|
||||||
defaultIntegrationsRepo,
|
'.apk',
|
||||||
);
|
defaultIntegrationsRepo,
|
||||||
} else {
|
);
|
||||||
return await _githubAPI.getLatestReleaseFile('.apk', repoName);
|
} else {
|
||||||
|
return await _githubAPI.getLatestReleaseFile('.apk', repoName);
|
||||||
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:revanced_manager/models/patch.dart';
|
||||||
import 'package:revanced_manager/models/patched_application.dart';
|
import 'package:revanced_manager/models/patched_application.dart';
|
||||||
import 'package:revanced_manager/services/manager_api.dart';
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
import 'package:revanced_manager/services/root_api.dart';
|
import 'package:revanced_manager/services/root_api.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:share_extend/share_extend.dart';
|
import 'package:share_extend/share_extend.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
|
@ -44,7 +45,8 @@ class PatcherAPI {
|
||||||
if (_patches.isEmpty) {
|
if (_patches.isEmpty) {
|
||||||
_patches = await _managerAPI.getPatches();
|
_patches = await _managerAPI.getPatches();
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
_patches = List.empty();
|
_patches = List.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,8 @@ class PatcherAPI {
|
||||||
filteredApps.add(app);
|
filteredApps.add(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,14 +127,19 @@ class PatcherAPI {
|
||||||
String packageName,
|
String packageName,
|
||||||
String originalFilePath,
|
String originalFilePath,
|
||||||
) async {
|
) async {
|
||||||
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
try {
|
||||||
if (hasRootPermissions) {
|
bool hasRootPermissions = await _rootAPI.hasRootPermissions();
|
||||||
originalFilePath = await _rootAPI.getOriginalFilePath(
|
if (hasRootPermissions) {
|
||||||
packageName,
|
originalFilePath = await _rootAPI.getOriginalFilePath(
|
||||||
originalFilePath,
|
packageName,
|
||||||
);
|
originalFilePath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return originalFilePath;
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
return originalFilePath;
|
||||||
}
|
}
|
||||||
return originalFilePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> runPatcher(
|
Future<void> runPatcher(
|
||||||
|
@ -151,7 +159,8 @@ class PatcherAPI {
|
||||||
if (settingsPatch != null) {
|
if (settingsPatch != null) {
|
||||||
selectedPatches.add(settingsPatch);
|
selectedPatches.add(settingsPatch);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,24 +178,29 @@ class PatcherAPI {
|
||||||
_outFile = File('${workDir.path}/out.apk');
|
_outFile = File('${workDir.path}/out.apk');
|
||||||
Directory cacheDir = Directory('${workDir.path}/cache');
|
Directory cacheDir = Directory('${workDir.path}/cache');
|
||||||
cacheDir.createSync();
|
cacheDir.createSync();
|
||||||
await patcherChannel.invokeMethod(
|
try {
|
||||||
'runPatcher',
|
await patcherChannel.invokeMethod(
|
||||||
{
|
'runPatcher',
|
||||||
'patchBundleFilePath': patchBundleFile.path,
|
{
|
||||||
'originalFilePath': await getOriginalFilePath(
|
'patchBundleFilePath': patchBundleFile.path,
|
||||||
packageName,
|
'originalFilePath': await getOriginalFilePath(
|
||||||
originalFilePath,
|
packageName,
|
||||||
),
|
originalFilePath,
|
||||||
'inputFilePath': inputFile.path,
|
),
|
||||||
'patchedFilePath': patchedFile.path,
|
'inputFilePath': inputFile.path,
|
||||||
'outFilePath': _outFile!.path,
|
'patchedFilePath': patchedFile.path,
|
||||||
'integrationsPath': mergeIntegrations ? integrationsFile!.path : '',
|
'outFilePath': _outFile!.path,
|
||||||
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
'integrationsPath': mergeIntegrations ? integrationsFile!.path : '',
|
||||||
'cacheDirPath': cacheDir.path,
|
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
||||||
'mergeIntegrations': mergeIntegrations,
|
'cacheDirPath': cacheDir.path,
|
||||||
'keyStoreFilePath': _keyStoreFile.path,
|
'mergeIntegrations': mergeIntegrations,
|
||||||
},
|
'keyStoreFilePath': _keyStoreFile.path,
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
print(e);
|
||||||
|
throw await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +220,8 @@ class PatcherAPI {
|
||||||
await AppInstaller.installApk(_outFile!.path);
|
await AppInstaller.installApk(_outFile!.path);
|
||||||
return await DeviceApps.isAppInstalled(patchedApp.packageName);
|
return await DeviceApps.isAppInstalled(patchedApp.packageName);
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,13 +229,18 @@ class PatcherAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sharePatchedFile(String appName, String version) {
|
void sharePatchedFile(String appName, String version) {
|
||||||
if (_outFile != null) {
|
try {
|
||||||
String prefix = appName.toLowerCase().replaceAll(' ', '-');
|
if (_outFile != null) {
|
||||||
String newName = '$prefix-revanced_v$version.apk';
|
String prefix = appName.toLowerCase().replaceAll(' ', '-');
|
||||||
int lastSeparator = _outFile!.path.lastIndexOf('/');
|
String newName = '$prefix-revanced_v$version.apk';
|
||||||
String newPath = _outFile!.path.substring(0, lastSeparator + 1) + newName;
|
int lastSeparator = _outFile!.path.lastIndexOf('/');
|
||||||
File shareFile = _outFile!.copySync(newPath);
|
String newPath =
|
||||||
ShareExtend.share(shareFile.path, 'file');
|
_outFile!.path.substring(0, lastSeparator + 1) + newName;
|
||||||
|
File shareFile = _outFile!.copySync(newPath);
|
||||||
|
ShareExtend.share(shareFile.path, 'file');
|
||||||
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
Sentry.captureException(e, stackTrace: s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import 'package:injectable/injectable.dart';
|
||||||
import 'package:revanced_manager/models/patch.dart';
|
import 'package:revanced_manager/models/patch.dart';
|
||||||
import 'package:revanced_manager/utils/check_for_gms.dart';
|
import 'package:revanced_manager/utils/check_for_gms.dart';
|
||||||
import 'package:timeago/timeago.dart';
|
import 'package:timeago/timeago.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
import 'package:sentry_dio/sentry_dio.dart';
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
class RevancedAPI {
|
class RevancedAPI {
|
||||||
|
@ -19,25 +21,36 @@ class RevancedAPI {
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> initialize(String apiUrl) async {
|
Future<void> initialize(String apiUrl) async {
|
||||||
bool isGMSInstalled = await checkForGMS();
|
try {
|
||||||
|
bool isGMSInstalled = await checkForGMS();
|
||||||
|
|
||||||
if (!isGMSInstalled) {
|
if (!isGMSInstalled) {
|
||||||
_dio = Dio(BaseOptions(
|
_dio = Dio(BaseOptions(
|
||||||
baseUrl: apiUrl,
|
baseUrl: apiUrl,
|
||||||
));
|
));
|
||||||
print('ReVanced API: Using default engine + $isGMSInstalled');
|
print('ReVanced API: Using default engine + $isGMSInstalled');
|
||||||
} else {
|
} else {
|
||||||
_dio = Dio(BaseOptions(
|
_dio = Dio(BaseOptions(
|
||||||
baseUrl: apiUrl,
|
baseUrl: apiUrl,
|
||||||
))
|
))
|
||||||
..httpClientAdapter = NativeAdapter();
|
..httpClientAdapter = NativeAdapter();
|
||||||
print('ReVanced API: Using CronetEngine + $isGMSInstalled');
|
print('ReVanced API: Using CronetEngine + $isGMSInstalled');
|
||||||
|
}
|
||||||
|
_dio.interceptors.add(_dioCacheManager.interceptor);
|
||||||
|
_dio.addSentry(
|
||||||
|
captureFailedRequests: true,
|
||||||
|
);
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
}
|
}
|
||||||
_dio.interceptors.add(_dioCacheManager.interceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearAllCache() async {
|
Future<void> clearAllCache() async {
|
||||||
await _dioCacheManager.clearAll();
|
try {
|
||||||
|
await _dioCacheManager.clearAll();
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, List<dynamic>>> getContributors() async {
|
Future<Map<String, List<dynamic>>> getContributors() async {
|
||||||
|
@ -49,7 +62,8 @@ class RevancedAPI {
|
||||||
String name = repo['name'];
|
String name = repo['name'];
|
||||||
contributors[name] = repo['contributors'];
|
contributors[name] = repo['contributors'];
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return contributors;
|
return contributors;
|
||||||
|
@ -60,7 +74,8 @@ class RevancedAPI {
|
||||||
var response = await _dio.get('/patches', options: _cacheOptions);
|
var response = await _dio.get('/patches', options: _cacheOptions);
|
||||||
List<dynamic> patches = response.data;
|
List<dynamic> patches = response.data;
|
||||||
return patches.map((patch) => Patch.fromJson(patch)).toList();
|
return patches.map((patch) => Patch.fromJson(patch)).toList();
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return List.empty();
|
return List.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +92,8 @@ class RevancedAPI {
|
||||||
t['repository'] == repoName &&
|
t['repository'] == repoName &&
|
||||||
(t['name'] as String).endsWith(extension),
|
(t['name'] as String).endsWith(extension),
|
||||||
);
|
);
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +110,8 @@ class RevancedAPI {
|
||||||
if (release != null) {
|
if (release != null) {
|
||||||
return release['version'];
|
return release['version'];
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -110,7 +127,8 @@ class RevancedAPI {
|
||||||
String url = release['browser_download_url'];
|
String url = release['browser_download_url'];
|
||||||
return await DefaultCacheManager().getSingleFile(url);
|
return await DefaultCacheManager().getSingleFile(url);
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -129,7 +147,8 @@ class RevancedAPI {
|
||||||
DateTime timestamp = DateTime.parse(release['timestamp'] as String);
|
DateTime timestamp = DateTime.parse(release['timestamp'] as String);
|
||||||
return format(timestamp, locale: 'en_short');
|
return format(timestamp, locale: 'en_short');
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:root/root.dart';
|
import 'package:root/root.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
||||||
class RootAPI {
|
class RootAPI {
|
||||||
final String _managerDirPath = '/data/local/tmp/revanced-manager';
|
final String _managerDirPath = '/data/local/tmp/revanced-manager';
|
||||||
|
@ -9,7 +10,8 @@ class RootAPI {
|
||||||
try {
|
try {
|
||||||
bool? isRooted = await Root.isRootAvailable();
|
bool? isRooted = await Root.isRootAvailable();
|
||||||
return isRooted != null && isRooted;
|
return isRooted != null && isRooted;
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +24,8 @@ class RootAPI {
|
||||||
return isRooted != null && isRooted;
|
return isRooted != null && isRooted;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,8 @@ class RootAPI {
|
||||||
apps.removeWhere((pack) => pack.isEmpty);
|
apps.removeWhere((pack) => pack.isEmpty);
|
||||||
return apps.map((pack) => pack.trim()).toList();
|
return apps.map((pack) => pack.trim()).toList();
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return List.empty();
|
return List.empty();
|
||||||
}
|
}
|
||||||
return List.empty();
|
return List.empty();
|
||||||
|
@ -121,7 +125,8 @@ class RootAPI {
|
||||||
await installApk(packageName, patchedFilePath);
|
await installApk(packageName, patchedFilePath);
|
||||||
await mountApk(packageName, originalFilePath);
|
await mountApk(packageName, originalFilePath);
|
||||||
return true;
|
return true;
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:revanced_manager/models/patched_application.dart';
|
||||||
import 'package:revanced_manager/services/patcher_api.dart';
|
import 'package:revanced_manager/services/patcher_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
class AppSelectorViewModel extends BaseViewModel {
|
class AppSelectorViewModel extends BaseViewModel {
|
||||||
|
@ -63,7 +64,8 @@ class AppSelectorViewModel extends BaseViewModel {
|
||||||
locator<PatcherViewModel>().notifyListeners();
|
locator<PatcherViewModel>().notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
_toast.show('appSelectorView.errorMessage');
|
_toast.show('appSelectorView.errorMessage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:timezone/timezone.dart' as tz;
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
@ -94,7 +95,8 @@ class HomeViewModel extends BaseViewModel {
|
||||||
int currentVersionInt =
|
int currentVersionInt =
|
||||||
int.parse(currentVersion.replaceAll(RegExp('[^0-9]'), ''));
|
int.parse(currentVersion.replaceAll(RegExp('[^0-9]'), ''));
|
||||||
return latestVersionInt > currentVersionInt;
|
return latestVersionInt > currentVersionInt;
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +137,8 @@ class HomeViewModel extends BaseViewModel {
|
||||||
} else {
|
} else {
|
||||||
_toast.show('homeView.errorDownloadMessage');
|
_toast.show('homeView.errorDownloadMessage');
|
||||||
}
|
}
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
_toast.show('homeView.errorInstallMessage');
|
_toast.show('homeView.errorInstallMessage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:revanced_manager/services/root_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:wakelock/wakelock.dart';
|
import 'package:wakelock/wakelock.dart';
|
||||||
|
|
||||||
|
@ -57,7 +58,8 @@ class InstallerViewModel extends BaseViewModel {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).then((value) => FlutterBackground.enableBackgroundExecution());
|
).then((value) => FlutterBackground.enableBackgroundExecution());
|
||||||
} on Exception {
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,91 +123,108 @@ class InstallerViewModel extends BaseViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> runPatcher() async {
|
Future<void> runPatcher() async {
|
||||||
update(0.0, 'Initializing...', 'Initializing installer');
|
try {
|
||||||
if (_patches.isNotEmpty) {
|
update(0.0, 'Initializing...', 'Initializing installer');
|
||||||
try {
|
if (_patches.isNotEmpty) {
|
||||||
update(0.1, '', 'Creating working directory');
|
try {
|
||||||
await _patcherAPI.runPatcher(
|
update(0.1, '', 'Creating working directory');
|
||||||
_app.packageName,
|
await _patcherAPI.runPatcher(
|
||||||
_app.apkFilePath,
|
_app.packageName,
|
||||||
_patches,
|
_app.apkFilePath,
|
||||||
);
|
_patches,
|
||||||
} catch (e) {
|
);
|
||||||
update(
|
} on Exception catch (e, s) {
|
||||||
-100.0,
|
update(
|
||||||
'Aborting...',
|
-100.0,
|
||||||
'An error occurred! Aborting\nError:\n$e',
|
'Aborting...',
|
||||||
);
|
'An error occurred! Aborting\nError:\n$e',
|
||||||
|
);
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
throw await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
update(-100.0, 'Aborting...', 'No app or patches selected! Aborting');
|
||||||
}
|
}
|
||||||
} else {
|
if (FlutterBackground.isBackgroundExecutionEnabled) {
|
||||||
update(-100.0, 'Aborting...', 'No app or patches selected! Aborting');
|
try {
|
||||||
}
|
FlutterBackground.disableBackgroundExecution();
|
||||||
if (FlutterBackground.isBackgroundExecutionEnabled) {
|
} on Exception catch (e, s) {
|
||||||
try {
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
FlutterBackground.disableBackgroundExecution();
|
// ignore
|
||||||
} on Exception {
|
}
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
|
await Wakelock.disable();
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
}
|
}
|
||||||
await Wakelock.disable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void installResult(BuildContext context, bool installAsRoot) async {
|
void installResult(BuildContext context, bool installAsRoot) async {
|
||||||
_app.isRooted = installAsRoot;
|
try {
|
||||||
bool hasMicroG = _patches.any((p) => p.name.endsWith('microg-support'));
|
_app.isRooted = installAsRoot;
|
||||||
bool rootMicroG = installAsRoot && hasMicroG;
|
bool hasMicroG = _patches.any((p) => p.name.endsWith('microg-support'));
|
||||||
bool rootFromStorage = installAsRoot && _app.isFromStorage;
|
bool rootMicroG = installAsRoot && hasMicroG;
|
||||||
bool ytWithoutRootMicroG =
|
bool rootFromStorage = installAsRoot && _app.isFromStorage;
|
||||||
!installAsRoot && !hasMicroG && _app.packageName.contains('youtube');
|
bool ytWithoutRootMicroG =
|
||||||
if (rootMicroG || rootFromStorage || ytWithoutRootMicroG) {
|
!installAsRoot && !hasMicroG && _app.packageName.contains('youtube');
|
||||||
return showDialog(
|
if (rootMicroG || rootFromStorage || ytWithoutRootMicroG) {
|
||||||
context: context,
|
return showDialog(
|
||||||
builder: (context) => AlertDialog(
|
context: context,
|
||||||
title: I18nText('installerView.installErrorDialogTitle'),
|
builder: (context) => AlertDialog(
|
||||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
title: I18nText('installerView.installErrorDialogTitle'),
|
||||||
content: I18nText(
|
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
rootMicroG
|
content: I18nText(
|
||||||
? 'installerView.installErrorDialogText1'
|
rootMicroG
|
||||||
: rootFromStorage
|
? 'installerView.installErrorDialogText1'
|
||||||
? 'installerView.installErrorDialogText3'
|
: rootFromStorage
|
||||||
: 'installerView.installErrorDialogText2',
|
? 'installerView.installErrorDialogText3'
|
||||||
|
: 'installerView.installErrorDialogText2',
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
CustomMaterialButton(
|
||||||
|
label: I18nText('okButton'),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
);
|
||||||
CustomMaterialButton(
|
} else {
|
||||||
label: I18nText('okButton'),
|
update(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
1.0,
|
||||||
)
|
'Installing...',
|
||||||
],
|
_app.isRooted
|
||||||
),
|
? 'Installing patched file using root method'
|
||||||
);
|
: 'Installing patched file using nonroot method',
|
||||||
} else {
|
);
|
||||||
update(
|
isInstalled = await _patcherAPI.installPatchedFile(_app);
|
||||||
1.0,
|
if (isInstalled) {
|
||||||
'Installing...',
|
update(1.0, 'Installed!', 'Installed!');
|
||||||
_app.isRooted
|
_app.isFromStorage = false;
|
||||||
? 'Installing patched file using root method'
|
_app.patchDate = DateTime.now();
|
||||||
: 'Installing patched file using nonroot method',
|
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
||||||
);
|
if (hasMicroG) {
|
||||||
isInstalled = await _patcherAPI.installPatchedFile(_app);
|
_app.name += ' ReVanced';
|
||||||
if (isInstalled) {
|
_app.packageName = _app.packageName.replaceFirst(
|
||||||
update(1.0, 'Installed!', 'Installed!');
|
'com.google.',
|
||||||
_app.isFromStorage = false;
|
'app.revanced.',
|
||||||
_app.patchDate = DateTime.now();
|
);
|
||||||
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
}
|
||||||
if (hasMicroG) {
|
await _managerAPI.savePatchedApp(_app);
|
||||||
_app.name += ' ReVanced';
|
|
||||||
_app.packageName = _app.packageName.replaceFirst(
|
|
||||||
'com.google.',
|
|
||||||
'app.revanced.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
await _managerAPI.savePatchedApp(_app);
|
|
||||||
}
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shareResult() {
|
void shareResult() {
|
||||||
_patcherAPI.sharePatchedFile(_app.name, _app.version);
|
try {
|
||||||
|
if (isInstalled) {
|
||||||
|
_patcherAPI.sharePatchedFile(_app.name, _app.version);
|
||||||
|
}
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shareLog() {
|
void shareLog() {
|
||||||
|
@ -213,10 +232,14 @@ class InstallerViewModel extends BaseViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> cleanPatcher() async {
|
Future<void> cleanPatcher() async {
|
||||||
_patcherAPI.cleanPatcher();
|
try {
|
||||||
locator<PatcherViewModel>().selectedApp = null;
|
_patcherAPI.cleanPatcher();
|
||||||
locator<PatcherViewModel>().selectedPatches.clear();
|
locator<PatcherViewModel>().selectedApp = null;
|
||||||
locator<PatcherViewModel>().notifyListeners();
|
locator<PatcherViewModel>().selectedPatches.clear();
|
||||||
|
locator<PatcherViewModel>().notifyListeners();
|
||||||
|
} on Exception catch (e, s) {
|
||||||
|
await Sentry.captureException(e, stackTrace: s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void openApp() {
|
void openApp() {
|
||||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -10,6 +10,7 @@ environment:
|
||||||
sdk: ">=2.17.5 <3.0.0"
|
sdk: ">=2.17.5 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
sentry_flutter: ^6.12.2
|
||||||
animations: ^2.0.4
|
animations: ^2.0.4
|
||||||
app_installer: ^1.1.0
|
app_installer: ^1.1.0
|
||||||
collection: ^1.16.0
|
collection: ^1.16.0
|
||||||
|
@ -71,15 +72,20 @@ dependencies:
|
||||||
timezone: ^0.8.0
|
timezone: ^0.8.0
|
||||||
url_launcher: ^6.1.5
|
url_launcher: ^6.1.5
|
||||||
wakelock: ^0.6.2
|
wakelock: ^0.6.2
|
||||||
|
sentry_dio: ^6.12.2
|
||||||
|
envied: ^0.2.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
json_serializable: ^6.3.1
|
||||||
build_runner: any
|
build_runner: any
|
||||||
flutter_launcher_icons: ^0.10.0
|
flutter_launcher_icons: ^0.10.0
|
||||||
flutter_lints: ^2.0.1
|
flutter_lints: ^2.0.1
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
injectable_generator: ^1.5.4
|
injectable_generator: ^1.5.4
|
||||||
json_serializable: ^6.3.1
|
envied_generator: ^0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
Loading…
Reference in a new issue