web-dev-qa-db-ja.com

MIUIの自動起動許可をプログラムで確認する方法は?

MIUI電話でのアプリの自動起動許可がオンかオフかをプログラムで確認する必要があります。 Facebookとwhatsappでは、この許可がデフォルトですでに有効になっていますが、どうすれば有効にできますか?

29
Ekta Aggarwal

今のところそれは不可能です。

オペレーティングシステムの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);
}

EDIT 2最近XIOMIのMi A1を使用しましたが、在庫はAndroid(miuiではない)なので、この電話にはautostart permission miuiからの設定。そのため、このようなデバイスの設定にユーザーを移動するときは注意してください。ここでは機能しません。

31
Nikhil

oppo、vivo、xiaomi、letv huawei、および名誉のために働く100%

この関数を呼び出すだけです

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

これは決して完璧な解決策ではなく、いくつかのテストが必要ですが、Xiaomiデバイスで自動起動許可を検出できました。

自動起動許可により、暗黙的なブロードキャストインテントを受信することでアプリを起動できます。このメソッドは、AlarmManagerを使用して暗黙的なブロードキャストをスケジュールし、アプリを強制終了して、ブロードキャストによって再スポーンが発生したかどうかを確認することで構成されます。アプリが最終的に起動することを確認するためだけに、2番目の明示的な意図もスケジュールされます。

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は、アクティビティのライフサイクルを追跡するもう1つのユーティリティです。必ず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();
    }

    /* ... */
}

念のため、すべてのサービスを停止することもできます。

4
SpaceBison

Nikhilの答え に加えて:

まず、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));
}

したがって、基本的に、同期アダプターが機能していない場合にバックグラウンドで同じタスクを実行するために別のサービスを実行していますが、最良なのは一度に1つだけ実行することです。ブール変数の値がすでに設定されているため、ユーザーが自動起動許可をオンにして再度オフにすると、上記のコードは失敗します。そのため、ブール変数の値を24時間ごとに1回デフォルトに設定できます。

お役に立てれば。

1
Vipul Kumar