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
반응형
'mobile > 🦖 Android' 카테고리의 다른 글
[Kotlin] 웹뷰에서 사이트 404 접속 체크하는 방법 (0) | 2024.06.30 |
---|---|
[Kotlin, android] webview에서 Alert가 안되는 오류 해결 방법 (0) | 2023.02.24 |
[Kotlin, android] webview google OAuth 403 오류 해결방법 (0) | 2023.02.24 |
[5분 내로] Android Emulator Hypervisor Driver for AMD 오류 해결하는 방법 (0) | 2023.02.20 |
코틀린 webview에서 자바스크립트 동작이 안되는 경우 (0) | 2021.04.30 |
Contents
소중한 공감 감사합니다