Ini merupakan catatanku setelah beberapa jam mencari cara untuk upload file di Webview menggunakan kotlin akhirnya bisa juga. Kode yang aku share di sini hanya untuk handling pemilihan file saja. Tidak termasuk kodingan untuk upload di sisi server. Untuk kodingan upload file di sisi server mungkin bisa melihat tutorial Cara Upload Gambar Menggunakan Ajax dan PHP.
Permasalahan
Ketika kita menggunakan WebView di sebuah aplikasi android untuk menampilkan form yang di dalamnya terdapat input type file maka kita tidak bisa memilih file yang akan diupload. Aku tidak tahu apakah itu merupakah bug dari WebView atau memang disengaja dibuat seperti itu dengan alasan keamanan.
Solusi
Kita harus membuat handling khusus menggunakan WebChromeClient() agar Webview yang kita gunakan bisa digunakan untuk memilih file yang akan diupload. Setelah file tersebut dipilih, selanjutnya diparse kedalam WebView lagi melalui onActivityResult() .
Membuat Handling Pemilihan File
Kode di bawah ini digunakan untuk mengahdel pemilihan file pada webview.
//deklarasikan ini sebagai variabel global var uploadMessage:ValueCallback<Array<Uri>>? = null private val FILECHOOSER_RESULTCODE = 1 val REQUEST_SELECT_FILE = 100 //setup webChromeClient() mWebView?.webChromeClient = object:WebChromeClient() { override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean { Log.d("alert", message) val dialogBuilder = AlertDialog.Builder(requireContext()) dialogBuilder.setMessage(message) .setCancelable(false) .setPositiveButton("OK") { _, _ -> result.confirm() } val alert = dialogBuilder.create() alert.show() return true } // For 3.0+ Devices (Start) // onActivityResult attached before constructor fun openFileChooser(uploadMsg : ValueCallback<Uri>, acceptType:String) { mUploadMessage = uploadMsg val i = Intent(Intent.ACTION_GET_CONTENT) i.addCategory(Intent.CATEGORY_OPENABLE) i.type = "*/*" startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE) } // For Lollipop 5.0+ Devices override fun onShowFileChooser(mWebView:WebView, filePathCallback:ValueCallback<Array<Uri>>, fileChooserParams:WebChromeClient.FileChooserParams):Boolean { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ if (uploadMessage != null) { uploadMessage?.onReceiveValue(null) uploadMessage = null } uploadMessage = filePathCallback val intent = fileChooserParams.createIntent() try { startActivityForResult(intent, REQUEST_SELECT_FILE) } catch (e: ActivityNotFoundException) { uploadMessage = null Toast.makeText(requireContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show() return false } return true }else{ return false } } //For Android 4.1 only fun openFileChooser(uploadMsg:ValueCallback<Uri>, acceptType:String, capture:String) { mUploadMessage = uploadMsg val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "*/*" startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE) } fun openFileChooser(uploadMsg:ValueCallback<Uri>) { //filePermission() mUploadMessage = uploadMsg val i = Intent(Intent.ACTION_GET_CONTENT) i.addCategory(Intent.CATEGORY_OPENABLE) i.type = "*/*" startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE) } }
Parse Hasil Pemilihan File Kedalam WebView
Kode untuk memarse hasil pemilihan file kedalam Webview adalah sebagai berikut:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if(requestCode == REQUEST_SELECT_FILE){ if(uploadMessage != null){ uploadMessage?.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode,data)) uploadMessage = null } } }else if(requestCode == FILECHOOSER_RESULTCODE){ if(mUploadMessage!=null){ var result = data?.data mUploadMessage?.onReceiveValue(result) mUploadMessage = null } }else{ Toast.makeText(requireContext(),"Failed to open file uploader, please check app permissions.",Toast.LENGTH_LONG).show() super.onActivityResult(requestCode, resultCode, data) } }