若是以爲掘金上看圖片放大看不清楚,能夠跳到另外的同步發佈的連接看,放大圖片下部有個能夠查看原圖功能,很清楚:項目需求討論 - WebView下拍照及圖片選擇功能html
如今不少app裏面,都會有這麼一個需求,就是上傳圖片的按鈕,固然按了這個按鈕以後,就會出現二種選擇: 1. 直接拍照,2. 相冊選擇現有圖片。android
由於如今的app這塊功能會有二個大的狀況:web
本文先討論HyBrid的app的實現狀況,下次再討論原生,不過其實大部分實現都是類似的。bash
其實這種在WebView配合下實現這類功能的文章不少不少,可是大多數都是上傳一大段代碼,而後讓你們本身看,千篇一概,因此本文主要是寫的完整的思路。服務器
咱們知道用戶會在網頁上點擊了某個按鈕,而後調用起安卓方面的相關操做。而後實現完整的功能。app
其實網頁端很簡單,只須要實現一個簡單的<input>
標籤便可。async
整體思路是一個<input>
標籤和一個<img>
標籤重疊在一塊兒(<input>
在上,<img>
在下,相似能夠理解<img>
做爲背景),當選完照片後,最後把圖片賦值給<img>
標籤。ide
可是在給<img>
賦值的時候我遇到過不一樣的狀況:ui
當在Android這邊拍照或者進入圖庫選完照片後,把圖片信息給了網頁端後,<input>
標籤的onchange監聽到了圖片選擇好了,網頁端直接把圖片上傳到服務器並傳回來一個地址,顯示時把地址拼接成能夠找到路徑的地址放在<img>
標籤中就能夠了。this
配合FileReader,FileReader是做爲文件API的重要成員用於讀取文件。能夠參考: h5 實現調用系統拍照或者選擇照片並預覽
由於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版原本進行大的劃分。
Android 5.0及以上版本:
Android 5.0如下版本:
都是openFileChooser方法,不一樣版本的裏面參數不一樣。
因此咱們能夠看到主要是openFileChooser
和onShowFileChooser
方法。
// 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);
};
複製代碼
因此咱們知道了,咱們最後是調用openFileChooser
和onShowFileChooser
方法裏面的ValueCallback
參數,調用它的onReceiveValue
方法把咱們的選擇的圖片的Uri傳入,網頁端那邊就會收到信息了,就知道用戶到底選擇了什麼圖片。
因此咱們最終目標就是獲取選擇的圖片的Uri,而後給ValueCallback.onReceiveValue方法,這就是咱們整個文章的最主要的流程。
上面咱們提到了,咱們最終目標是獲取用戶選取的圖片Uri
,而後傳給ValueCallback
就能夠。 因此咱們這裏就要講二大塊:
Uri
。根據這二點,咱們一步步來分析。
咱們確定想到是用戶點擊了某個按鈕後,咱們須要跳出一個彈框,而後上面有拍照和圖庫按鈕: 好比我使用系統自帶的選擇框(不一樣手機顯示的彈框不一樣):
因此咱們這裏知道了這個又要細分任務:
emmm......這塊我以爲應該不須要花更多的時間來講明瞭吧,主要就是:
而咱們要申請的權限無非就是 Camera的權限,還有讀寫外部存儲的權限。
咱們先來看拍照:
咱們知道打開某個界面,就是startActivity(Intent);日常好比跳到撥號界面等。只要對Intent設定相應的Action便可。 具體咱們能夠看谷歌的Android官方教程網頁便可:
咱們能夠看到有這些:
咱們能夠這個目錄中看到了相機,咱們具體看相機的介紹:
注:當您使用 ACTION_IMAGE_CAPTURE拍攝照片時,相機可能還會在結果 Intent 中返回縮小尺寸的照片副本(縮略圖),這個副本以 Bitmap 形式保存在名爲
data
的extra
字段中。
因此咱們這裏跳到拍照界面也是同樣,只要創建跳到相機界面的Intent便可:
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
複製代碼
由於有些人須要在本身的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_MULTIPLE
爲true
。
同時也給出了實例代碼:
這裏我要提一下,咱們在設置Intent
的Action
的時候不僅是可使用ACTION_GET_CONTENT
,還可使用ACTION_PICK
。
咱們能夠看到上面寫着能夠用來選擇數據,而後返回被選中的選項。
可是在具體手機操做上有點不一樣(不知道不一樣的手機系統會不會結果不一樣,我只測了模擬器):
ps:最坑的是用ACTION_GET_CONTEN時候多選圖片要長按操做,一直覺得沒成功,覺得多選圖片功能沒實現,後來在 Android: Intent.EXTRA_ALLOW_MULTIPLE allows only single picking 上面找到別人的答案,說須要長按
咱們能夠看到能夠自定義彈框,好比咱們設定固定的按鈕,而後再點擊特定按鈕後啓動咱們的上面提過的特定的Intent便可。
這裏咱們講若是隻是給定咱們想要啓動的多個Intent的選項,讓系統幫咱們彈出彈框及相關按鈕,關鍵字就是Intent.createChooser
方法
直接看圖片便可,寫的很詳細了,或者你們搜相關的關鍵字也是有不少文章的。好比:Android createChooser方法源碼簡析等。
startActivity
確定不夠,因此你們確定想到了使用
startActivityForResult
來啓動,這樣才能根據用戶不一樣的操做來進行相應的處理。
咱們知道須要複寫onActivityResult
來處理,主要也就三個參數(int requestCode, int resultCode, Intent data)
。具體的內容圖片裏面也寫的很清楚。
因此咱們ValueCallback實例在 WebChromeClient的方法裏面拿到了,Uri也經過相機或者圖庫的選擇下獲取到了。最終調用把獲取的Uri 賦值給ValueCallback.onReceiveValue()便可。
PS: 取消此次網頁點擊選取圖片的請求,只須要調用onReceiveValue(null)便可。
emm.......你們輕噴便可。。。。