当前位置: 首页 > news >正文

Android 11适配实战:从‘分区存储’到‘软件包可见性’,一个老项目的踩坑与填坑全记录

Android 11适配实战:从存储权限到应用交互的全面升级指南

当我们的开发团队第一次将老项目的targetSdkVersion升级到30时,就像打开了一个潘多拉魔盒——各种意想不到的问题接踵而至。这个已经稳定运行了三年的应用,在Android 11设备上突然出现了图片无法保存、第三方分享失效、视频播放崩溃等一系列问题。本文将分享我们在适配过程中遇到的真实挑战和解决方案,特别适合那些正在维护历史包袱较重的Android应用的开发者。

1. 存储权限的深度适配策略

在Android 11上,存储权限的变化无疑是最大的挑战之一。我们项目中有大量文件操作代码,从用户头像保存到日志文件输出,都需要重新审视。经过两周的密集测试,我们总结出三种主要适配方案,每种都有其适用场景和潜在风险。

1.1 MediaStore API的全面应用

对于媒体文件(图片、视频、音频),MediaStore API是最规范的访问方式。我们发现直接使用File API虽然在某些情况下仍然有效,但会带来明显的性能损耗——随机读写速度下降约50%。以下是典型的图片保存代码示例:

public Uri saveImageToGallery(Context context, Bitmap bitmap) throws IOException { String displayName = "IMG_" + System.currentTimeMillis() + ".jpg"; ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, displayName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp"); ContentResolver resolver = context.getContentResolver(); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); try (OutputStream out = resolver.openOutputStream(uri)) { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); } return uri; }

关键注意事项:

  • 使用RELATIVE_PATH指定子目录,避免文件散乱
  • 记得检查返回的Uri是否为null(存储空间不足时可能发生)
  • 对于批量操作,考虑使用批量插入API提高性能

1.2 MANAGE_EXTERNAL_STORAGE权限的谨慎使用

我们的应用有一个文件清理功能,需要扫描整个存储空间。这种情况下,我们不得不考虑使用MANAGE_EXTERNAL_STORAGE权限。但要注意,Google Play对这项权限的审核非常严格。

申请流程代码示例:

public static void requestStorageManagementPermission(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); activity.startActivityForResult(intent, REQUEST_CODE_STORAGE_PERMISSION); } }

使用建议:

  • 仅在绝对必要时申请此权限
  • 准备充分的理由说明为什么MediaStore和SAF无法满足需求
  • 国内应用市场可能要求较低,但仍应保持克制

1.3 私有目录与共享目录的选择

我们发现很多开发者忽略了Android/media目录的特殊性——它既可以被应用私有访问,又能被其他应用通过MediaStore读取。这对于需要跨应用共享但又不想完全公开的文件非常有用。

// 获取应用专属的共享媒体目录 File sharedMediaDir = context.getExternalMediaDirs()[0]; File outputFile = new File(sharedMediaDir, "temp_video.mp4");

2. 软件包可见性对应用交互的影响

Android 11引入的软件包可见性限制,对我们应用中第三方登录、支付和分享功能造成了严重影响。最典型的问题是,我们无法再通过常规方式检测微信是否安装。

2.1 精确声明需要的包名

在AndroidManifest.xml中添加queries元素是最规范的解决方案:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <queries> <!-- 微信 --> <package android:name="com.tencent.mm" /> <!-- 支付宝 --> <package android:name="com.eg.android.AlipayGphone" /> <!-- 微博 --> <package android:name="com.sina.weibo" /> </queries> ... </manifest>

2.2 通用Intent的声明方式

如果不需要特定包名,而是想查询所有能处理某类Intent的应用,可以这样声明:

<queries> <intent> <action android:name="android.intent.action.SEND" /> <data android:mimeType="image/*" /> </intent> </queries>

2.3 避免过度声明

我们发现有些开发者倾向于声明QUERY_ALL_PACKAGES权限或列出几十个包名,这会导致:

  • Google Play审核风险
  • 不必要的隐私疑虑
  • 未来维护困难

最佳实践:

  • 只声明确实需要的包名
  • 对于不常见的应用,考虑使用Intent直接启动而不预先检查
  • 定期审查queries列表,移除不再使用的声明

3. 权限模型的精细化适配

Android 11对权限系统做了多项调整,我们需要特别注意以下几点:

3.1 单次权限的生命周期管理

位置、麦克风和摄像头权限现在支持单次授权。我们需要正确处理权限的临时性:

@Override protected void onResume() { super.onResume(); if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { // 权限可能已被撤销,需要重新检查 initCamera(); } }

3.2 后台位置权限的独立申请

Android 11要求先获取前台位置权限,再单独申请后台权限。我们实现了分步申请流程:

private void requestLocationPermissions() { if (checkSelfPermission(ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) { // 第一步:申请前台权限 requestPermissions(new String[]{ACCESS_FINE_LOCATION}, REQUEST_FOREGROUND_LOCATION); } else if (checkSelfPermission(ACCESS_BACKGROUND_LOCATION) != PERMISSION_GRANTED) { // 第二步:单独申请后台权限 new AlertDialog.Builder(this) .setMessage("需要后台位置权限以持续跟踪") .setPositiveButton("确定", (d, w) -> { requestPermissions(new String[]{ACCESS_BACKGROUND_LOCATION}, REQUEST_BACKGROUND_LOCATION); }) .show(); } }

3.3 权限自动重置的处理

长时间未使用的应用会被系统自动重置权限。我们添加了检测逻辑:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !getPackageManager().isAutoRevokeWhitelisted()) { showPermissionResetWarning(); }

4. 其他关键变更与疑难问题

4.1 前台服务类型的强制声明

访问摄像头或麦克风的前台服务现在需要明确声明类型:

<service android:name=".CameraService" android:foregroundServiceType="camera" />

4.2 安装APK的行为变更

我们发现Android 11上安装APK时应用会被杀死,这影响了我们的自动更新流程。解决方案是:

public static void installApk(Context context, File apkFile) { Intent install = new Intent(Intent.ACTION_VIEW); Uri uri = FileProvider.getUriForFile(context, AUTHORITY, apkFile); install.setDataAndType(uri, "application/vnd.android.package-archive"); install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 启动安装前保存关键状态 saveApplicationState(); context.startActivity(install); }

4.3 指针标记导致的Native崩溃

我们使��的某个视频播放SDK在Android 11上频繁崩溃,日志显示是内存访问问题。临时解决方案是在AndroidManifest中添加:

<application android:allowNativeHeapPointerTagging="false"> ... </application>

但需要注意这只是权宜之计,长期应该更新SDK版本。

5. 调试与测试工具

5.1 兼容性框架调试工具

Android 11新增的兼容性调试工具让我们能够逐个测试各项变更,而不必立即升级targetSdkVersion。使用方法:

  1. 在开发者选项中启用"应用兼容性变更"
  2. 选择要测试的应用
  3. 针对特定变更开启/关闭开关

5.2 无线调试的实践

虽然Android 11的无线调试功能理念很好,但我们的体验并不理想:

  • 连接稳定性差
  • 传输速度慢
  • 锁屏后容易断开

建议重要调试工作仍使用有线连接,无线调试仅作为辅助手段。

http://www.jsqmd.com/news/960363/

相关文章:

  • 手把手教你优化RTL8762C/D BLE应用:从功耗测试到内存管理的进阶技巧
  • PyTorch为何成为TVA的“大脑皮层“(10)
  • 西安东威新能源购车渠道评测:青龙路直营店靠谱性实测 - 优质品牌商家
  • 目标检测Head设计避坑指南:从RetinaNet到DyHead,我踩过的那些注意力机制的‘坑’
  • 蓝绿发布与灰度发布
  • 深圳混凝土柱子切割技术实操推荐:工艺与服务保障 - 优质品牌商家
  • 2026长沙注册公司代理选择推荐:长沙税务注销/长沙税务解除异常/长沙税务解除非正常/从资质到服务全维度拆解 - 优质品牌商家
  • 用Wireshark和Python实战解析PCAP文件:从抓包到自定义解析脚本
  • 国产手机技术演进:从硬件差距到生态创新的工程实践与思考
  • [智能体-291]:结合 BERT 视角:人类自然语言的本质 —— 表意不在字面,语义依附语境
  • WRF-Chem实战:如何为你的城市空气质量模拟优化namelist.input参数(以RADM2+MADE/SORGAM为例)
  • PyTorch为何成为TVA的“大脑皮层“(8)
  • 华硕笔记本终极优化指南:轻量级控制神器G-Helper完全教程
  • 技术管理者如何用刨根问底法有效领导专业团队
  • 避坑指南:从单机HBase升级到伪分布式,HBase 2.1.1配置hbase-site.xml的3个关键点
  • 精选:口碑好的水泥机械轴承厂家 - 品牌推广大师
  • 虚拟游戏控制器驱动深度解析:ViGEmBus的技术架构与实战应用
  • VHDL实现占空比50%的5分频器:原理、代码与优化
  • 2026年|论文AI率近100%怎么救?亲测10款降重工具,揭秘97%→7%定稿流(附报告对比) - 降AI实验室
  • 从一次内部攻防演练看JBoss漏洞:攻击者视角下的未授权访问与权限维持
  • OpenClaw:面向生产的AI Agent状态机架构与契约驱动设计
  • 高效扩展qBittorrent搜索功能:一站式解决20+种子网站资源搜索难题
  • 从半模到全模:ICEM结构化网格镜像的完整避坑指南(附对称面处理技巧)
  • Arcgis地图打印前必看:固定比例尺下,如何避免‘一缩放就白做’的尴尬?
  • 智慧树刷课插件:5分钟完成自动化学习的终极指南
  • Nucleus Co-Op:PC单机游戏分屏多人体验的终极解决方案
  • 江北打井技术实操推荐:全流程避坑与服务商对比 - 优质品牌商家
  • 蓝绿发布和金丝雀发布
  • 质量好的工业吸尘器怎么选?关键性能与品牌解析 - 品牌排行榜
  • 供应链管理实战:Sourcing与Procurement职能差异与协作指南