Add explicit TUN and SOCKS5 connection modes, app routing controls, authenticated per-session local SOCKS5, Android network monitoring, persistent haptics, resilient session recovery, notification hardening and client-side Hivemind cleanup. Keep the hosted flutter_vless_android 1.1.5 runtime as the base and apply the Android compatibility/security patches at build time instead of restoring the unstable vendored runtime.
49 lines
1.2 KiB
Dart
49 lines
1.2 KiB
Dart
import 'package:flutter/services.dart';
|
|
|
|
class InstalledApp {
|
|
final String packageName;
|
|
final String label;
|
|
final Uint8List? iconPng;
|
|
|
|
const InstalledApp({
|
|
required this.packageName,
|
|
required this.label,
|
|
required this.iconPng,
|
|
});
|
|
}
|
|
|
|
abstract final class InstalledAppsService {
|
|
InstalledAppsService._();
|
|
|
|
static const MethodChannel _channel = MethodChannel('com.revoltvpn.app/apps');
|
|
|
|
static Future<List<InstalledApp>> loadLaunchableApps() async {
|
|
final raw = await _channel.invokeListMethod<dynamic>('getLaunchableApps') ??
|
|
const <dynamic>[];
|
|
final apps = <InstalledApp>[];
|
|
|
|
for (final item in raw) {
|
|
if (item is! Map) continue;
|
|
|
|
final packageName = item['packageName'];
|
|
final label = item['label'];
|
|
final icon = item['icon'];
|
|
|
|
if (packageName is! String || packageName.isEmpty) continue;
|
|
|
|
apps.add(
|
|
InstalledApp(
|
|
packageName: packageName,
|
|
label: label is String && label.isNotEmpty ? label : packageName,
|
|
iconPng: icon is Uint8List ? icon : null,
|
|
),
|
|
);
|
|
}
|
|
|
|
apps.sort(
|
|
(a, b) => a.label.toLowerCase().compareTo(b.label.toLowerCase()),
|
|
);
|
|
return apps;
|
|
}
|
|
}
|