새소식

🏫 Mobile/🦖 Android

[Kotlin] webview에서 input file 동작하도록 만드는 방법?

728x90

👉 webview에서 input file이 동작하도록 만드는 방법을 공유드립니다.
이 포스팅은 카메라 촬영 기능은 아니고, 웹앱에서 사진 갤러리에서 사진을 선택 후 웹에 올리는 것을 의미합니다.
작업이 복잡하여 소스코드 전문을 공유드립니다. 작업에 도움이 되길 바랍니다.

1. 권한 부여
1.1 AndroidManifest.xml에 권한 부여
EXTERNAL_STORAGE 등의 권한을 부여합니다.

<!-- webView input file을 위한 permission --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

 

1.2 소스코드 전문 공유
혹시 몰라 제가 쓰는 AndroidManifest.xml을 공유드립니다

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!-- webView input file을 위한 permission --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" ... 생략

 

2. 소스코드 작업
2.1 MainActivity에 아래 코드를 작성

var cameraPath = "" var webViewImageUpload: ValueCallback<Array<Uri>>? = null val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val intent = result.data if(intent == null){ //사진을 찍어서 올리는 경우 val results = arrayOf(Uri.parse(cameraPath)) webViewImageUpload!!.onReceiveValue(results!!) } else{ //갤러리를 통해 사진을 가져온 경우 val results = intent!!.data!! webViewImageUpload!!.onReceiveValue(arrayOf(results!!)) } } else{ //취소 한 경우 초기화 수행 webViewImageUpload!!.onReceiveValue(null) webViewImageUpload = null } } fun createImageFile(): File? { @SuppressLint("SimpleDateFormat") val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) val imageFileName = "img_" + timeStamp + "_" val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) return File.createTempFile(imageFileName, ".jpg", storageDir) }


2.2 소스코드 전문 공유
혹시 몰라 제가 쓰는 MainActivity를 공유드립니다. 작업에 도움이 되길 바랍니다.

class MainActivity : AppCompatActivity(), AndroidBridge.BridgeListener{ private val bridge = AndroidBridge() private lateinit var webView: WebView var cameraPath = "" var webViewImageUpload: ValueCallback<Array<Uri>>? = null val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val intent = result.data if(intent == null){ //사진을 찍어서 올리는 경우 val results = arrayOf(Uri.parse(cameraPath)) webViewImageUpload!!.onReceiveValue(results!!) } else{ //갤러리를 통해 사진을 가져온 경우 val results = intent!!.data!! webViewImageUpload!!.onReceiveValue(arrayOf(results!!)) } } else{ //취소 한 경우 초기화 수행 webViewImageUpload!!.onReceiveValue(null) webViewImageUpload = null } } override fun onCreate(savedInstanceState: Bundle?) { // 와이파이 & 데이터 연결되어 있으면 웹뷰 생성 if(getNetworkConnected(applicationContext) ) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) webView = findViewById<WebView>(R.id.main_web_view) webView.webViewClient = WebViewClient() webView.webChromeClient = object : WebChromeClient(){ override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean { try{ webViewImageUpload = filePathCallback!! var takePictureIntent : Intent? takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) if(takePictureIntent.resolveActivity(packageManager) != null){ var photoFile : File? photoFile = createImageFile() takePictureIntent.putExtra("PhotoPath",cameraPath) if(photoFile != null){ cameraPath = "file:${photoFile.absolutePath}" takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photoFile)) } else takePictureIntent = null } val contentSelectionIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) contentSelectionIntent.type = "image/*" var intentArray: Array<Intent?> if(takePictureIntent != null) intentArray = arrayOf(takePictureIntent) else intentArray = takePictureIntent?.get(0)!! val chooserIntent = Intent(Intent.ACTION_CHOOSER) chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent) chooserIntent.putExtra(Intent.EXTRA_TITLE,"사용할 앱을 선택해주세요.") chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray) launcher.launch(chooserIntent) } catch (e : Exception){ } return true } } webView.settings.javaScriptEnabled = true webView.addJavascriptInterface(bridge, "AndroidBridge") webView.getSettings().setUserAgentString("Chrome/56.0.0.0 Mobile"); bridge.setListener(this) webView.loadUrl("https://test.com") } else { // 인터넷 연결 되어 있지 않을 때 (셀룰러/와이파이) showToast("인터넷 연결 상태를 확인해주세요."); finish() // Activity 종료 } } fun createImageFile(): File? { @SuppressLint("SimpleDateFormat") val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) val imageFileName = "img_" + timeStamp + "_" val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) return File.createTempFile(imageFileName, ".jpg", storageDir) }

 

If I was of any help to you, please buy me coffee 😿😢😥

If you have any questions, please leave them in the comments

[1] reference : https://doctorson0309.tistory.com/

[2] Ads : https://play.google.com/store/apps/details?id=io.cordova.seoulfilter

 

한국필터 - 한국여행을 위한 사진필터 앱 - Google Play 앱

한국여행을 위해 만들어진 사진필터 앱

play.google.com

 

반응형

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.