Android M 请求非活动权限

49

我的小工具在Activity范围之外进行安全权限调用。是否可能在Activity之外请求Android M的权限?

6个回答

10
我找到了一个看起来很好用的解决方法。关键是创建一个透明的活动,只是用来请求权限,并在立即完成后结束。当然,你仍然需要上下文,但它不必是一个活动。
该活动可以通过广播返回结果(授予或拒绝),因为在活动之外无法使用 startActivtyForResult
你可以使用以下活动:
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AppCompatActivity

internal const val PERMISSIONS_KEY = "permissions"
internal const val ACTION_PERMISSIONS_GRANTED = "GetPermissionsActivity.permissions_granted"
internal const val ACTION_PERMISSIONS_DENIED = "GetPermissionsActivity.permissions_denied"

class GetPermissionsActivity: AppCompatActivity() {

    private val permissionRequestCode = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCompat.requestPermissions(
            this,
            intent.getStringArrayExtra(PERMISSIONS_KEY),
            permissionRequestCode
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == permissionRequestCode) {
            if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                sendBroadcast(Intent(ACTION_PERMISSIONS_GRANTED))
            } else {
                sendBroadcast(Intent(ACTION_PERMISSIONS_DENIED))
            }
            finish()
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }
}

这是用于活动的样式

<style name="Theme.Transparent" parent="Theme.AppCompat">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">false</item>
    <item name="android:windowAnimationStyle">@null</item>
</style>

在清单文件中:
<activity android:name="GetPermissionsActivity" android:theme="@style/Theme.Transparent" />

然后按照以下方式使用它(需要上下文)
class SomeClass : BroadcastReceiver() {

    private fun someFunction(context: Context) {
        val intentFilter = IntentFilter()
        intentFilter.addAction(ACTION_PERMISSIONS_GRANTED)
        intentFilter.addAction(ACTION_PERMISSIONS_DENIED)
        context.registerReceiver(this, intentFilter)
        val intent = Intent(context, GetPermissionsActivity::class.java)
        intent.putExtra(PERMISSIONS_KEY, arrayOf(<your permissions>))
        context.startActivity(intent)
    }

    override fun onReceive(context: Context, intent: Intent) {
        when {
            intent.action == ACTION_PERMISSIONS_GRANTED -> {
                context.unregisterReceiver(this)
                onPermissionsGranted()
            }
            intent.action == ACTION_PERMISSIONS_DENIED -> {
                context.unregisterReceiver(this)
                onPermissionsDenied()
            }
            else -> super.onReceive(context, intent)
        }
    }

    private fun onPermissionsGranted() {
        // ...
    }

    private fun onPermissionsDenied() {
        // ...
    }
}

5
不,这是不可能的。您可以发送通知,用户可以点击通知,然后使用一个活动来请求/管理权限(也许带有对话框主题)。

1
配置活动也是处理这个问题的好地方。尽管用户可以转到权限屏幕并撤销先前授予的任何权限,但仍需要通知方法。我还会考虑将小部件放入权限已撤销的UI状态作为另一种方法。 - Zsombor Erdődy-Nagy

4
你可以使用 Easy Permissions 库。
Android要求这些请求来自一个Activity。使用Easy Permissions就不再是问题了,只要提供Context,你可以从任何地方请求权限。此外,如果你请求的权限已经被授予,用户将不会收到提示。

enter image description here

完全透明地说,我们的公司管理和开发这个免费使用的库。话虽如此,我们有信心它是一个有用的工具,否则我们不会分享它。


这对我来说毫无意义。如果Android确实需要使用活动来请求权限,那么你的库必须是纯魔法,因为它可以做到不可能的事情。事实上,你使用了一个上下文。这就像标准的checkSelfPermission()一样。我看不出使用第三方库进行此权限检查的真正优势。也许我错过了什么... - The incredible Jan
@TheincredibleJan 感谢您的联系。Android确实需要一个“Activity”。像许多库一样,“Context”是必需的--它是魔法,但仍然基于现实世界 :)。最大的优点是,您可以从任何地方请求启用权限,甚至是不是“Activity”的类。此外,最新版本将允许您自动启用在您的“Manifest”文件中的所有权限。GitHub页面上有一个示例应用程序;如果您有几分钟,一定要查看一下。如果您有任何问题,请告诉我们。 - Newtron Labs
1
此解决方案在 S5 Android 6.0 上进行了测试,但不起作用,目前没有任何反应。 - Matan Tubul
无法安装库。 - M. Usman Khan

2

我认为可以在Activity外部请求权限,只要使用支持库中的方法

ActivityCompat.requestPermissions(Activity activity, String[] permissions, int requestCode)

并将Activity作为该方法的参数传递。

例如:

ActivityCompat.requestPermissions(targetActivity, new String[] {Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE);

其中,targetActivity是应该实现该方法的Activity:

onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)

这是处理权限请求结果的方法。


37
活动之外的意思是指来自服务或广播接收器,其中你根本没有活动。这个答案一点也没帮助。 - Gabe Sechan
通常情况下,您可以将上下文对象传递给非活动类,并在需要上下文但没有活动时使用它。不过,请求权限则是另一回事。 - Pedram
@Gabe,在某个方面你是正确的,但另一方面,问题没有说明提问者希望从哪里调用请求。因此我认为这是一个正确的答案。 - Opiatefuchs
@GabeSechan 如何在Android M中针对服务和广播设置权限? - Jatin Khattar
如何在AppWidgetProvider中设置权限?还是应该将其放在我的RemoteViewsService.RemoteViewsFactory中?我的小部件中的ListView需要检查位置。 - natsumiyu
@AndyBoy 目前我不知道有什么方法。我最好的答案是启动一个活动来请求它。 - Gabe Sechan

2

你只能从Activity或Fragment请求权限。

确定您的应用程序需要权限的Activity或Fragment中的某个点,然后调用requestPermission方法。发送通知无法起作用,因为您希望您的代码在获得所请求的权限之前一直处理,并从onRequestPermissionResult()方法恢复功能。


1
我正在创建一个需要在多个活动中检查权限的应用程序,因此我创建了一个静态类,可以在整个应用程序中使用。 它有效地工作了。 这对我有用。
我创建了一个方法来检查不同类中的权限请求,像这样。
public class CheckForPermissions implements ActivityCompat.OnRequestPermissionsResultCallback {
private static final int MY_PERMISSIONS_REQUEST_READ_LOCATION = 1;


    public static void checkForLocationPermissions(Activity context){
        if(ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)  != PackageManager.PERMISSION_GRANTED
        || ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)  != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(context,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_READ_LOCATION);

    }
}}

在我的Activity中,我这样调用了该方法。
        CheckForPermissions.checkForLocationPermissions(this);

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