Android 版本特性完全解析:从6.0到16.0的实用指南

前言:为什么要了解每个版本特性?​

作为 Android 开发者,我们经常遇到这样的问题:

  • "这个 API 为什么需要特定版本?"

  • "这个特性到底解决了什么实际问题?"

  • "我应该在什么场景下使用它?"

本文将深入解析每个 Android 版本的核心特性,告诉你它们是什么为什么需要 以及怎么用


一、Android 6.0 (API 23) - 用户隐私觉醒

特性1:运行时权限 (Runtime Permissions)​

是什么 ​:应用在运行时向用户请求权限,而不是在安装时一次性授予所有权限。

为什么要用​:

  • 用户可控:用户可以按需授予权限,用哪个功能给哪个权限

  • 透明化:用户清楚知道应用什么时候需要什么权限

  • 安全:恶意应用无法在用户不知情时获取敏感权限

实际用法​:

复制代码
// 传统方式(已废弃):安装时一次性获得所有权限
// 新方式:使用时按需请求

class CameraActivity : AppCompatActivity() {
    // 步骤1:检查是否已有权限
    private fun checkCameraPermission(): Boolean {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == 
               PackageManager.PERMISSION_GRANTED
    }
    
    // 步骤2:请求权限
    private fun requestCameraPermission() {
        ActivityCompat.requestPermissions(
            this, 
            arrayOf(Manifest.permission.CAMERA), 
            REQUEST_CODE_CAMERA
        )
    }
    
    // 步骤3:处理用户选择
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        if (requestCode == REQUEST_CODE_CAMERA && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 用户同意了,可以打开相机
            openCamera()
        } else {
            // 用户拒绝了,显示解释或禁用功能
            showPermissionDeniedMessage()
        }
    }
    
    fun openCamera() {
        if (checkCameraPermission()) {
            // 有权限,直接打开相机
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            startActivityForResult(intent, REQUEST_CAMERA)
        } else {
            // 没有权限,先请求权限
            requestCameraPermission()
        }
    }
}

现实场景​:微信扫码支付时,只有当你点击"扫码"时才请求相机权限,而不是安装时就要求相机权限。


二、Android 7.0 (API 24) - 多任务处理进化

特性1:多窗口模式 (Multi-Window)​

是什么​:允许两个应用同时在一个屏幕上运行,分为分屏、画中画、自由窗口三种模式。

为什么要用​:

  • 提升效率:用户可以边看视频边回消息

  • 更好的用户体验:应用需要适配不同尺寸和比例

实际用法​:

复制代码
class VideoPlayerActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 声明支持多窗口
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 启用画中画模式
            if (!isInPictureInPictureMode) {
                // 配置多窗口属性
                enterPictureInPictureModeIfSupported()
            }
        }
    }
    
    // 处理配置变化(窗口尺寸改变时调用)
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        
        // 根据新配置重新布局
        when {
            isInMultiWindowMode -> layoutForMultiWindow()
            isInPictureInPictureMode -> layoutForPipMode()
            else -> layoutForFullScreen()
        }
    }
    
    private fun layoutForPipMode() {
        // 画中画模式:简化UI,只保留核心内容
        binding.controlPanel.visibility = View.GONE
        binding.videoView.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
    }
    
    private fun layoutForMultiWindow() {
        // 分屏模式:适配窄屏布局
        binding.controlPanel.visibility = View.VISIBLE
        binding.videoView.layoutParams.height = resources.getDimensionPixelSize(R.dimen.multi_window_height)
    }
}

现实场景​:YouTube 视频在切换到其他应用时自动进入画中画模式,让你可以边看视频边做其他事情。


三、Android 8.0 (API 26) - 通知与后台管理

特性1:通知渠道 (Notification Channels)​

是什么​:将通知按类别分组,用户可以对不同类别的通知进行精细化管理。

为什么要用​:

  • 用户可控:用户可以关闭营销通知但保留重要消息

  • 分类明确:不同用途的通知分开管理

  • 提升体验:减少无关通知对用户的打扰

实际用法​:

复制代码
class NotificationManager {
    
    fun setupNotificationChannels() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 创建重要消息渠道(高优先级)
            val importantChannel = NotificationChannel(
                "important_messages", // 渠道ID
                "重要消息",           // 用户看到的名称
                NotificationManager.IMPORTANCE_HIGH // 高重要性(有声音和弹出)
            ).apply {
                description = "订单状态、支付提醒等重要消息"
                enableLights(true)
                lightColor = Color.RED
            }
            
            // 创建营销消息渠道(低优先级)
            val promotionChannel = NotificationChannel(
                "promotions",
                "促销活动",
                NotificationManager.IMPORTANCE_LOW // 低重要性(只在通知栏显示)
            ).apply {
                description = "优惠活动、新品推荐等消息"
            }
            
            // 注册渠道
            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannels(listOf(importantChannel, promotionChannel))
        }
    }
    
    fun sendOrderNotification(orderId: String) {
        // 使用重要消息渠道发送通知
        val notification = NotificationCompat.Builder(this, "important_messages")
            .setContentTitle("订单更新")
            .setContentText("订单 $orderId 已发货")
            .setSmallIcon(R.drawable.ic_shipping)
            .setAutoCancel(true)
            .build()
            
        NotificationManagerCompat.from(this).notify(orderId.hashCode(), notification)
    }
    
    fun sendPromotionNotification() {
        // 使用营销渠道发送通知
        val notification = NotificationCompat.Builder(this, "promotions")
            .setContentTitle("限时优惠")
            .setContentText("全场商品8折优惠")
            .setSmallIcon(R.drawable.ic_promotion)
            .setAutoCancel(true)
            .build()
            
        NotificationManagerCompat.from(this).notify("promotion".hashCode(), notification)
    }
}

现实场景​:淘宝App中,订单物流通知会响铃提醒,而商品推荐通知只静默显示在通知栏。


四、Android 10 (API 29) - 隐私保护重大升级

特性1:分区存储 (Scoped Storage)​

是什么​:应用只能访问自己的专属目录和特定类型的公共文件(如照片、音乐),不能随意访问整个存储空间。

为什么要用​:

  • 隐私保护:防止应用偷偷读取用户的私人文件

  • 数据安全:每个应用的数据相互隔离

  • 文件管理:用户清楚知道每个应用存储了什么

实际用法​:

复制代码
class FileManager {
    
    // 错误做法:直接访问任意路径(Android 10+ 已禁止)
    fun saveFileWrongWay(): Boolean {
        // 这行代码在 Android 10+ 会报错!
        val file = File("/sdcard/Download/myfile.txt")
        return file.writeText("hello")
    }
    
    // 正确做法:使用 MediaStore API
    fun saveImageToGallery(bitmap: Bitmap): Boolean {
        val contentValues = ContentValues().apply {
            // 文件信息
            put(MediaStore.Images.Media.DISPLAY_NAME, "my_photo_${System.currentTimeMillis()}.jpg")
            put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
            put(MediaStore.Images.Media.IS_PENDING, 1) // 标记为处理中
        }
        
        // 获取图片集合的URI
        val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
        } else {
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        }
        
        // 插入新图片记录
        val uri = contentResolver.insert(collection, contentValues) ?: return false
        
        return try {
            // 写入图片数据
            contentResolver.openOutputStream(uri).use { outputStream ->
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
            }
            
            // 标记为完成
            contentValues.clear()
            contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
            contentResolver.update(uri, contentValues, null, null)
            
            true
        } catch (e: Exception) {
            // 失败时删除记录
            contentResolver.delete(uri, null, null)
            false
        }
    }
    
    // 读取图片(需要权限)
    fun loadImagesFromGallery(): List<Bitmap> {
        val images = mutableListOf<Bitmap>()
        
        val projection = arrayOf(MediaStore.Images.Media._ID)
        val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
        
        contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection,
            null,
            null,
            sortOrder
        )?.use { cursor ->
            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
            
            while (cursor.moveToNext()) {
                val id = cursor.getLong(idColumn)
                val contentUri = ContentUris.withAppendedId(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id
                )
                
                try {
                    contentResolver.openInputStream(contentUri)?.use { inputStream ->
                        BitmapFactory.decodeStream(inputStream)?.let { bitmap ->
                            images.add(bitmap)
                        }
                    }
                } catch (e: SecurityException) {
                    // 没有权限访问这个文件
                    Log.w("FileManager", "No permission to access image: $contentUri")
                }
            }
        }
        
        return images
    }
}

现实场景​:微信保存图片到相册时,使用系统提供的保存接口,而不是直接往SD卡写文件。


五、Android 12 (API 31) - 用户体验革新

特性1:Material You 动态色彩

是什么​:系统从壁纸中提取颜色主题,并应用到所有支持的应用上。

为什么要用​:

  • 个性化:每个用户的手机都有独特的色彩主题

  • 一致性:所有应用保持统一的视觉风格

  • 沉浸感:应用与系统界面完美融合

实际用法​:

复制代码
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 应用动态色彩主题
        applyDynamicColors()
        
        setContentView(R.layout.activity_main)
    }
    
    private fun applyDynamicColors() {
        // Android 12+ 支持动态色彩
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            // 使用动态色彩主题
            setTheme(R.style.Theme_MyApp_Dynamic)
            
            // 监听动态色彩变化
            val dynamicColors = DynamicColors()
            dynamicColors.applyIfAvailable(this)
        } else {
            // 旧版本使用静态主题
            setTheme(R.style.Theme_MyApp_Static)
        }
    }
}

// styles.xml 中的主题配置
<!-- 动态色彩主题(Android 12+) -->
<style name="Theme.MyApp.Dynamic" parent="Theme.Material3.DynamicColors.DayNight">
    <!-- 系统会自动应用动态色彩 -->
</style>

<!-- 静态主题(Android 11及以下) -->
<style name="Theme.MyApp.Static" parent="Theme.MaterialComponents.DayNight">
    <item name="colorPrimary">@color/static_primary</item>
    <item name="colorSecondary">@color/static_secondary</item>
    <item name="colorSurface">@color/static_surface</item>
</style>

现实场景​:当用户更换手机壁纸时,Google 应用、Messages 等系统应用的颜色会自动匹配壁纸色调。


六、Android 13 (API 33) - 精细化权限控制

特性1:通知权限 (POST_NOTIFICATIONS)​

是什么​:应用发送通知需要用户显式授权,而不仅仅是创建通知渠道。

为什么要用​:

  • 用户控制:用户可以完全阻止某个应用发送任何通知

  • 减少骚扰:避免应用滥用通知功能

  • 透明化:用户清楚知道哪个应用想要发送通知

实际用法​:

复制代码
class NotificationPermissionHelper {
    
    fun checkAndRequestNotificationPermission(activity: Activity) {
        // Android 13+ 需要单独的通知权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            when {
                // 已经有权限
                isNotificationPermissionGranted(activity) -> {
                    setupNotificationChannels()
                    startNotificationService()
                }
                // 应该显示解释
                shouldShowRequestPermissionRationale(activity) -> {
                    showPermissionExplanation(activity) {
                        requestNotificationPermission(activity)
                    }
                }
                // 第一次请求
                else -> {
                    requestNotificationPermission(activity)
                }
            }
        } else {
            // Android 12及以下不需要单独权限
            setupNotificationChannels()
            startNotificationService()
        }
    }
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    private fun isNotificationPermissionGranted(context: Context): Boolean {
        return NotificationManagerCompat.from(context).areNotificationsEnabled()
    }
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    private fun requestNotificationPermission(activity: Activity) {
        val requestPermissionLauncher = activity.registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted ->
            if (isGranted) {
                // 用户允许通知,设置渠道并启动服务
                setupNotificationChannels()
                startNotificationService()
            } else {
                // 用户拒绝通知,禁用相关功能
                disableNotificationFeatures()
                showNotificationDisabledMessage()
            }
        }
        
        requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
    }
    
    private fun showPermissionExplanation(activity: Activity, onContinue: () -> Unit) {
        AlertDialog.Builder(activity)
            .setTitle("需要通知权限")
            .setMessage("为了及时向您推送订单状态、物流信息等重要消息,需要您允许通知权限。")
            .setPositiveButton("允许") { _, _ -> onContinue() }
            .setNegativeButton("拒绝", null)
            .show()
    }
}

现实场景​:新安装的银行App第一次启动时,会弹窗解释为什么需要通知权限(交易提醒、安全通知等),然后请求授权。


七、Android 14 (API 34) - 国际化与可访问性

特性1:语法性别支持 (Grammatical Gender)​

是什么​:根据语言语法性别(阳性、阴性、中性)显示不同的文本格式。

为什么要用​:

  • 语言准确性:在某些语言中,形容词、动词需要与主语性别一致

  • 本地化质量:提升非英语用户的体验

  • 文化适配:尊重不同语言的语法规则

实际用法​:

复制代码
class InternationalizationHelper {
    
    fun getLocalizedMessage(context: Context, userName: String, productCount: Int): String {
        val resources = context.resources
        val configuration = resources.configuration
        
        // Android 14+ 支持语法性别
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            when (configuration.grammaticalGender) {
                Configuration.GRAMMATICAL_GENDER_FEMININE -> {
                    resources.getQuantityString(R.plurals.message_female, productCount, userName, productCount)
                }
                Configuration.GRAMMATICAL_GENDER_MASCULINE -> {
                    resources.getQuantityString(R.plurals.message_male, productCount, userName, productCount)
                }
                Configuration.GRAMMATICAL_GENDER_NEUTER -> {
                    resources.getQuantityString(R.plurals.message_neuter, productCount, userName, productCount)
                }
                else -> {
                    resources.getQuantityString(R.plurals.message_unknown, productCount, userName, productCount)
                }
            }
        } else {
            // 旧版本使用通用格式
            resources.getQuantityString(R.plurals.message_generic, productCount, userName, productCount)
        }
    }
}

// strings.xml 中的多性别支持
<resources>
    <!-- 阴性(如法语、西班牙语中的女性用户) -->
    <plurals name="message_female">
        <item quantity="one">%1$s a acheté un produit. Elle est satisfaite.</item>
        <item quantity="other">%1$s a acheté %2$d produits. Elle est satisfaite.</item>
    </plurals>
    
    <!-- 阳性(男性用户) -->
    <plurals name="message_male">
        <item quantity="one">%1$s a acheté un produit. Il est satisfait.</item>
        <item quantity="other">%1$s a acheté %2$d produits. Il est satisfait.</item>
    </plurals>
    
    <!-- 中性(英语等不需要性别的语言) -->
    <plurals name="message_neuter">
        <item quantity="one">%1$s bought one product. They are satisfied.</item>
        <item quantity="other">%1$s bought %2$d products. They are satisfied.</item>
    </plurals>
</resources>

现实场景​:在法语中,如果用户是女性,需要说"Elle est satisfaite"(她满意),而男性则是"Il est satisfait"(他满意)。


八、Android 15+ - 未来特性展望

特性1:性能等级 API (Performance Class)​

是什么​:系统告诉应用当前设备的性能等级,应用可以根据设备能力调整功能。

为什么要用​:

  • 性能优化:低端设备使用简化功能,高端设备使用高级功能

  • 省电:避免在低端设备上运行耗电的功能

  • 体验适配:不同设备提供最适合的体验

实际用法​:

复制代码
class PerformanceOptimizer {
    
    fun optimizeForDevice(context: Context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            val performanceManager = context.getSystemService(Context.PERFORMANCE_SERVICE) as PerformanceManager
            val performanceClass = performanceManager.performanceLevel
            
            when (performanceClass) {
                PerformanceManager.PERFORMANCE_LEVEL_LOW -> {
                    // 低端设备:启用简化模式
                    enableLiteMode()
                    disableHeavyAnimations()
                    useLowResolutionAssets()
                }
                PerformanceManager.PERFORMANCE_LEVEL_MEDIUM -> {
                    // 中端设备:平衡模式
                    enableStandardFeatures()
                    useMediumAnimations()
                }
                PerformanceManager.PERFORMANCE_LEVEL_HIGH -> {
                    // 高端设备:全功能模式
                    enableAllFeatures()
                    useHighEndGraphics()
                    enableAIFeatures()
                }
                else -> {
                    // 未知设备:使用默认配置
                    enableStandardFeatures()
                }
            }
        } else {
            // 旧版本:基于内存和CPU手动检测
            optimizeManually()
        }
    }
    
    private fun enableLiteMode() {
        // 简化UI,减少动画,使用缓存策略
        binding.animationsEnabled = false
        binding.imageQuality = ImageQuality.LOW
        CacheStrategy.enableAggressiveCaching()
    }
    
    private fun enableAllFeatures() {
        // 启用所有高级功能
        binding.animationsEnabled = true
        binding.imageQuality = ImageQuality.HIGH
        AIManager.enableRealtimeProcessing()
    }
}

现实场景​:游戏在高性能手机上开启120帧模式和高级光影效果,在低端手机上锁定30帧并降低画质。


总结:Android 版本演进的核心逻辑

版本 核心目标 开发者需要做的
6.0 用户隐私控制 适配运行时权限请求
7.0 多任务效率 支持多窗口布局适配
8.0 通知管理 实现通知渠道分类
10 数据隐私 使用分区存储API
12 个性化体验 支持动态色彩主题
13 权限精细化 请求通知权限
14 国际化 适配语法性别
相关推荐
杨筱毅4 小时前
【底层机制】【Android】深入理解UI体系与绘制机制
android·底层机制
介一安全4 小时前
【Frida Android】基础篇8:Java层Hook基础——调用带对象参数的方法
android·网络安全·逆向·安全性测试·frida
puyaCheer4 小时前
Android 13 启动的时候会显示一下logo,很不友好
android·gitee
long_hai_d5 小时前
Aosp14桌面壁纸和锁屏壁纸的设置和加载分析
android
2501_916007476 小时前
iOS 26 软件性能测试 新版系统下评估全流程 + 多工具辅助方案
android·macos·ios·小程序·uni-app·cocoa·iphone
云霄IT6 小时前
绕过Frida检测反调试的一些办法
android·javascript
sang_xb7 小时前
Android 如何开启 16KB 模式
android·kotlin
alengan7 小时前
安卓上谷歌35版本
android
珹洺8 小时前
Java-Spring入门指南(二十五)Android 的历史,认识移动应用和Android 基础知识
android·java·spring