安卓 - 如何在小米设备上通过编程启用自启动选项?

15

我正在开发一款Android应用程序,想要显示推送通知。

在大多数设备上都能正常显示,除了小米手机(我正在使用的是红米Note 4)。我发现问题出在小米提供的“自启动”选项被默认禁用了,用户需要手动启用它。

但我想知道为什么有些安卓应用程序可以在没有任何用户交互的情况下启用这个选项,比如WhatsApp。如果我尝试重新安装WhatsApp并查看自启动选项,它是已启用的!

我无法说服我们的客户,告诉他这是小米等设备的功能,因为他指出有一些像我提到的例子那样正常工作的应用程序。

其他人也问过这个问题:

如何以编程方式将我的应用程序添加到Android的自启动应用程序列表中

如何检查小米制造商的移动设备上是否为我们的应用启用了AutoStart (自启动)

但我没有看到任何答案,并希望在这里发布,希望有人能回答这个问题。


有任何解决方案吗?请提供。 - Royz
5个回答

7
如果小米操作系统允许,从Play商店下载应用程序时,自动启动功能将自动启用,因为像Amazon、Google IO等应用程序也不允许自启动。在这种情况下,您需要进入安全权限-> 自启动 -> 然后从那里启用自启动。您无法通过代码使应用程序自启动,您只能显示对话框以启用自动启动并带用户进入自启动活动,但这不是一个好的选择,因为您无法检查自启动是否已启用。 小米在MIUI8中完成了此项工作,旨在节省电池。此问题浪费了我2天 XD
您可以参考这篇文章

谢谢您的回复。但是这并没有解决我的问题 :-(。我已经尝试从Play商店安装我的应用程序,但仍然面临相同的问题。 - Rakesh L
也许你没有卸载手机中已安装的应用程序的先前版本,这就是为什么。因为我曾经遇到过同样的问题,尝试了很多方法都不起作用,但当我从Play商店下载了相同的应用程序时,它为我解决了问题。 - Rohit Sharma
你使用了哪些依赖项来实现Firebase推送通知? - Rohit Sharma
你应该使用 compile 'com.google.firebase:firebase-core:11.8.0',然后尝试。 - Rohit Sharma
我会尝试这个,但是这个依赖在小米设备上具体做什么? - Rakesh L
显示剩余6条评论

6
让小米、OPPO、vivo等设备以编程方式启用Autostart选项
String manufacturer = android.os.Build.MANUFACTURER;
try {
      Intent intent = new Intent();
      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) {
      e.printStackTrace();
}

1
如果("meizu".equals(manufacturer, ignoreCase = true)) { intent = Intent("com.meizu.safe.security.SHOW_APPSEC") intent.addCategory(Intent.CATEGORY_DEFAULT) intent.putExtra("packageName", BuildConfig.APPLICATION_ID) } - ibad ur rahman
请在魅族设备上测试一下。我没有魅族设备。如果有人需要的话。 - ibad ur rahman

4

我知道现在分享答案有点晚了,但我还是想加入我的两分钱,因为这非常非常重要。我浪费了2天时间来解决这个问题。我尝试了这里提供的所有建议解决方案,但似乎没有任何东西能够工作。以下是我按照以下步骤实施的解决方案:

步骤#01 像您所做的那样创建前台服务,并在清单中相应地注册它。为了演示目的,我分享了服务的示例。

class MyService : Service() {

private var wakeLock: PowerManager.WakeLock? = null

override fun onBind(intent: Intent): IBinder? {
    Log.d(tag!!, "Some component want to bind with the service")
    // We don't provide binding, so return null
    return null
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    Log.d(tag!!, "onStartCommand executed with startId: $startId")
    // by returning this we make sure the service is restarted if the system kills the service
    return START_STICKY
}

override fun onCreate() {
    super.onCreate()
    Log.d(tag!!, "The service has been created".toUpperCase(Locale.ROOT))
    startForeground(1, NotificationUtils.createNotification(this))
    acquireLock()
}

override fun onDestroy() {
    super.onDestroy()
    Log.d(tag!!, "The service has been destroyed".toUpperCase(Locale.ROOT))
    Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show()
}

override fun onTaskRemoved(rootIntent: Intent?) {
    Log.d(tag!!, "onTaskRemoved")
    val restartServiceIntent = Intent(applicationContext, this.javaClass)
    restartServiceIntent.setPackage(packageName)
    val restartServicePendingIntent = PendingIntent.getService(applicationContext, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT)
    val alarmService = applicationContext.getSystemService(ALARM_SERVICE) as AlarmManager
    alarmService[AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000] = restartServicePendingIntent
    super.onTaskRemoved(rootIntent)
}

@SuppressLint("WakelockTimeout")
private fun acquireLock() {
    // we need this lock so our service gets not affected by Doze Mode
    wakeLock =
            (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
                newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyService::lock").apply {
                    acquire()
                }
            }
}

注意:我已经涵盖了所有可能出现的情况,以便在操作系统杀死服务时重新启动服务。但如果用户重启手机,则需要另外处理,可以通过其他stackoverflow答案轻松找到此用例。在广播中,只需启动服务即可。

步骤 #02 创建一个应用程序并在清单中注册。然后在您的应用程序类中添加以下代码行。

class MyApplication : Application() {

override fun onCreate() {
    super.onCreate()
    val receiver = ComponentName(this, MyService::class.java)
    val pm = packageManager

    pm.setComponentEnabledSetting(
        receiver,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP
    )
     }
}

这里,MyService 是组件名称,它可以是你的应用程序中已经在使用的服务或广播接收器。在我的案例中,我使用了Android服务。

现在,是时候在清单文件中注册这个应用程序类了。打开清单文件,在application标签中使用属性name,并放置你刚创建的应用程序类名MyApplication

第三步 没有第三步。完成了。你只需要安装apk,这样即使应用程序被杀死,服务也不会停止运行。我在Vivo设备上测试了以上解决方案,它可以正常工作。

注意:如果以上解决方案不起作用,请检查清单文件中的allowBackup属性,如果在清单文件中找到此属性,请将其删除,然后卸载应用程序并重新安装应用程序,它一定会起作用,然后你可以再设置该属性。


很好的方法。但我有小米设备。如果我从最近使用的应用程序中清除应用,它将清除堆栈中的所有数据,然后服务就不会自动启动。如何重新启动服务? - Mustufa Ansari

4

许多知名的应用程序在内存清理周期中没有被关闭(许多知名的OEM厂商对原版ROM进行了电池/内存优化),因为它们被这些制造商列入“白名单”。

对于您的应用程序,您可以手动将其加入白名单(通过相应设备的“设置”)或通过重定向用户到相应的设置页面来编程方式加入白名单。编程方式可以采用以下方法:

  1. Add below permissions in the App's manifest file:`

    <uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/> 
    <uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>`
    
  2. Redirect your to the Auto Start setting:

    if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
                    Intent intent = new Intent();
                    intent.setComponent(new 
    
    ComponentName("com.miui.securitycenter",
                                "com.miui.permcenter.autostart.AutoStartManagementActivity"));
                        startActivity(intent);
                } else if (Build.MANUFACTURER.equalsIgnoreCase("oppo")) {
                    try {
                        Intent intent = new Intent();
                        intent.setClassName("com.coloros.safecenter",
                                "com.coloros.safecenter.permission.startup.StartupAppListActivity");
                        startActivity(intent);
                    } catch (Exception e) {
                        try {
                            Intent intent = new Intent();
                            intent.setClassName("com.oppo.safe",
                                    "com.oppo.safe.permission.startup.StartupAppListActivity");
                            startActivity(intent);
                        } catch (Exception ex) {
                            try {
                                Intent intent = new Intent();
                                intent.setClassName("com.coloros.safecenter",
                                        "com.coloros.safecenter.startupapp.StartupAppListActivity");
                                startActivity(intent);
                            } catch (Exception exx) {
    
                            }
                        }
                    }
                }
    

其他OEM的AutoStart参考

我已经测试了这种方法并且可行,但可靠性仍然是一个问题,因为系统需要时间(在PoccoF1和小米设备上大约需要2分钟)来重新启动被杀死的服务。

但作为用户,我们可以防止应用的后台服务全部被杀死,具体如下:

  1. 按下最近使用的应用程序物理键(左侧按钮)。
  2. 将应用程序向下拖动一次(选择,按住并向下滑动),点击锁定图标(如果锁定处于打开状态)以锁定应用程序。
  3. 应用程序将处于锁定状态(即使您通过清除背景应用程序进程来清除,该应用程序仍将继续运行)。
  4. 同样地,如果您想要将其从锁定状态中删除,只需再次向下拖动一次,锁定符号将消失(清除后台进程将清除应用程序的运行)。

但是,使用此方式,大多数设备在重新启动时会重置应用程序的锁定状态。

编辑: 在观察前台服务的行为(在小米的RedmiS3,Android V6.0上)之后,以下是分析结果:

  1. 即使通过用户干预(如上所述)启用了“AutoStart”,服务也不总是重新启动(服务仅在少数情况下重新启动,但大多数时间没有)。
    此外,如果我在设备设置中搜索“AutoStart”,我看不到我的应用程序在AutoStart列表中。似乎上述方法仅提供Autostart权限而不启用它,未确定! 如果我通过设备设置将我的应用程序添加到“AutoStart”列表中,则我的服务将重新启动(尽管需要一些时间)。

  2. 在onTaskRemoved()回调中重新启动被杀死的服务可能是另一种选择,但是当服务被杀死时,该回调以出人意料的方式被调用。仅当通过返回键按下关闭应用程序时,此回调才会执行。如果我们最小化应用程序(暂停状态),则此回调永远不会在服务被杀死时调用。(正在寻找原因)

最近我发现另一种方式,被杀死的服务可以通过GCM通知事件重新启动。我怀疑GCM是否适用于设备上杀死应用程序的情况(我需要检查并验证行为)。但有一件事是肯定的:“这些OEM让程序员的生活变得很糟糕!”。


其他OEM链接的参考无法使用。 - Ahmad

2
据我所知,WhatsApp已被列入小米设备的自启白名单中,您无法改变这一点。当然,如果您的应用程序最终获得了与WhatsApp相同的流行度,小米也会将其列入白名单。在那之前,您只能要求用户通过类似以下方式显示自启功能并手动激活它:
try {
  Intent intent = new Intent();
  if ("xiaomi".equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
    intent.setComponent(new ComponentName("com.miui.securitycenter", 
          "com.miui.permcenter.autostart.AutoStartManagementActivity"));
  }

  // context is your Context
  List<ResolveInfo> list = context.getPackageManager()
                                  .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

  if  (list.size() > 0) {
    context.startActivity(intent);
  } 

} catch (Exception e) {
  Log.d("PERMISSION", e.toString());
}

请注意,我还没有针对当前的小米设备测试过这段代码。

1
谢谢。但是如何确定用户是否已手动启用。 - Rakesh L
我还没有找到解决方案。 - ישו אוהב אותך
好的。如果您找到了任何解决方案,请告诉我。 - Rakesh L
你好,你是否找到了启用或禁用的解决方案? - PPD
好的,谢谢回复。但是一旦您找到解决方案,请告诉我。 - PPD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接