Мне нужно программно проверить, включено или выключено разрешение на автоматический запуск моего приложения в телефоне MIUI. У Facebook и WhatsApp это разрешение уже включено по умолчанию, как я могу это сделать?
Как программно проверить разрешение автозапуска MIUI?
Ответы (8)
Пока это невозможно.
Поскольку это полностью зависит от их API операционной системы и настроек. Даже разработчики просили об этом на официальных форумах XIOMI, но ответа оттуда нет.
До сих пор даже нахожу ответ на этот вопрос, но мне ничего не помогло.
Пока это возможно только для телефонов с рутированным доступом. т.е. внесение изменений в свою прошивку, став суперпользователем. Но это совсем не рекомендуется, так как это может повредить телефон пользователя.
ИЗМЕНИТЬ 1
Вы можете перенаправить пользователя на страницу настроек разрешения автозапуска для включения вашего приложения, используя следующий код
String manufacturer = "xiaomi";
if (manufacturer.equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
//this will open auto start screen where user can enable permission for your app
Intent intent1 = new Intent();
intent1.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent1);
}
РЕДАКТИРОВАТЬ 2. Недавно я использовал Mi A1 от XIOMI, на котором установлен стандартный android (не miui), поэтому этот телефон не имеет autostart permission
настроек от miui. Так что будьте осторожны при переходе пользователя к настройкам на таких устройствах, потому что здесь это не будет работать.
100% работает для oppo, vivo, xiomi, letv huawei и honor
просто вызовите эту функцию
private void addAutoStartup() {
try {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
} else if ("oppo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
} else if ("vivo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
} else if ("Letv".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity"));
} else if ("Honor".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
}
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
startActivity(intent);
}
} catch (Exception e) {
Log.e("exc" , String.valueOf(e));
}
}
Это ни в коем случае не идеальное решение и требует некоторого тестирования, но с его помощью я смог определить разрешение автозапуска на моем устройстве Xiaomi.
Разрешение автозапуска позволяет запускать приложения, получая неявное широковещательное намерение. Этот метод состоит из планирования неявной трансляции с помощью AlarmManager, завершения работы приложения и проверки того, вызвало ли трансляция его повторное появление. Второе явное намерение также запланировано, чтобы убедиться, что приложение в конечном итоге запустится.
public class AutostartDetector extends BroadcastReceiver {
// I've omitted all the constant declaration to keep this snippet concise
// they should match the values used in the Manifest
public static void testAutoStart(Context context) {
long now = System.currentTimeMillis();
// this ID is for matching the implicit and explicit intents
// it might be unnecessary
String testId = Long.toHexString(now);
Intent implicitIntent = new Intent(ACTION_IMPLICIT_BROADCAST);
// the category is set just to make sure that no other receivers handle the broadcast
implicitIntent.addCategory(CATEGORY_AUTOSTART);
implicitIntent.putExtra(EXTRA_TEST_ID, testId);
PendingIntent implicitPendingIntent =
PendingIntent.getBroadcast(context, REQUEST_CODE_IMPLICIT_BROADCAST, implicitIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent explicitIntent = new Intent(ACTION_EXPLICIT_BROADCAST);
explicitIntent.addCategory(CATEGORY_AUTOSTART);
explicitIntent.setComponent(new ComponentName(context, AutostartDetector.class));
explicitIntent.putExtra(EXTRA_TEST_ID, testId);
PendingIntent explicitPendingIntent =
PendingIntent.getBroadcast(context, REQUEST_CODE_EXPLICIT_BROADCAST, explicitIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// calling commit() makes sure that the data is written before we kill the app
// again, this might be unnecessary
getSharedPreferences(context).edit().putInt(testId, TestStatus.STARTED).commit();
// the explicit intent is set with an additional delay to let the implicit one be received first; might require some fine tuning
alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY, implicitPendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY + EXPLICIT_INTENT_DELAY, explicitPendingIntent);
// kill the app - actually kind of tricky, see below
SelfKiller.killSelf(context);
}
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = getSharedPreferences(context);
String testId = intent.getStringExtra(EXTRA_TEST_ID);
if (testId == null) {
Log.w(TAG, "Null test ID");
return;
}
if (!sharedPreferences.contains(testId)) {
Log.w(TAG, "Unknown test ID: " + testId);
return;
}
String action = intent.getAction();
if (ACTION_IMPLICIT_BROADCAST.equals(action)) {
// we could assume right here that the autostart permission has been granted,
// but we should receive the explicit intent anyway, so let's use it
// as a test sanity check
Log.v(TAG, "Received implicit broadcast");
sharedPreferences.edit().putInt(testId, TestStatus.IMPLICIT_INTENT_RECEIVED).apply();
} else if (ACTION_EXPLICIT_BROADCAST.equals(action)) {
Log.v(TAG, "Received explicit broadcast");
int testStatus = sharedPreferences.getInt(testId, -1);
switch (testStatus) {
case TestStatus.STARTED:
// the implicit broadcast has NOT been received - autostart permission denied
Log.d(TAG, "Autostart disabled");
sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, false).apply();
notifyListener(false);
break;
case TestStatus.IMPLICIT_INTENT_RECEIVED:
// the implicit broadcast has been received - autostart permission granted
Log.d(TAG, "Autostart enabled");
sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, true).apply();
notifyListener(true);
break;
default:
Log.w(TAG, "Invalid test status: " + testId + ' ' + testStatus);
break;
}
}
}
private interface TestStatus {
int STARTED = 1;
int IMPLICIT_INTENT_RECEIVED = 2;
}
Объявление получателя в манифесте:
<receiver android:name=".autostart.AutostartDetector">
<intent-filter>
<category android:name="com.example.autostart.CATEGORY_AUTOSTART"/>
<action android:name="com.example.autostart.ACTION_IMPLICIT_BROADCAST"/>
<action android:name="com.example.autostart.ACTION_EXPLICIT_BROADCAST"/>
</intent-filter>
</receiver>
Еще одна проблема - надежное завершение работы приложения. Я использовал этот вспомогательный метод:
public static void killSelf(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(context.getPackageName());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// this is all we can do before ICS. luckily Xiaomi phones have newer system versions :)
System.exit(1);
return;
}
// set up a callback so System.exit() is called as soon as all
// the activities are finished
context.registerComponentCallbacks(new ComponentCallbacks2() {
@Override
public void onTrimMemory(int i) {
if (i == TRIM_MEMORY_UI_HIDDEN) {
Log.v(TAG, "UI Hidden");
System.exit(1);
}
}
/* ... */
});
// see below
ActivityTracker.getInstance().finishAllActivities();
}
ActivityTracker - еще одна утилита, отслеживающая жизненные циклы активности. Обязательно зарегистрируйте его в подклассе Application.
@RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public final class ActivityTracker implements Application.ActivityLifecycleCallbacks {
private final ArraySet<Activity> mCreatedActivities = new ArraySet<>();
public static ActivityTracker getInstance() {
return Holder.INSTANCE;
}
public static void init(Application application) {
application.registerActivityLifecycleCallbacks(getInstance());
}
public static void release(Application application) {
ActivityTracker activityTracker = getInstance();
application.unregisterActivityLifecycleCallbacks(activityTracker);
activityTracker.mCreatedActivities.clear();
}
public void finishAllActivities() {
// iterate over active activities and finish them all
for (Activity activity : mCreatedActivities) {
Log.v(TAG, "Finishing " + activity);
activity.finish();
}
}
public Set<Activity> getCreatedActivities() {
return Collections.unmodifiableSet(mCreatedActivities);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mCreatedActivities.add(activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
mCreatedActivities.remove(activity);
}
private static final class Holder {
private static final ActivityTracker INSTANCE = new ActivityTracker();
}
/* ... */
}
Вы также можете остановить все службы на всякий случай.
В дополнение к ответу Никхила:
Прежде всего, некоторые приложения, такие как Facebook, Whatsapp, по умолчанию занесены в белый список Xiomi, что означает, что для этих приложений автоматически будет включено разрешение на автоматический запуск.
Я также не нашел способа проверить разрешение на автоматический запуск, включено оно или нет, и включить его программно. Хотя, как указано выше, мы можем перенаправить пользователя на автоматический запуск разрешений, но когда нам нужно перенаправить пользователя, мы все еще не знаем, и это не будет работать на всех устройствах Xiomi.
Поэтому я использовал альтернативу для работы моего адаптера синхронизации. Я сохранил логическую переменную с именем isSyncAdapterRunning в общих настройках и устанавливал ее значение при каждом запуске адаптера синхронизации. Таким образом я смогу узнать, работает ли мой адаптер синхронизации или нет.
//in my sync adapter
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.e("TAG", "SyncStarted");
performSync(true);
}
public static void performSync(boolean fromSyncAdapterClass){
//write your code for sync operation
if(fromSyncAdapterClass){
setValueOfIsSyncAdapterRunningVariable();
}
}
Я сделал другую фоновую службу для выполнения той же задачи, если адаптер синхронизации не работает.
//In my other background service
public class BackgroundSyncService extends IntentService {
public BackgroundSyncService() {
super("BackgroundSyncService");
}
@Override
protected void onHandleIntent(Intent intent) {
SyncAdapter.performSync(false);
}
}
Теперь запустим адаптер синхронизации:
// start your sync adapter here
//And after that just start that service with a condition
if(!getValueOfIsSyncAdapterRunningVariable()){
startService(new Intent(context, BackgroundSyncService.class));
}
Так что в основном я запускаю другую службу для выполнения той же задачи в фоновом режиме, если мой адаптер синхронизации не работает, и лучше всего то, что только один из них будет работать за раз. Приведенный выше код завершится ошибкой, если пользователь включит разрешение на автоматический запуск и снова выключится, поскольку значение логической переменной уже установлено. Для этого вы можете установить значение логической переменной по умолчанию один раз в 24 часа.
Надеюсь это поможет.
Пока это невозможно. Поскольку это полностью зависит от их API операционной системы и настроек. Но я реализовал исправление с помощью SharedPreference. Это не решает проблему, но не позволяет приложению открывать экран настроек при каждом открытии приложения. Пример :
if (AppPref.getAutoStart(context).isEmpty() && AppPref.getAutoStart(context).equals("")) {
enableAutoStart();
}
private void enableAutoStart() {
if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
new AlertDialog.Builder(context)
.setTitle("Enable AutoStart")
.setMessage("Please allow this app to always run in the background,else our services can't be accessed.")
.setNegativeButton("Deny", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
AppPref.setAutoStart(context, "");
dialog.dismiss();
}
})
.setPositiveButton("ALLOW", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
AppPref.setAutoStart(context, "1");
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, "Can't perform action", Toast.LENGTH_SHORT).show();
}
dialog.dismiss();
}
})
.create()
.show();
}
}
Вы не можете проверить, включено ли разрешение автозапуска или нет, потому что функция автозапуска предоставляется только настраиваемой ОС, а не ОС Android, такой как mi, vivo, oppo, letv и т. Д.
Это обходной путь протестирован на телефонах MI, Honor и vivo.
Чтобы проверить, настроена ли ОС как miui, скопируйте и вставьте этот метод в класс активности, фрагмента или утилиты.
public static void getAutoStartPermission(final Activity context) {
final String build_info = Build.BRAND.toLowerCase();
switch (build_info) {
case "xiaomi":
Utilities.Companion.showAutorunDialog(context);
break;
case "letv":
Utilities.Companion.showAutorunDialog(context);
break;
case "oppo":
Utilities.Companion.showAutorunDialog(context);
break;
case "vivo":
Utilities.Companion.showAutorunDialog(context);
break;
case "Honor":
Utilities.Companion.showAutorunDialog(context);
break;
default:
break;
}
}
Где
fun showAutorunDialog(context: Context) {
val builder = AlertDialog.Builder(context)
//set title for alert dialog
builder.setTitle("Alert")
//set message for alert dialog
builder.setMessage("Enable Autostart permission for this app if its disabled in app settings in order to run application in background.")
builder.setCancelable(true)
//performing positive action
builder.setPositiveButton("Enable") { _, _ ->
addAutoStartup(context)
}
// Create the AlertDialog
var vpnDialog = builder.create()
// Set other dialog properties
vpnDialog!!.setCancelable(false)
vpnDialog!!.show()
}
private fun addAutoStartup(context:Context) {
try {
val intent = Intent()
val manufacturer = Build.MANUFACTURER
if ("xiaomi".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")
} else if ("oppo".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")
} else if ("vivo".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")
} else if ("Letv".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")
} else if ("Honor".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")
}
val list: List<ResolveInfo> = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
if (list.size > 0) {
context.startActivity(intent)
}
} catch (e: java.lang.Exception) {
Log.e("exc", e.toString())
}
}
Чтобы проверить, включено ли разрешение, я просто запускаю службу переднего плана и проверяю, работает ли она.
Услуга:
class ExtraPermissionStateService: Service() {
companion object {
private var instance: ExtraPermissionStateService? = null
fun isAppCanRunOnBackground(context: Context): Boolean {
val serviceIntent = Intent(context, ExtraPermissionStateService::class.java)
context.startService(serviceIntent)
return instance != null
}
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
instance = this
}
override fun onDestroy() {
super.onDestroy()
instance = null
}
}
назови это:
ExtraPermissionStateService.isAppCanRunOnBackground(context)
И не забудьте в манифесте:
<service android:name=".helpers.utils.ExtraPermissionStateService"/>
Вы должны разрешить и запретить системные разрешения.
ниже код:
private boolean checkPermission(){
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
if (result == PackageManager.PERMISSION_GRANTED){
return true;
} else {
return false;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Snackbar.make(view,"Permission Granted, Now you can access location data.",Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(view,"Permission Denied, You cannot access location data.",Snackbar.LENGTH_LONG).show();
}
break;
}
}