diff --git a/android/app/build.gradle b/android/app/build.gradle index 90500f3..32c3bdd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,6 +90,12 @@ flutter { source '../..' } +repositories { + maven { url 'https://jitpack.io' } +} + dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + def libsuVersion = '5.2.2' + implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" } diff --git a/android/app/src/main/kotlin/com/example/obtainium/MainActivity.kt b/android/app/src/main/kotlin/com/example/obtainium/MainActivity.kt index 7693e63..8fa95c1 100644 --- a/android/app/src/main/kotlin/com/example/obtainium/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/obtainium/MainActivity.kt @@ -1,6 +1,39 @@ package dev.imranr.obtainium import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.Result +import androidx.annotation.NonNull +import com.topjohnwu.superuser.Shell class MainActivity: FlutterActivity() { + private val installersChannel = "installers" + + private fun installWithRoot(apkFilePath: String, result: Result) { + Shell.sh("pm install -r -t " + apkFilePath).submit { out -> + val builder = StringBuilder() + for (data in out.getOut()) { + builder.append(data) + } + result.success(if (builder.toString().endsWith("Success")) 0 else 1) + } + } + + private fun installWithShizuku(apkFilePath: String, result: Result) { + val a = 1 + } + + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, installersChannel).setMethodCallHandler { + call, result -> + var apkFilePath: String? = call.argument("apkFilePath") + if (call.method == "installWithShizuku") { + installWithShizuku(apkFilePath.toString(), result) + } else if (call.method == "installWithRoot") { + installWithRoot(apkFilePath.toString(), result) + } + } + } } diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 35fbfcc..b8f0b48 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -33,6 +33,7 @@ import 'package:http/http.dart'; import 'package:android_intent_plus/android_intent.dart'; import 'package:flutter_archive/flutter_archive.dart'; import 'package:shared_storage/shared_storage.dart' as saf; +import 'installers_provider.dart'; final pm = AndroidPackageManager(); @@ -515,8 +516,14 @@ class AppsProvider with ChangeNotifier { await saveApps([apps[file.appId]!.app], attemptToCorrectInstallStatus: false); } - int? code = - await AndroidPackageInstaller.installApk(apkFilePath: file.file.path); + int? code; + if (settingsProvider.installMethod == InstallMethodSettings.normal) { + code = await AndroidPackageInstaller.installApk(apkFilePath: file.file.path); + } else if (settingsProvider.installMethod == InstallMethodSettings.shizuku) { + code = await Installers.installWithShizuku(apkFilePath: file.file.path); + } else if (settingsProvider.installMethod == InstallMethodSettings.root) { + code = await Installers.installWithRoot(apkFilePath: file.file.path); + } bool installed = false; if (code != null && code != 0 && code != 3) { throw InstallError(code); diff --git a/lib/providers/installers_provider.dart b/lib/providers/installers_provider.dart new file mode 100644 index 0000000..d9c8f93 --- /dev/null +++ b/lib/providers/installers_provider.dart @@ -0,0 +1,14 @@ +import 'dart:async'; +import 'package:flutter/services.dart'; + +class Installers { + static const MethodChannel _channel = MethodChannel('installers'); + + static Future installWithShizuku({required String apkFilePath}) async { + return await _channel.invokeMethod('installWithShizuku', {'apkFilePath': apkFilePath}); + } + + static Future installWithRoot({required String apkFilePath}) async { + return await _channel.invokeMethod('installWithRoot', {'apkFilePath': apkFilePath}); + } +}