android webview中的HTML文件输入(android 4.4,kitkat)

Posted

技术标签:

【中文标题】android webview中的HTML文件输入(android 4.4,kitkat)【英文标题】:HTML file input in android webview (android 4.4, kitkat) 【发布时间】:2013-11-21 20:04:56 【问题描述】:

我在 android webview 上使用<input type="file">。 由于这个线程,我得到了它的工作: File Upload in WebView

但接受的答案(或任何其他)不再适用于 android 4.4 kitkat webview。

有人知道怎么解决吗?

它也不适用于目标 18。

我查看了一些 android 4.4 源代码,似乎 WebChromeClient 没有改变,但我认为 setWebChromeClient 不再适用于 kitkat webview,或者至少不适用于 openFileChooser 功能。

【问题讨论】:

kitkat之前的webview渲染引擎是Webkit,现在改成Chromium了。您可能想阅读此迁移指南。 developer.android.com/guide/webapps/migrating.html 我知道 webview 现在不同了。我在迁移指南上没有看到任何关于这个问题的信息。 Android 4.4 上的默认浏览器不支持输入类型=文件字段吗?如果是这样,解决方法应该是和他们一样。有没有人研究过源代码来弄清楚他们是如何做到的? 将是一个答案 AFAIK,在 android 4.4 上没有默认浏览器,nexus 设备包含 chrome 作为默认浏览器,但其他制造商可以选择包含/许可他们想要的任何内容或使用 webview 构建自己的浏览器. Chrome 支持输入文件,但代码不包含在 android 4.4 【参考方案1】:

更新 2: 有一个更简单的插件可以与 phonegap/cordova 一起使用

https://github.com/MaginSoft/MFileChooser

更新: 带有 Cesidio DiBenedetto 插件的示例项目

https://github.com/jcesarmobile/FileBrowserAndroidTest

我在android开源项目上开了一个issue,答案是:

状态:按预期工作

很遗憾,openFileChooser 不是公共 API。我们正在开发未来版本的 Android 中的公共 API。

对于使用 phonegap/cordova 的用户,此解决方法已发布在错误跟踪器上:

Cesidio DiBenedetto 添加了评论 - 28/Mar/14 01:27

大家好,我也遇到了这个问题,所以我写了一个 Cordova FileChooser 插件暂时是一个“创可贴”。 基本上,在 Android 4.4(KitKat) 中,如之前的 cmets 所述, 文件对话框未打开。但是 onclick 事件仍然是 触发,因此您可以调用 FileChooser 插件 打开一个文件对话框,选择后,您可以设置一个变量 包含文件的完整路径。此时,您可以使用 FileTransfer 插件上传到您的服务器并连接到 onprogress 事件以显示进度。这个插件主要是配置的 对于Android 4.4,所以我建议继续使用本机 Android 早期版本的文件对话框。可能有问题 使用插件,因为我还没有完全测试所有可能的场景 很多设备,但我已经将它安装在 Nexus 5 上并且运行良好。

https://github.com/cdibened/filechooser

未对其进行测试,因为我构建了自己的解决方法

来自 Chromium 开发者的评论

我们将在下一个专业中为 WebViewClient 添加一个公共 API 释放以处理文件请求。

他们现在似乎认为这是一个错误,他们将修复它

【讨论】:

我不能分享它,但它是另一个phonegap插件,不能很好地处理大文件,所以我结束了使用Cesidio DiBenedetto的插件 只需将您的 targetSdkVersion 设置为小于 18 我很确定我试过了,但我会重新检查,谢谢你的评论【参考方案2】:

我设法在我的应用程序中实现了提到的Cesidio DiBenedetto's workaround。它工作得很好,但对于以前从未使用过PhoneGap/Cordove 的人(比如我)来说可能有点棘手。所以这是我在实施时整理的一些小方法。

Apache Cordova 是一个平台,可让您仅使用网络技术构建多平台移动应用程序。关键特性是将原生 API 导出到 javascript,因此提供了一种在网站和原生应用程序之间进行通信的方式。典型的 PhoneGap/Cordova 应用程序是一个静态网站,它与 Cordova 层捆绑在一个 APK 中。但是您可以使用 Cordova 显示远程网站,这就是我们的情况。

解决方法如下:我们使用CordovaWebView 代替标准的WebView 来显示我们的网站。当用户单击浏览以选择文件时,我们使用标准 JavaScript (jQuery...) 捕获该单击,并使用 Cordova API 在本机端激活 Cesidio DiBenedetto 的文件选择器插件,这将打开一个漂亮的文件浏览器。当用户选择一个文件时,该文件将被发送回 JavaScript 端,然后我们将其上传到我们的网络服务器。

要知道的重要一点是,您需要为您的网站添加 Cordova 支持。好的,现在实际操作方法...

首先,您必须将 Cordova 添加到您现有的应用程序中。我关注了this documentation。有些步骤我不清楚,所以我会尝试解释更多:

    在您的应用程序之外的某个地方下载并提取 Cordova,然后按照描述构建 cordova-3.4.0.jar。由于 local.properties 文件丢失,它可能会第一次失败。您将被指示如何在错误输出中创建它;您只需将其指向您用于构建 Android 应用程序的 SDK。

    将编译后的 jar 文件复制到您的应用程序 lib 目录,并将 jar 作为库添加。如果你像我一样使用 Android Studio,只需确保在 build.gradle 中的 dependencies 中有 compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])。然后只需点击 Sync project with gradle files 按钮就可以了。

    您不必创建 /res/xml/main.xml 文件。你可以像对待标准 WebView 一样对待 CordovaWebView,这样你就可以将它直接放到你的布局文件中。

    现在只需按照原始文档中的步骤 5-7 将您自己的 Activity 放在一起,CordobaWebView 将在其中运行。检查您下载的 Cordova 包中的 /framework/src/org/apache/cordova/CordovaActivity.java 是个好主意。您可以简单地复制大多数需要实现的方法。 6. 步骤对于我们的目的非常重要,因为它将允许使用文件选择器插件。

    请勿在任何地方复制任何 HTML 和 JavaScript 文件,我们稍后会将其添加到您的网站。

    不要忘记复制 config.xml 文件(您不必更改它)。

要在CordovaWebView 中加载您的网站,只需将其网址传递给cwv.loadUrl() 而不是Config.getStartUrl()

其次,您必须将FileChooser plugin 添加到您的应用程序中。由于我们没有使用标准的 Cordova 设置,因此我们不能按照自述文件中的说明点击 cordova plugin add,我们有手动添加。

    下载存储库并将源文件复制到您的应用程序。确保 res 文件夹的内容进入您的应用程序 res 文件夹。您现在可以忽略 JavaScript 文件。

    为您的应用添加READ_EXTERNAL_STORAGE 权限。

    将以下代码添加到/res/xml/config.xml

<feature name="FileChooser">
    <param name="android-package" value="com.cesidiodibenedetto.filechooser.FileChooser" />
</feature>

现在是为您的网站添加 Cordova 支持的时候了。这比听起来简单,您只需将 cordova.js 链接到您的网站,但是,那里有两件事需要了解。

首先,每个平台(Android、ios、WP)都有自己的cordova.js,所以请确保你使用的是Android版本(你可以在你下载的Cordova包中找到它/framework/assets/www)。

其次,如果要从CordovaWebView 和标准浏览器(桌面或移动)访问您的网站,通常最好仅在页面显示时加载 cordova.js CordovaWebView。我找到了几种检测CordovaWebView 的方法,但以下一种方法对我有用。以下是您网站的完整代码:

function getAndroidVersion(ua) 
    var ua = ua || navigator.userAgent; 
    var match = ua.match(/Android\s([0-9\.]*)/);
    return match ? parseFloat(match[1]) : false;
;

if (window._cordovaNative && getAndroidVersion() >= 4.4) 
    // We have to use this ugly way to get cordova working
    document.write('<script src="/js/cordova.js" type="text/javascript"></script>');

请注意,我们还会检查 Android 版本。只有 KitKat 需要此解决方法。

此时您应该能够从您的网站手动调用 FileChooser 插件。

var cordova = window.PhoneGap || window.Cordova || window.cordova;
cordova.exec(function(data) , function(data) , 'FileChooser', 'open', []);

这应该会打开文件浏览器并让您选择一个文件。请注意,这只能在事件 deviceready 被触发后完成。要对其进行测试,只需使用 jQuery 将此代码绑定到某个按钮即可。

最后一步是将所有这些放在一起并让上传表单正常工作。要实现这一点,您只需按照 README 中描述的 Cesidio DiBenedetto 的说明进行操作。当用户在 FileChooser 中选择文件时,文件路径会返回到 JavaScript 端,从那里另一个 Cordova 插件 FileTransfer 用于执行实际上传。这意味着文件是在本机端上传的,而不是在CordovaWebView 中(如果我理解正确的话)。

我不想在我的应用程序中添加另一个 Cordova 插件,而且我也不确定它如何与 cookie 一起工作(我需要随请求发送 cookie,因为只允许经过身份验证的用户上传文件)所以我决定按我的方式做。我修改了 FileChooser 插件,因此它不返回路径而是返回整个文件。因此,当用户选择一个文件时,我读取它的内容,使用base64 对其进行编码,将其作为 JSON 传递给客户端,在那里我对其进行解码并使用 JavaScript 将其发送到服务器。它可以工作,但有一个明显的缺点,因为 base64 对 CPU 的要求很高,所以当上传大文件时应用程序可能会冻结一点。

要做到这一点,首先将此方法添加到FileUtils

public static byte[] readFile(final Context context, final Uri uri) throws IOException 
    File file = FileUtils.getFile(context, uri);
    return org.apache.commons.io.FileUtils.readFileToByteArray(file);

请注意,它使用 Apache Commons 库,所以不要忘记包含它或实现文件读取其他不需要外部库的方式。

接下来,修改 FileChooser.onActivityResult 方法以返回文件内容而不是其路径:

// Get the URI of the selected file
final Uri uri = data.getData();
Log.i(TAG, "Uri = " + uri.toString());
JSONObject obj = new JSONObject();
try 
    obj.put("filepath", FileUtils.getPath(this.cordova.getActivity(), uri));
    obj.put("name", FileUtils.getFile(this.cordova.getActivity(), uri).getName());
    obj.put("type", FileUtils.getMimeType(this.cordova.getActivity(), uri));

    // attach the actual file content as base64 encoded string
    byte[] content = FileUtils.readFile(this.cordova.getActivity(), uri);
    String base64Content = Base64.encodeToString(content, Base64.DEFAULT);
    obj.put("content", base64Content);

    this.callbackContext.success(obj);
 catch (Exception e) 
    Log.e("FileChooser", "File select error", e);
    this.callbackContext.error(e.getMessage());

最后,这是您将在您的网站上使用的代码(需要 jQuery):

var cordova = window.PhoneGap || window.Cordova || window.cordova;
if (cordova) 
    $('form.fileupload input[type="file"]', context).on("click", function(e)     
        cordova.exec(
            function(data)  
                var url = $('form.fileupload', context).attr("action");

                // decode file from base64 (remove traling = first and whitespaces)
                var content = atob(data.content.replace(/\s/g, "").replace(/=+$/, ""));

                // convert string of bytes into actual byte array
                var byteNumbers = new Array(content.length);
                for (var i = 0; i < content.length; i++) 
                    byteNumbers[i] = content.charCodeAt(i);
                
                var byteContent = new Uint8Array(byteNumbers);

                var formData = new FormData();
                var blob = new Blob([byteContent], type: data.type); 
                formData.append('file', blob, data.name);

                $.ajax(
                    url: url,
                    data: formData,
                    processData: false,
                    contentType: false,
                    type: 'POST',
                    success: function(data, statusText, xhr)
                        // do whatever you need
                    
                );
            ,
            function(data)  
                console.log(data);
                alert("error");
            ,
            'FileChooser', 'open', []);
    );

嗯,就是这样。我花了几个小时才完成这项工作,所以我分享我的知识,并希望它可能对某人有所帮助。

【讨论】:

是否有示例项目可以在我的 android 4.4.2 中进行测试? 我要试试这个。它在 android 4.4.1 版本中可以正常工作吗? 不,很遗憾没有示例项目。但是请参阅@A 的答案。 Salam Alassadi ... 从 Android 4.4.3 开始,似乎不再需要这种解决方法。我不确定实施此解决方法是否仍然值得,因为大多数 KitKat 设备迟早会获得 4.4.3 更新。 我需要为 4.4.1 找到工作。所以我现在正在实现它。在 4.4.1 设备中是否可以正常工作? ,我已经实现了您的解决方案。我已将警报消息放入 cordova.js 文件中。其中我在调用 cordova.js 文件时收到 deviceready 事件未触发错误。我不知道解决此错误.如何调试此 cordova.js 文件。【参考方案3】:

如果有人仍在寻找使用 kitkat 上的 webview 进行文件输入的解决方案。

在 android 4.4 上单击时未调用 openFileChooserhttps://code.google.com/p/android/issues/detail?id=62220

一个名为 Crosswalk 的基于铬的库可以用来解决这个问题 https://crosswalk-project.org/documentation/downloads.html

步骤 1. 将从上述链接下载的 xwalk_core_library android 项目作为库导入到您的项目中 2.在您的布局xml中添加以下内容

       <org.xwalk.core.XWalkView
            android:id="@+id/webpage_wv"
            android:layout_
            android:layout_          
        />

3。在活动的 onCreate 方法中,执行以下操作

mXwalkView = (XWalkView) context.findViewById(R.id.webpage_wv);
mXwalkView.setUIClient(new UIClient(mXwalkView));
mXwalkView.load(navigateUrl, null); //navigate url is your page URL

    添加活动类变量

    私有 ValueCallback mFilePathCallback; 私有 XWalkView mXwalkView

    现在应该会显示文件输入对话框。但是,您需要提供回调来获取文件并将其发送到服务器。

    您需要覆盖活动的 onActivityResult

    public void onActivityResult(int requestCode, int resultCode, Intent intent) 
      super.onActivityResult(requestCode, resultCode, intent);
    
    if (mXwalkView != null) 
    
        if (mFilePathCallback != null) 
            Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
                    : intent.getData();
            if (result != null) 
                String path = MediaUtility.getPath(getActivity(), result);
                Uri uri = Uri.fromFile(new File(path));
                mFilePathCallback.onReceiveValue(uri);
             else 
                mFilePathCallback.onReceiveValue(null);
            
        
    
        mFilePathCallback = null;
    
    mXwalkView.onActivityResult(requestCode, resultCode, intent);
    
    
    

    MediaUtility 类可以在 Get real path from URI, Android KitKat new storage access framework查看 Paul Burke 的回答

    要获取 mFilePathCallback 的数据对象,请在您的活动中创建一个子类

    class UIClient extends XWalkUIClient 
    public UIClient(XWalkView xwalkView) 
        super(xwalkView);
    
    
    public void openFileChooser(XWalkView view,
            ValueCallback<Uri> uploadFile, String acceptType, String capture) 
        super.openFileChooser(view, uploadFile, acceptType, capture);
    
        mFilePathCallback = uploadFile;
        Log.d("fchooser", "Opened file chooser.");
    
    

    你已经完成了。文件上传现在应该可以工作了。 不要忘记将 Crosswalk 所需的权限添加到您的清单中。

    使用权限 android:name="android.permission.ACCESS_FINE_LOCATION" 使用权限 android:name="android.permission.ACCESS_NETWORK_STATE" 使用权限 android:name="android.permission.ACCESS_WIFI_STATE" 使用权限 android:name="android.permission.CAMERA" 使用权限 android:name="android.permission.INTERNET" 使用权限 android:name="android.permission.MODIFY_AUDIO_SETTINGS" 使用权限 android:name="android.permission.RECORD_AUDIO" 使用权限 android:name="android.permission.WAKE_LOCK" 使用权限 android:name="android.permission.WRITE_EXTERNAL_STORAGE"

【讨论】:

问题是人行横道给应用程序增加了很多重量,我认为它增加了 30-50MB。无论如何我都赞成你的答案,因为除了重量问题之外,它不仅是输入文件的好选择,与系统 webview 相比,它还具有性能改进 你可以添加一个演示应用程序。 @agomes 感谢这个解决方法,在 4.4.2 中成功上传文件后。现在我被困在下载问题上。点击后我无法下载文件,任何帮助 mXwalkView.onActivityResult(requestCode, resultCode, intent);从 onActivityResult 中删除这一行。这导致应用程序因重复结果交付错误而崩溃。 @agomes 可以发布整个代码。我正在寻找相同的解决方案。【参考方案4】:

webview 中的文件选择器现在可以在最新的 Android 版本 4.4.3 中使用。

自己使用 Nexus 5 尝试过。

【讨论】:

如果您从新的 android 4.4 选项(例如“最近”、“下载”、“驱动器”等)中选择文件,是否可以正常工作? @jcesarmobile 是的。最近的文档和相机拍摄。两者都工作正常。 @A.SalamAlasaadi 它可以工作,但它现在正在捕获没有扩展名的文件名。对此有任何修复吗?我在 Nexus 5 上进行了测试。 @input 是的,我注意到了这一点。我所做的是在后面的代码中手动添加扩展。【参考方案5】:

尽管Kitkat版本与webview type=file表单域不兼容,我们可以使用webview的addJavascriptInterface方法来完成文件上传任务。服务端判断android的版本,如果低于4.4,使用WebViewChromeClient私有方法,如果4.4以上,让服务端调用android方法相互通信(例如上传文件内容异步)

// 代码

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app");

这是一个可能有帮助的链接...

call-android-methods-from-javascript

【讨论】:

【参考方案6】:

我为这个问题构建了自己的解决方案,没有使用任何库、Cordova 插件或自定义 WebView,它在所有 Android 版本中都能正常工作。

此解决方案涉及使用一些非常简单的 Javascript 在 WebView 中的网站和 Android 应用程序之间进行通信,并直接从您的 Android 应用程序执行文件选择和上传,删除所有 openFileChooser()、showFileChooser() 和onShowFileChooser() WebChromeClient 方法。

第一步是在用户单击文件输入时从网站触发 javascript 控制台消息编写唯一代码,用于上传文件具有唯一的名称或路径。例如,将完整的日期时间与一个巨大的随机数连接起来:

<input type="file" name="user_file" onclick="console.log('app.upload=20170405173025_456743538912');">

然后您的应用可以覆盖 WebChromeClient 的 onConsoleMessage() 方法读取此消息、检测该消息、读取代码并触发文件选择

webview.setWebChromeClient(new WebChromeClient() 
    // Overriding this method you can read messages from JS console.
    public boolean onConsoleMessage(ConsoleMessage message)          
        String messageText = message.message();
        // Check if received message is a file upload and get the unique code
        if(messageText.length()>11 && messageText.substring(0,11).equals("app.upload=")) 
           String code = messageText.substring(11);
           triggerFileUploadSelection(code);
           return true;
        
        return false;
    
);

对于文件选择,您可以像这样使用简单的 Android ACTION_PICK intent

public void triggerFileUploadSelection(String code)
    // For Android 6.0+ you must check for permissions in runtime to read from external storage
    checkOrRequestReadPermission();

    // Store code received from Javascript to use it later (code could also be added to the intent as an extra)
    fileUploadCode = code;

    // Build a simple intent to pick any file, you can replace "*/*" for "image/*" to upload only images if needed
    Intent filePickerIntent = new Intent(Intent.ACTION_PICK);
    filePickerIntent.setType("*/*");

    // FILE_UPLOAD_CODE is just any unique integer request code to identify the activity result when the user selects the file
    startActivityForResult( Intent.createChooser(filePickerIntent, getString(R.string.chooseFileToUpload) ), FILE_UPLOAD_CODE );

在用户选择(或不选择)文件后,您可以接收文件 Uri,并将其转换为真实的文件路径

@Override
public void onActivityResult (int requestCode, int resultCode, Intent data) 
    if(requestCode==FILE_UPLOAD_CODE) 
        if(data != null && resultCode == RESULT_OK)
            // user selected a file
            try
                Uri selectedFileUri = data.getData();
                if(selectedFileUri!=null) 
                    // convert file URI to a real file path with an auxiliary function (below)
                    String filePath = getPath(selectedFileUri);
                    if(filePath!=null) 
                        // I got the file path, I can upload the file to the server (I pass webview as an argument to be able to update it when upload is completed)
                        uploadSelectedFile(getApplicationContext(), filePath, fileUploadCode, webview);
                    else
                        showToastFileUploadError();
                    
                else
                    showToastFileUploadError();
                
            catch (Exception e)
                e.printStackTrace();
                showToastFileUploadError();
            
        else
            // user didn't select anything
        
    


// I used this method for images, and it uses MediaStore.Images so you should probably 
// use another method to get the path from the Uri if you are working with any kind of file
public String getPath(Uri uri) 
    String[] projection =  MediaStore.Images.Media.DATA ;
    Cursor cursor = managedQuery(uri, projection, null, null, null);
    if(cursor==null)return null;
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);

uploadSelectedFile 方法简单地创建一个包含所有信息(filePath、fileUploadCode 和 WebView)的对象,并触发使用该信息上传文件的 AsyncTask,并在 WebView 完成时更新完成:

public static void uploadSelectedFile(Context c, String filePath, String code, WebView webView)
    // YOU CAN SHOW A SPINNER IN THE WEB VIEW EXECUTING ANY JAVASCRIPT YOU WANT LIKE THIS:
    webView.loadUrl("javascript: Element.show('my_upload_spinner');void 0"); 
    // void 0 avoids at the end avoids some browser redirection problems when executing javascript commands like this

    // CREATE A REQUEST OBJECT (you must also define this class with those three fields and a response field that we will use later):
    FileUploadRequest request = new FileUploadRequest(filePath, code, webView);

    // Trigger an async task to upload the file, and pass on the request object with all needed data
    FileUploadAsyncTask task = new FileUploadAsyncTask();
    task.execute(request);

AsyncTask 接收包含所有信息的请求对象,并使用 MultipartUtility 构建多部分请求并将其发送到服务器 很容易。你可以从很多地方获得很多 Java Multipart Utilities,其中之一在这里:http://www.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmatically

public class FileUploadAsyncTask extends AsyncTask<FileUploadRequest, Void, FileUploadRequest> 
    @Override
    protected FileUploadRequest doInBackground(FileUploadRequest... requests) 
        FileUploadRequest request = requests[0];

        try 
            // Generate a multipart request pointing to the URL where you will receive uploaded file
            MultipartUtility multipart = new MultipartUtility("http://www.example.com/file_upload.php", "UTF-8");
            // Add a field called file_code, to send the code to the server script
            multipart.addFormField("file_code", request.code);
            // Add the file to the request
            multipart.addFilePart("file_path", new File(request.filePath));

            // Send the request to the server and get the response and save it back in the request object
            request.response = multipart.finish(); // response from server.
         catch (IOException e) 
            request.response = "FAILED";
            e.printStackTrace();
        
        return request;
    

现在我们已经将文件上传到服务器,我们可以再次使用 Javascript 从我们 AsyncTask 中的 onPostExecute 方法更新我们的网站。最重要的是将文件代码设置在表单的隐藏字段中,这样您就可以在用户发送表单时获取该代码。您还可以在网站中显示消息,甚至可以轻松显示上传的图片(如果是图片):

@Override
protected void onPostExecute(FileUploadRequest request) 
    super.onPostExecute(request);

    // check for a response telling everything if upload was successful or failed
    if(request.response.equals("OK"))
        // set uploaded file code field in a hidden field in your site form (ESSENTIAL TO ASSOCIATE THE UPLOADED FILE WHEN THE USER SENDS THE WEBSITE FORM)
        request.webView.loadUrl("javascript: document.getElementById('app_upload_code_hidden').value = '"+request.code+"';void 0");

        // Hide spinner (optional)
        //request.webView.loadUrl("javascript: Element.hide('my_upload_spinner');void 0");

        // show a message in the website, or the uploaded image in an image tag setting the src attribute 
        // to the URL of the image you just uploaded to your server. 
        // (you must implement your own fullUrl method in your FileUploadRequest class)
        // request.webView.loadUrl("javascript: document.getElementById('app_uploaded_image').src = '"+request.fullUrl()+"';void 0");
        // request.webView.loadUrl("javascript: Element.show('app_uploaded_image');void 0");
    

现在 Android 部分已经完成,您需要在服务器端接收您通过 Android 应用 AsyncTask 上传的文件并将其保存在您需要的任何地方。

您还必须在用户发送网站表单时对其进行处理,并对用户从应用上传的文件执行任何您需要的操作。为此,您将获得表单中的文件代码(我们在 onPostExecute() 的字段中完成了该代码),并且您必须使用该文件代码来查找应用已上传到的文件你的服务器。为此,您可以将文件保存在使用该代码作为文件名的路径中,或者将代码和您上传文件的路径保存在数据库中。

此解决方案仅依赖于可用且与所有 Android 版本兼容的元素,因此它应该可以在任何设备上运行(我还没有收到用户对此的抱怨)。

如果您在同一页面中有多个文件输入,您可以发送字段编号或额外标识符以及初始 javascript 消息中的唯一文件代码,传递该标识符在所有应用程序代码中,并使用它来更新 onPostExecute() 中的正确元素。

我在这里对实际代码进行了一些修改,所以如果有任何失败,可能是重命名时出现的拼写错误或一些小细节。

需要处理的信息非常多,所以如果有人需要任何澄清或有建议或更正,请告诉我。

【讨论】:

【参考方案7】:

Kitkat 的新文件浏览器在 Chrome 上同样疯狂,看看 WebView 现在如何使用 Chromium,这可能是一个相关问题。我发现直接从相机上传文件是可行的,但不是从“图像”文件夹中上传。如果您要从“图库”上传,则可以访问相同的文件。呸。

似乎已准备好修复但正在等待发布:

https://code.google.com/p/chromium/issues/detail?id=278640

【讨论】:

这里的问题是甚至没有调用openFileChooser,chrome问题与新的android 4.4存储访问框架有关。希望下次更新时调用 openFileChooser【参考方案8】:

如果您只想在您的网站周围添加一个 webview 包装器并将其作为应用程序启动,请不要使用默认的 android webview 环顾四周,无论哪种方式都令人头疼..对我来说有两件事没有不行 1. 输入文件 2. Stripe checkout integeration(使用高级JS API)

我做了什么从黑暗中走出来

刚刚使用 Cordova 创建了一个示例应用程序。比我们想象的要简单得多。

    从其官方页面安装 Cordova,构建示例应用。 它会给你一个apk文件。 (你明白了)

    您从创建的应用程序转到 www 文件夹并打开 index.js,找到并将该行替换为 onDeviceReady: function() window.open('http://yourdomain.com/yourpage') 再次运行应用程序,它将打开网站

    现在是主步骤。到目前为止,Cordova 只使用了一个适度的 webview。总有一天,一切都应该改变。将人行横道插件添加到您的 Cordova 应用程序,它将用全新的完整铬视图替换缓慢的 webview https://crosswalk-project.org/documentation/cordova.html

    运行 cordova clean,然后运行 ​​cordova build --release 以清理旧版本。

    打开Cordva app给出的app目录里面的config.xml,添加&lt;allow-navigation href="http://yourdomain.com/*" /&gt; 再次运行应用程序。魔法!。

【讨论】:

【参考方案9】:

当使用 crosswalk-webview-21.51.546.7 并通过相机选择图片时。在onActivityResult() the intent.getData() 中是null。这意味着无法通过相机上传图像。

【讨论】:

以上是关于android webview中的HTML文件输入(android 4.4,kitkat)的主要内容,如果未能解决你的问题,请参考以下文章

android webview 怎样监听HTML中的按钮并得到按钮的url

Android Webview:获取输入类型文件元素的 ValueCallback

Android 下的 WebView 中数据如何保存

处理文件选择器 android 6.0 webview

将 HTML 文件中的外部 javascript 文件从 android assets 文件夹加载到 WebView

android 怎么在代码中引用assets中的资源