반응형
안드로이드 카메라 촬영 Android10과 그 이하
1)Android 10 이상은 외부저장소 경로를 가져올수가 없다.
그래서 MediaStore를 이용하여 Media저장을 해야한다. 권한은 카메라만 있어도 저장됨.
2)Android 10 미만은 외부저장소를 사용 할 수 있으니 외부저장소에 생성하여 저장.
권한은 카메라, 외부저장소(Read, Write)필요.
-문제: 처음에 1)방법으로 해보았는데 Andrid9(갤럭시8)에서 사진촬영 후 uri에 값이 null임, intent.data에 uri들어있음
사진 촬영된 것도 조그만한 이미지로 잡혀서 실제 사용을 못할 정도(섬네일 사진을 가져오는듯)
-찾은방법: 2)방법을 사용하면서 FileProvider를 이용해 파일공유를 해주어 원본을 가져오는 법
2-1) res/xml 폴더에 path 정의
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="storage/emulated" path="."/>
</paths>
2-2) AndroidManifest에 FileProvider 정의
<!-- Android 10미만 카메라 사진촬영 후 원본 파일 가져오는 공유 Provider -->
<provider
android:authorities="com.smadian.ainanny.provider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
tools:replace="android:resource"
android:resource="@xml/filepaths"/>
</provider>
===여기서 tools:replace="android:authorities" 와 tools:replace="android:resource" 는
내 프로젝트에서 TedPermission라이브러리를 쓰고있는데 build시 provider가 중복으로 되어있어서 추가해줌.
//팝업창 띄우기
AlertDialog.Builder(requireContext())
.setItems(R.array.photoSelect){ _, which ->
when(which){
0->{
//촬영하기
cameraShoot()
}
1->{
//사진첩에서 가져오기
Intent().apply {
type = "image/*"
action = Intent.ACTION_GET_CONTENT
startActivityForResult(this, Constants.REQUEST_PHOTOBOOK_IMPORT)
}
}
2->{
//기본 이미지
babyRegistMethodVM.babyImageUrl.value = ""
}
}
}
.show()
/**
* 사진 촬영 하기
*/
private fun cameraShoot(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//Android 10 이상
PermissionUtil.requestTedPermission(Manifest.permission.CAMERA)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { permissionResult ->
if (permissionResult.isGranted) {
val values = ContentValues().apply {
val fileName = "${Constants.FILE_PHOTO_NAME}${SystemClock.currentThreadTimeMillis()}.jpg"
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpg")
//추가 경로를 설정
put(MediaStore.Images.Media.RELATIVE_PATH, Constants.FILE_SAVE_FOLDER)
//IS_PENDING 속성을 1로 해주는 것은 파일을 write할 때 까지 다른 곳에서 사용 못하게 하는 것입니다.
//파일을 모두 write 할때 이 속성을 0으로 update 해주어야 합니다.
//현 포스팅은 카메라 예제로 외부에서 수정할 수 있어야 하므로 0으로 설정하거나 따로 처리 하지 않습니다.
//1로 되어 있으면 카메라로 찍은 이미지가 저장되지 않습니다.
//0으로 되어 있으면 카메라로 찍은 이미지가 저장 됩니다.
put(MediaStore.Images.Media.IS_PENDING, 0)
}
//권한 없이도 진행 가능 합니다.
//경로 -> content://media/external/images/media/84
babyRegistMethodVM.contentUri = activity?.contentResolver?.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
putExtra(MediaStore.EXTRA_OUTPUT, babyRegistMethodVM.contentUri)
startActivityForResult(this, Constants.REQUEST_PHOTO_SHOOT)
}
}
}
}else{
//10 미만 , 내부 저장소 권한을 줘야 파일 저장됨.
PermissionUtil.requestTedPermission(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { permissionResult ->
if (permissionResult.isGranted) {
try {
val dirPath: String = Environment.getExternalStorageDirectory().absolutePath.toString() + "/" + Constants.FILE_SAVE_FOLDER
val dir = File(dirPath)
if (!dir.exists()) {
dir.mkdir()
}
val filePathData = File.createTempFile(Constants.FILE_PHOTO_NAME, ".jpg", dir)
if (!filePathData.exists()) {
filePathData.createNewFile()
}
babyRegistMethodVM.contentUri = FileProvider.getUriForFile(requireContext(), requireContext().packageName+".provider", filePathData)
Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
putExtra(MediaStore.EXTRA_OUTPUT, babyRegistMethodVM.contentUri)
startActivityForResult(this, Constants.REQUEST_PHOTO_SHOOT)
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}
}
}
//결과 값 받아서 처리
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
Constants.REQUEST_PHOTO_SHOOT->{
if(resultCode != Activity.RESULT_OK){
//만약 카메라를 사용해 사진을 찍지 않고 뒤로 가게 되면 생성한 uri를 제거해 주어야 합니다.
//그렇게 하지 않으면 검은 화면의 빈 파일이 갤러리에 존재하게 됩니다.
babyRegistMethodVM.contentUri?.let {
activity?.contentResolver?.delete(it, null, null)
babyRegistMethodVM.contentUri = null
return
}
}
babyRegistMethodVM.contentUri?.let {
startCropImageActivity(it)
}
}
Constants.REQUEST_PHOTOBOOK_IMPORT->{
//사진앨범
if(resultCode != Activity.RESULT_OK) return
data?.let {
it.data?.let {uri->
startCropImageActivity(uri)
}
}
}
CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE->{
//Crop한후에 데이터
val result = CropImage.getActivityResult(data)
if(resultCode == Activity.RESULT_OK){
babyRegistMethodVM.contentUri = null
babyRegistMethodVM.babyImageUrl.value = result.uri.toString()
LogUtil.e(tag, "=========${result.uri}")
}else if(resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE){
babyRegistMethodVM.contentUri = null
LogUtil.e(tag, result.error)
}
}
}
}
반응형
'안드로이드 > SDK version' 카테고리의 다른 글
[Android] OS 14 USE_FULL_SCREEN_INTENT 권한 & ForegroundServiceType (0) | 2024.06.24 |
---|---|
Android 12이상 Notification & BroadCastReceiver, Service StartActivity문제 (0) | 2024.03.20 |
registerForActivityResult가 onResume보다 늦게 호출이 되는 문제 (0) | 2023.01.11 |
[Android] Notification 오레오 대응 (0) | 2022.10.27 |
[Android] Android12에서 File에 대한 직렬화(Serialization) 문제 (0) | 2022.08.03 |