1. 程式人生 > >Webview 相容android4.4版本上傳本地圖片

Webview 相容android4.4版本上傳本地圖片

針對Webview 支援上傳本地圖片情況,查詢大量資料後發現對版本4.4相容沒有現成的解決方案,目前根據現有開源原始碼做個修改,可以支援相容支援4.4版本上傳圖片:

具體是在onActivityResult 裡多加了層判斷:

 /*
          * 若當前版本API為19, 則把Uri路徑轉換成new File性質的Uri路徑
          * 若非 則按照之前方法呼叫即可
          * */
          if (Build.VERSION.SDK_INT == 19) {
          
              String realPathFromURI =
getRealPathFromURI(intent.getData()); File file = new File(realPathFromURI); if(file.exists()){ Uri uri = Uri.fromFile(file); mFileUploadCallbackFirst.onReceiveValue(uri); } } else { mFileUploadCallbackFirst.
onReceiveValue(intent.getData()); }

根據Uri 獲取圖片真實路徑的方法用的是:

  /*
    * 
    * 獲取Uri圖片真實路徑的方法
    * */
    public String getRealPathFromURI(Uri contentUri) {
        String res = null;
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = mContext.getContentResolver
().query(contentUri, proj, null, null, null); if (cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); res = cursor.getString(column_index); } cursor.close(); return res; }

此方法,測試後webview可以相容4.4版本上傳本地圖片。

修改原始碼後的所有程式碼 如下:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Environment;
import android.os.Message;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Base64;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ClientCertRequest;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.PermissionRequest;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
 
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
 
/*
 * Android-AdvancedWebView (https://github.com/delight-im/Android-AdvancedWebView)
 * Copyright (c) delight.im (https://www.delight.im/)
 * Licensed under the MIT License (https://opensource.org/licenses/MIT)
 */
 
/**
 * Advanced WebView component for Android that works as intended out of the box
 */
@SuppressWarnings("deprecation")
public class MyWebView extends WebView {
 
    private Context mContext;
 
    public interface Listener {
        void onPageStarted(String url, Bitmap favicon);
 
        void onPageFinished(String url);
 
        void onPageError(int errorCode, String description, String failingUrl);
 
        void onDownloadRequested(String url, String suggestedFilename, String mimeType, long contentLength, String contentDisposition, String userAgent);
 
        void onExternalPageRequest(String url);
    }
 
    public static final String PACKAGE_NAME_DOWNLOAD_MANAGER = "com.android.providers.downloads";
    protected static final int REQUEST_CODE_FILE_PICKER = 51426;
    protected static final String DATABASES_SUB_FOLDER = "/databases";
    protected static final String LANGUAGE_DEFAULT_ISO3 = "eng";
    protected static final String CHARSET_DEFAULT = "UTF-8";
    /**
     * Alternative browsers that have their own rendering engine and *may* be installed on this device
     */
    protected static final String[] ALTERNATIVE_BROWSERS = new String[]{"org.mozilla.firefox", "com.android.chrome", "com.opera.browser", "org.mozilla.firefox_beta", "com.chrome.beta", "com.opera.browser.beta"};
    protected WeakReference<Activity> mActivity;
    protected WeakReference<Fragment> mFragment;
    protected Listener mListener;
    protected final List<String> mPermittedHostnames = new LinkedList<String>();
    /**
     * File upload callback for platform versions prior to Android 5.0
     */
    protected ValueCallback<Uri> mFileUploadCallbackFirst;
    /**
     * File upload callback for Android 5.0+
     */
    protected ValueCallback<Uri[]> mFileUploadCallbackSecond;
    protected long mLastError;
    protected String mLanguageIso3;
    protected int mRequestCodeFilePicker = REQUEST_CODE_FILE_PICKER;
    protected WebViewClient mCustomWebViewClient;
    protected WebChromeClient mCustomWebChromeClient;
    protected boolean mGeolocationEnabled;
    protected String mUploadableFileTypes = "*/*";
    protected final Map<String, String> mHttpHeaders = new HashMap<String, String>();
 
    public MyWebView(Context context) {
        super(context);
        init(context);
    }
 
    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
 
    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
 
    public void setListener(final Activity activity, final Listener listener) {
        setListener(activity, listener, REQUEST_CODE_FILE_PICKER);
    }
 
    public void setListener(final Activity activity, final Listener listener, final int requestCodeFilePicker) {
        if (activity != null) {
            mActivity = new WeakReference<Activity>(activity);
        } else {
            mActivity = null;
        }
 
        setListener(listener, requestCodeFilePicker);
    }
 
    public void setListener(final Fragment fragment, final Listener listener) {
        setListener(fragment, listener, REQUEST_CODE_FILE_PICKER);
    }
 
    public void setListener(final Fragment fragment, final Listener listener, final int requestCodeFilePicker) {
        if (fragment != null) {
            mFragment = new WeakReference<Fragment>(fragment);
        } else {
            mFragment = null;
        }
 
        setListener(listener, requestCodeFilePicker);
    }
 
    protected void setListener(final Listener listener, final int requestCodeFilePicker) {
        mListener = listener;
        mRequestCodeFilePicker = requestCodeFilePicker;
    }
 
    @Override
    public void setWebViewClient(final WebViewClient client) {
        mCustomWebViewClient = client;
    }
 
    @Override
    public void setWebChromeClient(final WebChromeClient client) {
        mCustomWebChromeClient = client;
    }
 
    @SuppressLint("SetJavaScriptEnabled")
    public void setGeolocationEnabled(final boolean enabled) {
        if (enabled) {
            getSettings().setJavaScriptEnabled(true);
            getSettings().setGeolocationEnabled(true);
            setGeolocationDatabasePath();
        }
 
        mGeolocationEnabled = enabled;
    }
 
    @SuppressLint("NewApi")
    protected void setGeolocationDatabasePath() {
        final Activity activity;
 
        if (mFragment != null && mFragment.get() != null && Build.VERSION.SDK_INT >= 11 && mFragment.get().getActivity() != null) {
            activity = mFragment.get().getActivity();
        } else if (mActivity != null && mActivity.get() != null) {
            activity = mActivity.get();
        } else {
            return;
        }
 
        getSettings().setGeolocationDatabasePath(activity.getFilesDir().getPath());
    }
 
    public void setUploadableFileTypes(final String mimeType) {
        mUploadableFileTypes = mimeType;
    }
 
    /**
     * Loads and displays the provided HTML source text
     *
     * @param html the HTML source text to load
     */
    public void loadHtml(final String html) {
        loadHtml(html, null);
    }
 
    /**
     * Loads and displays the provided HTML source text
     *
     * @param html    the HTML source text to load
     * @param baseUrl the URL to use as the page's base URL
     */
    public void loadHtml(final String html, final String baseUrl) {
        loadHtml(html, baseUrl, null);
    }
 
    /**
     * Loads and displays the provided HTML source text
     *
     * @param html       the HTML source text to load
     * @param baseUrl    the URL to use as the page's base URL
     * @param historyUrl the URL to use for the page's history entry
     */
    public void loadHtml(final String html, final String baseUrl, final String historyUrl) {
        loadHtml(html, baseUrl, historyUrl, "utf-8");
    }
 
    /**
     * Loads and displays the provided HTML source text
     *
     * @param html       the HTML source text to load
     * @param baseUrl    the URL to use as the page's base URL
     * @param historyUrl the URL to use for the page's history entry
     * @param encoding   the encoding or charset of the HTML source text
     */
    public void loadHtml(final String html, final String baseUrl, final String historyUrl, final String encoding) {
        loadDataWithBaseURL(baseUrl, html, "text/html", encoding, historyUrl);
    }
 
    @SuppressLint("NewApi")
    @SuppressWarnings("all")
    public void onResume() {
        if (Build.VERSION.SDK_INT >= 11) {
            super.onResume();
        }
        resumeTimers();
    }
 
    @SuppressLint("NewApi")
    @SuppressWarnings("all")
    public void onPause() {
        pauseTimers();
        if (Build.VERSION.SDK_INT >= 11) {
            super.onPause();
        }
    }
 
    public void onDestroy() {
        // try to remove this view from its parent first
        try {
            ((ViewGroup) getParent()).removeView(this);
        } catch (Exception ignored) {
        }
 
        // then try to remove all child views from this view
        try {
            removeAllViews();
        } catch (Exception ignored) {
        }
 
        // and finally destroy this view
        destroy();
    }
 
    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        if (requestCode == mRequestCodeFilePicker) {
            if (resultCode == Activity.RESULT_OK) {
                if (intent != null) {
                    int sdkInt = Build.VERSION.SDK_INT;
                    android.util.Log.e("tag", "當前的版本為" + sdkInt);
                    if (mFileUploadCallbackFirst != null) {
                        /*
                        * 若當前版本API為19, 則把Uri路徑轉換成new File性質的Uri路徑
                        * 若非 則按照之前方法呼叫即可
                        * */
                       <span style="color:#3333FF;"> if (Build.VERSION.SDK_INT == 19) {
 
                            String realPathFromURI = getRealPathFromURI(intent.getData());
                            File file = new File(realPathFromURI);
                           if(file.exists()){
                               Uri uri = Uri.fromFile(file);
                               mFileUploadCallbackFirst.onReceiveValue(uri);
                           }
 
                        } else {
                            mFileUploadCallbackFirst.onReceiveValue(intent.getData());
                        }</span>
 
                        mFileUploadCallbackFirst = null;
                    } else if (mFileUploadCallbackSecond != null) {
                        Uri[] dataUris = null;
 
                        try {
                            if (intent.getDataString() != null) {
                                dataUris = new Uri[]{Uri.parse(intent.getDataString())};
                            } else {
                                if (Build.VERSION.SDK_INT >= 16) {
                                    if (intent.getClipData() != null) {
                                        final int numSelectedFiles = intent.getClipData().getItemCount();
 
                                        dataUris = new Uri[numSelectedFiles];
 
                                        for (int i = 0; i < numSelectedFiles; i++) {
                                            dataUris[i] = intent.getClipData().getItemAt(i).getUri();
                                        }
                                    }
                                }
                            }
                        } catch (Exception ignored) {
                        }
 
                        mFileUploadCallbackSecond.onReceiveValue(dataUris);
                        mFileUploadCallbackSecond = null;
                    }
                }
            } else {
                if (mFileUploadCallbackFirst != null) {
                    mFileUploadCallbackFirst.onReceiveValue(null);
                    mFileUploadCallbackFirst = null;
                } else if (mFileUploadCallbackSecond != null) {
                    mFileUploadCallbackSecond.onReceiveValue(null);
                    mFileUploadCallbackSecond = null;
                }
            }
        }
    }
 
    /**
     * Adds an additional HTTP header that will be sent along with every HTTP `GET` request
     * <p/>
     * This does only affect the main requests, not the requests to included resources (e.g. images)
     * <p/>
     * If you later want to delete an HTTP header that was previously added this way, call `removeHttpHeader()`
     * <p/>
     * The `WebView` implementation may in some cases overwrite headers that you set or unset
     *
     * @param name  the name of the HTTP header to add
     * @param value the value of the HTTP header to send
     */
    public void addHttpHeader(final String name, final String value) {
        mHttpHeaders.put(name, value);
    }
 
    /**
     * Removes one of the HTTP headers that have previously been added via `addHttpHeader()`
     * <p/>
     * If you want to unset a pre-defined header, set it to an empty string with `addHttpHeader()` instead
     * <p/>
     * The `WebView` implementation may in some cases overwrite headers that you set or unset
     *
     * @param name the name of the HTTP header to remove
     */
    public void removeHttpHeader(final String name) {
        mHttpHeader