权限机制 :
Android通过权限控制应用对系统资源的访问。
动态权限(如相机、位置)需要运行时申请。
签名机制 :
梗概 在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 文件中用来声明应用程序所需功能和权限的元素。
<uses-feature>
:用来声明应用程序所需的硬件或软件功能特性。 例如,可以使用 <uses-feature>
声明应用程序需要相机、GPS、蓝牙等功能。 这样,Google Play 商店就可以根据设备的功能特性来过滤应用程序,确保只有支持相应功能的设备可以安装该应用程序。
示例:
1 2 COPY <uses-feature android:name ="android.hardware.camera" /> <uses-feature android:name ="android.hardware.bluetooth" />
<uses-permission>
:用来声明应用程序所需的权限 Android 系统通过权限来控制应用程序对设备资源的访问。 例如,可以使用 <uses-permission>
声明应用程序需要访问设备的摄像头、存储空间、联系人等权限。
示例:
1 2 COPY <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 COPY <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 COPY if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ 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 COPY 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 () { 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 COPY 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 COPY 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连接来保护数据传输的安全性。