웹뷰에서 Android 갤러리 접근해서 사진 가져오기 (Kotlin/Android)

박진성·2023년 4월 16일
0
post-custom-banner

웹뷰에서 Android 갤러리 접근해서 사진 가져오기 (Kotlin/Android)

→ Step1 WebChromeClient 를 커스텀해서, onShowFileChooser 함수를 오버라이드한다

  • 웹에서 input type=”file” 하게되면 호출됨
class MyWebChromeClient(private val act: Activity, private val link: MainActivity.RoomToWebview) : WebChromeClient(){

    private val TAG = "debugging"

    override fun onShowFileChooser(
        webView: WebView?,
        filePathCallback: ValueCallback<Array<Uri>>?,
        fileChooserParams: FileChooserParams?
    ): Boolean {
        Log.d(TAG,"앨범에서 사진선택")
        link.gotoGallery(filePathCallback)
        Log.d(TAG,"종료")
        return true
    }
}

→ Step2 가장 먼저 filePathCallback 을 초기화 해준다!!! 필수

  • 참고로 mFilePathCallback 은 싱글톤에 선언된 ValueCallback<Array>? 형태의 변수이다. 초기화는 null 로 되어있는 상태
// 프로필 사진 변경 갤러리 접근
fun gotoGallery(filePathCallback : ValueCallback<Array<Uri>>?) {
    mFilePathCallback = filePathCallback
    onCheckProfilePermission()
}

→ Step3 그후 파일미디어 접근권한에 대한 체크 및 요청을 해준다

  • 권한 있으면 → 바로 openGallery() 함수 실행
  • 권한 없으면
    • 권한요청 모달 막혀있는 경우 → 설정탭으로 이동시킴 (gotoSettings)
    • 권한요청 모달 안막혀있는 경우 → 권한요청 모달 등장
// 프로필 사진 변경 권한 체크 & 로직

private fun onCheckProfilePermission(){
    // 권한 없을경우, 있을경우 분기처리
    if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
        Log.d(TAG,"권한없음. 권한요청")

        if(!ActivityCompat.shouldShowRequestPermissionRationale(this@MainActivity, Manifest.permission.READ_EXTERNAL_STORAGE)){
            showCustomToast("권한을 허용해주세요")
            gotoSettings("image")
        }else{
            ActivityCompat.requestPermissions(this@MainActivity,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE),
                RC_PROFILE_PERMISSION)
        }
    } else {
        Log.d(TAG,"권한있음. 갤러리 열기")
        openGallery()
    }
}
  • 권한요청에 대한 콜백

    • 권한 허용하기 누른경우 → openGallery() 호출
    • 권한 거부하기 누른경우 → 반드시!!!! mFilePathCallback?.onReceiveValue(null) 처리!!!!
  • mFilePathCallback?.onReceiveValue 를 null 값으로 주지 않으면, 다음번에 onShowFileChooser 가 진행중 상태로 남게되어 호출되지 않는다

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    
    if(requestCode == RC_PROFILE_PERMISSION){

        // 프로필이미지 권한설정 결과
        Log.d(TAG,"프로필 이미지 권한설정 결과")

        for(result in grantResults){
            if (result == PackageManager.PERMISSION_GRANTED){
                showCustomToast("권한이 허용되었습니다")
                openGallery()
                break
            }else{
                showCustomToast("권한이 허용되지 않았습니다")
                mFilePathCallback?.onReceiveValue(null)
                break
            }
        }
    }

}

→ Step4 openGallery() 함수로 갤러리 열기

  • 초기에 val galleryIntent = Intent(Intent.*ACTION_PICK*, MediaStore.Images.Media.*EXTERNAL_CONTENT_URI*) 가 아닌 val galleryIntent = Intent(Intent.*ACTION_PICK)* 으로 하였더니, 웹에서 반응하지 못하였다…. chat gpt 도움으로 해당 코드 수정함
  • Intent.ACTION_PICK : 갤러리로 바로 이동
    • 다른종류의 action intent 도 많이 있다. 알아보자
private fun openGallery(){
    // 갤러리 오픈 인텐트 지정
    val galleryIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
    // 갤러리 오픈. 반환코드 RC_GALLERY
    startActivityForResult(galleryIntent, RC_GALLERY)
}

→ Step5 갤러리 intent 의 콜백을 받아줄 onActivityResult 선언

  • 데이터 안에 있는 uri를 꺼내서,
  • 배열형태로 바꾼뒤 onReceiveValue 안에 넣어주면 끝!!
  • 당연히 else 일 경우 예외처리로 mFilePathCallback?.onReceiveValue(null) 수행
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if(requestCode == RC_GALLERY){
        // 갤러리 사진선택 결과
        Log.d(TAG,"$resultCode  $data")
        if (resultCode == Activity.RESULT_OK) {
            data?.data?.let { uri ->
                mFilePathCallback?.onReceiveValue(arrayOf(uri))
            }
        } else {
            mFilePathCallback?.onReceiveValue(null)
        }
        mFilePathCallback = null
    } else if(requestCode == RC_SETTINGS){
        mFilePathCallback?.onReceiveValue(null)
    }
}
profile
Android Developer
post-custom-banner

0개의 댓글