兩篇起步使用webview參考文章,第一篇解除限制,但會調用外部瀏覽器打開鏈接,第二篇 覆蓋shouldOverrideUrlLoading return true
https://www.jb51.net/article/104199.htm
https://www.cnblogs.com/sohowang/p/3998155.html
android 多媒體和相機詳解五(先學習下相機和相冊的基本操作)
https://www.2cto.com/kf/201207/143320.html
有拍照和選相冊(拍照后無法上傳,相冊選擇可以)
https://blog.csdn.net/a_running_wolf/article/details/77983739
https://download.csdn.net/download/st666/9621904?locationNum=4
真正可用的拍照上傳例子在這(可正常拍照,但沒有選擇相冊)
https://download.csdn.net/download/wangchsh2008/10232317
但是上面這些例子都沒有圖片壓縮功能,上傳拍照的照片過大(>2M)通過流量的會失敗,看來還是有一定的實用限制
H5異步上傳前台(支持選擇后即時查看圖片)
<input type="file" name="thefile" id="j-file"> <img src="" id='j-img' alt="" width="100%"> <button id='j-btn'>upload</button> <script type="text/javascript"> var o_file = document.getElementById('j-file'), o_btn = document.getElementById('j-btn'), o_img = document.getElementById('j-img'), target_file = null; o_file.addEventListener('change',function(event){ var file = event.target.files[0]; if(!file) return; target_file = file; var url = window.URL.createObjectURL(target_file); if(/image/.test(target_file.type)){ o_img.setAttribute('src',url); }else{ console.log('請選擇圖片'); } },false); o_btn.onclick = function(){ if(!target_file) return; //數據處理 var data = new FormData(); data.append('thefile',target_file); var xhr = new XMLHttpRequest(); if(xhr.upload){ xhr.upload.addEventListener("progress", function(e){ var loaded = e.loaded; //已經上傳大小情況 var tot = e.total; //附件總大小 var per = Math.floor(100*loaded/tot); //已經上傳的百分比 console.log(per+'%');//進度 }, false); } xhr.onreadystatechange = function(e) { if (xhr.readyState == 4) { if (xhr.status >=200&&xhr.status<300||xhr.status==304) { //上傳成功 } } }; xhr.onloadend = function(){ //無論失敗或成功 } xhr.onerror = function(){ //網絡失敗 } // 開始上傳 xhr.open("POST",'/LBM/Home/SspBuzPicMng/uploadFile', true); xhr.send(data); } </script>
安卓代碼(拍照+相冊選擇都可以哦,流量上傳超過2M容易失敗)
package com.gtj.admin.gapt; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.content.ClipData; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Parcelable; import android.os.StrictMode; import android.provider.MediaStore; import android.support.annotation.RequiresApi; import android.support.v4.app.ActivityCompat; import android.text.format.DateFormat; import android.util.Log; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.util.Calendar; import java.util.Locale; public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); private WebView mWebView; private String TMP_URL = "http://221.2.169.102:50001/LBM"; private ValueCallback<Uri> mUploadMessage;// 表單的數據信息 private ValueCallback<Uri[]> mUploadCallbackAboveL; private final static int FILECHOOSER_RESULTCODE = 1;// 表單的結果回調</span> private Uri imageUri; File file; @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.main_web); mWebView.loadUrl(TMP_URL); mWebView.getSettings().setJavaScriptEnabled(true); //mWebView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH); WebSettings settings = mWebView.getSettings(); settings.setDomStorageEnabled(true); settings.setUseWideViewPort(true); settings.setLoadWithOverviewMode(true); settings.setAllowContentAccess(true); // 是否可訪問Content Provider的資源,默認值 true settings.setAllowFileAccess(true); // 是否可訪問本地文件,默認值 true // 是否允許通過file url加載的Javascript讀取本地文件,默認值 false settings.setAllowFileAccessFromFileURLs(false); // 是否允許通過file url加載的Javascript讀取全部資源(包括文件,http,https),默認值 false settings.setAllowUniversalAccessFromFileURLs(false); settings.setJavaScriptEnabled(true); settings.setSupportZoom(true); //檢查權限 checkAppPermission(); mWebView.setWebViewClient(new WebViewClient() { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { //返回false,意味着請求過程里,不管有多少次的跳轉請求(即新的請求地址),均交給webView自己處理,這也是此方法的默認處理 //返回true,說明你自己想根據url,做新的跳轉,比如在判斷url符合條件的情況下,我想讓webView加載http://ask.csdn.net/questions/178242 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (request.getUrl().toString().contains("sina.cn")){ view.loadUrl("http://ask.csdn.net/questions/178242"); return true; } } view.loadUrl(request.getUrl().toString()); return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { // TODO Auto-generated method stub super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { // TODO Auto-generated method stub super.onPageFinished(view, url); } }); mWebView.setWebChromeClient(new WebChromeClient() { @Override // onShowFileChooser詳解 http://teachcourse.cn/2224.html public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { mUploadCallbackAboveL = filePathCallback; take(); return true; } public void openFileChooser(ValueCallback<Uri> uploadMsg) { mUploadMessage = uploadMsg; take(); } public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { mUploadMessage = uploadMsg; take(); } public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { mUploadMessage = uploadMsg; take(); } }); //android 7.0系統解決拍照的問題 // StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); // StrictMode.setVmPolicy(builder.build()); // builder.detectFileUriExposure(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == FILECHOOSER_RESULTCODE) { updatePhotos(); if (null == mUploadMessage && null == mUploadCallbackAboveL) return; Uri result = data == null || resultCode != RESULT_OK ? null : data.getData(); if (mUploadCallbackAboveL != null) { onActivityResultAboveL(requestCode, resultCode, data); } else if (mUploadMessage != null) { Log.e("result", result + ""); if (result == null) { // mUploadMessage.onReceiveValue(imageUri); mUploadMessage.onReceiveValue(imageUri); mUploadMessage = null; Log.e("imageUri", imageUri + ""); } else { mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } } } @SuppressWarnings("null") @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) { if (requestCode != FILECHOOSER_RESULTCODE || mUploadCallbackAboveL == null) { return; } Uri[] results = null; if (resultCode == Activity.RESULT_OK) { if (data == null) { results = new Uri[]{imageUri}; } else { String dataString = data.getDataString(); ClipData clipData = data.getClipData(); if (clipData != null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { ClipData.Item item = clipData.getItemAt(i); results[i] = item.getUri(); } } if (dataString != null) results = new Uri[]{Uri.parse(dataString)}; } } if (results != null) { mUploadCallbackAboveL.onReceiveValue(results); mUploadCallbackAboveL = null; } else { results = new Uri[]{imageUri}; mUploadCallbackAboveL.onReceiveValue(results); mUploadCallbackAboveL = null; } return; } private void take() { // int hasCameraContactsPermission = ActivityCompat.checkSelfPermission(this,Manifest.permission.CAMERA); // if (hasCameraContactsPermission != PackageManager.PERMISSION_GRANTED) { // String[] PERMISSIONS_STORAGE = { // Manifest.permission.CAMERA}; // // ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, // 1); // } // // int hasWriteContactsPermission = ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE); // if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) { // String[] PERMISSIONS_STORAGE = { // Manifest.permission.WRITE_EXTERNAL_STORAGE}; // // ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, // 1); // } Log.i(TAG,""+Environment.getExternalStorageDirectory().getPath()); // 指定拍照存儲位置的方式調起相機 String filePath = Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_PICTURES + File.separator; String fileName = "IMG_" + DateFormat.format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg"; file = new File(filePath + fileName); imageUri = Uri.fromFile(file); //調用照相機和瀏覽圖片庫代碼 // Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); // captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // // Intent Photo = new Intent(Intent.ACTION_PICK, // android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); // // Intent chooserIntent = Intent.createChooser(Photo, "Image Chooser"); // chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent}); // startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); //調用系統相機,此代碼在android 7.0以上有問題,需要在onCreate方法加入StrictMode.VmPolicy.Builder解決辦法 // Intent intentCamera = new Intent(); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加這一句表示對目標應用臨時授權該Uri所代表的文件 // } // intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE); // //將拍照結果保存至photo_file的Uri中,不保留在相冊中 // intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // startActivityForResult(intentCamera, FILECHOOSER_RESULTCODE); //Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); //captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); //兼容android 7.0+版本的照相機調用代碼 Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (captureIntent.resolveActivity(getPackageManager()) != null) { /*獲取當前系統的android版本號*/ int currentapiVersion = android.os.Build.VERSION.SDK_INT; Log.e("currentapiVersion","currentapiVersion====>"+currentapiVersion); if (currentapiVersion<24){ captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); //startActivityForResult(intent, FILECHOOSER_RESULTCODE); }else { ContentValues contentValues = new ContentValues(1); contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath()); Uri uri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); //startActivityForResult(intent, FILECHOOSER_RESULTCODE); } } else { Toast.makeText(this, "照相機不存在", Toast.LENGTH_SHORT).show(); return; } Intent Photo = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); Intent chooserIntent = Intent.createChooser(Photo, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent}); startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); } private void updatePhotos() { // 該廣播即使多發(即選取照片成功時也發送)也沒有關系,只是喚醒系統刷新媒體文件 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(imageUri); sendBroadcast(intent); } //這里檢查了存儲權限,如果有需要,可以先檢查下相機權限。 此方法用戶對權限禁止或允許 未做判斷,需要進一步完善 private void checkAppPermission(){ int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; final int REQUEST_EXTERNAL_STORAGE = 1; ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); } } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gtj.admin.gapt" > <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity><!-- ATTENTION: This was auto-generated to add Google Play services to your project for App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information. --> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> </manifest>