前言:因為一直在做E家的項目,剛好碰到這么一個功能蜒什,就是頁面需要調用相機测秸、圖庫,但是因為SDK版本高低不同灾常,尤其是7.0+的霎冯,需要做適配,所以自己總結了一兩個類岗憋,功能簡單而且易懂肃晚,拿下來就能用。
一個意外的坑仔戈,如果點擊沒有反應关串,要去看看設置->權限那里,是不是沒有打開相關的權限监徘,例如讀取SD卡晋修、攝像頭等,很重要,很重要凰盔,很重要墓卦。準備開始了:
一、H5頁面的標簽
<input type="file" accept=".jpeg, .jpg, .png" name="upload_file" id="js-title-img-input">
二户敬、AndroidManifest權限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" /> <!-- 使用照相機權限 -->
<uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自動聚焦權限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
三落剪、在Application的onCreate中
//兼容7.0拍照
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
四睁本、自定義WebChromeClien
class MyWebChromeClient extends WebChromeClient {
其他代碼、忠怖、呢堰、
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
}
// For Android > 4.1.1
public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType, String capture) {
WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
}
// For Android > 5.0支持多張上傳
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> uploadMsg,
FileChooserParams fileChooserParams) {
WebCameraHelper.getInstance().mUploadCallbackAboveL = uploadMsg;
WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
return true;
}
}
五、最重要的核心類WebCameraHelper
**
* @desc web頁面調用本地照相機凡泣、圖庫的相關助手
* @auth 方毅超
* @time 2017/12/8 16:25
*/
public class WebCameraHelper {
private static class SingletonHolder {
static final WebCameraHelper INSTANCE = new WebCameraHelper();
}
public static WebCameraHelper getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 圖片選擇回調
*/
public ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> mUploadCallbackAboveL;
public Uri fileUri;
public static final int TYPE_REQUEST_PERMISSION = 3;
public static final int TYPE_CAMERA = 1;
public static final int TYPE_GALLERY = 2;
/**
* 包含拍照和相冊選擇
*/
public void showOptions(final Activity act) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(act);
alertDialog.setOnCancelListener(new ReOnCancelListener());
alertDialog.setTitle("選擇");
alertDialog.setItems(new CharSequence[]{"相機", "相冊"},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
if (ContextCompat.checkSelfPermission(act,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// 申請WRITE_EXTERNAL_STORAGE權限
ActivityCompat
.requestPermissions(
act,
new String[]{Manifest.permission.CAMERA},
TYPE_REQUEST_PERMISSION);
} else {
toCamera(act);
}
} else {
Intent i = new Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);// 調用android的圖庫
act.startActivityForResult(i,
TYPE_GALLERY);
}
}
});
alertDialog.show();
}
/**
* 點擊取消的回調
*/
private class ReOnCancelListener implements
DialogInterface.OnCancelListener {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
mUploadMessage = null;
}
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(null);
mUploadCallbackAboveL = null;
}
}
}
/**
* 請求拍照
* @param act
*/
public void toCamera(Activity act) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 調用android的相機
// 創(chuàng)建一個文件保存圖片
fileUri = Uri.fromFile(FileManager.getImgFile(act.getApplicationContext()));
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
act.startActivityForResult(intent, TYPE_CAMERA);
}
/**
* startActivityForResult之后要做的處理
* @param requestCode
* @param resultCode
* @param intent
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == TYPE_CAMERA) { // 相冊選擇
if (resultCode == -1) {//RESULT_OK = -1枉疼,拍照成功
if (mUploadCallbackAboveL != null) { //高版本SDK處理方法
Uri[] uris = new Uri[]{fileUri};
mUploadCallbackAboveL.onReceiveValue(uris);
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) { //低版本SDK 處理方法
mUploadMessage.onReceiveValue(fileUri);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "無法獲取數(shù)據(jù)", Toast.LENGTH_LONG).show();
}
} else { //拍照不成功,或者什么也不做就返回了鞋拟,以下的處理非常有必要骂维,不然web頁面不會有任何響應
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(fileUri);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "無法獲取數(shù)據(jù)", Toast.LENGTH_LONG).show();
}
}
} else if (requestCode == TYPE_GALLERY) {// 相冊選擇
if (mUploadCallbackAboveL != null) {
mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) {
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else {
// Toast.makeText(CubeAndroid.this, "無法獲取數(shù)據(jù)", Toast.LENGTH_LONG).show();
}
}
}
}
六、還需要一個小小的文件管理類FileManager
/**
* @desc
* @auth 方毅超
* @time 2017/12/8 14:41
*/
public class FileManager {
public static final String ROOT_NAME = "RongYifu";
public static final String LOG_NAME = "UserLog";
public static final String CACHE_NAME = "Cache";
public static final String IMAGE_NAME = "Image";
public static final String RECORD_NAME = "Voice";
public static final String ROOT_PATH = File.separator + ROOT_NAME
+ File.separator;
public static final String LOG_PATH_NAME = File.separator + LOG_NAME
+ File.separator;
public static final String CACHE_PATH_NAME = File.separator + CACHE_NAME
+ File.separator;
public static final String IMAGE_PATH_NAME = File.separator + IMAGE_NAME
+ File.separator;
public static final String RECORD_PATH_NAME = File.separator + RECORD_NAME
+ File.separator;
public static final String ACTION_DEL_ALL_IMAGE_CACHE = "com.citic21.user_delImageCache";
public static final String CODE_ENCODING = "utf-8";
public static String getRootPath(Context appContext) {
String rootPath = null;
if (checkMounted()) {
rootPath = getRootPathOnSdcard();
} else {
rootPath = getRootPathOnPhone(appContext);
}
return rootPath;
}
public static String getRootPathOnSdcard() {
File sdcard = Environment.getExternalStorageDirectory();
String rootPath = sdcard.getAbsolutePath() + ROOT_PATH;
return rootPath;
}
public static String getRootPathOnPhone(Context appContext) {
File phoneFiles = appContext.getFilesDir();
String rootPath = phoneFiles.getAbsolutePath() + ROOT_PATH;
return rootPath;
}
public static String getSdcardPath() {
File sdDir = null;
boolean sdCardExist = checkMounted(); // 判斷sd卡是否存在
if (sdCardExist) {
sdDir = Environment.getExternalStorageDirectory();// 獲取跟目錄
return sdDir.getPath();
}
return "/";
}
// SD卡剩余空間
public long getSDFreeSize() {
// 取得SD卡文件路徑
File path = Environment.getExternalStorageDirectory();
StatFs sf = new StatFs(path.getPath());
// 獲取單個數(shù)據(jù)塊的大小(Byte)
long blockSize = sf.getBlockSize();
// 空閑的數(shù)據(jù)塊的數(shù)量
long freeBlocks = sf.getAvailableBlocks();
// 返回SD卡空閑大小
// return freeBlocks * blockSize; //單位Byte
// return (freeBlocks * blockSize)/1024; //單位KB
return (freeBlocks * blockSize) / 1024 / 1024; // 單位MB
}
public static boolean checkMounted() {
return Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState());
}
public static String getUserLogDirPath(Context appContext) {
String logPath = getRootPath(appContext) + LOG_PATH_NAME;
return logPath;
}
// 緩存整體路徑
public static String getCacheDirPath(Context appContext) {
String imagePath = getRootPath(appContext) + CACHE_PATH_NAME;
return imagePath;
}
// 圖片緩存路徑
public static String getImageCacheDirPath(Context appContext) {
String imagePath = getCacheDirPath(appContext) + IMAGE_PATH_NAME;
return imagePath;
}
// 創(chuàng)建一個圖片文件
public static File getImgFile(Context context) {
File file = new File(getImageCacheDirPath(context));
if (!file.exists()) {
file.mkdirs();
}
String imgName = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File imgFile = new File(file.getAbsolutePath() + File.separator
+ "IMG_" + imgName + ".jpg");
return imgFile;
}
// 創(chuàng)建拍照處方單路徑
public static File initCreatImageCacheDir(Context appContext) {
String rootPath = getImageCacheDirPath(appContext);
File dir = new File(rootPath);
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
public static final String getFileSize(File file) {
String fileSize = "0.00K";
if (file.exists()) {
fileSize = FormetFileSize(file.length());
return fileSize;
}
return fileSize;
}
public static String FormetFileSize(long fileS) {// 轉換文件大小
DecimalFormat df = new DecimalFormat("0.00");
String fileSizeString = "";
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "K";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "M";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "G";
}
return fileSizeString;
}
public static boolean writeStringToFile(String text, File file) {
try {
return writeStringToFile(text.getBytes(CODE_ENCODING), file);
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
return false;
}
}
static void close(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean writeStringToFile(byte[] datas, File file) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(datas);
fos.flush();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
close(fos);
}
return false;
}
/**
* @param oldpath URL 的 md5+"_tmp"
* @param newpath URL 的 md5+
* @return
*/
public static boolean renameFileName(String oldpath, String newpath) {
try {
File file = new File(oldpath);
if (file.exists()) {
file.renameTo(new File(newpath));
}
return true;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
public static final boolean isFileExists(File file) {
if (file.exists()) {
return true;
}
return false;
}
public static final long getFileSizeByByte(File file) {
long fileSize = 0l;
if (file.exists()) {
fileSize = file.length();
return fileSize;
}
return fileSize;
}
public static boolean checkCachePath(Context appContext) {
String path = getCacheDirPath(appContext);
File file = new File(path);
if (!file.exists()) {
return false;
}
return true;
}
public static String getUrlFileName(String resurlt) {
if (!TextUtils.isEmpty(resurlt)) {
int nameIndex = resurlt.lastIndexOf("/");
String loacalname = "";
if (nameIndex != -1) {
loacalname = resurlt.substring(nameIndex + 1);
}
int index = loacalname.indexOf("?");
if (index != -1) {
loacalname = loacalname.substring(0, index);
}
return loacalname;
} else {
return resurlt;
}
}
// 存儲map類型數(shù)據(jù) 轉換為Base64進行存儲
public static String SceneList2String(Map<String, String> SceneList)
throws IOException {
ByteArrayOutputStream toByte = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(toByte);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
oos.writeObject(SceneList);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 對byte[]進行Base64編碼
String SceneListString = new String(Base64.encode(toByte.toByteArray(),
Base64.DEFAULT));
return SceneListString;
}
}
至此贺纲,所有角色介紹完畢航闺,以下看看大概怎么用吧!可以在Activity或Fragment中哮笆。只要設置一下WebChromeClient来颤,然后在onActivityResult中做返回處理:
1汰扭、webView.setWebChromeClient(new MyWebChromeClient());//設置WebChromeClient
2稠肘、 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
WebCameraHelper.getInstance().onActivityResult(requestCode, resultCode, intent);
}
后言:情況就是這么個情況。這是自己東拼西湊總結的一個小小使用方法萝毛。
感謝:
android Webview 上傳圖片兼容各android版本
Android 7.0 FileUriExposedException 解決项阴,支持新浪微博
android 7.0系統(tǒng)解決拍照的問題android.os.FileUriExposedException:
Android7.0下調用相機閃退的解決方案,這還有一個拍視頻功能的