웹 보기에서 파일 업로드
웹 뷰에서 파일을 업로드하는 데 어려움을 겪고 있습니다.제안된 모든 솔루션(예: 이 SO 게시물)을 구글에 검색하여 구현했지만 작동하지 않습니다.
나는 파일을 업로드하기 위해 다음과 같은 코드를 가진 HTML 페이지를 가지고 있습니다.
<form method="POST" enctype="multipart/form-data">
File to upload: <input type="file" name="uploadfile">
<input type="submit" value="Press to Upload..."> to upload the file!
</form>
파이어폭스와 같은 데스크톱 브라우저와 에뮬레이터 / AVD의 내장 브라우저에서 잘 작동합니다. 예를 들어, "Browse..요소별로 렌더링된 버튼을 누르면 브라우저에서 업로드할 파일을 선택할 수 있는 대화 상자가 열립니다.
그러나 Android 3.0 에뮬레이터/AVD에서 "파일 선택"을 클릭하면 아무 일도 일어나지 않고 파일 대화 상자도 열리지 않습니다!
이것은 모든 안드로이드 버전을 위한 완전한 솔루션입니다, 저도 이것 때문에 힘들었어요.
public class MyWb extends Activity {
/** Called when the activity is first created. */
WebView web;
ProgressBar progressBar;
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE=1;
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if(requestCode==FILECHOOSER_RESULTCODE)
{
if (null == mUploadMessage) return;
Uri result = intent == null || resultCode != RESULT_OK ? null
: intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
web = (WebView) findViewById(R.id.webview01);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
web = new WebView(this);
web.getSettings().setJavaScriptEnabled(true);
web.loadUrl("http://www.script-tutorials.com/demos/199/index.html");
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(new WebChromeClient()
{
//The undocumented magic method override
//Eclipse will swear at you if you try to put @Override here
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MyWb.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MyWb.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE);
}
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MyWb.this.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MyWb.FILECHOOSER_RESULTCODE );
}
});
setContentView(web);
}
public class myWebClient extends WebViewClient
{
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
progressBar.setVisibility(View.GONE);
}
}
//flipscreen not loading again
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
// To handle "Back" key press event for WebView to go back to previous screen.
/*@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}*/
}
또한 이 예시와 같은 "업로드 페이지"는 이미지 미리보기 기능이 있기 때문에 미리보기 없이 간단한 php 업로드를 사용하고 싶다면 <4 버전>에서는 작동하지 않는다는 것을 추가하고 싶습니다.
업데이트:
여기에서 막대사탕 장치에 대한 솔루션을 찾으십시오. 그리고 뻔뻔스럽게 대해 주셔서 감사합니다.
업데이트 2:
지금까지 모든 안드로이드 기기를 위한 완벽한 솔루션이며 이것은 더 발전된 버전입니다. 당신은 그것을 조사해야 합니다. 아마도 도움이 될 것입니다.
허니콤(API 11)에서 안드로이드 11로의 작업 방법
스와티쉬노이에 의해 업데이트된 대로, 이것은 파이 이상에서도 작동합니다.
static WebView mWebView;
private ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> uploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;
onActivityResult()
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
if (requestCode == REQUEST_SELECT_FILE)
{
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
uploadMessage = null;
}
}
else if (requestCode == FILECHOOSER_RESULTCODE)
{
if (null == mUploadMessage)
return;
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
else
Toast.makeText(getActivity().getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
}
지은금에서onCreate()
또는onCreateView()
.
WebSettings mWebSettings = mWebView.getSettings();
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setSupportZoom(false);
mWebSettings.setAllowFileAccess(true);
mWebSettings.setAllowContentAccess(true);
mWebView.setWebChromeClient(new WebChromeClient()
{
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
}
// For Lollipop 5.0+ Devices
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
{
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try
{
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e)
{
uploadMessage = null;
Toast.makeText(getActivity().getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
//For Android 4.1 only
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
{
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
}
protected void openFileChooser(ValueCallback<Uri> uploadMsg)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
});
이것이 제가 찾은 유일한 해결책입니다!
WebView webview;
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return;
Uri result = intent == null || resultCode != RESULT_OK ? null
: intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
// Next part
class MyWebChromeClient extends WebChromeClient {
// The undocumented magic method override
// Eclipse will swear at you if you try to put @Override here
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
Cv5appActivity.this.startActivityForResult(
Intent.createChooser(i, "Image Browser"),
FILECHOOSER_RESULTCODE);
}
}
5.0 롤리팝에서 구글은 공식적인 방법인 WebChromeClient.를 ShowFileChooser에 추가했습니다.파일 선택 도구는 입력 허용 마임 유형을 사용하도록 파일 선택 도구를 자동으로 생성하는 방법도 제공합니다.
public class MyWebChromeClient extends WebChromeClient {
// reference to activity instance. May be unnecessary if your web chrome client is member class.
private MyActivity activity;
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// make sure there is no existing message
if (myActivity.uploadMessage != null) {
myActivity.uploadMessage.onReceiveValue(null);
myActivity.uploadMessage = null;
}
myActivity.uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
myActivity.uploadMessage = null;
Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
}
public class MyActivity extends ... {
public static final int REQUEST_SELECT_FILE = 100;
public ValueCallback<Uri[]> uploadMessage;
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null) return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
uploadMessage = null;
}
}
}
}
KitKat 이전의 Android 버전의 경우, 다른 답변에서 언급한 개인적인 방법이 작동합니다.KitKat(4.4)에 대한 좋은 해결 방법을 찾지 못했습니다.
저는 다양한 버전의 안드로이드를 처리하기 위해 3개의 인터페이스 정의가 필요하다는 것을 알게 되었습니다.
public void openFileChooser(ValueCallback < Uri > uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE);
}
public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType) {
openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg);
}
이 솔루션은 허니콤과 아이스크림 샌드위치에도 효과가 있습니다.구글이 멋진 새 기능(속성 허용)을 도입하고 하위 호환성을 위해 과부하를 구현하는 것을 잊은 것 같습니다.
protected class CustomWebChromeClient extends WebChromeClient
{
// For Android 3.0+
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType )
{
context.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
context.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MainActivity.FILECHOOSER_RESULTCODE );
}
// For Android < 3.0
public void openFileChooser( ValueCallback<Uri> uploadMsg )
{
openFileChooser( uploadMsg, "" );
}
}
하이파러의 완전한 해결책은 저에게 매우 도움이 됩니다.
하지만 다른 마임 유형 지원, 캡처 장치(카메라, 비디오, 오디오 레코더) 나열, 캡처 장치 즉시 열기(예: <input accept="image/*;message") 등 많은 문제를 만났습니다.
그래서 저는 기본 웹 브라우저 앱과 똑같이 작동하는 솔루션을 만들었습니다.
안드로이드-4.4.3_r1/src/com/안드로이드/브라우저/UploadHandler.java를 사용했습니다. (루퍼트 랜슬리 덕분에)
package org.mospi.agatenativewebview;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView) findViewById(R.id.webView1);
initWebView(webView);
webView.loadUrl("http://google.com"); // TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
webView.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
// Android 4.4, 4.4.1, 4.4.2
// openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2,
// you may use your own java script interface or other hybrid framework.
// Android 5.0.1
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
String acceptTypes[] = fileChooserParams.getAcceptTypes();
String acceptType = "";
for (int i = 0; i < acceptTypes.length; ++ i) {
if (acceptTypes[i] != null && acceptTypes[i].length() != 0)
acceptType += acceptTypes[i] + ";";
}
if (acceptType.length() == 0)
acceptType = "*/*";
final ValueCallback<Uri[]> finalFilePathCallback = filePathCallback;
ValueCallback<Uri> vc = new ValueCallback<Uri>() {
@Override
public void onReceiveValue(Uri value) {
Uri[] result;
if (value != null)
result = new Uri[]{value};
else
result = null;
finalFilePathCallback.onReceiveValue(result);
}
};
openFileChooser(vc, acceptType, "filesystem");
return true;
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
웹 보기에서 파일 업로드 // import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
}
res/values/string.xml의 추가 문자열 리소스:
<string name="uploads_disabled">File uploads are disabled.</string>
<string name="choose_upload">Choose file for upload</string>
proguard를 사용하는 경우 proguard-project에서 아래 옵션이 필요할 수 있습니다.txt :
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
업데이트 #1 (2015.09.09)
Android 5.0.1 호환성을 위한 코드를 추가합니다.
Android 8용 Kotlin 솔루션:
private var mUploadMessage: ValueCallback<Uri>? = null
private var uploadMessage: ValueCallback<Array<Uri>>? = null
상수:
const val FILECHOOSER_RESULTCODE = 1
const val REQUEST_SELECT_FILE = 100
웹 보기 설정:
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest?) {
Log.d("MainActivity", "onPermissionRequest")
requestPermission(request)
}
// For Android 3.0+
fun openFileChooser(uploadMsg: ValueCallback<*>, acceptType: String) {
mUploadMessage = uploadMsg as ValueCallback<Uri>
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "*/*"
this@MainActivity.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE)
}
//For Android 4.1
fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
mUploadMessage = uploadMsg
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "image/*"
this@MainActivity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE)
}
protected fun openFileChooser(uploadMsg: ValueCallback<Uri>) {
mUploadMessage = uploadMsg
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE)
}
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
uploadMessage = filePathCallback
val intent = fileChooserParams!!.createIntent()
try {
startActivityForResult(intent, REQUEST_SELECT_FILE)
} catch (e: ActivityNotFoundException) {
uploadMessage = null
Toast.makeText(applicationContext, "Cannot Open File Chooser", Toast.LENGTH_LONG).show()
return false
}
return true
}
}
그리고 onActivityResult 파트:
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)
return
print("result code = " + resultCode)
var results: Array<Uri>? = WebChromeClient.FileChooserParams.parseResult(resultCode, data)
uploadMessage?.onReceiveValue(results)
uploadMessage = null
}
} else if (requestCode === FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
val result = if (intent == null || resultCode !== RESULT_OK) null else intent.data
mUploadMessage?.onReceiveValue(result)
mUploadMessage = null
} else
Toast.makeText(applicationContext, "Failed to Upload Image", Toast.LENGTH_LONG).show()
}
우리의 의도 변수가 "데이터"라는 것에 주목하십시오.
이것은 나를 위한 일입니다.또한 누가트와 마시멜로를 위해 일합니다.[
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int FCR = 1;
WebView webView;
private String mCM;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> mUMA;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (Build.VERSION.SDK_INT >= 21) {
Uri[] results = null;
//Check if response is positive
if (resultCode == Activity.RESULT_OK) {
if (requestCode == FCR) {
if (null == mUMA) {
return;
}
if (intent == null) {
//Capture Photo if no image available
if (mCM != null) {
results = new Uri[]{Uri.parse(mCM)};
}
} else {
String dataString = intent.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
}
}
mUMA.onReceiveValue(results);
mUMA = null;
} else {
if (requestCode == FCR) {
if (null == mUM) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUM.onReceiveValue(result);
mUM = null;
}
}
}
@SuppressLint({"SetJavaScriptEnabled", "WrongViewCast"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
}
webView = (WebView) findViewById(R.id.ifView);
assert webView != null;
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= 21) {
webSettings.setMixedContentMode(0);
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT < 19) {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.setWebViewClient(new Callback());
webView.loadUrl("https://infeeds.com/");
webView.setWebChromeClient(new WebChromeClient() {
//For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FCR);
}
// For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FCR);
}
//For Android 4.1+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FCR);
}
//For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
if (mUMA != null) {
mUMA.onReceiveValue(null);
}
mUMA = filePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCM);
} catch (IOException ex) {
Log.e(TAG, "Image file creation failed", ex);
}
if (photoFile != null) {
mCM = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
Intent[] intentArray;
if (takePictureIntent != null) {
intentArray = new Intent[]{takePictureIntent};
} else {
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, FCR);
return true;
}
});
}
// Create an image file
private File createImageFile() throws IOException {
@SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "img_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return File.createTempFile(imageFileName, ".jpg", storageDir);
}
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (webView.canGoBack()) {
webView.goBack();
} else {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
public class Callback extends WebViewClient {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(getApplicationContext(), "Failed loading app!", Toast.LENGTH_SHORT).show();
}
}
}
2019: 이 코드는 나에게 효과가 있었습니다 (Androids 5 - 9에서 테스트됨).
package com.example.filechooser;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends Activity {
// variables para manejar la subida de archivos
private final static int FILECHOOSER_RESULTCODE = 1;
private ValueCallback<Uri[]> mUploadMessage;
// variable para manejar el navegador empotrado
WebView mainWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// instanciamos el webview
mainWebView = findViewById(R.id.main_web_view);
// establecemos el cliente interno para que la navegacion no se salga de la aplicacion
mainWebView.setWebViewClient(new MyWebViewClient());
// establecemos el cliente chrome para seleccionar archivos
mainWebView.setWebChromeClient(new MyWebChromeClient());
// configuracion del webview
mainWebView.getSettings().setJavaScriptEnabled(true);
// cargamos la pagina
mainWebView.loadUrl("https://example.com");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// manejo de seleccion de archivo
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage || intent == null || resultCode != RESULT_OK) {
return;
}
Uri[] result = null;
String dataString = intent.getDataString();
if (dataString != null) {
result = new Uri[]{ Uri.parse(dataString) };
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
// ====================
// Web clients classes
// ====================
/**
* Clase para configurar el webview
*/
private class MyWebViewClient extends WebViewClient {
// permite la navegacion dentro del webview
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
/**
* Clase para configurar el chrome client para que nos permita seleccionar archivos
*/
private class MyWebChromeClient extends WebChromeClient {
// maneja la accion de seleccionar archivos
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// asegurar que no existan callbacks
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
}
mUploadMessage = filePathCallback;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*"); // set MIME type to filter
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FILECHOOSER_RESULTCODE );
return true;
}
}
}
희망이 당신을 도울 수 있습니다.
나는 정의할 필요가 있다고 생각했습니다.public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
Android 4.1에서 사용할 수 있습니다.그리고 미셸 올리비에의 해결책을 따랐습니다.
실제로 Kitkat에 파일 선택기를 표시하고, 이미지를 선택하고, 작업 결과에서 파일 경로를 가져올 수 있었지만, "수정"할 수 없는 유일한 방법은 입력을 파일 데이터로 채우도록 하는 것입니다.
활동에서 입력 필드에 액세스하는 방법을 아는 사람이 있습니까?이 예제 코멘트를 사용하고 있습니다.이 마지막 조각, 즉 벽에 있는 마지막 벽돌을 제자리에 놓아야만 하는 것입니까(코드에서 직접 이미지 파일 업로드를 트리거할 수 있습니다).
업데이트 #1
나는 하드코어 안드로이드 개발자가 아니기 때문에 초보자 수준의 코드를 보여드리겠습니다.이미 존재하는 활동에 새 활동을 작성하는 중
매니페스트 부분
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:label="TestApp">
<activity android:name=".BrowseActivity"></activity>
</application>
이 예제 답변에서 내 BrowseActivity 클래스를 만들고 있습니다.WebChromeClient() 인스턴스는 마지막 부분을 제외하고는 기본적으로 동일하게 보이며 선택 도구 UI 부분을 트리거합니다...
private final static int FILECHOOSER_RESULTCODE=1;
private final static int KITKAT_RESULTCODE = 2;
...
// The new WebChromeClient() looks pretty much the same, except one piece...
WebChromeClient chromeClient = new WebChromeClient(){
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) { /* Default code */ }
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) { /* Default code */ }
//For Android 4.1, also default but it'll be as example
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.FILECHOOSER_RESULTCODE);
}
// The new code
public void showPicker( ValueCallback<Uri> uploadMsg ){
// Here is part of the issue, the uploadMsg is null since it is not triggered from Android
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.KITKAT_RESULTCODE);
}}
그리고 다른 것들.
web = new WebView(this);
// Notice this part, setting chromeClient as js interface is just lazy
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(chromeClient, "jsi" );
web.getSettings().setAllowFileAccess(true);
web.getSettings().setAllowContentAccess(true);
web.clearCache(true);
web.loadUrl( "http://as3breeze.com/upload.html" );
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(chromeClient);
@Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d("Result", "("+requestCode+ ") - (" +resultCode + ") - (" + intent + ") - " + mUploadMessage);
if (null == intent) return;
Uri result = null;
if(requestCode==FILECHOOSER_RESULTCODE)
{
Log.d("Result","Old android");
if (null == mUploadMessage) return;
result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else if (requestCode == KITKAT_RESULTCODE) {
Log.d("Result","Kitkat android");
result = intent.getData();
final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
String path = getPath( this, result);
File selectedFile = new File(path);
//I used you example with a bit of editing so thought i would share, here i added a method to upload the file to the webserver
File selectedFile = new File(path);
UploadFile(selectedFile);
//mUploadMessage.onReceiveValue( Uri.parse(selectedFile.toString()) );
// Now we have the file but since mUploadMessage was null, it gets errors
}
}
public void UploadFile(File selectedFile)
{
Random rnd = new Random();
String sName = "File" + rnd.nextInt(999999) + selectedFile.getAbsolutePath().substring(selectedFile.getAbsolutePath().lastIndexOf("."));
UploadedFileName = sName;
uploadFile = selectedFile;
if (progressBar != null && progressBar.isShowing())
{
progressBar.dismiss();
}
// prepare for a progress bar dialog
progressBar = new ProgressDialog(mContext);
progressBar.setCancelable(true);
progressBar.setMessage("Uploading File");
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressBar.show();
new Thread() {
public void run()
{
int serverResponseCode;
String serverResponseMessage;
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
String pathToOurFile = uploadFile.getAbsolutePath();
String urlServer = "http://serveraddress/Scripts/UploadHandler.php?name" + UploadedFileName;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
try
{
FileInputStream fileInputStream = new FileInputStream(uploadFile);
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
Log.i("File", urlServer);
// Allow Inputs & Outputs.
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// Set HTTP method to POST.
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
Log.i("File", "Open conn");
outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile +"\"" + lineEnd);
outputStream.writeBytes(lineEnd);
Log.i("File", "write bytes");
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
Log.i("File", "available: " + fileInputStream.available());
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
Log.i("file", "Bytes Read: " + bytesRead);
while (bytesRead > 0)
{
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = connection.getResponseCode();
serverResponseMessage = connection.getResponseMessage();
Log.i("file repsonse", serverResponseMessage);
//once the file is uploaded call a javascript function to verify the user wants to save the image
progressBar.dismiss();
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Log.i("start", "File name: " + UploadedFileName);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')");
}
});
fileInputStream.close();
outputStream.flush();
outputStream.close();
}
catch (Exception ex)
{
Log.i("exception", "Error: " + ex.toString());
}
}
}.start();
}
마지막으로, 실제 파일 경로를 얻기 위한 몇 가지 코드, SO에서 발견된 코드, 저는 저자가 그의 작품에 대한 크레딧을 얻을 수 있도록 댓글에도 게시 URL을 추가했습니다.
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
* @source https://stackoverflow.com/a/20559175
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
* @source https://stackoverflow.com/a/20559175
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
* @source https://stackoverflow.com/a/20559175
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
* @source https://stackoverflow.com/a/20559175
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
* @source https://stackoverflow.com/a/20559175
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
마지막으로 HTML 페이지는 showPicker의 새로운 방법을 트리거해야 합니다(특히 A4.4의 경우).
<form id="form-upload" method="post" enctype="multipart/form-data">
<input id="fileupload" name="fileupload" type="file" onclick="javascript:prepareForPicker();"/>
</form>
<script type="text/javascript">
function getAndroidVersion() {
var ua = navigator.userAgent;
var match = ua.match(/Android\s([0-9\.]*)/);
return match ? match[1] : false;
};
function prepareForPicker(){
if(getAndroidVersion().indexOf("4.4") != -1){
window.jsi.showPicker();
return false;
}
}
function CheckImage(name)
{
//Check to see if user wants to save I used some ajax to save the file if necesarry
}
</script>
Google의 자체 브라우저는 이 문제에 대한 포괄적인 솔루션을 제공하므로 자체적인 수준을 보장합니다.
Android 4.0.4에서 openFileChooser 구현
Android 4.0.4에서 Handler 클래스 업로드
나에게 맞는 솔루션을 찾았습니다!파일에 규칙을 하나 더 추가합니다.proguard-android.txt
:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
당신은 이 링크를 방문했습니까?http://groups.google.com/group/android-developers/browse_thread/thread/dcaf8b2fdd8a90c4/62d5e2ffef31ebdb
http://moazzam-khan.com/blog/ ?tag=hosts-filen-file
http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/
Java lib Apache Commons를 통한 파일 업로드의 간결한 예
저는 당신이 이것으로부터 도움을 받을 것이라고 생각합니다.
웹 보기 - 단일 및 다중 파일 선택
이 코드를 구현하는 데 2분이 필요합니다.
빌드.그래들
implementation 'com.github.angads25:filepicker:1.1.1'
Java 코드:
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.bivoiclient.utils.Constants;
import com.github.angads25.filepicker.controller.DialogSelectionListener;
import com.github.angads25.filepicker.model.DialogConfigs;
import com.github.angads25.filepicker.model.DialogProperties;
import com.github.angads25.filepicker.view.FilePickerDialog;
import java.io.File;
public class WebBrowserScreen extends Activity {
private WebView webView;
private ValueCallback<Uri[]> mUploadMessage;
private FilePickerDialog dialog;
private String LOG_TAG = "DREG";
private Uri[] results;
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complain);
webView = findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();
webSettings.setAppCacheEnabled(true);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webSettings.setJavaScriptEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setAllowFileAccess(true);
webView.setWebViewClient(new PQClient());
webView.setWebChromeClient(new PQChromeClient());
if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.loadUrl(Constants.COMPLAIN_URL);
}
private void openFileSelectionDialog() {
if (null != dialog && dialog.isShowing()) {
dialog.dismiss();
}
//Create a DialogProperties object.
final DialogProperties properties = new DialogProperties();
//Instantiate FilePickerDialog with Context and DialogProperties.
dialog = new FilePickerDialog(WebBrowserScreen.this, properties);
dialog.setTitle("Select a File");
dialog.setPositiveBtnName("Select");
dialog.setNegativeBtnName("Cancel");
properties.selection_mode = DialogConfigs.MULTI_MODE; // for multiple files
// properties.selection_mode = DialogConfigs.SINGLE_MODE; // for single file
properties.selection_type = DialogConfigs.FILE_SELECT;
//Method handle selected files.
dialog.setDialogSelectionListener(new DialogSelectionListener() {
@Override
public void onSelectedFilePaths(String[] files) {
results = new Uri[files.length];
for (int i = 0; i < files.length; i++) {
String filePath = new File(files[i]).getAbsolutePath();
if (!filePath.startsWith("file://")) {
filePath = "file://" + filePath;
}
results[i] = Uri.parse(filePath);
Log.d(LOG_TAG, "file path: " + filePath);
Log.d(LOG_TAG, "file uri: " + String.valueOf(results[i]));
}
mUploadMessage.onReceiveValue(results);
mUploadMessage = null;
}
});
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (null != mUploadMessage) {
if (null != results && results.length >= 1) {
mUploadMessage.onReceiveValue(results);
} else {
mUploadMessage.onReceiveValue(null);
}
}
mUploadMessage = null;
}
});
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
if (null != mUploadMessage) {
if (null != results && results.length >= 1) {
mUploadMessage.onReceiveValue(results);
} else {
mUploadMessage.onReceiveValue(null);
}
}
mUploadMessage = null;
}
});
dialog.show();
}
public class PQChromeClient extends WebChromeClient {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// Double check that we don't have any existing callbacks
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
}
mUploadMessage = filePathCallback;
openFileSelectionDialog();
return true;
}
}
//Add this method to show Dialog when the required permission has been granted to the app.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (dialog != null) {
openFileSelectionDialog();
}
} else {
//Permission has not been granted. Notify the user.
Toast.makeText(WebBrowserScreen.this, "Permission is Required for getting list of files", Toast.LENGTH_SHORT).show();
}
}
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
public class PQClient extends WebViewClient {
ProgressBar progressDialog;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// If url contains mailto link then open Mail Intent
if (url.contains("mailto:")) {
// Could be cleverer and use a regex
//Open links in new browser
view.getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
// Here we can open new activity
return true;
} else {
// Stay within this webview and load url
view.loadUrl(url);
return true;
}
}
// Show loader on url load
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Then show progress Dialog
// in standard case YourActivity.this
if (progressDialog == null) {
progressDialog = findViewById(R.id.progressBar);
progressDialog.setVisibility(View.VISIBLE);
}
}
// Called when all page resources loaded
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function(){ " +
"document.getElementById('android-app').style.display='none';})()");
try {
// Close progressDialog
progressDialog.setVisibility(View.GONE);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
KitKat에서는 스토리지 액세스 프레임워크를 사용할 수 있습니다.
스토리지 액세스 프레임워크/클라이언트 애플리케이션 작성
솔루션: https://github.com/delight-im/Android-AdvancedWebView
Fragent를 위한 솔루션:
활동과 조각의 차이는 onActivityResult에만 있습니다.
조각:
lateinit var webViewGlobal: AdvancedWebView private set
class WebViewFragment : Fragment(), AdvancedWebView.Listener {
private lateinit var binding: FragmentWebViewBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentWebViewBinding.inflate(inflater)
webViewGlobal = binding.webWiew
return binding.root
}
}
활동:
class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
webViewGlobal.onActivityResult(requestCode, resultCode, data)
super.onActivityResult(requestCode, resultCode, data)
}
}
안드로이드 11:
<application
...
android:requestLegacyExternalStorage="true"
...
/>
매니페스트:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
저는 안드리오드가 처음이고 이것 때문에 어려움을 겪었습니다.Google 참조 가이드 웹 보기에 따라.
기본적으로 WebView는 브라우저와 같은 위젯을 제공하지 않으며 JavaScript를 사용할 수 없으며 웹 페이지 오류는 무시됩니다.UI의 일부로 HTML을 표시하는 것이 목표라면 이 방법으로도 괜찮을 것입니다. 사용자는 웹 페이지를 읽는 것 이상으로 웹 페이지와 상호 작용할 필요가 없으며 웹 페이지도 사용자와 상호 작용할 필요가 없습니다.전체 웹 브라우저를 실제로 사용하려면 웹 보기로 표시하는 대신 URL Intent를 사용하여 브라우저 응용 프로그램을 호출할 수 있습니다.
MainActivity.java에서 실행한 예제 코드.
Uri uri = Uri.parse("https://www.example.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
제외됨
package example.com.myapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.content.Intent;
import android.net.Uri;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uri uri = Uri.parse("http://www.example.com/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
getSupportActionBar().hide();
}}
저는 이 문제에 대해 거의 한 달 동안 조사했습니다.모든 것이 실패했습니다.여러 웹 사이트에 표시되는 모든 코드가 제대로 작동하지 않습니다.하지만 여기에 최고의 해결책이 있습니다.
https://github.com/chiclaim/android-webview-upload-file
스텝
복제 또는 다운로드 클릭
로컬 디렉터리에서 ziple 가져오기
zip 파일의 압축을 풉니다.
Android 스튜디오 열기
파일로 이동 ----> 열기 ---> 내용의 압축을 푼 디렉토리로 이동합니다.
mainActivity.java의 webView.loadUrl("your url here")에서 필요한 웹 URL을 변경합니다.
Android 스튜디오 3.4.2 버전과 잘 작동합니다.
사용자 지정 WebChromeClient:
class AppChromeClient(private val fragmentWeakReference: WeakReference<WebViewFragment>) :
WebChromeClient() {
private var openFileCallback: ValueCallback<Array<Uri>>? = null
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
if (filePathCallback == null) {
return (super.onShowFileChooser(webView, filePathCallback, fileChooserParams))
}
openFileCallback = filePathCallback
val webViewFragment = fragmentWeakReference.get() ?: return false
webViewFragment.launchGetMultipleContents("*/*")
return true
}
fun receiveFileCallback(result: Array<Uri>) {
openFileCallback?.onReceiveValue(result)
openFileCallback = null
}
}
WebView 조각:
class WebViewFragment : Fragment() {
private var _binding: FragmentWebviewBinding? = null
private val binding get() = _binding!!
private lateinit var webView: WebView
private val chromeClient = AppChromeClient(WeakReference(this))
private var contentLauncher: ActivityResultLauncher<String> = getMultipleContentLauncher()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWebviewBinding.inflate(inflater, container, false)
webView.webChromeClient = chromeClient
val url = requireContext().getString(R.string.app_domain)
webView.setting.javaScriptEnabled = true
webView.loadUrl(url)
return binding.root
}
private fun getMultipleContentLauncher(): ActivityResultLauncher<String> {
return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
if (list.isEmpty()) {
showToast("No files selected")
}
chromeClient.receiveFileCallback(list.toTypedArray())
}
}
fun launchGetMultipleContents(type: String) {
contentLauncher.launch(type)
}
}
제게는, 이것이 효과가 있었습니다. 누군가에게 도움이 되기를 바랍니다.
에 protected void onCreate
행 예를 들어 다음과 같습니다.
// Initialize WebView and set onShowFileChooser listener
WebView webView = findViewById(R.id.revieveWebview);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return false;
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
// Handle error
}
});
내부에 재정의 일부가 추가되었습니다.protected void onPostCreate(Bundle savedInstanceState)
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
// Save callback
mFilePathCallback = filePathCallback;
// Create intent to open file chooser for image selection
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
// Launch file chooser
Intent chooserIntent = Intent.createChooser(intent, "Choose Image");
startActivityForResult(chooserIntent, 44745);
return true;
}
그리고 이것은 공개 수업 활동입니다.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 44745) {
if(resultCode == RESULT_OK) {
if(data != null) {
// Get the selected image URI(s)
Uri uri = data.getData();
Uri[] results = new Uri[]{uri};
// Return the selected image URI(s) to the WebView
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
}
} else {
mFilePathCallback.onReceiveValue(null);
mFilePathCallback = null;
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
또한 저는 이것이 공개 수업 활동에 필요했습니다.
private ValueCallback<Uri[]> mFilePathCallback;
언급URL : https://stackoverflow.com/questions/5907369/file-upload-in-webview
'programing' 카테고리의 다른 글
과학적 표기법 방지 (0) | 2023.09.18 |
---|---|
스크립트가 이미 실행 중이면 실행 안 함 (0) | 2023.09.18 |
페이지를 닫을 때(남기지 않을 때) 언로드하기 전에 jquery? (0) | 2023.08.29 |
jquery, ID 내 클래스 선택기 (0) | 2023.08.29 |
Count(*)>0보다 효율적으로 존재합니까? (0) | 2023.08.29 |