mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-23 01:29:40 +02:00
Move to plugins🐱🎉
This commit is contained in:
@@ -92,18 +92,6 @@ repositories {
|
|||||||
maven { url 'https://jitpack.io' }
|
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]
|
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
android.applicationVariants.all { variant ->
|
android.applicationVariants.all { variant ->
|
||||||
|
@@ -1,156 +1,5 @@
|
|||||||
package dev.imranr.obtainium
|
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.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() {
|
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<Intent?>(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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<IPackageManager> PACKAGE_MANAGER = new Singleton<IPackageManager>() {
|
|
||||||
@Override
|
|
||||||
protected IPackageManager create() {
|
|
||||||
return IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Singleton<IUserManager> USER_MANAGER = new Singleton<IUserManager>() {
|
|
||||||
@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<UserInfo> 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<UserInfo> 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<UserInfo> 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;
|
|
||||||
}*/
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
package dev.imranr.obtainium.util;
|
|
||||||
|
|
||||||
public abstract class Singleton<T> {
|
|
||||||
|
|
||||||
private T mInstance;
|
|
||||||
|
|
||||||
protected abstract T create();
|
|
||||||
|
|
||||||
public final T get() {
|
|
||||||
synchronized (this) {
|
|
||||||
if (mInstance == null) {
|
|
||||||
mInstance = create();
|
|
||||||
}
|
|
||||||
return mInstance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx2048M
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
@@ -283,9 +283,11 @@
|
|||||||
"selectX": "Select {}",
|
"selectX": "Select {}",
|
||||||
"parallelDownloads": "Allow parallel downloads",
|
"parallelDownloads": "Allow parallel downloads",
|
||||||
"useShizuku": "Use Shizuku or Sui to install",
|
"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",
|
"useSystemFont": "Use the system font",
|
||||||
"systemFontError": "Error loading the system font: {}",
|
|
||||||
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
|
"useVersionCodeAsOSVersion": "Use app versionCode as OS-detected version",
|
||||||
"requestHeader": "Request header",
|
"requestHeader": "Request header",
|
||||||
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
|
"useLatestAssetDateAsReleaseDate": "Use latest asset upload as release date",
|
||||||
|
@@ -283,9 +283,11 @@
|
|||||||
"selectX": "Выбрать {}",
|
"selectX": "Выбрать {}",
|
||||||
"parallelDownloads": "Разрешить параллельные загрузки",
|
"parallelDownloads": "Разрешить параллельные загрузки",
|
||||||
"useShizuku": "Использовать Shizuku или Sui для установки",
|
"useShizuku": "Использовать Shizuku или Sui для установки",
|
||||||
"shizukuBinderNotFound": "Совместимый сервис Shizuku не найден",
|
"shizukuBinderNotFound": "Совместимый сервис Shizuku не найден, возможно он не запущен",
|
||||||
|
"shizukuOld": "Устаревшая версия Shizuku (<11), обновите",
|
||||||
|
"shizukuOldAndroidWithADB": "Shizuku работает на Android < 8.1 с ADB, обновите Android или используйте Sui",
|
||||||
|
"shizukuPretendToBeGooglePlay": "Указать Google Play как источник установки",
|
||||||
"useSystemFont": "Использовать системный шрифт",
|
"useSystemFont": "Использовать системный шрифт",
|
||||||
"systemFontError": "Ошибка загрузки системного шрифта: {}",
|
|
||||||
"useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС",
|
"useVersionCodeAsOSVersion": "Использовать код версии приложения как версию, обнаруженную ОС",
|
||||||
"requestHeader": "Заголовок запроса",
|
"requestHeader": "Заголовок запроса",
|
||||||
"useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска",
|
"useLatestAssetDateAsReleaseDate": "Использовать последнюю загрузку ресурса в качестве даты выпуска",
|
||||||
|
@@ -12,6 +12,7 @@ import 'package:obtainium/providers/settings_provider.dart';
|
|||||||
import 'package:obtainium/providers/source_provider.dart';
|
import 'package:obtainium/providers/source_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:share_plus/share_plus.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';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class SettingsPage extends StatefulWidget {
|
class SettingsPage extends StatefulWidget {
|
||||||
@@ -402,12 +403,17 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
value: settingsProvider.useShizuku,
|
value: settingsProvider.useShizuku,
|
||||||
onChanged: (useShizuku) {
|
onChanged: (useShizuku) {
|
||||||
if (useShizuku) {
|
if (useShizuku) {
|
||||||
NativeFeatures.checkPermissionShizuku().then((resCode) {
|
ShizukuApkInstaller.checkPermission().then((resCode) {
|
||||||
settingsProvider.useShizuku = resCode == 1;
|
settingsProvider.useShizuku = resCode!.startsWith('granted');
|
||||||
if (resCode == 0) {
|
switch(resCode){
|
||||||
showError(ObtainiumError(tr('cancelled')), context);
|
case 'binder_not_found':
|
||||||
} else if (resCode == -1) {
|
showError(ObtainiumError(tr('shizukuBinderNotFound')), context);
|
||||||
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 {
|
} else {
|
||||||
@@ -416,6 +422,24 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
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,
|
height32,
|
||||||
Text(
|
Text(
|
||||||
tr('sourceSpecific'),
|
tr('sourceSpecific'),
|
||||||
@@ -459,25 +483,35 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
),
|
),
|
||||||
height16,
|
height16,
|
||||||
localeDropdown,
|
localeDropdown,
|
||||||
height16,
|
FutureBuilder(
|
||||||
Row(
|
builder: (ctx, val) {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
return (val.data?.version.sdkInt ?? 0) >= 34
|
||||||
children: [
|
? Column(
|
||||||
Flexible(child: Text(tr('useSystemFont'))),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Switch(
|
children: [
|
||||||
value: settingsProvider.useSystemFont,
|
height16,
|
||||||
onChanged: (useSystemFont) {
|
Row(
|
||||||
if (useSystemFont) {
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
NativeFeatures.loadSystemFont()
|
children: [
|
||||||
.then((val) {
|
Flexible(child: Text(tr('useSystemFont'))),
|
||||||
settingsProvider.useSystemFont = true;
|
Switch(
|
||||||
});
|
value: settingsProvider.useSystemFont,
|
||||||
} else {
|
onChanged: (useSystemFont) {
|
||||||
settingsProvider.useSystemFont = false;
|
if (useSystemFont) {
|
||||||
}
|
NativeFeatures.loadSystemFont().then((val) {
|
||||||
})
|
settingsProvider.useSystemFont = true;
|
||||||
],
|
});
|
||||||
),
|
} else {
|
||||||
|
settingsProvider.useSystemFont = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
future: DeviceInfoPlugin().androidInfo),
|
||||||
height16,
|
height16,
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@@ -34,7 +34,7 @@ import 'package:android_intent_plus/android_intent.dart';
|
|||||||
import 'package:flutter_archive/flutter_archive.dart';
|
import 'package:flutter_archive/flutter_archive.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:shared_storage/shared_storage.dart' as saf;
|
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();
|
final pm = AndroidPackageManager();
|
||||||
|
|
||||||
@@ -634,7 +634,7 @@ class AppsProvider with ChangeNotifier {
|
|||||||
!(await canDowngradeApps())) {
|
!(await canDowngradeApps())) {
|
||||||
throw DowngradeError();
|
throw DowngradeError();
|
||||||
}
|
}
|
||||||
if (needsBGWorkaround) {
|
if (needsBGWorkaround && !settingsProvider.useShizuku) {
|
||||||
// The below 'await' will never return if we are in a background process
|
// 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
|
// 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
|
// 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;
|
int? code;
|
||||||
if (!settingsProvider.useShizuku) {
|
if (!settingsProvider.useShizuku) {
|
||||||
code = await AndroidPackageInstaller.installApk(
|
code = await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
|
||||||
apkFilePath: file.file.path);
|
|
||||||
} else {
|
} else {
|
||||||
code = (await NativeFeatures.installWithShizuku(
|
code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(),
|
||||||
apkFileUri: file.file.uri.toString()))
|
settingsProvider.pretendToBeGooglePlay ? "com.android.vending" : "");
|
||||||
? 0
|
|
||||||
: 1;
|
|
||||||
}
|
}
|
||||||
bool installed = false;
|
bool installed = false;
|
||||||
if (code != null && code != 0 && code != 3) {
|
if (code != null && code != 0 && code != 3) {
|
||||||
@@ -828,11 +825,16 @@ class AppsProvider with ChangeNotifier {
|
|||||||
throw ObtainiumError(tr('cancelled'));
|
throw ObtainiumError(tr('cancelled'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int code = await NativeFeatures.checkPermissionShizuku();
|
String? code = await ShizukuApkInstaller.checkPermission();
|
||||||
if (code == 0) {
|
switch(code!){
|
||||||
throw ObtainiumError(tr('cancelled'));
|
case 'binder_not_found':
|
||||||
} else if (code == -1) {
|
throw ObtainiumError(tr('shizukuBinderNotFound'));
|
||||||
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) {
|
if (!willBeSilent && context != null && !settingsProvider.useShizuku) {
|
||||||
|
@@ -4,36 +4,13 @@ import 'package:android_system_font/android_system_font.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class NativeFeatures {
|
class NativeFeatures {
|
||||||
static const MethodChannel _channel = MethodChannel('native');
|
|
||||||
static bool _systemFontLoaded = false;
|
static bool _systemFontLoaded = false;
|
||||||
static bool _callbacksApplied = false;
|
|
||||||
static int _resPermShizuku = -2; // not set
|
|
||||||
|
|
||||||
static Future<ByteData> _readFileBytes(String path) async {
|
static Future<ByteData> _readFileBytes(String path) async {
|
||||||
var bytes = await File(path).readAsBytes();
|
var bytes = await File(path).readAsBytes();
|
||||||
return ByteData.view(bytes.buffer);
|
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 {
|
static Future loadSystemFont() async {
|
||||||
if (_systemFontLoaded) return;
|
if (_systemFontLoaded) return;
|
||||||
var fontLoader = FontLoader('SystemFont');
|
var fontLoader = FontLoader('SystemFont');
|
||||||
@@ -42,23 +19,4 @@ class NativeFeatures {
|
|||||||
fontLoader.load();
|
fontLoader.load();
|
||||||
_systemFontLoaded = true;
|
_systemFontLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<int> 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<bool> installWithShizuku({required String apkFileUri}) async {
|
|
||||||
return await _channel.invokeMethod(
|
|
||||||
'installWithShizuku', {'apkFileUri': apkFileUri});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -82,6 +82,15 @@ class SettingsProvider with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get pretendToBeGooglePlay{
|
||||||
|
return prefs?.getBool('pretendToBeGooglePlay') ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set pretendToBeGooglePlay(bool pretendToBeGooglePlay) {
|
||||||
|
prefs?.setBool('pretendToBeGooglePlay', pretendToBeGooglePlay);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
ThemeSettings get theme {
|
ThemeSettings get theme {
|
||||||
return ThemeSettings
|
return ThemeSettings
|
||||||
.values[prefs?.getInt('theme') ?? ThemeSettings.system.index];
|
.values[prefs?.getInt('theme') ?? ThemeSettings.system.index];
|
||||||
|
79
pubspec.lock
79
pubspec.lock
@@ -5,10 +5,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: android_intent_plus
|
name: android_intent_plus
|
||||||
sha256: e92d14009f3f6ebafca6a601958aaebb793559fb03a1961fe3c5596db95af2cb
|
sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.1"
|
version: "5.0.2"
|
||||||
android_package_installer:
|
android_package_installer:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -63,10 +63,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.5.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -135,10 +135,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus
|
name: connectivity_plus
|
||||||
sha256: e9feae83b1849f61bad9f6f33ee00646e3410d54ce0821e02f262f9901dad3c9
|
sha256: ebe15d94de9dd7c31dc2ac54e42780acdf3384b1497c69290c9f3c5b0279fc57
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "6.0.2"
|
||||||
connectivity_plus_platform_interface:
|
connectivity_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -199,10 +199,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
sha256: "50fb435ed30c6d2525cbfaaa0f46851ea6131315f213c0d921b0e407b34e3b84"
|
sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.1"
|
version: "10.1.0"
|
||||||
device_info_plus_platform_interface:
|
device_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -284,10 +284,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_archive
|
name: flutter_archive
|
||||||
sha256: "004132780d382df5171589ab793e2efc9c3eef570fe72d78b4ccfbfbe52762ae"
|
sha256: "22e931ef6ef764edc922e425e46f4a4f888e864b976f4ecbe54aea9859abc090"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.0"
|
version: "6.0.2"
|
||||||
flutter_fgbg:
|
flutter_fgbg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -316,10 +316,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_local_notifications
|
name: flutter_local_notifications
|
||||||
sha256: f9a05409385b77b06c18f200a41c7c2711ebf7415669350bb0f8474c07bd40d1
|
sha256: a701df4866f9a38bb8e4450a54c143bbeeb0ce2381e7df5a36e1006f3b43bb28
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "17.0.0"
|
version: "17.0.1"
|
||||||
flutter_local_notifications_linux:
|
flutter_local_notifications_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -353,10 +353,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.17"
|
version: "2.0.19"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -371,10 +371,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: fluttertoast
|
name: fluttertoast
|
||||||
sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1
|
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.2.4"
|
version: "8.2.5"
|
||||||
gtk:
|
gtk:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -547,18 +547,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.4"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -683,10 +683,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: share_plus
|
name: share_plus
|
||||||
sha256: "05ec043470319bfbabe0adbc90d3a84cbff0426b9d9f3a6e2ad3e131fa5fa629"
|
sha256: fb5319f3aab4c5dda5ebb92dca978179ba21f8c783ee4380910ef4c1c6824f51
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.2"
|
version: "8.0.3"
|
||||||
share_plus_platform_interface:
|
share_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -699,18 +699,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.3"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.2"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -759,6 +759,15 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.1"
|
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:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -864,18 +873,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
|
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.5"
|
version: "6.2.6"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
|
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.3.1"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -928,10 +937,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8
|
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.3"
|
version: "4.4.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1000,10 +1009,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
|
sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1029,5 +1038,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.3 <4.0.0"
|
||||||
flutter: ">=3.19.0"
|
flutter: ">=3.19.0"
|
||||||
|
@@ -72,6 +72,10 @@ dependencies:
|
|||||||
git:
|
git:
|
||||||
url: https://github.com/re7gog/android_system_font
|
url: https://github.com/re7gog/android_system_font
|
||||||
ref: master
|
ref: master
|
||||||
|
shizuku_apk_installer:
|
||||||
|
git:
|
||||||
|
url: https://github.com/re7gog/shizuku_apk_installer
|
||||||
|
ref: master
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user