feat: sentry integration.

This commit is contained in:
Aunali321 2022-10-14 23:35:33 +05:30
parent 007b518503
commit f1261398e9
12 changed files with 329 additions and 186 deletions

5
.gitignore vendored
View file

@ -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

View file

@ -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(

View file

@ -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 {

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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);
} }
} }

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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');
} }
} }

View file

@ -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');
} }
} }

View file

@ -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() {

View file

@ -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