权限申请

梗概

在Android 6.0 (API 级别 23) 以下申请权限是非常简单的,直接在 AndroidManifest.xml 这个配置文件中加入申请权限的列表就可以了

但是在Android 6.0 (API 级别 23) 以上的版就不可以这样申请了,因为这样申请权限对用户来说是非常危险的,应用已安装就获取了全部权限,也不知道这些权限应用要来干什么,可能是用户不希望发生的一些操作。
所以在Android 6.0之后,一些危险的权限就要动态申请了,哪些是危险权限呢,下面是官方提供的一个需要动态申请的危险权限:

这里将其列出,一共9组24个。需要注意的是,权限按组分类,当一个权限被同意时,同一组内的权限自动同时被授权。

权限组名 权限名称
CALENDAR(日历) READ_CALENDAR
WRITE_CALENDAR
CAMERA(相机) CAMERA
CONTACTS(联系人) READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION(位置) ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE(麦克风) RECORD_AUDIO
PHONE(手机) READ_PHONE_STATE
CALL_PHONE
ERAD_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS(传感器) BODY_SENSORS
SMS(短信) SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE(存储卡) READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

如果要使用上面的权限,除了要在 AndroidManifest.xml 这个配置文件声明,还要在代码中增加动态申请

(一)普通权限

<uses-feature><uses-permission> 是 AndroidManifest.xml 文件中用来声明应用程序所需功能和权限的元素。

  1. <uses-feature>:用来声明应用程序所需的硬件或软件功能特性。
    例如,可以使用 <uses-feature> 声明应用程序需要相机、GPS、蓝牙等功能。
    这样,Google Play 商店就可以根据设备的功能特性来过滤应用程序,确保只有支持相应功能的设备可以安装该应用程序。

示例:

1
2
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.bluetooth" />
  1. <uses-permission>:用来声明应用程序所需的权限
    Android 系统通过权限来控制应用程序对设备资源的访问。
    例如,可以使用 <uses-permission> 声明应用程序需要访问设备的摄像头、存储空间、联系人等权限。

示例:

1
2
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

总结:

  • <uses-feature> 用来声明应用程序所需的硬件或软件功能特性。
  • <uses-permission> 用来声明应用程序所需的权限。

(二)动态申请权限

说明

动态申请权限指的是在应用程序运行时,根据需要向用户请求权限的过程。
在Android应用程序中,某些权限属于危险权限,需要获取用户的明确授权才能使用,这些权限一般都需要 在运行时进行动态请求
开发者需要在应用程序代码中进行 权限检查 ,如果发现权限未被授权,则需要通过系统提供的权限请求机制向用户显示请求权限的对话框,请求用户授权相应的权限。
用户可以选择授权或拒绝权限,开发者需要根据用户的选择进行相应的处理。

动态申请权限可以让用户更直观地了解应用程序对隐私权限的使用情况, 增强用户对应用安全性和隐私保护的信任
通过动态权限请求,开发者可以更好地控制应用程序的权限使用,并在权限被拒绝时提供相应的提示和处理,从而提升用户体验和应用程序的安全性。

一些权限是属于危险权限(访问受保护的资源或执行敏感操作),需要动态申请的

请求单个权限

在 AndroidManifest.xml 文件声明自己需要什么权限

1
2
3
4
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-permission android:name="android.permission.CALL_PHONE"/>

Activity 的 onCreat() 中 :

先检测是否有对应权限(用户是否已经同意过了),没有权限再去申请权限
checkSelfPermission
registerForActivityResult

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
//申请具体权限
//registerForActivityResult() 申请的结果
//ActivityResultContracts.RequestPermission() 申请什么权限:权限/访问视频/访问图片
val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
//处理的结果,用户同意或者不同意需要做什么
if (it){
//用户同意
}else{
// 用户拒绝了拨打电话权限,处理拒绝权限的逻辑
Toast.makeText(this, "拨打电话权限被拒绝", Toast.LENGTH_SHORT).show()
}
}

//具体申请什么权限,触发系统权限请求对话框,提示用户允许或拒绝电话权限
permissionLauncher.launch(Manifest.permission.CALL_PHONE)
}
  • ActivityResultLauncher
  • registerForActivityResult
  • launch

写入权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MainActivity : AppCompatActivity() {
private lateinit var writePermissionLauncher: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

writePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
Log.v("pxd","获取权限结果:$it")
}
checkPermission()
}

private fun checkPermission(){
//这里的 Manifest 是 android 里面的
if(ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
writePermissionLauncher.launch(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
}

多个权限

如果需要获取多个权限,可以通过创建多个 ActivityResultLauncher 来分别请求每个权限。以下是一个示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MainActivity : AppCompatActivity() {
private lateinit var writePermissionLauncher : ActivityResultLauncher<String>
private lateinit var cameraPermissionLauncher : ActivityResultLauncher<String>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

writePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
Log.v("pxd","写入权限获取结果:$it")
}

cameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
Log.v("pxd","相机权限获取结果:$it")
}

checkPermissions()
}

private fun checkPermissions(){
if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
writePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}

if(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}

在上面的示例中,我们创建了两个 ActivityResultLauncher 分别用于请求 WRITE_EXTERNAL_STORAGE 和 CAMERA 权限。在 checkPermissions() 方法中,我们分别检查这两个权限是否已经被授予,如果没有就调用对应的 launcher 来请求权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MainActivity : AppCompatActivity() {
private lateinit var multiplePermissionsLauncher: ActivityResultLauncher<Array<String>>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

multiplePermissionsLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.entries.forEach {
Log.v("pxd", "权限 ${it.key} 获取结果:${it.value}")
}
}

checkPermissions()
}

private fun checkPermissions(){
val permissionsToRequest = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)

val permissionsMap = permissionsToRequest.associateWith {
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
}

val permissionsToRequestArray = permissionsMap.filterValues { it }.keys.toTypedArray()

if (permissionsToRequestArray.isNotEmpty()) {
multiplePermissionsLauncher.launch(permissionsToRequestArray)
}
}
}

usesCleartextTraffic

android:usesCleartextTraffic=”true”

在AndroidManifest.xml文件中使用android:usesCleartextTraffic=”true”属性可以允许应用程序通过非加密的明文流量发送网络请求。默认情况下,Android 9和更高版本禁用了应用程序使用明文流量进行网络通信,因为明文流量可能会导致安全风险。当使用明文流量时,敏感数据可能会被中间人攻击者拦截和窃取。因此,谨慎使用此属性,并确保网络通信安全。

如果您的应用程序需要与不支持加密通信的服务器进行通信,您可以使用android:usesCleartextTraffic=”true”属性来明确告知系统允许明文流量。但是为了保障通信安全,建议尽可能地使用加密通信,例如HTTPS连接来保护数据传输的安全性。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2023-2025 Annie
  • Visitors: | Views:

嘿嘿 请我吃小蛋糕吧~

支付宝
微信