110/16 - 整合Android 6到Android 11

都把权限写完了,该来做个小整理,这次我们整合Android 6Android 11,没有Android 5是因为太老旧,是该淘汰,没有Android 12则是我没有实机可以测试。

版本名称 版号 上版日期 SDK版本 官方支援
Lollipop 5.0 – 5.1.1 2014年11月12日 21 - 22 不支援
Marshmallow 6.0 – 6.0.1 2015年10月05日 23 不支援
Nougat 7.0 – 7.1.2 2016年08月22日 24 - 25 不支援
Oreo 8.0 – 8.1 2017年08月21日 26 - 27 支援
Pie 9 2018年08月06日 28 支援
Q 10 2019年09月03日 29 支援
R 11 2020年09月08日 30 支援
S 12 2021年??月??日 31 支援

AndroidManifest.xml要记得新增权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

因为会重复呼叫,所以把拍照改成函式,主要是以Android 9为分水岭,Android 9以下才需要权限,Android 10以上就使用MediaStore,所以不用权限;符合官方规范所说,不要随便跟使用者要求权限

private fun startTakePicture() {
    
    var uri: Uri? = null
    
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
        val permissionList = arrayOf(
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE
        )
        
        if (!EasyPermissions.hasPermissions(this, *permissionList)) {
            EasyPermissions.requestPermissions(
                this,
                "请提供读写档案权限",
                BaseConstants.READ_WRITE_PERMISSIONS,
                *permissionList
            )
            return
        }
        
        if (!isCreateFolder(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES))) {
            Log.d("maho", "资料夹建立失败")
            return
        }
        
        val phoneFile = File(  
        Environment.getExternalStoragePublicDirectory("${Environment.DIRECTORY_PICTURES}/AndroidSystem"),
            "004.jpg"
        )
        
        uri = getPictureUri(phoneFile)
    }
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val contentValue = ContentValues().apply {
            this.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "004.jpg")
            this.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
            this.put(
                MediaStore.Images.ImageColumns.RELATIVE_PATH,
                "${Environment.DIRECTORY_PICTURES}/AndroidSystem"
                )
            )
        }
        
        uri = contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentValue
        )
    }
    
    createVersionCheckResultLauncher.launch(uri)
}

是点击的部份

aclMbCreateVersionCheckPicture.setOnClickListener {
    startTakePicture()
}

使用者同意权限的部份

override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
    if (BaseConstants.READ_WRITE_PERMISSIONS == requestCode) {
        startTakePicture()
    }
}

启动器的部份

private val createVersionCheckResultLauncher =
    registerForActivityResult(ActivityResultContracts.TakePicture()) { isTakePicture ->
        
        if (!isTakePicture) {
            Log.d("maho", "拍照建立档案失败")
            return@registerForActivityResult
        }
        
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
            val phoneFile = File(                Environment.getExternalStoragePublicDirectory("${Environment.DIRECTORY_PICTURES}/AndroidSystem"),
                "004.jpg"
            )
            
            MediaScannerConnection.scanFile(this, arrayOf(phoneFile.toString()), null) { _, _ ->
            }
            
            aclIvVersionCheckPicture.setImageURI(getPictureUri(phoneFile))
        }
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val selection = "${MediaStore.Images.ImageColumns.DISPLAY_NAME} = '004.jpg'"
            val orderBy = "${MediaStore.Images.ImageColumns.DATE_ADDED} DESC"
            
            val uriQuery = contentResolver.query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null,
                selection,
                null,
                orderBy
            ) ?: return@registerForActivityResult
            
            uriQuery.moveToFirst()
            
            val pictureId =
                uriQuery.getLong(uriQuery.getColumnIndex(MediaStore.Images.ImageColumns._ID))
                
            val uri = ContentUris.withAppendedId(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                pictureId
            )
            
            MediaScannerConnection.scanFile(this, arrayOf(uri.toString()), null) { _, _ ->
            }
            
            aclIvVersionCheckPicture.setImageURI(uri)
        }
    }

这样的话,就能顺利的在Andoird 6Android 11执行,拍照後会在Pictures/应用程序名称资料夹中建立档案,虽然应用程序移除後照片还是会留在手机中,但也符合官方建议。


<<:  【Day16】TestBench 的撰写技巧

>>:  Re: 新手让网页 act 起来: Day16 - 探索 useState (2)

初学者跪着学JavaScript Day24 : 原型不会,但你还有class

一日客语:中文:蛋 客语:唇 ES6语法 是constructor function 一种语法糖 函...

【JavaScript】检查Array阵列的各种方式

本篇搭配 LeetCode 1.Two Sum 题目: Given an array of inte...

小结

惯例在最後一天做个总结啦,不过回头看第一天条列的内容清单,发现还漏掉一个建构周期任务的介绍没写到,没...

GKE (二)

GKE 应用 经过昨天说的建立GKE想必应该已经有了自己的丛集了,那如何在GCP上去使用GKE呢?可...

Day 17:今天来部署你的 Angular 应用程序吧!

昨天我们已经将制作好的版型,套用到 Angular 的根元件 AppComponent,今天,我们就...