如何以编程方式检查MIUI自动启动权限?

问题描述 投票:26回答:5

我需要以编程方式检查MIUI手机中我的应用程序的自动启动权限是打开还是关闭。 Facebook和whatsapp默认已启用此权限,我该怎么办?

android autostart background-service
5个回答
31
投票

现在,这是不可能的。

因为它完全取决于他们的操作系统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我最近使用了来自XIOMI的Mi A1,它有股票android(不是miui)所以这款手机没有来自miui的autostart permission设置。因此,在将用户导航到此类设备中的设置时要小心,因为它在此处不起作用。


17
投票

100%为oppo,vivo,xiaomi,letv huawei和荣誉工作

只需调用此功能

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));
    }
}

4
投票

这不是一个完美的解决方案,它需要一些测试,但我已经能够检测到我的小米设备上的自动启动权限。

自动启动权限允许通过接收隐式广播意图来启动应用程序。此方法包括使用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();
    }

    /* ... */
}

您可能还想要停止所有服务以确保。


1
投票

除了Nikhil's answer

首先,一些应用程序,如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小时将布尔变量的值设置为默认值一次。

希望这可以帮助。


-3
投票

您必须允许和拒绝系统权限。

以下是代码:

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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.