1. 欢迎
简介
应用权限用于授予对应用沙盒所提供的数据和功能以外的数据和功能的访问权限。它们允许应用访问互联网、设备位置信息和相机等,从而提升应用功能。
如需使用这些功能,您需要向用户请求权限。此 Codelab 会引导您执行一系列必要的步骤来添加运行时权限,并检查这些权限是否授予成功。
所需条件
- 最新版本的 Android Studio。
您应当已掌握的内容
- Kotlin 训练营中介绍的 Kotlin 相关内容
- 使用 Kotlin 开发 Android 应用中介绍的基本 Android 开发技能
学习内容
- 如何向 Android 清单添加权限。
- 如何请求权限。
- 如何处理权限请求被接受或被拒绝的情况。
- 如何检查是否已授予权限。
构建内容
您将开发一个请求相机权限的应用。需要实现的是对应用的权限处理,而不是对相机的操作。
2. 创建 Android Studio 项目
- 启动一个新的 Android Studio 项目。
- 选择 Empty Activity。
- 将项目命名为 Permissions Codelab,并将语言设置为“Kotlin”。
3. 设置代码
- 将以下依赖项的最新版本添加到您的应用级
build.gradle
文件中。通过这些依赖项,您可以使用稍后会在此 Codelab 中介绍的Activity
库。
implementation "androidx.activity:activity-ktx:1.2.2"
implementation "androidx.fragment:fragment-ktx:1.3.2"
- 在 Android 代码块中将
viewBinding
构建选项设置为 true,以启用 ViewBinding。
android {
...
buildFeatures {
viewBinding true
}
}
- 然后按绿色锤子按钮进行构建。这将生成一个名为
ActivityMainBinding
的绑定类,稍后您会将其用于ViewBinding
。
- 转到
activity_main.xml
文件,然后将代码替换为以下代码。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Request Permissions"
android:onClick="onClickRequestPermission"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 将下面的字符串添加到
strings.xml
文件中。
<string name="app_name">Permissions Codelab</string>
<string name="permission_required">Camera access is required to display the camera preview.</string>
<string name="ok">OK</string>
<string name="permission_granted">Permission is granted. You can use the camera now.</string>
- 在
MainActivity.kt
中的onCreate()
方法之前,为布局和ViewBinding
定义变量。
private lateinit var layout: View
private lateinit var binding: ActivityMainBinding
- 将
onCreate()
方法中的代码替换为以下代码。此代码会初始化绑定,创建一个表示视图的val
,并将其设置为绑定的根,然后将布局设置为绑定的mainLayout
。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
layout = binding.mainLayout
setContentView(view)
}
- 在该文件底部的
MainActivity
类下,添加一个扩展函数,用于在整个 Codelab 中显示信息提示控件。
fun View.showSnackbar(
view: View,
msg: String,
length: Int,
actionMessage: CharSequence?,
action: (View) -> Unit
) {
val snackbar = Snackbar.make(view, msg, length)
if (actionMessage != null) {
snackbar.setAction(actionMessage) {
action(this)
}.show()
} else {
snackbar.show()
}
}
4. 向清单添加权限
首先,您需要使用 <uses-permission>
标记声明您的权限将在 Android manifest
中使用。
有时,您请求的权限也会有其他要求。在这种情况下,除非设备配有相机,否则您无法使用相机应用。因此,您还需要向清单中添加 <uses-feature>
标记。
- 在
AndroidManifest.xml
文件中,在<application>
标记之前添加相机权限。
<uses-permission android:name="android.permission.CAMERA" />
5. 创建权限启动器
在 MainActivity.kt
中,创建一个名为 requestPermissionLauncher
的 val
,然后将下面这段代码复制到其中。接下来我们将逐条讲解这段代码。
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
Log.i("Permission: ", "Granted")
} else {
Log.i("Permission: ", "Denied")
}
}
- 将
requestPermissionLauncher
设置为与registerForActivityResult
相等,并传入ActivityResultContracts.RequestPermission()
。
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission())
- 添加回调以处理授予权限或不授予权限的情形。在本示例中,我们会记录结果。
{ isGranted: Boolean ->
if (isGranted) {
Log.i("Permission: ", "Granted")
} else {
Log.i("Permission: ", "Denied")
}
}
6. 请求权限
- 创建一个名为
onClickRequestPermission(view: View)
的函数,然后将下面这段代码复制到其中。接下来我们将逐条讲解这段代码。
fun onClickRequestPermission(view: View) {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
layout.showSnackbar(
view,
getString(R.string.permission_granted),
Snackbar.LENGTH_INDEFINITE,
null
) {}
}
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) -> {
layout.showSnackbar(
view,
getString(R.string.permission_required),
Snackbar.LENGTH_INDEFINITE,
getString(R.string.ok)
) {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
else -> {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
- 设置
when
语句以涵盖下面三种情况:已获得权限;应用认为其应该显示权限请求的理由;以及尚未收到权限请求。
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
}
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) -> {
}
else -> {
}
}
- 如果已获得权限,应用就会显示信息提示控件来告知用户这一情况。
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
layout.showSnackbar(
view,
getString(R.string.permission_granted),
Snackbar.LENGTH_INDEFINITE,
null
) {}
}
- 如果
shouldShowRequestPermissionRationale()
返回 true,应用就会显示一个界面,详细说明相应功能为何需要该特定权限,同时为用户提供在界面中允许/拒绝该权限请求的方式。
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) -> {
layout.showSnackbar(
view,
getString(R.string.permission_required),
Snackbar.LENGTH_INDEFINITE,
getString(R.string.ok)
) {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
- 否则,请求权限。
else -> {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
7. 总结
大功告成!此 Codelab 介绍了添加运行时权限的方式,您可以用来添加有关位置信息、网络和媒体等方面的权限!