【问题标题】:Android - How to Enable Autostart option programmatically in Xiaomi devices?Android - 如何在小米设备中以编程方式启用自动启动选项?
【发布时间】:2018-09-03 12:31:21
【问题描述】:

我正在开发一个想要在其中显示推送通知的 android 应用程序。

除了小米手机(我用的是红米Note 4)外,大部分设备都显示良好。我发现的问题是,小米提供的Autostart选项默认是关闭的,需要用户手动开启。

但我想知道我可以看到一些 Android 应用程序在没有任何用户交互的情况下启用此选项,例如:WhatsApp。如果我尝试重新安装 WhatsApp 并看到自动启动选项,它已启用!

我无法说服我们的客户说这是小米之类的设备的功能,因为他指出了一些运行良好的应用程序,就像我上面提到的示例一样。

有人问过这个问题

Add my app to AutoStart apps list in android programmatically

How to check AutoStart is enabled for our App in Xiaomi manufacturer mobile device Programmatically

但我看不到他们的任何答案,并在此处发布,希望有人对此有答案。

【问题讨论】:

  • 有什么解决办法吗?请

标签: android push-notification autostart


【解决方案1】:

如果小米操作系统需要它,当您从 playstore 下载应用程序时,自动启动功能将自动启用,因为亚马逊、谷歌 IO 等应用程序也不允许自动启动,在这种情况下,您必须转到安全权限 ->自动启动->然后从那里启用自动启动。您不能通过代码使应用程序自动启动,您所能做的就是显示一个对话框以启用自动启动并将用户带到自动启动活动,但这不是一个好的选择,因为您无法检查是否启用自动启动。 这是 Mi 在 MIUI8 中为节省电池所做的。这个问题浪费了我 2 天 XD

您可以参考this article

【讨论】:

  • 感谢您的回复。但这并不能解决我的问题:-(。我尝试从 Play 商店安装我的应用程序,但仍然面临同样的问题
  • 也许你没有卸载安装在你手机中的那个应用程序的以前版本这就是为什么因为我面临同样的问题发现很多东西没有用但是当我从 playstore 下载相同的应用程序时为我做了工作
  • 我可以知道 Play 商店中的应用程序,以便我可以像 Manifest 中那样对其进行一些研究吗?有一个允许备份的属性,因此应用程序数据会保留一些时间它可能会发生也正因为如此
  • 您将哪些依赖项用于 Firebase 推送通知。
【解决方案2】:

小米、OPPO、vivo等设备以编程方式启用自动启动选项

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

【讨论】:

  • else if ("meizu".equals(manufacturer, ignoreCase = true)) { intent = Intent("com.meizu.safe.security.SHOW_APPSEC") intent.addCategory(Intent.CATEGORY_DEFAULT) intent .putExtra("packageName", BuildConfig.APPLICATION_ID) }
  • 请在魅族设备上检查一下。我没有魅族设备。如果有人想要这个
【解决方案3】:

很少有流行的应用程序在后台运行而不在内存清理周期中被杀死(许多流行的 OEM 定制库存 ROM 以进行电池/内存优化),因为它们被这些制造商“列入白名单”。 对于您的应用,您可以手动(通过设备的相应“设置”)将其列入白名单,也可以通过将用户重定向到相应的设置页面以编程方式将应用列入白名单。以编程方式,您可以执行以下操作:

  1. 在应用的清单文件中添加以下权限:`

    <uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/> 
    <uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>`
    
  2. 将您重定向到自动启动设置:

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

AutoStart Reference For other OEMs

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

但作为用户,我们可以防止应用程序的后台服务一起被杀死,如下所示:

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

但是,通过这种方式,应用程序的锁定状态将在大多数设备上重新启动时重置。

编辑: 观察前台服务的行为(在小米RedmiS3,Android V6.0上)分析如下:

    1234563 br> 此外,如果我在设备设置中搜索“自动启动”,我无法在自动启动列表中看到我的应用程序。似乎上述方法仅提供自动启动权限但未启用它,不确定!。 而且,如果我通过设备设置将我的应用添加到“自动启动”列表中,我的服务会重新启动(尽管需要一些时间)。
  1. 在 onTaskRemoved() 回调中重新启动被杀死的服务可能是另一种选择,但是当服务被杀死时,这个回调会以令人惊讶的方式被调用。只有当应用程序通过后退键正确关闭时才会执行此回调。如果我们最小化应用程序(暂停状态),则不会在服务终止时调用此回调。 (寻找原因)

最近我发现了另一种方法,可以通过 GCM 通知事件重新启动被杀死的服务。我怀疑当应用程序在设备上被杀死时 GCM 是否正常工作(我需要检查这一点并验证行为)。但这是肯定的“这些 OEM 让程序员的生活陷入地狱!)。

【讨论】:

    【解决方案4】:

    我知道现在分享答案为时已晚,但我会把我的两分钱放在这里,因为它非常非常重要。我浪费了两天的时间来解决这个问题。我尝试了此处提供的所有建议解决方案,但似乎没有任何效果。以下是我在以下步骤中实施的解决方案:

    步骤#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 是组件名称,可以是您已经在应用中使用的Service 或Broadcast Receiver。就我而言,我尝试使用 Android 服务

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

    步骤#03 没有第三步。你完成了。您只需安装 apk,这样即使应用程序被杀死,Service 也不会被杀死。我在 Vivo 设备上测试了上述解决方案,它有效

    注意:如果上述解决方案不起作用,请检查清单文件中的 allowBackup 属性,如果您在清单文件中发现此属性,只需将其删除并卸载应用程序,然后再安装应用程序它肯定会起作用,然后您可以再次设置该属性。

    【讨论】:

    • 优秀的方法。但我有小米设备。如果我从最近的应用程序中清除应用程序,它将清除堆栈中的所有数据,然后服务不会自动启动。如何重新启动服务?
    【解决方案5】:

    据我所知,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());
    }
    

    请注意,我没有测试当前小米设备的代码。

    【讨论】:

    • 谢谢。但是如何识别用户是否已经手动启用。
    • 我还没有找到解决方案。
    • 好的。如果您能找到任何解决方案,请告诉我
    • 嗨,如果启用了,你找到解决方案了吗?
    • 好的,谢谢您的回复。但是,一旦您找到解决方案,请告诉我。
    猜你喜欢
    • 1970-01-01
    • 2016-03-12
    • 2017-01-15
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多