news 2026/8/7 17:47:30

Android11 新特性与适配指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android11 新特性与适配指南

Android 11(API 30)引入了多项重要特性和权限变更,核心集中在存储权限、后台位置、包可见性、前台服务等方面。本文基于 Kotlin 语言,从核心变更点、适配方案、代码示例等维度讲解适配要点。

一、核心变更概览

变更类别核心影响适配优先级
存储权限废弃WRITE_EXTERNAL_STORAGE,引入分区存储强制启用
后台位置权限单独申请ACCESS_BACKGROUND_LOCATION,需用户显式授权
包可见性应用默认无法查询其他应用,需在清单声明可见范围
前台服务限制新增类型限制,后台启动前台服务需特殊权限
权限对话框优化新增「仅本次」选项,权限授权逻辑变更
悬浮窗权限SYSTEM_ALERT_WINDOW权限申请流程变更

二、分区存储适配(最核心)

1. 变更说明

Android 11 强制启用分区存储(Scoped Storage),应用只能访问:

  • 应用私有目录(/Android/data/包名/):无需权限
  • 媒体文件(图片/音频/视频):通过 MediaStore API 访问
  • 下载文件:通过DownloadManager或存储访问框架(SAF)

2. 适配方案

(1)基础配置(清单文件)
<!-- 保留旧权限(兼容低版本),但Android 11不再生效 --><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28"/><!-- Android 11访问媒体文件仅需读权限 --><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><!-- 如需批量修改/删除媒体文件,需申请此权限 --><uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"tools:ignore="ScopedStorage"/><!-- 可选:临时关闭分区存储(仅过渡用,不推荐) --><applicationandroid:requestLegacyExternalStorage="true"android:targetSdkVersion="30"></application>
(2)读取媒体文件(Kotlin)

通过 MediaStore 查询图片示例:

/** * 读取设备中的图片文件 */funqueryImages(context:Context):List<Uri>{valimageUris=mutableListOf<Uri>()valprojection=arrayOf(MediaStore.Images.Media._ID,MediaStore.Images.Media.DISPLAY_NAME,MediaStore.Images.Media.DATE_ADDED)// 按添加时间倒序查询valsortOrder="${MediaStore.Images.Media.DATE_ADDED}DESC"context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,projection,null,null,sortOrder)?.use{cursor->validColumn=cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)while(cursor.moveToNext()){valid=cursor.getLong(idColumn)valuri=ContentUris.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?{valcontentValues=ContentValues().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_INT>=Build.VERSION_CODES.Q){put(MediaStore.Images.Media.IS_PENDING,1)// 标记为待处理}}valcontentUri=MediaStore.Images.Media.EXTERNAL_CONTENT_URIvaruri:Uri?=nulltry{uri=context.contentResolver.insert(contentUri,contentValues)uri?.let{context.contentResolver.openOutputStream(it)?.use{outputStream->bitmap.compress(Bitmap.CompressFormat.JPEG,90,outputStream)}if(Build.VERSION.SDK_INT>=Build.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_INT>=Build.VERSION_CODES.R){Environment.isExternalStorageManager()}else{true}}/** * 申请管理所有文件的权限 */funrequestManageExternalStoragePermission(activity:Activity){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R&&!Environment.isExternalStorageManager()){valintent=Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply{data=Uri.parse("package:${activity.packageName}")}activity.startActivityForResult(intent,REQUEST_CODE_MANAGE_STORAGE)}}

三、后台位置权限适配

1. 变更说明

Android 11 要求后台位置权限需单独申请,且必须先获得前台位置权限(ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION)。

2. 适配代码

(1)清单声明
<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"/><uses-permissionandroid:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
(2)权限申请逻辑
// 权限请求码privateconstvalREQUEST_CODE_LOCATION=1001/** * 检查并申请位置权限 */funcheckAndRequestLocationPermission(activity:Activity){valforegroundPermissions=arrayOf(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 11+)if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R&&ContextCompat.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:Array<outString>,grantResults:IntArray){super.onRequestPermissionsResult(requestCode,permissions,grantResults)if(requestCode==REQUEST_CODE_LOCATION){if(grantResults.isNotEmpty()&&grantResults[0]==PackageManager.PERMISSION_GRANTED){// 权限已授予if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R&&permissions.contains(Manifest.permission.ACCESS_BACKGROUND_LOCATION)){// 后台位置权限处理}}else{// 权限被拒绝,引导用户到设置页开启if(!ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[0])){valintent=Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply{data=Uri.parse("package:$packageName")}startActivity(intent)}}}}

四、包可见性适配

1. 变更说明

Android 11 限制应用查询设备上其他应用的信息,需在AndroidManifest.xml中声明需要访问的应用包名或意图。

2. 适配方案

(1)声明可见应用(清单文件)
<queries><!-- 允许查询特定包名的应用 --><packageandroid:name="com.example.targetapp"/><!-- 允许查询支持特定意图的应用 --><intent><actionandroid:name="android.intent.action.VIEW"/><dataandroid:scheme="http"/></intent><!-- 允许查询所有已安装应用(仅特殊场景使用) --><packageandroid:name="androidx.core.content.pm.PackageManagerCompat"/></queries>
(2)查询应用是否安装(Kotlin)
/** * 检查应用是否安装(Android 11+适配) */funisAppInstalled(context:Context,packageName:String):Boolean{returntry{if(Build.VERSION.SDK_INT>=Build.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 要求前台服务必须指定类型(如locationmediaPlayback等),且禁止后台应用启动前台服务(特殊场景需申请SYSTEM_ALERT_WINDOW权限)。

2. 适配代码

(1)清单声明前台服务类型
<serviceandroid:name=".MyForegroundService"android:foregroundServiceType="location|mediaPlayback"><intent-filter><actionandroid:name="com.example.MyForegroundService"/></intent-filter></service>
(2)启动前台服务(Kotlin)
/** * 启动前台服务(Android 11+适配) */funstartForegroundService(context:Context){valserviceIntent=Intent(context,MyForegroundService::class.java)if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){context.startForegroundService(serviceIntent)}else{context.startService(serviceIntent)}}// 服务内部实现classMyForegroundService:Service(){privatevalNOTIFICATION_ID=1001privatevalCHANNEL_ID="ForegroundServiceChannel"overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{createNotificationChannel()valnotification=NotificationCompat.Builder(this,CHANNEL_ID).setContentTitle("前台服务标题").setContentText("前台服务内容").setSmallIcon(R.drawable.ic_notification).build()// Android 11+需指定服务类型if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){startForeground(NOTIFICATION_ID,notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)}else{startForeground(NOTIFICATION_ID,notification)}// 业务逻辑处理returnSTART_STICKY}privatefuncreateNotificationChannel(){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){valchannel=NotificationChannel(CHANNEL_ID,"前台服务通道",NotificationManager.IMPORTANCE_DEFAULT)valmanager=getSystemService(NotificationManager::class.java)manager.createNotificationChannel(channel)}}overridefunonBind(intent:Intent):IBinder?=null}

六、其他适配要点

1. 权限对话框「仅本次」选项处理

Android 11 新增「仅本次」权限授权选项,需处理权限临时授权的场景:

/** * 检查权限是否为临时授权(仅本次) */funisPermissionTemporaryGranted(activity:Activity,permission:String):Boolean{returnif(Build.VERSION.SDK_INT>=Build.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_INT>=Build.VERSION_CODES.M){Settings.canDrawOverlays(context)}else{true}}/** * 申请悬浮窗权限 */funrequestOverlayPermission(activity:Activity,requestCode:Int){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M&&!Settings.canDrawOverlays(activity)){valintent=Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply{data=Uri.parse("package:${activity.packageName}")}activity.startActivityForResult(intent,requestCode)}}

七、适配建议

  1. 分阶段适配:先兼容 Android 11 核心变更(存储、位置),再处理次要特性;
  2. 测试覆盖:在 Android 11 真机/模拟器上测试,重点验证权限申请、文件操作、后台服务;
  3. 兼容低版本:使用Build.VERSION.SDK_INT做版本判断,保证低版本正常运行;
  4. 避免滥用权限MANAGE_EXTERNAL_STORAGE仅在必要时申请,优先使用分区存储 API;
  5. 遵循官方规范:定期查看 Android 11 官方适配文档 跟进最新变更。

八、参考资源

  • 安卓11官方文档
  • 安卓11行为变更

以上适配方案覆盖 Android 11 核心变更点,可根据项目实际需求调整代码逻辑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 19:32:02

高端成果与需求端断层如何破局?区域科技创新体系可借助知识产权智能运营平台实现闭环的体系化竞争壁垒。

观点作者&#xff1a;科易网AI技术转移研究院在科技创新日益成为国家核心竞争力的今天&#xff0c;高校院所作为科技成果的重要源头&#xff0c;其成果转化效率直接影响着创新链与产业链的深度融合。然而&#xff0c;长期以来&#xff0c;“高端成果与需求端断层”问题一直是制…

作者头像 李华
网站建设 2026/8/7 15:45:24

技术转移机构如何借助生成式AI赋能工具重塑差异化服务优势?

观点作者&#xff1a;科易网AI技术转移研究院在当前科技成果转化领域&#xff0c;高校已成为创新成果的重要源头&#xff0c;但“不能转”“不敢转”“不会转”等问题依然制约着转化效率。为破除这些障碍&#xff0c;高校积极探索有组织科技成果转化路径&#xff0c;通过政策环…

作者头像 李华
网站建设 2026/8/7 3:26:15

57、SQL 网络与分布式数据库全解析

SQL 网络与分布式数据库全解析 1. 分布式数据库面临的挑战 在构建和管理分布式数据库时,会遇到一系列棘手的问题,这些问题涉及到数据兼容性、系统目录、混合供应商环境、分布式死锁以及恢复等多个方面。 - 数据兼容性 :不同的计算机系统支持不同的数据类型,即便提供相…

作者头像 李华
网站建设 2026/8/7 3:26:18

MeshLabelImageColor 读取医学标签图像数据(MetaImage 格式)

一&#xff1a;主要的知识点 1、说明 本文只是教程内容的一小段&#xff0c;因博客字数限制&#xff0c;故进行拆分。主教程链接&#xff1a;vtk教程——逐行解析官网所有Python示例-CSDN博客 2、知识点纪要 本段代码主要涉及的有①vtkColorTransferFunction颜色映射&#…

作者头像 李华
网站建设 2026/8/7 20:38:40

61、SQL 中的抽象数据类型与继承机制

SQL 中的抽象数据类型与继承机制 1. 操作 LOB 数据 在处理包含文档文本的大对象(LOB)数据时,我们可能需要检索包含 LOB 的行,并更新 LOB 数据中间的部分内容。以下是一个示例代码,展示了如何实现这一操作: declare lob CLOB; textbuf varchar(255); begin /* Put…

作者头像 李华
网站建设 2026/8/7 15:23:27

69、SQL 的现状与未来:专业数据库与市场趋势洞察

SQL 的现状与未来:专业数据库与市场趋势洞察 1. 事件处理与数据库连接 在当今的数据处理领域,企业数据库管理系统(DBMS)起着关键作用。企业 DBMS 链接能够让事件处理引擎将来自数据馈送的数据与从传统企业数据库中检索的数据进行合并。目前,所有主流产品都支持通过 JDBC…

作者头像 李华