From 7b882d9bd85b807df4ccb8ab38ca2c77015d303b Mon Sep 17 00:00:00 2001 From: Gregory Velichko Date: Sun, 14 Apr 2024 18:40:32 +0300 Subject: [PATCH] =?UTF-8?q?Move=20to=20plugins=F0=9F=90=B1=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 12 -- .../dev/imranr/obtainium/MainActivity.kt | 153 +----------------- .../obtainium/util/ApplicationUtils.java | 37 ----- .../obtainium/util/IIntentSenderAdaptor.java | 23 --- .../obtainium/util/IntentSenderUtils.java | 14 -- .../obtainium/util/PackageInstallerUtils.java | 41 ----- .../util/ShizukuSystemServerApi.java | 68 -------- .../dev/imranr/obtainium/util/Singleton.java | 17 -- android/gradle.properties | 2 +- assets/translations/en.json | 6 +- assets/translations/ru.json | 6 +- lib/pages/settings.dart | 84 +++++++--- lib/providers/apps_provider.dart | 28 ++-- lib/providers/native_provider.dart | 42 ----- lib/providers/settings_provider.dart | 9 ++ pubspec.lock | 79 +++++---- pubspec.yaml | 4 + 17 files changed, 141 insertions(+), 484 deletions(-) delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/ApplicationUtils.java delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/IIntentSenderAdaptor.java delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/IntentSenderUtils.java delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/PackageInstallerUtils.java delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/ShizukuSystemServerApi.java delete mode 100644 android/app/src/main/kotlin/dev/imranr/obtainium/util/Singleton.java diff --git a/android/app/build.gradle b/android/app/build.gradle index 6c35e02..d461e41 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -92,18 +92,6 @@ repositories { maven { url 'https://jitpack.io' } } -dependencies { - def shizuku_version = '13.1.5' - implementation "dev.rikka.shizuku:api:$shizuku_version" - implementation "dev.rikka.shizuku:provider:$shizuku_version" - - def hidden_api_version = '4.3.1' - implementation "dev.rikka.tools.refine:runtime:$hidden_api_version" - implementation "dev.rikka.hidden:compat:$hidden_api_version" - compileOnly "dev.rikka.hidden:stub:$hidden_api_version" - implementation "org.lsposed.hiddenapibypass:hiddenapibypass:4.3" -} - ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3] import com.android.build.OutputFile android.applicationVariants.all { variant -> diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/MainActivity.kt b/android/app/src/main/kotlin/dev/imranr/obtainium/MainActivity.kt index eeeb366..09cd313 100644 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/MainActivity.kt +++ b/android/app/src/main/kotlin/dev/imranr/obtainium/MainActivity.kt @@ -1,156 +1,5 @@ package dev.imranr.obtainium -import android.content.Intent -import android.content.IntentSender -import android.content.pm.IPackageInstaller -import android.content.pm.IPackageInstallerSession -import android.content.pm.PackageInstaller -import android.content.pm.PackageManager -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.os.Process -import androidx.annotation.NonNull -import dev.imranr.obtainium.util.IIntentSenderAdaptor -import dev.imranr.obtainium.util.IntentSenderUtils -import dev.imranr.obtainium.util.PackageInstallerUtils -import dev.imranr.obtainium.util.ShizukuSystemServerApi 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 java.io.IOException -import java.util.concurrent.CountDownLatch -import org.lsposed.hiddenapibypass.HiddenApiBypass -import kotlinx.coroutines.async -import kotlinx.coroutines.GlobalScope -import rikka.shizuku.Shizuku -import rikka.shizuku.Shizuku.OnRequestPermissionResultListener -import rikka.shizuku.ShizukuBinderWrapper -class MainActivity: FlutterActivity() { - private var nativeChannel: MethodChannel? = null - private val SHIZUKU_PERMISSION_REQUEST_CODE = (1000..2000).random() - - private fun shizukuCheckPermission(result: Result) { - try { - if (Shizuku.isPreV11()) { // Unsupported - result.success(-1) - } else if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { - result.success(1) - } else if (Shizuku.shouldShowRequestPermissionRationale()) { // Deny and don't ask again - result.success(0) - } else { - Shizuku.requestPermission(SHIZUKU_PERMISSION_REQUEST_CODE) - result.success(-2) - } - } catch (_: Exception) { // If shizuku binder not found - result.success(-1) - } - } - - private val shizukuRequestPermissionResultListener = OnRequestPermissionResultListener { - requestCode: Int, grantResult: Int -> - if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) { - val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0 - nativeChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res)) - } - } - - private suspend fun shizukuInstallApk(apkFileUri: String, result: Result) { - val uri = Uri.parse(apkFileUri) - var res = false - var session: PackageInstaller.Session? = null - try { - val iPackageInstaller: IPackageInstaller = - ShizukuSystemServerApi.PackageManager_getPackageInstaller() - val isRoot = Shizuku.getUid() == 0 - // The reason for use "com.android.shell" as installer package under adb - // is that getMySessions will check installer package's owner - val installerPackageName = if (isRoot) packageName else "com.android.shell" - var installerAttributionTag: String? = null - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - installerAttributionTag = attributionTag - } - val userId = if (isRoot) Process.myUserHandle().hashCode() else 0 - val packageInstaller = PackageInstallerUtils.createPackageInstaller( - iPackageInstaller, installerPackageName, installerAttributionTag, userId) - val params = - PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) - var installFlags: Int = PackageInstallerUtils.getInstallFlags(params) - installFlags = installFlags or (0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/ - or 0x00000004 /*PackageManager.INSTALL_ALLOW_TEST*/) - PackageInstallerUtils.setInstallFlags(params, installFlags) - val sessionId = packageInstaller.createSession(params) - val iSession = IPackageInstallerSession.Stub.asInterface( - ShizukuBinderWrapper(iPackageInstaller.openSession(sessionId).asBinder())) - session = PackageInstallerUtils.createSession(iSession) - val inputStream = contentResolver.openInputStream(uri) - val openedSession = session.openWrite("apk.apk", 0, -1) - val buffer = ByteArray(8192) - var length: Int - try { - while (inputStream!!.read(buffer).also { length = it } > 0) { - openedSession.write(buffer, 0, length) - openedSession.flush() - session.fsync(openedSession) - } - } finally { - try { - inputStream!!.close() - openedSession.close() - } catch (e: IOException) { - e.printStackTrace() - } - } - val results = arrayOf(null) - val countDownLatch = CountDownLatch(1) - val intentSender: IntentSender = - IntentSenderUtils.newInstance(object : IIntentSenderAdaptor() { - override fun send(intent: Intent?) { - results[0] = intent - countDownLatch.countDown() - } - }) - session.commit(intentSender) - countDownLatch.await() - res = results[0]!!.getIntExtra( - PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE) == 0 - } catch (_: Exception) { - res = false - } finally { - if (session != null) { - try { - session.close() - } catch (_: Exception) { - res = false - } - } - } - result.success(res) - } - - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - super.configureFlutterEngine(flutterEngine) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - HiddenApiBypass.addHiddenApiExemptions("") - } - Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener) - nativeChannel = MethodChannel( - flutterEngine.dartExecutor.binaryMessenger, "native") - nativeChannel!!.setMethodCallHandler { - call, result -> - if (call.method == "checkPermissionShizuku") { - shizukuCheckPermission(result) - } else if (call.method == "installWithShizuku") { - val apkFileUri: String = call.argument("apkFileUri")!! - GlobalScope.async { shizukuInstallApk(apkFileUri, result) } - } - } - } - - override fun onDestroy() { - super.onDestroy() - Shizuku.removeRequestPermissionResultListener(shizukuRequestPermissionResultListener) - } -} +class MainActivity: FlutterActivity() diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/ApplicationUtils.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/ApplicationUtils.java deleted file mode 100644 index 6aa7489..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/ApplicationUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.imranr.obtainium.util; - -import android.annotation.SuppressLint; -import android.app.Application; -import android.os.Build; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class ApplicationUtils { - - private static Application application; - - public static Application getApplication() { - return application; - } - - public static void setApplication(Application application) { - ApplicationUtils.application = application; - } - - public static String getProcessName() { - if (Build.VERSION.SDK_INT >= 28) - return Application.getProcessName(); - else { - try { - @SuppressLint("PrivateApi") - Class activityThread = Class.forName("android.app.ActivityThread"); - @SuppressLint("DiscouragedPrivateApi") - Method method = activityThread.getDeclaredMethod("currentProcessName"); - return (String) method.invoke(null); - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/IIntentSenderAdaptor.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/IIntentSenderAdaptor.java deleted file mode 100644 index 2178c77..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/IIntentSenderAdaptor.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.imranr.obtainium.util; - -import android.content.IIntentReceiver; -import android.content.IIntentSender; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; - -public abstract class IIntentSenderAdaptor extends IIntentSender.Stub { - - public abstract void send(Intent intent); - - @Override - public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - send(intent); - return 0; - } - - @Override - public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - send(intent); - } -} diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/IntentSenderUtils.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/IntentSenderUtils.java deleted file mode 100644 index ab6acba..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/IntentSenderUtils.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.imranr.obtainium.util; - -import android.content.IIntentSender; -import android.content.IntentSender; - -import java.lang.reflect.InvocationTargetException; - -public class IntentSenderUtils { - - public static IntentSender newInstance(IIntentSender binder) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - //noinspection JavaReflectionMemberAccess - return IntentSender.class.getConstructor(IIntentSender.class).newInstance(binder); - } -} diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/PackageInstallerUtils.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/PackageInstallerUtils.java deleted file mode 100644 index 9d5ae14..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/PackageInstallerUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.imranr.obtainium.util; - -import android.content.Context; -import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageInstallerSession; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageManager; -import android.os.Build; - -import java.lang.reflect.InvocationTargetException; - -@SuppressWarnings({"JavaReflectionMemberAccess"}) -public class PackageInstallerUtils { - - public static PackageInstaller createPackageInstaller(IPackageInstaller installer, String installerPackageName, String installerAttributionTag, int userId) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return PackageInstaller.class.getConstructor(IPackageInstaller.class, String.class, String.class, int.class) - .newInstance(installer, installerPackageName, installerAttributionTag, userId); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - return PackageInstaller.class.getConstructor(IPackageInstaller.class, String.class, int.class) - .newInstance(installer, installerPackageName, userId); - } else { - return PackageInstaller.class.getConstructor(Context.class, PackageManager.class, IPackageInstaller.class, String.class, int.class) - .newInstance(ApplicationUtils.getApplication(), ApplicationUtils.getApplication().getPackageManager(), installer, installerPackageName, userId); - } - } - - public static PackageInstaller.Session createSession(IPackageInstallerSession session) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - return PackageInstaller.Session.class.getConstructor(IPackageInstallerSession.class) - .newInstance(session); - - } - - public static int getInstallFlags(PackageInstaller.SessionParams params) throws NoSuchFieldException, IllegalAccessException { - return (int) PackageInstaller.SessionParams.class.getDeclaredField("installFlags").get(params); - } - - public static void setInstallFlags(PackageInstaller.SessionParams params, int newValue) throws NoSuchFieldException, IllegalAccessException { - PackageInstaller.SessionParams.class.getDeclaredField("installFlags").set(params, newValue); - } -} diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/ShizukuSystemServerApi.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/ShizukuSystemServerApi.java deleted file mode 100644 index 6dcdf75..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/ShizukuSystemServerApi.java +++ /dev/null @@ -1,68 +0,0 @@ -package dev.imranr.obtainium.util; - -import android.content.Context; -import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageManager; -import android.content.pm.UserInfo; -import android.os.Build; -import android.os.IUserManager; -import android.os.RemoteException; - -import java.util.List; - -import rikka.shizuku.ShizukuBinderWrapper; -import rikka.shizuku.SystemServiceHelper; - -public class ShizukuSystemServerApi { - - private static final Singleton PACKAGE_MANAGER = new Singleton() { - @Override - protected IPackageManager create() { - return IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package"))); - } - }; - - private static final Singleton USER_MANAGER = new Singleton() { - @Override - protected IUserManager create() { - return IUserManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(Context.USER_SERVICE))); - } - }; - - public static IPackageInstaller PackageManager_getPackageInstaller() throws RemoteException { - IPackageInstaller packageInstaller = PACKAGE_MANAGER.get().getPackageInstaller(); - return IPackageInstaller.Stub.asInterface(new ShizukuBinderWrapper(packageInstaller.asBinder())); - } - - public static List UserManager_getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated) throws RemoteException { - if (Build.VERSION.SDK_INT >= 30) { - return USER_MANAGER.get().getUsers(excludePartial, excludeDying, excludePreCreated); - } else { - try { - return USER_MANAGER.get().getUsers(excludeDying); - } catch (NoSuchFieldError e) { - return USER_MANAGER.get().getUsers(excludePartial, excludeDying, excludePreCreated); - } - } - } - - // method 2: use transactRemote directly - /*public static List UserManager_getUsers(boolean excludeDying) { - Parcel data = SystemServiceHelper.obtainParcel(Context.USER_SERVICE, "android.os.IUserManager", "getUsers"); - Parcel reply = Parcel.obtain(); - data.writeInt(excludeDying ? 1 : 0); - - List res = null; - try { - ShizukuService.transactRemote(data, reply, 0); - reply.readException(); - res = reply.createTypedArrayList(UserInfo.CREATOR); - } catch (RemoteException e) { - Log.e("ShizukuSample", "UserManager#getUsers", e); - } finally { - data.recycle(); - reply.recycle(); - } - return res; - }*/ -} diff --git a/android/app/src/main/kotlin/dev/imranr/obtainium/util/Singleton.java b/android/app/src/main/kotlin/dev/imranr/obtainium/util/Singleton.java deleted file mode 100644 index e535245..0000000 --- a/android/app/src/main/kotlin/dev/imranr/obtainium/util/Singleton.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.imranr.obtainium.util; - -public abstract class Singleton { - - private T mInstance; - - protected abstract T create(); - - public final T get() { - synchronized (this) { - if (mInstance == null) { - mInstance = create(); - } - return mInstance; - } - } -} diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a..f622fd8 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx2048M android.useAndroidX=true android.enableJetifier=true diff --git a/assets/translations/en.json b/assets/translations/en.json index 167fa06..c026b2f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -283,9 +283,11 @@ "selectX": "Select {}", "parallelDownloads": "Allow parallel downloads", "useShizuku": "Use Shizuku or Sui to install", - "shizukuBinderNotFound": "Сompatible Shizuku service wasn't found", + "shizukuBinderNotFound": "Shizuku service not found, probably it's not launched", + "shizukuOld": "Old Shizuku version (<11), update it", + "shizukuOldAndroidWithADB": "Shizuku running on Android < 8.1 with ADB, update Android or use Sui instead", + "shizukuPretendToBeGooglePlay": "Set Google Play as the installation source", "useSystemFont": "Use the system font", - "systemFontError": "Error loading the system font: {}", "useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version", "requestHeader": "Request header", "useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 0dffae4..9b912b0 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -283,9 +283,11 @@ "selectX": "Выбрать {}", "parallelDownloads": "Разрешить параллельные загрузки", "useShizuku": "Использовать Shizuku или Sui для установки", - "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден", + "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден, возможно он не запущен", + "shizukuOld": "Устаревшая версия Shizuku (<11), обновите", + "shizukuOldAndroidWithADB": "Shizuku работает на Android < 8.1 с ADB, обновите Android или используйте Sui", + "shizukuPretendToBeGooglePlay": "Указать Google Play как источник установки", "useSystemFont": "Использовать системный шрифт", - "systemFontError": "Ошибка загрузки системного шрифта: {}", "useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС", "requestHeader": "Заголовок запроса", "useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска", diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index b8e4def..68bad3a 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -12,6 +12,7 @@ import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/source_provider.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:shizuku_apk_installer/shizuku_apk_installer.dart'; import 'package:url_launcher/url_launcher_string.dart'; class SettingsPage extends StatefulWidget { @@ -402,12 +403,17 @@ class _SettingsPageState extends State { value: settingsProvider.useShizuku, onChanged: (useShizuku) { if (useShizuku) { - NativeFeatures.checkPermissionShizuku().then((resCode) { - settingsProvider.useShizuku = resCode == 1; - if (resCode == 0) { - showError(ObtainiumError(tr('cancelled')), context); - } else if (resCode == -1) { - showError(ObtainiumError(tr('shizukuBinderNotFound')), context); + ShizukuApkInstaller.checkPermission().then((resCode) { + settingsProvider.useShizuku = resCode!.startsWith('granted'); + switch(resCode){ + case 'binder_not_found': + showError(ObtainiumError(tr('shizukuBinderNotFound')), context); + case 'old_shizuku': + showError(ObtainiumError(tr('shizukuOld')), context); + case 'old_android_with_adb': + showError(ObtainiumError(tr('shizukuOldAndroidWithADB')), context); + case 'denied': + showError(ObtainiumError(tr('cancelled')), context); } }); } else { @@ -416,6 +422,24 @@ class _SettingsPageState extends State { }) ], ), + if (settingsProvider.useShizuku) + Column( + children: [ + height16, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text(tr('shizukuPretendToBeGooglePlay'))), + Switch( + value: settingsProvider.pretendToBeGooglePlay, + onChanged: (value) { + settingsProvider.pretendToBeGooglePlay = value; + }) + ], + ) + ], + ), height32, Text( tr('sourceSpecific'), @@ -459,25 +483,35 @@ class _SettingsPageState extends State { ), height16, localeDropdown, - height16, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: Text(tr('useSystemFont'))), - Switch( - value: settingsProvider.useSystemFont, - onChanged: (useSystemFont) { - if (useSystemFont) { - NativeFeatures.loadSystemFont() - .then((val) { - settingsProvider.useSystemFont = true; - }); - } else { - settingsProvider.useSystemFont = false; - } - }) - ], - ), + FutureBuilder( + builder: (ctx, val) { + return (val.data?.version.sdkInt ?? 0) >= 34 + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + height16, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible(child: Text(tr('useSystemFont'))), + Switch( + value: settingsProvider.useSystemFont, + onChanged: (useSystemFont) { + if (useSystemFont) { + NativeFeatures.loadSystemFont().then((val) { + settingsProvider.useSystemFont = true; + }); + } else { + settingsProvider.useSystemFont = false; + } + }) + ] + ) + ] + ) + : const SizedBox.shrink(); + }, + future: DeviceInfoPlugin().androidInfo), height16, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index ee8364f..904ac8e 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -34,7 +34,7 @@ import 'package:android_intent_plus/android_intent.dart'; import 'package:flutter_archive/flutter_archive.dart'; import 'package:share_plus/share_plus.dart'; import 'package:shared_storage/shared_storage.dart' as saf; -import 'native_provider.dart'; +import 'package:shizuku_apk_installer/shizuku_apk_installer.dart'; final pm = AndroidPackageManager(); @@ -634,7 +634,7 @@ class AppsProvider with ChangeNotifier { !(await canDowngradeApps())) { throw DowngradeError(); } - if (needsBGWorkaround) { + if (needsBGWorkaround && !settingsProvider.useShizuku) { // The below 'await' will never return if we are in a background process // To work around this, we should assume the install will be successful // So we update the app's installed version first as we will never get to the later code @@ -647,13 +647,10 @@ class AppsProvider with ChangeNotifier { } int? code; if (!settingsProvider.useShizuku) { - code = await AndroidPackageInstaller.installApk( - apkFilePath: file.file.path); + code = await AndroidPackageInstaller.installApk(apkFilePath: file.file.path); } else { - code = (await NativeFeatures.installWithShizuku( - apkFileUri: file.file.uri.toString())) - ? 0 - : 1; + code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(), + settingsProvider.pretendToBeGooglePlay ? "com.android.vending" : ""); } bool installed = false; if (code != null && code != 0 && code != 3) { @@ -828,11 +825,16 @@ class AppsProvider with ChangeNotifier { throw ObtainiumError(tr('cancelled')); } } else { - int code = await NativeFeatures.checkPermissionShizuku(); - if (code == 0) { - throw ObtainiumError(tr('cancelled')); - } else if (code == -1) { - throw ObtainiumError(tr('shizukuBinderNotFound')); + String? code = await ShizukuApkInstaller.checkPermission(); + switch(code!){ + case 'binder_not_found': + throw ObtainiumError(tr('shizukuBinderNotFound')); + case 'old_shizuku': + throw ObtainiumError(tr('shizukuOld')); + case 'old_android_with_adb': + throw ObtainiumError(tr('shizukuOldAndroidWithADB')); + case 'denied': + throw ObtainiumError(tr('cancelled')); } } if (!willBeSilent && context != null && !settingsProvider.useShizuku) { diff --git a/lib/providers/native_provider.dart b/lib/providers/native_provider.dart index 428069f..1b9877a 100644 --- a/lib/providers/native_provider.dart +++ b/lib/providers/native_provider.dart @@ -4,36 +4,13 @@ import 'package:android_system_font/android_system_font.dart'; import 'package:flutter/services.dart'; class NativeFeatures { - static const MethodChannel _channel = MethodChannel('native'); static bool _systemFontLoaded = false; - static bool _callbacksApplied = false; - static int _resPermShizuku = -2; // not set static Future _readFileBytes(String path) async { var bytes = await File(path).readAsBytes(); return ByteData.view(bytes.buffer); } - static Future _handleCalls(MethodCall call) async { - if (call.method == 'resPermShizuku') { - _resPermShizuku = call.arguments['res']; - } - } - - static Future _waitWhile(bool Function() test, - [Duration pollInterval = const Duration(milliseconds: 250)]) { - var completer = Completer(); - check() { - if (test()) { - Timer(pollInterval, check); - } else { - completer.complete(); - } - } - check(); - return completer.future; - } - static Future loadSystemFont() async { if (_systemFontLoaded) return; var fontLoader = FontLoader('SystemFont'); @@ -42,23 +19,4 @@ class NativeFeatures { fontLoader.load(); _systemFontLoaded = true; } - - static Future checkPermissionShizuku() async { - if (!_callbacksApplied) { - _channel.setMethodCallHandler(_handleCalls); - _callbacksApplied = true; - } - int res = await _channel.invokeMethod('checkPermissionShizuku'); - if (res == -2) { - await _waitWhile(() => _resPermShizuku == -2); - res = _resPermShizuku; - _resPermShizuku = -2; - } - return res; - } - - static Future installWithShizuku({required String apkFileUri}) async { - return await _channel.invokeMethod( - 'installWithShizuku', {'apkFileUri': apkFileUri}); - } } diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 5f888ec..b2596b2 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -82,6 +82,15 @@ class SettingsProvider with ChangeNotifier { notifyListeners(); } + bool get pretendToBeGooglePlay{ + return prefs?.getBool('pretendToBeGooglePlay') ?? false; + } + + set pretendToBeGooglePlay(bool pretendToBeGooglePlay) { + prefs?.setBool('pretendToBeGooglePlay', pretendToBeGooglePlay); + notifyListeners(); + } + ThemeSettings get theme { return ThemeSettings .values[prefs?.getInt('theme') ?? ThemeSettings.system.index]; diff --git a/pubspec.lock b/pubspec.lock index 56163f3..5b288dc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: "direct main" description: name: android_intent_plus - sha256: e92d14009f3f6ebafca6a601958aaebb793559fb03a1961fe3c5596db95af2cb + sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.2" android_package_installer: dependency: "direct main" description: @@ -63,10 +63,10 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -135,10 +135,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: e9feae83b1849f61bad9f6f33ee00646e3410d54ce0821e02f262f9901dad3c9 + sha256: ebe15d94de9dd7c31dc2ac54e42780acdf3384b1497c69290c9f3c5b0279fc57 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" connectivity_plus_platform_interface: dependency: transitive description: @@ -199,10 +199,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "50fb435ed30c6d2525cbfaaa0f46851ea6131315f213c0d921b0e407b34e3b84" + sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 url: "https://pub.dev" source: hosted - version: "10.0.1" + version: "10.1.0" device_info_plus_platform_interface: dependency: transitive description: @@ -284,10 +284,10 @@ packages: dependency: "direct main" description: name: flutter_archive - sha256: "004132780d382df5171589ab793e2efc9c3eef570fe72d78b4ccfbfbe52762ae" + sha256: "22e931ef6ef764edc922e425e46f4a4f888e864b976f4ecbe54aea9859abc090" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.0.2" flutter_fgbg: dependency: "direct main" description: @@ -316,10 +316,10 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: f9a05409385b77b06c18f200a41c7c2711ebf7415669350bb0f8474c07bd40d1 + sha256: a701df4866f9a38bb8e4450a54c143bbeeb0ce2381e7df5a36e1006f3b43bb28 url: "https://pub.dev" source: hosted - version: "17.0.0" + version: "17.0.1" flutter_local_notifications_linux: dependency: transitive description: @@ -353,10 +353,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.19" flutter_test: dependency: "direct dev" description: flutter @@ -371,10 +371,10 @@ packages: dependency: "direct main" description: name: fluttertoast - sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1 + sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" url: "https://pub.dev" source: hosted - version: "8.2.4" + version: "8.2.5" gtk: dependency: transitive description: @@ -547,18 +547,18 @@ packages: dependency: "direct main" description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.4" path_provider_foundation: dependency: transitive description: @@ -683,10 +683,10 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "05ec043470319bfbabe0adbc90d3a84cbff0426b9d9f3a6e2ad3e131fa5fa629" + sha256: fb5319f3aab4c5dda5ebb92dca978179ba21f8c783ee4380910ef4c1c6824f51 url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "8.0.3" share_plus_platform_interface: dependency: transitive description: @@ -699,18 +699,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_foundation: dependency: transitive description: @@ -759,6 +759,15 @@ packages: url: "https://pub.dev" source: hosted version: "0.8.1" + shizuku_apk_installer: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: "25acc02612c2e0fcae40d312e047ac48106f8f6b" + url: "https://github.com/re7gog/shizuku_apk_installer" + source: git + version: "0.0.1" sky_engine: dependency: transitive description: flutter @@ -864,18 +873,18 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" + sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" url: "https://pub.dev" source: hosted - version: "6.2.5" + version: "6.2.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_ios: dependency: transitive description: @@ -928,10 +937,10 @@ packages: dependency: transitive description: name: uuid - sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "4.3.3" + version: "4.4.0" vector_math: dependency: transitive description: @@ -1000,10 +1009,10 @@ packages: dependency: transitive description: name: win32_registry - sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" + sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" xdg_directories: dependency: transitive description: @@ -1029,5 +1038,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.3.3 <4.0.0" flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index f9bc3e1..05c3970 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -72,6 +72,10 @@ dependencies: git: url: https://github.com/re7gog/android_system_font ref: master + shizuku_apk_installer: + git: + url: https://github.com/re7gog/shizuku_apk_installer + ref: master dev_dependencies: flutter_test: