建设通网站是什么时间成立,编程常用代码大全,国家高新技术企业公示,iphone做网站服务器Android 11#xff08;API 30#xff09;引入了多项重要特性和权限变更#xff0c;核心集中在存储权限、后台位置、包可见性、前台服务 等方面。本文基于 Kotlin 语言#xff0c;从核心变更点、适配方案、代码示例等维度讲解适配要点。
一、核心变更概览
变更类别核心影响…Android 11API 30引入了多项重要特性和权限变更核心集中在存储权限、后台位置、包可见性、前台服务等方面。本文基于 Kotlin 语言从核心变更点、适配方案、代码示例等维度讲解适配要点。一、核心变更概览变更类别核心影响适配优先级存储权限废弃WRITE_EXTERNAL_STORAGE引入分区存储强制启用高后台位置权限单独申请ACCESS_BACKGROUND_LOCATION需用户显式授权高包可见性应用默认无法查询其他应用需在清单声明可见范围中前台服务限制新增类型限制后台启动前台服务需特殊权限中权限对话框优化新增「仅本次」选项权限授权逻辑变更中悬浮窗权限SYSTEM_ALERT_WINDOW权限申请流程变更低二、分区存储适配最核心1. 变更说明Android 11 强制启用分区存储Scoped Storage应用只能访问应用私有目录/Android/data/包名/无需权限媒体文件图片/音频/视频通过 MediaStore API 访问下载文件通过DownloadManager或存储访问框架SAF2. 适配方案1基础配置清单文件!-- 保留旧权限兼容低版本但Android 11不再生效 --uses-permissionandroid:nameandroid.permission.READ_EXTERNAL_STORAGE/uses-permissionandroid:nameandroid.permission.WRITE_EXTERNAL_STORAGEandroid:maxSdkVersion28/!-- Android 11访问媒体文件仅需读权限 --uses-permissionandroid:nameandroid.permission.READ_EXTERNAL_STORAGE/!-- 如需批量修改/删除媒体文件需申请此权限 --uses-permissionandroid:nameandroid.permission.MANAGE_EXTERNAL_STORAGEtools:ignoreScopedStorage/!-- 可选临时关闭分区存储仅过渡用不推荐 --applicationandroid:requestLegacyExternalStoragetrueandroid:targetSdkVersion30/application2读取媒体文件Kotlin通过 MediaStore 查询图片示例/** * 读取设备中的图片文件 */funqueryImages(context:Context):ListUri{valimageUrismutableListOfUri()valprojectionarrayOf(MediaStore.Images.Media._ID,MediaStore.Images.Media.DISPLAY_NAME,MediaStore.Images.Media.DATE_ADDED)// 按添加时间倒序查询valsortOrder${MediaStore.Images.Media.DATE_ADDED}DESCcontext.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,projection,null,null,sortOrder)?.use{cursor-validColumncursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)while(cursor.moveToNext()){validcursor.getLong(idColumn)valuriContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,id)imageUris.add(uri)}}returnimageUris}3写入媒体文件Kotlin保存图片到公共相册示例/** * 保存图片到公共相册 * param bitmap 要保存的图片 * param displayName 文件名 */funsaveImageToGallery(context:Context,bitmap:Bitmap,displayName:String):Uri?{valcontentValuesContentValues().apply{put(MediaStore.Images.Media.DISPLAY_NAME,displayName)put(MediaStore.Images.Media.MIME_TYPE,image/jpeg)put(MediaStore.Images.Media.RELATIVE_PATH,Pictures/MyApp)// 保存到Pictures/MyApp目录if(Build.VERSION.SDK_INTBuild.VERSION_CODES.Q){put(MediaStore.Images.Media.IS_PENDING,1)// 标记为待处理}}valcontentUriMediaStore.Images.Media.EXTERNAL_CONTENT_URIvaruri:Uri?nulltry{uricontext.contentResolver.insert(contentUri,contentValues)uri?.let{context.contentResolver.openOutputStream(it)?.use{outputStream-bitmap.compress(Bitmap.CompressFormat.JPEG,90,outputStream)}if(Build.VERSION.SDK_INTBuild.VERSION_CODES.Q){contentValues.clear()contentValues.put(MediaStore.Images.Media.IS_PENDING,0)context.contentResolver.update(it,contentValues,null,null)}}}catch(e:Exception){uri?.let{context.contentResolver.delete(it,null,null)}e.printStackTrace()}returnuri}4批量操作媒体文件需 MANAGE_EXTERNAL_STORAGE 权限/** * 检查是否有管理所有文件的权限 */funhasManageExternalStoragePermission(context:Context):Boolean{returnif(Build.VERSION.SDK_INTBuild.VERSION_CODES.R){Environment.isExternalStorageManager()}else{true}}/** * 申请管理所有文件的权限 */funrequestManageExternalStoragePermission(activity:Activity){if(Build.VERSION.SDK_INTBuild.VERSION_CODES.R!Environment.isExternalStorageManager()){valintentIntent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply{dataUri.parse(package:${activity.packageName})}activity.startActivityForResult(intent,REQUEST_CODE_MANAGE_STORAGE)}}三、后台位置权限适配1. 变更说明Android 11 要求后台位置权限需单独申请且必须先获得前台位置权限ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION。2. 适配代码1清单声明uses-permissionandroid:nameandroid.permission.ACCESS_FINE_LOCATION/uses-permissionandroid:nameandroid.permission.ACCESS_COARSE_LOCATION/uses-permissionandroid:nameandroid.permission.ACCESS_BACKGROUND_LOCATION/2权限申请逻辑// 权限请求码privateconstvalREQUEST_CODE_LOCATION1001/** * 检查并申请位置权限 */funcheckAndRequestLocationPermission(activity:Activity){valforegroundPermissionsarrayOf(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION)// 先检查前台位置权限if(ContextCompat.checkSelfPermission(activity,foregroundPermissions[0])!PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(activity,foregroundPermissions,REQUEST_CODE_LOCATION)}else{// 前台权限已获取申请后台位置权限Android 11if(Build.VERSION.SDK_INTBuild.VERSION_CODES.RContextCompat.checkSelfPermission(activity,Manifest.permission.ACCESS_BACKGROUND_LOCATION)!PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(activity,arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),REQUEST_CODE_LOCATION)}}}/** * 处理权限申请结果 */overridefunonRequestPermissionsResult(requestCode:Int,permissions:ArrayoutString,grantResults:IntArray){super.onRequestPermissionsResult(requestCode,permissions,grantResults)if(requestCodeREQUEST_CODE_LOCATION){if(grantResults.isNotEmpty()grantResults[0]PackageManager.PERMISSION_GRANTED){// 权限已授予if(Build.VERSION.SDK_INTBuild.VERSION_CODES.Rpermissions.contains(Manifest.permission.ACCESS_BACKGROUND_LOCATION)){// 后台位置权限处理}}else{// 权限被拒绝引导用户到设置页开启if(!ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[0])){valintentIntent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply{dataUri.parse(package:$packageName)}startActivity(intent)}}}}四、包可见性适配1. 变更说明Android 11 限制应用查询设备上其他应用的信息需在AndroidManifest.xml中声明需要访问的应用包名或意图。2. 适配方案1声明可见应用清单文件queries!-- 允许查询特定包名的应用 --packageandroid:namecom.example.targetapp/!-- 允许查询支持特定意图的应用 --intentactionandroid:nameandroid.intent.action.VIEW/dataandroid:schemehttp//intent!-- 允许查询所有已安装应用仅特殊场景使用 --packageandroid:nameandroidx.core.content.pm.PackageManagerCompat//queries2查询应用是否安装Kotlin/** * 检查应用是否安装Android 11适配 */funisAppInstalled(context:Context,packageName:String):Boolean{returntry{if(Build.VERSION.SDK_INTBuild.VERSION_CODES.TIRAMISU){context.packageManager.getPackageInfo(packageName,PackageManager.PackageInfoFlags.of(0))}else{Suppress(DEPRECATION)context.packageManager.getPackageInfo(packageName,0)}true}catch(e:PackageManager.NameNotFoundException){false}}五、前台服务适配1. 变更说明Android 11 要求前台服务必须指定类型如location、mediaPlayback等且禁止后台应用启动前台服务特殊场景需申请SYSTEM_ALERT_WINDOW权限。2. 适配代码1清单声明前台服务类型serviceandroid:name.MyForegroundServiceandroid:foregroundServiceTypelocation|mediaPlaybackintent-filteractionandroid:namecom.example.MyForegroundService//intent-filter/service2启动前台服务Kotlin/** * 启动前台服务Android 11适配 */funstartForegroundService(context:Context){valserviceIntentIntent(context,MyForegroundService::class.java)if(Build.VERSION.SDK_INTBuild.VERSION_CODES.O){context.startForegroundService(serviceIntent)}else{context.startService(serviceIntent)}}// 服务内部实现classMyForegroundService:Service(){privatevalNOTIFICATION_ID1001privatevalCHANNEL_IDForegroundServiceChanneloverridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{createNotificationChannel()valnotificationNotificationCompat.Builder(this,CHANNEL_ID).setContentTitle(前台服务标题).setContentText(前台服务内容).setSmallIcon(R.drawable.ic_notification).build()// Android 11需指定服务类型if(Build.VERSION.SDK_INTBuild.VERSION_CODES.R){startForeground(NOTIFICATION_ID,notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)}else{startForeground(NOTIFICATION_ID,notification)}// 业务逻辑处理returnSTART_STICKY}privatefuncreateNotificationChannel(){if(Build.VERSION.SDK_INTBuild.VERSION_CODES.O){valchannelNotificationChannel(CHANNEL_ID,前台服务通道,NotificationManager.IMPORTANCE_DEFAULT)valmanagergetSystemService(NotificationManager::class.java)manager.createNotificationChannel(channel)}}overridefunonBind(intent:Intent):IBinder?null}六、其他适配要点1. 权限对话框「仅本次」选项处理Android 11 新增「仅本次」权限授权选项需处理权限临时授权的场景/** * 检查权限是否为临时授权仅本次 */funisPermissionTemporaryGranted(activity:Activity,permission:String):Boolean{returnif(Build.VERSION.SDK_INTBuild.VERSION_CODES.R){ActivityCompat.checkSelfPermission(activity,permission)PackageManager.PERMISSION_GRANTED!ActivityCompat.shouldShowRequestPermissionRationale(activity,permission)}else{false}}2. 悬浮窗权限适配/** * 检查悬浮窗权限 */funhasOverlayPermission(context:Context):Boolean{returnif(Build.VERSION.SDK_INTBuild.VERSION_CODES.M){Settings.canDrawOverlays(context)}else{true}}/** * 申请悬浮窗权限 */funrequestOverlayPermission(activity:Activity,requestCode:Int){if(Build.VERSION.SDK_INTBuild.VERSION_CODES.M!Settings.canDrawOverlays(activity)){valintentIntent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply{dataUri.parse(package:${activity.packageName})}activity.startActivityForResult(intent,requestCode)}}七、适配建议分阶段适配先兼容 Android 11 核心变更存储、位置再处理次要特性测试覆盖在 Android 11 真机/模拟器上测试重点验证权限申请、文件操作、后台服务兼容低版本使用Build.VERSION.SDK_INT做版本判断保证低版本正常运行避免滥用权限MANAGE_EXTERNAL_STORAGE仅在必要时申请优先使用分区存储 API遵循官方规范定期查看 Android 11 官方适配文档 跟进最新变更。八、参考资源安卓11官方文档安卓11行为变更以上适配方案覆盖 Android 11 核心变更点可根据项目实际需求调整代码逻辑。