Android

WebView 파일 업로드

그란. 2022. 6. 14. 10:52

input type="file" 인 HTML 폼에 파일 업로드 하는 방법 및 추가적인 UI 설정

 

1. 파일 업로드

 

- Activity에 전역으로 ValueCallback<Array<Uri>> 변수 생성 

private var uploadMessage: ValueCallback<Array<Uri>>? = null

private val fileChooserCallback = 				//launch할 callback 설정
    registerForActivityResult(ActivityResultContracts.OpenDocument()) {
        if (it == null) {  						// 아무것도 선택하지 않았을때
            uploadMessage?.onReceiveValue(null)
            uploadMessage = null
            return@registerForActivityResult
        }
        try {
            uploadMessage?.onReceiveValue(arrayOf(it))
            uploadMessage = null
            Toast.makeText(this, "업로드 성공", Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            Toast.makeText(this, "업로드 실패", Toast.LENGTH_SHORT).show()
            e.printStackTrace()
        }
    }

 

webChromeClient = BodyWebChromeClient(this@WebViewActivity)

 

class BodyWebChromeClient(activity: WebViewActivity) : WebChromeClient() {
    private val activityRef = WeakReference(activity) 

    override fun onShowFileChooser(
        webView: WebView?,
        filePathCallback: ValueCallback<Array<Uri>>?,
        fileChooserParams: FileChooserParams?
    ): Boolean {
        val activity = activityRef.get() ?: return false
        fileChooserParams?.acceptTypes?.get(0)?.toString() ?: return false
        activity.checkPermission(filePathCallback)     //권한 검사 시작
        return true
    }
}

 

//TedPermission 이용 
private fun checkPermission(filePathCallback: ValueCallback<Array<Uri>>?) {
    TedPermission.Builder()
        .setPermissionListener(object : PermissionListener {
            override fun onPermissionGranted() {
                if (uploadMessage != null) {
                    uploadMessage?.onReceiveValue(null)
                }
                uploadMessage = filePathCallback
                fileChooserCallback.launch(arrayOf("*/*"))
            }

            override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
                Toast.makeText(this@WebViewActivity, "권한이 없습니다.", Toast.LENGTH_SHORT).show()
            }
        })
        .setDeniedMessage("이 권한이 없으면 이력서를 업로드할 수 없습니다.")
        .setPermissions(
            Manifest.permission.READ_EXTERNAL_STORAGE
        ).check()
}

 

 

포인트

it : Uri!  라고 되어있어 널체크가 필요없을것으로 생각했지만 nullable. 

아무것도 선택되지 않는 경우 null을 반환, 

 


2. 추가 UI 설정 

 

투박한 자바스크립트 팝업 대신 앱의 AlertDialog 로 override

override fun onJsConfirm(
    view: WebView?,
    url: String?,
    message: String?,
    result: JsResult?
): Boolean {
    val activity = activityRef.get() ?: return false
    BodyAlertDialog.Builder(activity.baseContext)
        .setMessage(message ?: "")
        .setPositiveButton("확인")
        .show()
    return true
}

 

 

로딩 처리

- 처음 로딩을 true 로 시작한다 

onPageCommitVisible : 페이지가 처음 보이면 로딩 off 

onPageStarted : 다른 페이지로 이동할때 로딩 on 

onPageFinished :  다른 페이지가 로드 되면 로딩 off 

override fun onPageCommitVisible(view: WebView?, url: String?) {
    super.onPageCommitVisible(view, url)
    setLoading(false)
}

override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
    super.onPageStarted(view, url, favicon)
    setLoading(true)
}

override fun onPageFinished(view: WebView?, url: String?) {
    setLoading(false)
    super.onPageFinished(view, url)
}

private fun setLoading(isLoad: Boolean) {
    val activity = activityRef.get() ?: return
    activity.viewDataBinding.pgbLoading.isGone = !isLoad
}