都把權限寫完了,該來做個小整理,這次我們整合Android 6到Android 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 6到Android 11執行,拍照後會在Pictures/應用程式名稱資料夾中建立檔案,雖然應用程式移除後照片還是會留在手機中,但也符合官方建議。