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