真正可用的安卓webview html圖片上傳限制突破處理(拍照+相冊都可以用)


兩篇起步使用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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM