我需要以编程方式检查 MIUI 手机中我的应用程序的自动启动权限是打开还是关闭。Facebook 和 whatsapp 已默认启用此权限,我该怎么做?
10 回答
目前是不可能的。
因为它完全取决于他们的操作系统 API 和定制。甚至开发者在小米官方论坛上也提出了这个要求,但那里没有任何回应。
直到现在,即使我找到了这个问题的答案,但没有任何帮助。
暂时只有root手机才有可能。即通过成为超级用户在他们的固件中进行定制。但这一点也不可取,因为它可能会损坏用户的手机。
编辑 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
我最近使用了来自 XIOMI 的 Mi A1,它有股票 android(不是 miui)所以这款手机没有来自 miui 的autostart permission
设置。因此,在将用户导航到此类设备中的设置时要小心,因为它在这里不起作用。
100%为OPPO、vivo、小米、乐视华为、荣耀工作
只需调用此函数
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));
}
}
这无论如何都不是一个完美的解决方案,它需要一些测试,但我已经能够用它检测到我的小米设备上的自动启动权限。
自动启动权限允许通过接收隐式广播意图来启动应用程序。此方法包括使用 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();
}
/* ... */
}
您可能还想停止所有服务以确保安全。
目前是不可能的。因为它完全取决于他们的操作系统 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();
}
}
除了Nikhil 的回答:
首先,Facebook、Whatsapp 等一些应用程序默认被小米列入白名单,这意味着这些应用程序将自动开启自动启动权限。
我也没有找到任何方法来检查自动启动权限是否已启用并以编程方式启用它。尽管如上答案表明我们可以将用户重定向到自动启动权限活动,但是当我们必须重定向用户时,我们仍然不知道,而且这也不适用于所有 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 小时将布尔变量的值设置为默认值一次。
希望这可以帮助。
您无法检查是否启用了自动运行权限,因为自动运行功能仅由自定义操作系统提供,而不是由 mi、vivo、oppo、letv 等 android 操作系统提供
这是在 MI、Honor 和 vivo 手机上测试的解决方法。
要检查os是否像miui一样自定义,请将此方法复制并粘贴到activity、fragment或util类中
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())
}
}
这段代码对我有用。简单易行。信用
private State getAutoStartState(Activity activity) throws Exception {
Class<?> clazz;
try {
clazz = Class.forName(CLAZZ);
} catch (ClassNotFoundException ignored) {
// we don't know if its enabled, class
// is not found, no info
return State.NO_INFO;
}
final Method method = getMethod(clazz);
if (method == null) {
// exception raised while search the method,
// or it doesn't exist
return State.NO_INFO;
}
// the method is a public method, It's still
// better to do this
method.setAccessible(true);
// the target object is null, because the
// method is static
final Object result = method.invoke(null, getActivity(),
getActivity().getPackageName());
// the result should be an Int
if (!(result instanceof Integer))
throw new Exception();
final int _int = (int) result;
if (_int == ENABLED)
return State.ENABLED;
else if (_int == DISABLED)
return State.DISABLED;
return State.UNKNOWN;
}
private Method getMethod(Class<?> clazz) {
try {
return clazz.getDeclaredMethod("getApplicationAutoStart",
Context.class, String.class);
} catch (Exception ignored) {
// this should not happen, probably
// MIUI version is updated, lets give a last try
return null;
}
}
public void checkMIUIAutoStart(Activity activity) throws Exception {
if (getAutoStartState(activity) == State.DISABLED) {
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);
}
}else {
Toast.makeText(activity, "Auto-start is enabled.", Toast.LENGTH_SHORT).show();
}
}
您可以使用此库检查 MIUI 10、11 和 12 上的自动启动权限状态。
https://github.com/XomaDev/MIUI-autostart
// make sure device is MIUI device, else an
// exception will be thrown at initialization
Autostart autostart = new Autostart(applicationContext);
State state = autostart.getAutoStartState();
if (state == State.DISABLED) {
// now we are sure that autostart is disabled
// ask user to enable it manually in the settings app
} else if (state == State.ENABLED) {
// now we are also sure that autostart is enabled
}
要检查是否启用了权限,我只是启动了一个前台服务并检查是否正在运行。
服务:
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;
}
}