새소식

mobile/🦖 Android

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

728x90

🔥 Question

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

🧙 Answer

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

🧭 References

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

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

 

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

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

play.google.com

 

반응형
Contents

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

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