【问题标题】:Android navigate back to Application from Android SettingsAndroid 从 Android 设置导航回应用程序
【发布时间】:2018-05-06 20:10:52
【问题描述】:

由于 android 从 Android 设置返回的方式,我的用户体验不一致。

在我的应用程序中,用户需要授予我的应用程序对ACTION_USAGE_ACCESS_SETTINGS 的访问权限,我通过以下方式访问:

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

为我的应用程序打开设置后,我需要用户返回我的应用程序。我知道的唯一方法是让他们按下手机上的后退按钮(很想知道在切换设置后是否可以自动返回!!!?!)。

现在将发生以下两种情况之一:

1) 用户最近没有使用过android设置,所以它还没有打开(即在打开的应用程序抽屉中打开)。第一次按下后退按钮将根据需要将它们带到我的应用程序。

2) 用户最近使用过安卓设置。因此设置已经在应用程序抽屉中打开。现在,当用户按下返回时,Android 将带他们返回他们最近使用的每个设置页面(即返回按钮带他们浏览他们在 android 设置页面中的历史记录)。可能需要按 2、3 或 4 次后退按钮才能离开 Android 设置并返回到我的应用程序。这显然是糟糕的 UI/UX,我想知道是否有更好的方法?

我注意到在安装 Google 应用程序时,将设置切换为 ON 后,它会自动退出并返回到调用该设置的应用程序。能够做到这一点将是理想的,但我无法解决。

谢谢!

【问题讨论】:

  • 一般来说,您可以通过摆脱FLAG_ACTIVITY_NEW_TASK 来帮助您的事业,因为您特别想将其纳入您自己的任务中。实际上,您不能保证返回按钮的行为,因为它受您链接到的应用程序的控制。
  • @CommonsWare,谢谢,这个改变意味着我只需要按两次后退按钮,这可以改善最坏的情况。我想你不知道为什么在安装 Google Apps 时,它会在将设置切换到 ON 位置后立即恢复到调用应用程序? (即,您滑动到 ON,然后无需按返回按钮即可切换回原始应用程序)这是只有 Google 才能实现的功能,还是有什么方法可以更改我的应用程序以使其成为可能?
  • “这个改变意味着我只需要按两次后退按钮”——第一次按 BACK 会带你去哪里?
  • 意图启动到“具有使用访问权限的应用程序”设置页面,然后单击我的应用程序,这会将我带到我的应用程序的“使用访问权限”页面。然后,我可以将我的应用程序的“允许使用访问”切换为“开启”。按回一次将我带回“具有使用访问权限的应用程序”设置页面。按第二次将我带回到我的应用程序的调用活动。

标签: android android-navigation android-settings


【解决方案1】:

抱歉,如果答案迟到了,但我将答案留在这里,以供其他人解决这个问题。对我来说,问题可能出在我们自己而不是 Android 上。例如,我有一个监听器,它监听开关的状态

setOnCheckedChangeListener { _, _ ->
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                intent.data =
                    Uri.fromParts(
                        "package",
                        navigator.activeFragment?.activity?.packageName,
                        null
                    )
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

                navigator.activeFragment?.startActivity(intent)
            }

这段代码发生了什么?

用户转到设置,然后返回。如果您在用户返回后在此处设置了更新 UI 的内容,如下所示,那么这将导致多个侦听器监听开关的变化

    override fun onResume() {
    super.onResume()
    if (!isFirst) {
        // Notify that user might have change the notification setting
        (binding.rvSetting2.adapter as SettingAdapter).notifyItemChanged(0)
    }
    isFirst = false

我的解决方案

你可以在监听器中加入这一行,这会移除当前的开关监听器,这样可以避免在开关改变之后再去设置。

                setOnCheckedChangeListener { _, _ ->
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                intent.data =
                    Uri.fromParts(
                        "package",
                        navigator.activeFragment?.activity?.packageName,
                        null
                    )
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

                navigator.activeFragment?.startActivity(intent)

                // Remove the current listener in case of user went back from Setting and call on bind view holder again
                // This cause multiple listener listen to the change of this switch
                setOnCheckedChangeListener(null)
            }

我知道这只是我个人的解决方案,但如果你分享类似的方法,这可能会有所帮助。

【讨论】:

    【解决方案2】:

    @Geordie Wicks 提供的解决方案与我想要的很接近,但似乎在启动 intent 之前打开 Android 设置会导致返回按钮将您带到之前的 Android 设置屏幕。

    我的解决方案涉及另外两个标志,Intent.FLAG_ACTIVITY_CLEAR_TOPIntent.FLAG_ACTIVITY_CLEAR_TASK

    您可以如下定义您的intent

    Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                    intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    startActivity(intent);
    

    根据我的经验,这样一来,无论 Android 设置是否事先打开,按下后退按钮都会将您带回您的应用程序。

    【讨论】:

      【解决方案3】:

      根据 Ufkoku 的回答,我使用了对权限状态的定期检查。为了让用户回来,我使用了 startActivityForResult 和 finishActivity。

      示例代码:我将其用于“USAGE_ACCESS_SETTINGS”。

      var intent = Intent("android.settings.USAGE_ACCESS_SETTINGS")
      intent.data = Uri.fromParts("package", "com.example.app", null)
      startActivityForResult(intent,101)
      
      var timer = Timer(true)
      timer.scheduleAtFixedRate(object: TimerTask(){
          override fun run(){
              if(checkUsageAccessPermission()){ // checkUsageAccessPermission() is a helper function
                  finishActivity(101)
                  cancel()                    
              }
          }
      }, 0, 1000)
      

      【讨论】:

        【解决方案4】:

        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent);

        这也是最简单的导航方式

        【讨论】:

          【解决方案5】:

          好的,所以在尝试了大约一百万件事之后,我想出了 3 种不同的方法来改善我的问题。

          1) 由@CommonsWare 提供,通过删除 FLAG_ACTIVITY_NEW_TASK,它可以防止所需的后按次数不一致,这意味着每次用户只需按两次。

          2) 在对标志的进一步研究后,我发现使用三个组合:

          Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
                              intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                              intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                              intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                              startActivity(intent);
          

          将所需的背压次数减少到 1 次背压。这是简单合理的用户友好。

          3) 在设置意图触发后,使用处理程序不断检查所需的权限。这似乎有点像 hack,我不敢相信没有更好的方法可以做到这一点,但它的工作原理与使用 Google App 时完全一样。即,一旦您将开关切换为打开,它就会退出 Android 设置页面,并返回到您离开的应用程序。我正在使用:

          Handler handler = new Handler();
          
          Runnable checkSettingOn = new Runnable() {
          
              @Override
              //@TargetApi(23)
              public void run() {
                  Log.d(TAG, "run: 1");
                  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                      Log.d(TAG, "run: 2");
                      return;
                  }
                  if (isAccessGranted()) {
                      Log.d(TAG, "run: 3");
                      //You have the permission, re-launch MainActivity
                      Intent i = new Intent(MainActivity.this, MainActivity.class);
                      Log.d(TAG, "run: 4");
                      i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                      startActivity(i);
                      return;
                  }
                  handler.postDelayed(this, 200);
              }
          };
          

          然后,当您触发进入 Android 设置页面的意图时,请务必启动处理程序:

          handler.postDelayed(checkSettingOn, 1000);
          

          希望这可以帮助遇到类似问题的其他人。

          【讨论】:

          • 好消息:有一种内置方法可以检测用户何时授予使用权限。见stackoverflow.com/a/54838247/238753
          • 方法#2不适用于设置应用程序已经运行并且在设置应用程序中使用ActionBar back的情况......(至少对于区域设置页面)
          • 启用位置设置后我们可以执行 startActivityForResult() 回到 App 吗?
          【解决方案6】:

          启动设置活动后,您可以运行定期任务,该任务每隔 500 毫秒调用一次,并检查是否已授予权限。
          使用标志 singleTask/singleInstance 标记您的设置活动,并在获得许可的情况下启动它。现有的活动实例将被移到顶部。

          我这样做是为了通知访问权限。

          【讨论】:

          • 谢谢,这就是我最终采用的方法,它看起来有点像 hack,但它是我认为对最终用户最友好的解决方案。我接受我的回答,因为它有更多细节,但给你赏金,我希望没问题并且在规则范围内。
          • 启用位置设置后我们可以执行 startActivityForResult() 回到 App 吗?
          • @KPradeepKumarReddy 当您使用 startActivityForResult 时,它仅表示已启动的活动将在已开始的活动结束期间将结果返回给启动活动。
          【解决方案7】:

          您必须确认您只打开您需要打开的应用程序的设置。不要打开主设置应用程序。仅打开所需的应用设置。因此,只要您按回,您就会跳回您的应用程序。

          Uri uri = Uri.fromParts("package", getPackageName(), null);
          Intent intent = new Intent();                            
          intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
          intent.setData(uri);
          startActivity(intent);
          

          【讨论】:

          • 启用位置设置后我们可以执行 startActivityForResult() 回到 App 吗?
          • 你说的不是问题。它需要 Settings.ACTION_USAGE_ACCESS_SETTINGS,如果您在代码中传递 Settings.ACTION_USAGE_ACCESS_SETTINGS 而不是 Settings.ACTION_APPLICATION_DETAILS_SETTINGS,那么您的代码就会崩溃!
          【解决方案8】:

          你可以在这里做一件事。你必须确认你只打开你需要打开的设置组件....不要打开主设置应用程序。在您想要的设置应用程序中仅打开一个组件。所以这样一来,当您按回时,您将跳回您的应用程序。

          例如,如果我想在设置中打开蓝牙设置 应用程序,我不会打开主设置应用程序,而是会打开 只有蓝牙组件的设置。这样,当我按下回我 将返回我自己的应用程序,因为我还没有打开主设置应用程序,所以我不需要在其中导航。

          ComponentName cn = new ComponentName("com.android.settings", 
                             "com.android.settings.bluetooth.BluetoothSettings");
          

          【讨论】:

          • 谢谢,但很遗憾,您无法使用此方法直接访问您的应用程序的 USAGE_SETTINGS 页面。 :(您必须先进入通用使用设置页面,然后选择您的应用程序。
          • 不,有很多方法......下载活动启动器应用程序......它是一个应用程序,可为您的手机中的所有活动提供包名称。找到使用设置并点击它。它会给你一个包名,把它放在组件名中,你就可以开始了!
          • 好的,我试过了,它给出了一个 ActivityNotFoundException。
          • 这是一个非常有趣的应用程序,但谢谢,我想我可以使用它来绕过我的一些问题,并直接获取信息而无需实际授予应用程序所需的权限。有点像安全漏洞?该应用可以直接访问使用设置,无需请求许可?
          • 是的,它确实如此,它不能给出那个错误我认为你没有正确放置包名称....我已经尝试了很多次。它不会失败。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-01-23
          • 2014-06-06
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 2016-02-09
          • 1970-01-01
          相关资源
          最近更新 更多