2022-08-14 20:40:34 +02:00
|
|
|
import 'package:root/root.dart';
|
|
|
|
|
|
|
|
class RootAPI {
|
2022-08-18 16:33:33 +02:00
|
|
|
final String _managerDirPath = "/data/adb/revanced_manager";
|
|
|
|
final String _postFsDataDirPath = "/data/adb/post-fs-data.d";
|
|
|
|
final String _serviceDDirPath = "/data/adb/service.d";
|
2022-08-14 20:40:34 +02:00
|
|
|
|
2022-08-25 01:51:47 +02:00
|
|
|
Future<bool> isAppInstalled(String packageName) async {
|
|
|
|
if (packageName.isNotEmpty) {
|
|
|
|
String? res = await Root.exec(
|
|
|
|
cmd: 'ls "$_managerDirPath/$packageName"',
|
|
|
|
);
|
|
|
|
if (res != null && res.isNotEmpty) {
|
|
|
|
res = await Root.exec(
|
|
|
|
cmd: 'ls "$_serviceDDirPath/$packageName.sh"',
|
|
|
|
);
|
|
|
|
return res != null && res.isNotEmpty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<List<String>> getInstalledApps() async {
|
2022-08-14 20:40:34 +02:00
|
|
|
try {
|
2022-08-15 04:31:36 +02:00
|
|
|
String? res = await Root.exec(
|
2022-08-25 01:51:47 +02:00
|
|
|
cmd: 'ls "$_managerDirPath"',
|
2022-08-15 04:31:36 +02:00
|
|
|
);
|
2022-08-25 01:51:47 +02:00
|
|
|
if (res != null) {
|
|
|
|
List<String> apps = res.split('\n');
|
|
|
|
for (String packageName in apps) {
|
|
|
|
bool isInstalled = await isAppInstalled(packageName);
|
|
|
|
if (!isInstalled) {
|
|
|
|
apps.remove(packageName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-14 20:40:34 +02:00
|
|
|
} on Exception {
|
2022-08-25 01:51:47 +02:00
|
|
|
return List.empty();
|
2022-08-14 20:40:34 +02:00
|
|
|
}
|
2022-08-25 01:51:47 +02:00
|
|
|
return List.empty();
|
2022-08-14 20:40:34 +02:00
|
|
|
}
|
|
|
|
|
2022-08-15 04:31:36 +02:00
|
|
|
Future<void> deleteApp(String packageName, String originalFilePath) async {
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'am force-stop "$packageName"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'su -mm -c "umount -l $originalFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
2022-08-18 16:33:33 +02:00
|
|
|
cmd: 'rm -rf "$_managerDirPath/$packageName"',
|
2022-08-15 04:31:36 +02:00
|
|
|
);
|
|
|
|
await Root.exec(
|
2022-08-18 16:33:33 +02:00
|
|
|
cmd: 'rm -rf "$_serviceDDirPath/$packageName.sh"',
|
2022-08-15 04:31:36 +02:00
|
|
|
);
|
|
|
|
await Root.exec(
|
2022-08-18 16:33:33 +02:00
|
|
|
cmd: 'rm -rf "$_postFsDataDirPath/$packageName.sh"',
|
2022-08-15 04:31:36 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:40:34 +02:00
|
|
|
Future<bool> installApp(
|
|
|
|
String packageName,
|
|
|
|
String originalFilePath,
|
|
|
|
String patchedFilePath,
|
|
|
|
) async {
|
|
|
|
try {
|
2022-08-14 22:32:03 +02:00
|
|
|
await Root.exec(
|
2022-08-18 16:33:33 +02:00
|
|
|
cmd: 'mkdir -p "$_managerDirPath/$packageName"',
|
2022-08-14 20:40:34 +02:00
|
|
|
);
|
2022-08-15 04:31:36 +02:00
|
|
|
installServiceDScript(packageName);
|
|
|
|
installPostFsDataScript(packageName);
|
|
|
|
installApk(packageName, patchedFilePath);
|
|
|
|
mountApk(packageName, originalFilePath, patchedFilePath);
|
2022-08-14 20:40:34 +02:00
|
|
|
return true;
|
|
|
|
} on Exception {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 04:31:36 +02:00
|
|
|
Future<void> installServiceDScript(String packageName) async {
|
2022-08-14 20:40:34 +02:00
|
|
|
String content = '#!/system/bin/sh\n'
|
2022-08-15 04:31:36 +02:00
|
|
|
'while [ "\$(getprop sys.boot_completed | tr -d \'"\'"\'\\\\r\'"\'"\')" != "1" ]; do sleep 1; done\n'
|
2022-08-18 16:33:33 +02:00
|
|
|
'base_path=$_managerDirPath/$packageName/base.apk\n'
|
2022-08-15 04:31:36 +02:00
|
|
|
'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n'
|
|
|
|
'[ ! -z \$stock_path ] && mount -o bind \$base_path \$stock_path';
|
2022-08-18 16:33:33 +02:00
|
|
|
String scriptFilePath = '$_serviceDDirPath/$packageName.sh';
|
2022-08-14 22:32:03 +02:00
|
|
|
await Root.exec(
|
2022-08-15 04:31:36 +02:00
|
|
|
cmd: 'echo \'$content\' > "$scriptFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'chmod 744 "$scriptFilePath"',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> installPostFsDataScript(String packageName) async {
|
|
|
|
String content = '#!/system/bin/sh\n'
|
|
|
|
'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n'
|
|
|
|
'[ ! -z \$stock_path ] && umount -l \$stock_path';
|
2022-08-18 16:33:33 +02:00
|
|
|
String scriptFilePath = '$_postFsDataDirPath/$packageName.sh';
|
2022-08-15 04:31:36 +02:00
|
|
|
await Root.exec(
|
|
|
|
cmd: 'echo \'$content\' > "$scriptFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'chmod 744 "$scriptFilePath"',
|
2022-08-14 22:32:03 +02:00
|
|
|
);
|
2022-08-14 20:40:34 +02:00
|
|
|
}
|
|
|
|
|
2022-08-15 04:31:36 +02:00
|
|
|
Future<void> installApk(String packageName, String patchedFilePath) async {
|
2022-08-18 16:33:33 +02:00
|
|
|
String newPatchedFilePath = '$_managerDirPath/$packageName/base.apk';
|
2022-08-15 04:31:36 +02:00
|
|
|
await Root.exec(
|
|
|
|
cmd: 'cp "$patchedFilePath" "$newPatchedFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'chmod 644 "$newPatchedFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'chown system:system "$newPatchedFilePath"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'chcon u:object_r:apk_data_file:s0 "$newPatchedFilePath"',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> mountApk(
|
2022-08-14 20:40:34 +02:00
|
|
|
String packageName,
|
|
|
|
String originalFilePath,
|
|
|
|
String patchedFilePath,
|
|
|
|
) async {
|
2022-08-18 16:33:33 +02:00
|
|
|
String newPatchedFilePath = '$_managerDirPath/$packageName/base.apk';
|
2022-08-15 04:31:36 +02:00
|
|
|
await Root.exec(
|
|
|
|
cmd: 'am force-stop "$packageName"',
|
|
|
|
);
|
|
|
|
await Root.exec(
|
|
|
|
cmd: 'su -mm -c "umount -l $originalFilePath"',
|
|
|
|
);
|
2022-08-14 22:32:03 +02:00
|
|
|
await Root.exec(
|
2022-08-15 04:31:36 +02:00
|
|
|
cmd: 'su -mm -c "mount -o bind $newPatchedFilePath $originalFilePath"',
|
2022-08-14 22:32:03 +02:00
|
|
|
);
|
2022-08-14 20:40:34 +02:00
|
|
|
}
|
|
|
|
}
|