項目需求討論 - WebView下拍照及圖片選擇功能

前言:

若是以爲掘金上看圖片放大看不清楚,能夠跳到另外的同步發佈的連接看,放大圖片下部有個能夠查看原圖功能,很清楚:項目需求討論 - WebView下拍照及圖片選擇功能html

如今不少app裏面,都會有這麼一個需求,就是上傳圖片的按鈕,固然按了這個按鈕以後,就會出現二種選擇: 1. 直接拍照,2. 相冊選擇現有圖片。android

由於如今的app這塊功能會有二個大的狀況:web

  1. 所有原生的 app 來實現。
  2. HyBrid 的 app 來實現。

本文先討論HyBrid的app的實現狀況,下次再討論原生,不過其實大部分實現都是類似的。bash

其實這種在WebView配合下實現這類功能的文章不少不少,可是大多數都是上傳一大段代碼,而後讓你們本身看,千篇一概,因此本文主要是寫的完整的思路。服務器

正文:

咱們知道用戶會在網頁上點擊了某個按鈕,而後調用起安卓方面的相關操做。而後實現完整的功能。app

1. 網頁端:

其實網頁端很簡單,只須要實現一個簡單的<input>標籤便可。async

整體思路是一個<input>標籤和一個<img>標籤重疊在一塊兒(<input>在上,<img>在下,相似能夠理解<img>做爲背景),當選完照片後,最後把圖片賦值給<img>標籤。ide

可是在給<img>賦值的時候我遇到過不一樣的狀況:ui

  1. 當在Android這邊拍照或者進入圖庫選完照片後,把圖片信息給了網頁端後,<input>標籤的onchange監聽到了圖片選擇好了,網頁端直接把圖片上傳到服務器並傳回來一個地址,顯示時把地址拼接成能夠找到路徑的地址放在<img>標籤中就能夠了。this

  2. 配合FileReader,FileReader是做爲文件API的重要成員用於讀取文件。能夠參考: h5 實現調用系統拍照或者選擇照片並預覽

2. Android端:

2.1 WebChromeClient

由於Android端訪問網頁大部分使用的是WebView,因此咱們這裏仍是用WebView來講明。

既然用戶在網頁上點擊了<input>,咱們確定須要WebView能監聽到,比如原生的Button點擊咱們要監聽也要寫一個OnclickListener來實現監聽。咱們這裏使用的是WebChromeClient

public class ImgWebChromeClient extends WebChromeClient {
        
      //.......
      //.......
        
     public ImgWebChromeClient(Activity activity) {
         this.activity = activity;
     }

        
        
}
複製代碼

咱們實現咱們的類,繼承WebChromeClient。而後咱們就能夠把這個咱們本身定義的WebChromeClient設置給咱們的WebView。

webView.setWebChromeClient(new ImgWebChromeClient(this));
複製代碼

咱們能夠看到咱們在WebChromeClient在監聽<input>點擊事件的時候,還要根據不一樣的版原本區分,主要是以Android 5.0版原本進行大的劃分。

  1. Android 5.0及以上版本:

  2. Android 5.0如下版本:

都是openFileChooser方法,不一樣版本的裏面參數不一樣。

因此咱們能夠看到主要是openFileChooseronShowFileChooser方法。

// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> valueCallback) {
            ***
}

// For Android  >= 3.0
public void openFileChooser(ValueCallback valueCallback, String acceptType) {
            ***
}

//For Android  >= 4.1
public void openFileChooser(ValueCallback<Uri> valueCallback, 
                String acceptType, String capture) {
            ***
}

// For Android >= 5.0
@Override
public boolean onShowFileChooser(WebView webView, 
                ValueCallback<Uri[]> filePathCallback, 
                WebChromeClient.FileChooserParams fileChooserParams) {
            ***
     return true;
}
複製代碼

不論是什麼版本,咱們看到這幾個方法的參數裏面都有ValueCallback參數。

/**
 * A callback interface used to provide values asynchronously.
 */
public interface ValueCallback<T> {
    /**
     * Invoked when the value is available.
     * @param value The value.
     */
    public void onReceiveValue(T value);
};
複製代碼

因此咱們知道了,咱們最後是調用openFileChooseronShowFileChooser方法裏面的ValueCallback參數,調用它的onReceiveValue方法把咱們的選擇的圖片的Uri傳入,網頁端那邊就會收到信息了,就知道用戶到底選擇了什麼圖片。

因此咱們最終目標就是獲取選擇的圖片的Uri,而後給ValueCallback.onReceiveValue方法,這就是咱們整個文章的最主要的流程。

2.2 獲取相關圖片的Uri

上面咱們提到了,咱們最終目標是獲取用戶選取的圖片Uri,而後傳給ValueCallback就能夠。 因此咱們這裏就要講二大塊:

  1. 用戶怎麼跳到本身想要的界面(相機 or 圖庫)
  2. 用戶在本身想要的界面選擇好了圖片後 (拍好了照片 or 在圖庫選擇好了圖片),如何獲取相關圖片的Uri

根據這二點,咱們一步步來分析。

2.2.1 相機 or 圖庫

咱們確定想到是用戶點擊了某個按鈕後,咱們須要跳出一個彈框,而後上面有拍照和圖庫按鈕: 好比我使用系統自帶的選擇框(不一樣手機顯示的彈框不一樣):

因此咱們這裏知道了這個又要細分任務:

  1. 獲取相關權限
  2. 如何點擊按鈕後能夠跳到相應界面(拍照 or 圖庫)。
  3. 如何建立彈框,把上面的按鈕顯示在上面
2.2.1.1 獲取相關權限

emmm......這塊我以爲應該不須要花更多的時間來講明瞭吧,主要就是:

  1. 檢查權限 (checkSelfPermission)
  2. 請求權限(requestPermissions)
  3. 回調事件處理(onRequestPermissionsResult)

而咱們要申請的權限無非就是 Camera的權限,還有讀寫外部存儲的權限。

2.2.1.2 如何點擊按鈕後能夠跳到相應界面(拍照 or 圖庫):

咱們先來看拍照:

2.2.1.2.1 設置打開相機Intent的Action

咱們知道打開某個界面,就是startActivity(Intent);日常好比跳到撥號界面等。只要對Intent設定相應的Action便可。 具體咱們能夠看谷歌的Android官方教程網頁便可:

Android指南 - 通用 Intent

咱們能夠看到有這些:

咱們能夠這個目錄中看到了相機,咱們具體看相機的介紹:

:當您使用 ACTION_IMAGE_CAPTURE拍攝照片時,相機可能還會在結果 Intent 中返回縮小尺寸的照片副本(縮略圖),這個副本以 Bitmap 形式保存在名爲 dataextra 字段中。

因此咱們這裏跳到拍照界面也是同樣,只要創建跳到相機界面的Intent便可:

Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
複製代碼
2.2.1.2.2 設置相機拍攝的照片的存儲位置

由於有些人須要在本身的APP中調用拍照的功能,存在本身指定的目錄下面,因此須要在startActivity啓動相機界面時候同時傳遞過去信息,告訴拍照了以後照片存的位置。

1.咱們先指定咱們的要存儲的照片的路徑Uri:

其實很簡單,設定咱們接下去要拍的照片的完整存儲路徑,而後獲得File對象,再經過Uri.fromFile方法再經過剛纔咱們的File對象來得到Uri

(固然若是這裏你只須要打開系統相機,如下第二部分能夠忽略)

2.獲取全部相機的Intent集合:

由於咱們手機上面可能有不少個相機軟件,因此咱們須要先找到能打開各自相機軟件的Intent,咱們經過PackageManager.queryIntentActivities的方式來進行符合拍照Action的Intent的軟件,而後獲得它們具體的詳細信息,好比包名及對應的activity名字等,而後把相應的Intent變得更加詳細便可。

3.把uri賦值給Intent:

在上面貼出的Android 官方網頁上面的相機部分其實也提到過了如何設置存儲位置:

因此這裏咱們只須要找到相應的Intent,而後把咱們的Uri位置賦值給Intent便可:

intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
複製代碼

最後只須要startActivity去啓動咱們這個指定了打開相機的特定Intent便可。


拍照說完了,咱們再來看在圖庫界面選擇圖片: 其實整體思路和拍照是如出一轍,無非就是指定Intent是打開了圖庫的Intent。

仍是在剛纔的Android 官網咱們能夠看到:

由於咱們是查看本地的圖片,因此咱們要使用 ACTION_GET_CONTENT,同時指定MIME類型是圖片類型,若是要進行圖片多選,就再指定EXTRA_ALLOW_MULTIPLEtrue

同時也給出了實例代碼:

這裏我要提一下,咱們在設置IntentAction的時候不僅是可使用ACTION_GET_CONTENT,還可使用ACTION_PICK

咱們能夠看到上面寫着能夠用來選擇數據,而後返回被選中的選項。

可是在具體手機操做上有點不一樣(不知道不一樣的手機系統會不會結果不一樣,我只測了模擬器):

ps:最坑的是用ACTION_GET_CONTEN時候多選圖片要長按操做,一直覺得沒成功,覺得多選圖片功能沒實現,後來在 Android: Intent.EXTRA_ALLOW_MULTIPLE allows only single picking 上面找到別人的答案,說須要長按

2.2.2 出現選擇框讓用戶選擇

咱們能夠看到能夠自定義彈框,好比咱們設定固定的按鈕,而後再點擊特定按鈕後啓動咱們的上面提過的特定的Intent便可。

這裏咱們講若是隻是給定咱們想要啓動的多個Intent的選項,讓系統幫咱們彈出彈框及相關按鈕,關鍵字就是Intent.createChooser方法

直接看圖片便可,寫的很詳細了,或者你們搜相關的關鍵字也是有不少文章的。好比:Android createChooser方法源碼簡析等。

2.2.3 獲取用戶在相機或者圖庫選擇的圖片Uri

由於咱們不是單純的跳到了相機界面或者是圖庫界面就能夠了,咱們還須要獲取用戶在那些應用外的界面到底選了什麼圖片,因此單純的 startActivity確定不夠,因此你們確定想到了使用 startActivityForResult來啓動,這樣才能根據用戶不一樣的操做來進行相應的處理。

咱們知道須要複寫onActivityResult來處理,主要也就三個參數(int requestCode, int resultCode, Intent data)。具體的內容圖片裏面也寫的很清楚。


2.3 Uri 和 ValueCallback

因此咱們ValueCallback實例在 WebChromeClient的方法裏面拿到了,Uri也經過相機或者圖庫的選擇下獲取到了。最終調用把獲取的Uri 賦值給ValueCallback.onReceiveValue()便可。

PS: 取消此次網頁點擊選取圖片的請求,只須要調用onReceiveValue(null)便可。

結語:

emm.......你們輕噴便可。。。。

相關文章
相關標籤/搜索