当前位置: 首页 > 知识库问答 >
问题:

您能否在Android Marshmallow(API 23)的运行时权限模型中同步请求权限?

慎峻
2023-03-14

假设您有这样一种方法:

public boolean saveFile (Url url, String content) {

   // save the file, this can be done a lot of different ways, but
   // basically the point is...

   return save_was_successful;
}

在整个应用程序中,如果要将文件保存到外部存储,可以执行以下操作。。。

if (saveFile(external_storage_url, "this is a test")) {
   // yay, success!
} else { // notify the user something was wrong or handle the error }

这是一个简化的示例,所以不要讨论我关于阻止UI、正确处理异常等的情况。如果您不喜欢文件保存,您可以想象一个getTouch()getPhoneState()或其他任何东西。关键是它是一个需要权限的操作,它返回一些值,并且在整个应用程序中使用。

在Android中

但是在新的Marshmallow(API 23)运行时权限模型中,在您可以将文件保存到外部存储之前,您应该(1)检查是否已授予权限。如果没有,可能(2)以干杯或其他方式展示请求的理由(如果系统认为这是个好主意),以及(3)要求用户通过对话框开通权限,然后基本上坐下来等待回调......

(因此,你的应用程序正在等待……)

(4) 当用户最终响应该对话框时,onRequestPermissionsResult()方法将启动,您的代码现在(5)必须筛选他们实际响应的权限请求,无论用户说是还是否(据我所知,无法处理“否”与“否”的对比,也无法再次询问),(6)弄清楚他们最初试图完成的是什么,这促使整个请求权限过程,以便程序最终能够(7)继续并完成这件事。

要知道用户在步骤(6)中试图做什么,需要事先传递一个特殊代码(“权限请求响应”),该代码在文档中被描述为权限请求类型(摄像头/联系人等)的标识符,但在我看来更像是“具体地说,当您意识到需要请求权限时,您正在尝试做什么”代码,由于同一权限/组可能在代码中用于多种目的,因此您需要使用此代码在获得权限后将执行返回到适当的位置。

我可能完全误解了这应该是如何工作的——因此,如果我还差得很远,请告诉我——但更重要的是,由于异步“等待用户响应”部分,我真的不知道如何使用前面描述的saveFile()方法来完成上述所有操作。我考虑过的想法很老套,肯定是错误的。

今天的Android开发者播客暗示,可能会有一个同步解决方案即将出现,甚至有人在Android Studio中讨论了一种神奇的、一步到位的alt-enter类型的“添加权限请求”工具。不过,如何将运行时权限过程插入到存储文件(saveFile())或其他文件中--我的想法大致如下:

public boolean saveFile(Url url, String content) {
   //   this next line will check for the permission, ask the user
   //   for permission if required, maybe even handle the rationale
   //   situation
   if (!checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        R.string.permission_storage_rationale))
       {
           return false; // or throw an exception or whatever
       } else {

   // try to save the file

   return save_was_successful;

   }
}

因此,如果用户没有并且拒绝授予权限,则上述检查权限()将失败。也许可以使用一个循环来尝试问3次或更多的问题,或者如果该方法处理了一个理智的“不要惹人烦”策略,那就更好了。

这可能吗?向往的这样的解决方案会阻止UI线程吗?从播客上看,谷歌似乎即将推出这样的解决方案,但我想知道是否有什么东西——一个方便的类,一个模式,什么东西——不需要每个人都重构所有需要权限的操作,我必须假设这些操作可能会变得相当混乱。

很抱歉问了这么长时间,但我想尽可能完整。我将不再广播我的答案。谢谢

更新:这是上面提到的播客的成绩单。

听41:20左右。在此讨论中:

粗略成绩单:

Tor Norbye(工具团队):“因此,开发人员似乎不需要做很多工作。但我理解部分问题是,这些调用不是同步调用,对吧?所以,你必须-实际上改变你的活动编写方式,使其具有回调功能-所以它真的有点像一个状态机,在这种状态下,你——

Poiesz(产品经理):“啊——我想——可能有一个——同步响应的选项——”

诺比:“哦,那会使事情——”

Poiesz:“我可以在内部与人们交谈。我记得有一次关于同步的讨论——但我们可以找到答案。”

Norbye:“是的。事实上,我们应该把它加入到工具中。在那里你可以轻松地重构…”

然后,他谈到在工具中使用注释来确定哪些API需要权限。。(目前为止,这在IMO中还不太管用)以及他希望这些工具在发现未经检查的“危险”方法调用时,有一天能够实际生成所需的代码:

诺拜:“…如果你也在M上,它会说,‘嘿,你真的是在检查这个权限还是在捕获安全异常?’,如果你没有,我们会说‘你可能需要做些什么来请求这里的权限。’我想做的是快速修复你可以去‘CHING’的地方,它会插入所有正确的请求内容,但事情回来了,w在我看来,这需要进行很多重构——添加接口和回调,以及更改流,而这是我们无法做到的。但如果有一个简单的同步模式,作为临时的或永久的东西,那就太好了。"

共有3个答案

何辰沛
2023-03-14

所以我讨厌回答我自己的问题,特别是关于我的示例中使用的android.permission.WRITE_EXTERNAL_STORAGE权限,但管他呢。

对于读取和/或写入文件,实际上有一种方法可以完全避免请求然后检查权限,从而绕过我上面描述的整个流程。这样,我给出的示例saveFile(Url Url,String content)方法可以继续同步工作。

我认为该解决方案在API 19中有效,通过让文档提供者充当“中间人”,基本上代表应用程序要求用户“请选择要写入的特定文件”(即“文件选择器”),然后在用户选择文件(或键入新文件名)后,消除了对写入外部存储权限的需要,应用程序现在被神奇地授予了对该Uri执行此操作的权限,因为用户已经专门授予了它。

无需“官方”权限。

这种借用权限的方式是存储访问框架的一部分,Ian Lake在大型Android BBQ上对此进行了讨论。这里有一个名为“忘记存储权限:共享和协作的备选方案”的视频,它介绍了基本内容,以及您如何专门使用它来完全绕过权限要求。

这并不能完全解决所有情况下的同步/异步权限问题,但对于任何类型的外部文档,甚至是由提供者提供的文档(如gDrive、Box.net、Dropbox等),这可能是一个值得检查的解决方案。

诸嘉澍
2023-03-14

简短回答:不,今天没有任何同步操作。在完成操作之前,您必须检查自己是否具有正确的权限,或者作为最后一个选项,您可以为安全异常设置一个try/catch块。在catch块中,您可以通知用户操作因权限问题而失败。此外,还有一点:当权限被吊销时,应用程序不会从主活动重新启动,因此即使在onResume()中,也必须检查权限。

汪庆
2023-03-14

至于Marshmallow,我的理解是你不能。

我必须在我的应用程序中解决同样的问题。我是这样做的:

  1. 重构:将依赖于某种权限的所有代码块移动到自己的方法中
  2. 更多重构:确定每个方法的触发器(如启动活动、点击控件等),如果方法具有相同的触发器,则将它们分组。(如果两个方法最终具有相同的触发器并需要相同的权限集,请考虑合并它们。)
  3. 甚至更多的重构:找出什么取决于以前调用过的新方法,并确保调用这些方法的时间是灵活的:要么将其移动到方法本身,要么至少确保无论您做什么,如果您的方法以前没有被调用过,都不会引发异常,并且只要调用了该方法,它就会按照预期的方式运行
  4. 请求代码:对于这些方法中的每一种(或其组),定义一个整数常量作为请求代码
  5. 检查和请求权限:将这些方法/方法组中的每个方法包装到以下代码中:

.

if (ContextCompat.checkSelfPermission(this, Manifest.permission.SOME_PERMISSION) == PackageManager.PERMISSION_GRANTED)
    doStuffThatRequiresPermission();
else
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.SOME_PERMISSION}, Const.PERM_REQUEST_DO_STUFF_THAT_REQUIRES_PERMISSION);

请注意,API需要Active来处理运行时权限请求。如果您有非交互式组件(例如Service),请查看如何从Android Marshmlow中的服务请求权限,以获取有关如何解决此问题的建议。基本上,最简单的方法是显示一个通知,然后会弹出一个活动,它只显示运行时权限对话框。这是我在应用程序中解决这个问题的方法。

 类似资料:
  • 首先,我知道这是一个重复的问题,但我已经看过了其他类似问题的答案,没有找到成功的解决方案。 我已经开发了一款应用程序,可以在我的测试设备上完美运行,这是一款运行Android L(5.0.1)的三星S4。不过,我希望这款应用程序也能在较新版本的Android上运行。 我知道Android M的请求权限已更改,因此必须在运行时请求权限,但当我尝试实现此功能时,对话框从未出现,因此从未请求所需的权限。

  • 我最近更新了我的应用程序,以支持android 6Marshmallow。我按照指示https://developer.android.com/training/permissions/requesting.html 并添加了请求权限Manifest.permission.RECEIVE_SMS。当 im 运行以下代码时: 我得到 java.lang.SecurityException:权限拒绝:

  • 我做错了什么?

  • 问题内容: 我正在测试我的应用,即使清单中已经定义了,它也会被强制关闭。我在某处已经读到,如果我在运行时请求权限,则不会强制关闭您的应用程序。我也已经阅读了这个android文档,用于请求运行时权限。 因此,我知道我们可以请求一个如下所示的权限,该权限在android文档中有所提及。 上面的代码具有获取结果的回调方法。 我的问题是要向用户确切请求权限?我们应该在应用启动时使用请求权限还是应该在需要

  • 问题内容: 我有用于调用操作的代码,并且我需要声明运行时权限的最佳方式IVE我尝试了许多代码,但我始终会出错 这是我的基本代码,任何有关使其具有运行时权限的建议,请先谢谢 } 问题答案: 在您的方法中尝试此代码 现在,调用创建一个单独的方法: 添加以下两种用于运行时权限检查的方法: 还要确保将其添加到清单中: 碎片 如果您在中尝试使用此代码 ,请更改 至 并且也改变 至

  • 是否可以在同一个对话框中同时请求多个权限,比如读联系人、读短信和写外部存储? 如果是,如何做到?请提供一个例子。 我已经在网上搜索了几个小时,但找不到方法。请帮忙!