android开发分享在android webview(android 4.4,kitkat)中inputHTML文件

我正在使用android webview上的<input type="file"> 。 我得到它的工作感谢这个线程: 在WebView中的file upload

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

任何人都知道如何解决它?

它也不适用于目标18。

我看了一些Android 4.4的源代码,似乎WebChromeClient没有改变,但我认为setWebChromeClient不再工作在kitkat webview,或至less不是openFileChooser函数。

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

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

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

    状态:WorkingAsItended

    不幸的是,openFileChooser不是一个公共的API。 我们正在开发未来Android版本的公共API。

    对于那些使用phonegap / cordova的人来说,这个解决方法是发布在bug跟踪器上的:

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

    嘿,我一直在遇到这个问题,所以我暂时写了一个Cordova FileChooser插件给一个“创可贴”。 基本上,在Android 4.4(KitKat)中,正如前面的评论所述,文件对话框并没有打开。 然而,onclick事件仍然被触发,所以你可以调用FileChooser插件来打开一个文件对话框,一旦select,你可以设置一个包含文件完整path的variables。 在这一点上,你可以使用FileTransfer插件上传到你的服务器,并钩进onprogress事件来显示进度。 此插件主要针对Android 4.4进行configuration,所以我build议继续使用早期版本的Android的本机文件对话框。 这个插件可能存在问题,因为我没有在许多设备上完全testing所有可能的场景,但是我已经将它安装在Nexus 5上,并且工作正常。

    没有testing,因为我build立了我自己的解决方法

    铬开发者的评论

    我们将在下一个主要版本中为WebViewClient添加一个公共API来处理文件请求。

    看来他们现在认为它是一个错误,他们正在修复它

    我设法在我的应用程序中实现提到的Cesidio DiBenedetto的解决方法 。 它工作的很好,但对于以前从未使用过PhoneGap / Cordove的人来说(比如我)可能有点棘手。 所以这是我在实施的时候放在一起的。

    Apache Cordova是一个平台,可让您使用Web技术构build多平台移动应用程序。 其主要特点是它将本地API导出到JavaScript,因此提供了一种在网站和本地应用程序之间进行通信的方式。 典型的PhoneGap / Cordova应用程序是一个静态网站,与Cordova图层捆绑在一个APK中。 但是您可以使用Cordova来显示远程网站,这就是我们的情况。

    解决方法如下:我们使用CordovaWebView来显示我们的网站,而不是标准的WebView 。 当用户点击浏览select文件时,我们使用标准的JavaScript(jQuery …)捕获点击,并使用Cordova API,我们激活了Cesidio DiBenedetto的filechooser插件在本机端,这将打开一个不错的文件浏览器。 当用户select一个文件时,文件将从我们上传到我们的networking服务器的地方发回到JavaScript端。

    重要的是要知道,你需要添加cordova支持你的网站。 好的,现在的实际情况是…

    首先,您必须将Cordova添加到现有的应用程序中。 我遵循这个文件 。 有些步骤我不清楚,所以我会试着解释一下:

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

    其次,你必须添加FileChooser插件到你的应用程序。 由于我们没有使用标准的Cordova设置,所以我们不能只按照自述文件中的说明打cordova plugin add ,我们必须手动添加它。

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

    现在是时候添加cordova支持您的网站。 这听起来比较简单,你只需要把cordova.js链接到你的网站上,然而,有两件事要知道。

    首先,每个平台(Android,iOS,WP)都有自己的cordova.js ,因此请确保使用Android版本(可以在/ framework / assets / www中下载的Cordova包中find它)。

    其次,如果要从CordovaWebView和标准浏览器(桌面或移动设备)访问您的网站,只有在CordovaWebView显示页面时才加载cordova.js是一个好主意。 我发现了几种检测CordovaWebView方法,但是下面的方法适用于我。 以下是您网站的完整代码:

     function getAndroidVersion(ua) { var ua = ua || navigator.userAgent; var match = ua.match(/Androids([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', [{}]); 

    这应该打开文件浏览器,让你select一个文件。 请注意,这只能在事件deviceready被触发后才能完成。 要testing它,只需使用jQuery将此代码绑定到某个button即可。

    最后一步是把这一切放在一起,让上传表单工作。 要做到这一点,您可以简单地按照自述文件中所述的Cesidio DiBenedetto的说明进行操作。 当用户在FileChooser中select文件时,文件path将返回到另一个Cordova插件FileTransfer用于执行实际上传的JavaScript端。 这意味着文件是上传到本地,而不是在CordovaWebView (如果我理解正确的话)。

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

    要做到这一点,首先将此方法添加到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方法以返回文件内容而不是其path:

     // 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', [{}]); }); } 

    那么,就是这样。 我花了好几个小时才搞定这个工作,所以我分享我的知识,希望能帮助别人。

    如果有人仍然在寻找解决scheme,使用kitkat上的webview文件input。

    当在Android 4.4上点击时,openFileChooser不会被调用

    一个叫做Crosswalk的基于铬的库可以用来解决这个问题

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

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

    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 

    在webview中的文件select器现在可以在最新的Android 4.4.3版本中运行。

    尝试使用Nexus 5自己。

    尽pipeKitkat版本与webview type = file表单字段不兼容,我们可以使用webview的addJavascriptInterface方法来完成file upload任务。 服务器端应该判断android的版本,如果它低于4.4 ,使用WebViewChromeClient私有方法,如果4.4或更高版本,让服务器调用android方法相互通信(例如上传文件内容asynchronous)

    //代码

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

    这是一个链接,可能有帮助…

    呼叫Android的方法-从JavaScript的

    我为这个问题build立了我自己的解决scheme,而不使用任何库,Cordova插件或自定义WebViews,并且它在所有Android版本中都能正常工作。

    这个解决scheme涉及到使用一些非常简单的Javascript在WebView和Android应用程序之间进行通信,并从Android应用程序直接执行文件select和上传, 删除所有openFileChooser(),showFileChooser()和onShowFileChooser() WebChromeClient方法。

    第一步是在用户点击一个文件input时,从网站触发一个javascript控制台消息编写一个唯一的代码 ,用来上传带有唯一名称或path的文件。 例如,将完整的date时间与一个巨大的随机数连接起来:

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

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

     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; } }); 

    对于文件select ,你可以像这样使用一个简单的Android ACTION_PICKE意图

     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 ); } 

    用户select一个文件(或不),你可以接收文件Uri ,并将其转换为一个真正的文件path

     @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方法只是简单地创build一个包含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构build多部分请求,并将其轻松发送到服务器 。 您可以从许多地方获得大量的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("https://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; } 

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

     @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()中的一个字段中完成了该代码),并且必须使用该文件代码来查找应用程序上传到服务器的文件 。 为了达到这个目的,你可以用这个代码作为文件名保存在一个path中,或者把代码和你上传文件的path保存到数据库中。

    这个解决scheme只依赖于可用的元素,并且与所有Android版本兼容,所以它可以在任何设备上工作(而且我还没有收到用户对此的抱怨)。

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

    我在这里修改了一些实际的代码,所以如果有什么失败的话,在重命名一些东西的时候可能会是一个错字或者一些细节。

    这是相当多的信息处理,所以如果任何人需要任何澄清或有build议或更正,请告诉我。

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

    看起来像一个修复已经准备好,但等待释放:

    如果你打算只在你的网站上添加一个webview wrapper并作为一个应用程序启动它,只是不要使用默认的android webview来查看,这种方式或者其他的方式是一个非常头痛的问题。对于我来说,两件事情都不起作用out 1.input文件2. Stripe checkout integeration(使用高级的JS API)

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

    刚刚使用Cordova创build了一个示例应用程序。 我们认为它更简单。

    当使用crosswalk-webview-21.51.546.7并通过相机select图片。 在onActivityResult() the intent.getData()null 。 这意味着通过相机上传图片无法正常工作。

      以上就是android开发分享在android webview(android 4.4,kitkat)中inputHTML文件相关内容,想了解更多android开发(异常处理)及android游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/addevelopment/523385.html

      (0)
      上一篇 2020年12月11日
      下一篇 2020年12月11日

      精彩推荐