解決WebView文件上傳無法重複選擇問題

640?wx_fmt=png

今日科技快訊

近日,高德公司以不正當競爭糾紛爲案由,將嘀嘀公司起訴至法院。高德認爲滴滴打車採用教唆、勸誘等不正當手段,使該公司多名高管、工程師與其脫離僱傭關係,並有部分員工離職前夕大量拷貝其公司商業祕密的行爲。

作者簡介

又到了週五啦,提前祝大家週末愉快!

本篇來自 釗林 的投稿,分享了一個解決WebView文件上傳無法重複選擇問題的方案,希望能夠幫助到大家。

釗林 的博客地址:

http://teachcourse.cn

正文

Android 開發使用 WebView 控件加載包含表單的 H5 網頁,點擊上傳文件按鈕,彈出對話框,選擇從相冊獲取照片、拍照或打開手機文件管理器,從 Android 手機選取一張圖片或一個文件,然後通過 ValueCallback 接口傳遞,在 WebView 加載的 H5網頁 顯示。

這裏有一個問題,點擊「取消」或返回按鈕,無法重複回調 onShowFileChooser openFileChooser 方法,控制檯打印:

Attempted to finish an input event but the input event receiver has already been disposed

一、深入理解onShowFileChooser或openFileChooser

WebChromeClient 各個方法這裏不再贅述,特殊說明關於 WebChromeClient,它既不是接口也不是抽象類,但聲明的方法很多方法體都是空的,這是讓釗林感到疑惑之一。查看 WebView 源碼,setWebChromeClient() 傳入 WebChromeClient 對象,然後使用傳入的對象,調用 WebChromeClient 聲明的方法,再將一些參數傳遞返回 WebChromeClient 空方法體。在 WebView 源碼裏面代碼也很簡單,詳細的處理處理邏輯看不到,這是讓釗林感到疑惑之二,感覺像一個黑箱子。

然後就一直想,那麼重寫 WebChromeClient 的方法有什麼作用呢?先看一下 onShowFileChooser,如下:

640?wx_fmt=png

該方法的作用,告訴當前APP,打開一個文件選擇器,比如:打開相冊、啓動拍照或打開本地文件管理器,實際上更好的理解,WebView 加載包含上傳文件的表單按鈕,HTML 定義了 input 標籤,同時 input 的 type 類型爲 file,手指點擊該按鈕,回調 onShowFileChooser 這個方法,在這個重寫的方法裏面打開相冊、啓動照片或打開本地文件管理器,甚至做其他任何的邏輯處理,點擊一次回調一次的前提是請求被取消,而取消該請求回調的方法:給 ValueCallback 接口的 onReceiveValue 抽象方法傳入 null,同時 onShowFileChooser 方法返回 true

ValueCallback 的抽象方法被回調 onShowFileChooser 方法返回 true;反之返回 false;再來看一下 openFileChooser 的源碼,如下:

640?wx_fmt=png

在所有發佈的SDK版本中,openFileChooser 是一個隱藏的方法,使用 onShowFileChooser 代替,但是最好同時重寫 showFileChooser openFileChooser 方法,Android 4.4.X 以上的系統回調 onShowFileChooser 方法,低於或等於 Android 4.4.X 的系統回調 openFileChooser 方法,只重寫 onShowFileChooser openFileChooser 造成在有的系統可以正常回調,在有的系統點擊沒有反應。

仔細分析 onShowFileChooser openFileChooser 回調方法,這兩個方法之間的區別:

第一個區別:前者 ValueCallback 接口回傳一個 Uri數組,後者回傳一個 Uri對象,在 onActivityResult 回調方法中調用 ValueCallback 接口方法 onReceiveValue 傳入參數特別注意。

640?wx_fmt=png

第二個區別:前者 將 後者的 acceptType、capture 封裝成 FileChooserParams 抽象類

二、實例展示onShowFileChooser或openFileChooser處理過程

640?wx_fmt=png

這是實例運行的效果圖,H5表單寫入兩個上傳文件的按鈕,點擊其中一個從底部彈出對話框,選擇相冊文件或拍照,點擊「取消」按鈕,再次點擊「上傳文件」按鈕能夠再次回調 onShowFileChooser openFileChooser 方法。

在之前的理解中,誤解 onShowFileChooser openFileChooser 只能打開相冊或啓動相機拍照,其實不僅僅是這樣,onShowFileChooser openFileChooser 既然是一個回調的方法,可以重複執行各種邏輯代碼,比如:啓動另一個Activity、彈窗對話框、錄製視頻或錄音等

在上面的例子中,執行彈窗操作,將彈窗的處理代碼放置 onShowFileChooser openFileChooser 方法體,如下:

640?wx_fmt=png

點擊彈窗 取消按鈕、點擊打開相冊 取消操作 取消拍照,可能無法再次回調onShowFileChooser openFileChooser 方法,如果你沒有在點擊彈窗取消方法中或 onActivityResult 回調方法 resultCode==RESULT_CANCELED 處理,再次點擊上傳按鈕,打印出 log:

Attempted to finish an input event but the input event receiver has already been disposed

同時,點擊沒有效果。解決方案:

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

在不期待回調 mFilePathCallback 的 onReceiveValue 方法時,調用 cancelFilePathCallback(),解決點擊上傳按鈕無法重複回調的問題。

更多

每天學習累了,看些搞笑的段子放鬆一下吧。關注最具娛樂精神的公衆號,每天都有好心情。

640?wx_fmt=gif

如果你有好的技術文章想和大家分享,歡迎向我的公衆號投稿,投稿具體細節請在公衆號主頁點擊「投稿」菜單查看。

歡迎長按下圖 -> 識別圖中二維碼或者掃一掃關注我的公衆號:

640?wx_fmt=jpeg