一张表看懂 Android 8-15 所有适配要点

11 阅读6分钟

一张表看懂 Android 8-15 所有适配要点

Android 系统每年发布一个新版本,每个版本都有行为变更和新的限制。本文以表格形式汇总 Android 8 到 Android 15 所有需要适配的核心要点,方便开发者快速查阅。建议收藏,新版本发布后会持续更新。


一、快速查阅总表

Android 版本API发布年份必须适配的核心变更适配优先级
8.0 Oreo262017通知渠道、后台执行限制中(旧设备)
9.0 Pie282018Apache HTTP 移除、前台服务权限中(旧设备)
10 Q292019分区存储、后台启动 Activity 限制高(大量设备)
11 R302020包可见性、单次权限
12 S312021SplashScreen API、PendingIntent 可变性
13 Tiramisu332022通知权限、精细化媒体权限
14 Upside Down Cake342023前台服务类型、广播注册导出声明
15 Vanilla Ice Cream352024Edge-to-Edge、16KB 页面、前台服务超时高(Google Play 强制)

二、Android 8.0(API 26)适配要点

变更影响适配方案
通知渠道(Notification Channel)targetSdk ≥ 26 必须创建渠道才能显示通知使用 NotificationChannel 创建渠道
后台执行限制对后台应用限制 Service 和 Broadcast改用 JobIntentServiceWorkManager
安装 APK 需要权限安装 APK 需要 REQUEST_INSTALL_PACKAGES 权限在 Manifest 中声明权限,并引导用户授权
透明 Activity 限制不允许透明主题的全屏 Activity移除透明主题或改为 Dialog 样式

代码示例:创建通知渠道

// Android 8.0+ 必须创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "default_channel_id",
        "默认通知渠道",
        NotificationManager.IMPORTANCE_DEFAULT
    ).apply {
        description = "默认渠道描述"
    }
    val notificationManager = getSystemService(NotificationManager::class.java)
    notificationManager.createNotificationChannel(channel)
}

三、Android 9.0(API 28)适配要点

变更影响适配方案
Apache HTTP 客户端移除使用了 org.apache.http 的应用会崩溃在 Manifest 中添加 useLibrary 'org.apache.http.legacy'
前台服务需要权限启动前台服务需要 FOREGROUND_SERVICE 权限在 Manifest 中声明权限
刘海屏适配需要适配 DisplayCutout使用 WindowInsets.getDisplayCutout()
HTTPS 网络请求限制默认禁止明文流量(HTTP)创建 res/xml/network_security_config.xml 允许明文流量,或全量迁移到 HTTPS

代码示例:允许明文流量(仅调试环境)

<!-- res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </domain-config>
</network-security-config>

<!-- AndroidManifest.xml 中 application 标签添加 -->
android:networkSecurityConfig="@xml/network_security_config"

四、Android 10(API 29)适配要点

变更影响适配方案
Scoped Storage(分区存储)外部存储访问受限使用 MediaStore 访问媒体文件
后台启动 Activity 限制不能直接从后台启动 Activity使用通知引导用户点击,或申请 SYSTEM_ALERT_WINDOW 权限
深色模式(Dark Mode)系统级深色模式适配 DayNight 主题
手势导航适配需要处理 Window Insets使用 ViewCompat.setOnApplyWindowInsetsListener

代码示例:兼容深色模式

// styles.xml(日间主题)
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primaryDark</item>
</style>

// colors.xml 中提供日间和夜间两套颜色
// values/colors.xml → 日间颜色
// values-night/colors.xml → 夜间颜色

五、Android 11(API 30)适配要点

变更影响适配方案
包可见性(Package Visibility)查询其他应用需要声明 <queries>在 Manifest 中添加 <queries> 元素
单次权限(One-time Permission)位置、麦克风、摄像头支持单次授权无需额外适配,系统自动处理
权限对话框频繁请求限制用户在短时间内拒绝两次后,第三次不再弹出对话框引导用户到设置页面授权
前台服务类型需要指定前台服务类型(Android 14 强制)提前声明 foregroundServiceType

代码示例:声明包可见性

<!-- 查询所有已安装应用(需要权限) -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

<!-- 或精确声明需要查询的应用 -->
<queries>
    <package android:name="com.example.targetapp" />
    <intent>
        <action android:name="android.intent.action.SEND" />
    </intent>
</queries>

六、Android 12(API 31)适配要点

变更影响适配方案
SplashScreen API统一启动页规范使用 SplashScreen 兼容库
PendingIntent 必须声明可变性不声明会崩溃显式指定 FLAG_MUTABLEFLAG_IMMUTABLE
前台服务通知延迟前台服务启动后通知会延迟显示无需适配,了解行为变化即可
蓝牙权限细化旧蓝牙权限废弃使用 BLUETOOTH_SCAN / BLUETOOTH_CONNECT
精确闹钟权限需要 SCHEDULE_EXACT_ALARM 权限请求权限或使用非精确闹钟

代码示例:PendingIntent 可变性

val pendingIntent = PendingIntent.getActivity(
    context,
    requestCode,
    intent,
    // ✅ 必须显式指定可变性
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

代码示例:SplashScreen 适配

// 在 Activity 的 onCreate 中
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // Android 12+ 的 SplashScreen API
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val splashScreen = installSplashScreen()
        // 保持启动页,直到应用准备好
        splashScreen.setKeepOnScreenCondition { !isAppReady }
    }
    
    setContentView(R.layout.activity_main)
}

七、Android 13(API 33)适配要点

变更影响适配方案
通知权限需要动态申请 POST_NOTIFICATIONS 权限使用 requestPermissionLauncher 请求权限
精细化媒体权限READ_EXTERNAL_STORAGE 拆分为三个权限使用 READ_MEDIA_IMAGES 等权限
Wi-Fi 权限变更靠近 Wi-Fi 设备不需要位置权限使用 NEARBY_WIFI_DEVICES 权限
Clipboard 内容隐藏敏感内容可以隐藏在剪贴板中使用 ClipDescription.EXTRA_IS_SENSITIVE

代码示例:请求通知权限

private val requestPermissionLauncher =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        if (isGranted) {
            showNotification()
        } else {
            // 引导用户到设置页面开启
        }
    }

fun checkNotificationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.POST_NOTIFICATIONS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }
}

八、Android 14(API 34)适配要点

变更影响适配方案
前台服务类型必须声明Manifest 中必须指定 foregroundServiceType<service> 标签中添加 android:foregroundServiceType
动态广播注册必须指定导出行为registerReceiver() 必须传 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED显式指定导出行为
OpenJDK 17 行为变更正则表达式、UUID 生成等行为变化回归测试核心逻辑
更严格的 Intent 过滤规则Intent 过滤器必须显式声明 exported在 Manifest 中显式声明

代码示例:注册广播(Android 14+ 兼容)

val filter = IntentFilter("com.example.MY_ACTION")

// 接收其他应用的广播 → 需要导出
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    context.registerReceiver(myReceiver, filter, Context.RECEIVER_EXPORTED)
} else {
    context.registerReceiver(myReceiver, filter)
}

// 只接收应用内部广播 → 不导出(更安全)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    context.registerReceiver(myReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
}

九、Android 15(API 35)适配要点

变更影响适配方案
Edge-to-Edge 强制适配应用显示区域扩展至全屏使用 WindowInsets 处理系统栏间距
16KB 页面大小使用 NDK 的应用需要适配升级 AGP 到 8.3+,重新编译 so 库
前台服务超时限制dataSync/mediaProcessing 类型有 24 小时时长限制改用 WorkManager 或处理 onTimeout 回调
最低 targetSdk 要求targetSdk < 24 无法安装升级 targetSdkVersion 到 24+
OpenJDK 17 对齐字符串格式化等行为变更避免使用 %0$s 等不合规格式

代码示例:Edge-to-Edge 适配(非 Compose)

ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.root)) { v, insets ->
    val statusBar = insets.getInsets(WindowInsetsCompat.Type.statusBars())
    val navigationBar = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
    
    v.setPadding(
        navigationBar.left,
        statusBar.top,
        navigationBar.right,
        navigationBar.bottom
    )
    
    insets
}

十、Gradle 配置建议(2026 年推荐)

// app/build.gradle
android {
    compileSdk 35
    
    defaultConfig {
        minSdk 21        // 覆盖 99%+ 设备
        targetSdk 35      // 紧跟最新版本
        multiDexEnabled true
    }
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    
    kotlinOptions {
        jvmTarget = '17'
    }
}

dependencies {
    implementation "androidx.core:core-ktx:1.13.0"
    implementation "androidx.activity:activity-ktx:1.9.0"
    implementation "androidx.fragment:fragment-ktx:1.7.0"
}

十一、适配优先级建议

根据应用的目标用户和业务需求,按以下优先级进行适配:

优先级版本理由
P0(立即适配)Android 15Google Play 强制要求
P0(立即适配)Android 13通知权限影响消息到达
P1(3 个月内)Android 14前台服务类型、广播注册
P1(3 个月内)Android 12PendingIntent 可变性(安全)
P2(6 个月内)Android 10/11分区存储、包可见性
P3(按需适配)Android 8/9存量设备较少

十二、参考资源


本文会持续更新,建议收藏。如果你发现某个版本的适配要点有遗漏,欢迎在评论区补充。如果本文对你有帮助,欢迎点赞收藏。