`
ch_kexin
  • 浏览: 897612 次
  • 性别: Icon_minigender_2
  • 来自: 青岛
社区版块
存档分类
最新评论

WebView完美解决上传图库图片

 
阅读更多

  我们在使用WebView这个控件的时候,经常需要去写一些方法供H5页面调用,我在开发的过程中遇到这样一个需求,通过点击H5页面上的按钮调用Android手机的图库,并且进行上传图片。

   通过网上查找资料,找到了WebChromeClient的一个隐藏方法openFileChooser();

  • Android3.0以下的SDK,openFileChooser仅有一个参数:openFileChooser(ValueCallback< Uri > uploadFile)。
  • Android3.0以上的SDK,openFileChooser有两个参数:openFileChooser(ValueCallback< Uri > uploadFile, String acceptType)。
  • Android4.1以上的SDK,openFileChooser增加到三个参数:openFileChooser(ValueCallback< Uri > uploadFile, String acceptType, String capture)。
  • Android5.0以上的SDK,openFileChooser被onShowFileChooser给替代了,onShowFileChooser(WebView webview,ValueCallback< Uri > filePathCallback,FileChooserParams fileChooserParams)。

Android6.0的SDK,WebChromeClient.class里的openFileChooser和onShowFileChooser的源码: 
方法openFileChooser:

 /**
     * Tell the client to open a file chooser.
     * @param uploadFile A ValueCallback to set the URI of the file to upload.
     *      onReceiveValue must be called to wake up the thread.a
     * @param acceptType The value of the 'accept' attribute of the input tag
     *         associated with this file picker.
     * @param capture The value of the 'capture' attribute of the input tag
     *         associated with this file picker.
     *
     * @deprecated Use {@link #showFileChooser} instead.
     * @hide This method was not published in any SDK version.
     */
    @SystemApi
    @Deprecated
    public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
        uploadFile.onReceiveValue(null);
    }

 方法onShowFileChooser:

 /**
     * Tell the client to show a file chooser.
     *
     * This is called to handle HTML forms with 'file' input type, in response to the
     * user pressing the "Select File" button.
     * To cancel the request, call <code>filePathCallback.onReceiveValue(null)</code> and
     * return true.
     *
     * @param webView The WebView instance that is initiating the request.
     * @param filePathCallback Invoke this callback to supply the list of paths to files to upload,
     *                         or NULL to cancel. Must only be called if the
     *                         <code>showFileChooser</code> implementations returns true.
     * @param fileChooserParams Describes the mode of file chooser to be opened, and options to be
     *                          used with it.
     * @return true if filePathCallback will be invoked, false to use default handling.
     *
     * @see FileChooserParams
     */
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
            FileChooserParams fileChooserParams) {
        return false;
    }

 来看下代码: 

这是一个内部类,重写WebChromeClient的openFileChooser和onShowFileChooser。

   /**
     * 内部类
     */
    class MyWebChromeClient extends WebChromeClient {

        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                String acceptType) {
            if (mUploadMessage != null)
                return;
            mUploadMessage = uploadMsg;
            selectImage(RESULT_CODE_PICK_FROM_ALBUM_BELLOW_LOLLILOP);
        }

        // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, "");
        }

        // For Android > 4.1.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                String acceptType, String capture) {
            openFileChooser(uploadMsg, acceptType);
        }

        // For Android 5.0+
        public boolean onShowFileChooser(WebView webView,
                ValueCallback<Uri[]> filePathCallback,
                FileChooserParams fileChooserParams) {
            mUploadCallbackAboveL = filePathCallback;
            selectImage(RESULT_CODE_PICK_FROM_ALBUM_ABOVE_LOLLILOP);
            return true;
        }

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }
    }

 openFileChooser和onShowFileChooser方法,当Web页面上点击了<input type="file"/>的标签时,不同版本的SDK调用openFileChooser或者onShowFileChooser。

选择完图片后,进入onActivityResult,根据不同的requestCode值区分开AndroidSDK 5.0以上和5.0以下,5.0以下传回Uri对象,5.0以上传回Uri数组。其中处理下onActivityResult传回来的Intent data,将Intent data转换成Uri。

    /**选择后,回传值*/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (mUploadMessage == null && mUploadCallbackAboveL == null) {
            return;
        }
        Uri uri = null;
        switch (requestCode) {
        case RESULT_CODE_PICK_FROM_ALBUM_BELLOW_LOLLILOP:
            uri = afterChosePic(data);
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(uri);
                mUploadMessage = null;
            }
            break;
        case RESULT_CODE_PICK_FROM_ALBUM_ABOVE_LOLLILOP:
            try {
                uri = afterChosePic(data);
                if (uri == null) {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[] { });
                    mUploadCallbackAboveL = null;
                    break;
                }
                if (mUploadCallbackAboveL != null && uri != null) {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[] { uri });
                    mUploadCallbackAboveL = null;
                }
            } catch (Exception e) {
                mUploadCallbackAboveL = null;
                e.printStackTrace();
            }
            break;
        }
    }

 

下面把完整的代码贴上来:

WebViewActivity.java

package com.lwd.webviewupimg;

import java.io.File;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore.Images.ImageColumns;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * @author lwd
 * @create 2016年8月17日
 */
@SuppressLint("SetJavaScriptEnabled")
public class WebViewActivity extends Activity{
    private WebView webview;
    private ValueCallback<Uri> mUploadMessage;
    private ValueCallback<Uri[]> mUploadCallbackAboveL;
    private final int RESULT_CODE_PICK_FROM_ALBUM_BELLOW_LOLLILOP = 1;
    private final int RESULT_CODE_PICK_FROM_ALBUM_ABOVE_LOLLILOP = 2;
    private String url = "";//这里添加含有图片上传功能的H5页面访问地址即可。
    String compressPath = "";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);
        initData();
    }

    public void initData() {
        webview = (WebView) findViewById(R.id.webview);
        initWebView();
        webview.loadUrl(url);
    }
    @SuppressWarnings("deprecation")
    private void initWebView(){
        webview.setScrollBarStyle(View.GONE);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        webview.getSettings().setDomStorageEnabled(false);
        webview.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
        webview.getSettings().setPluginState(WebSettings.PluginState.ON);
        webview.getSettings().setAllowFileAccess(true);
        webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
        webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        webview.getSettings().setUseWideViewPort(true);
        webview.getSettings().setLoadWithOverviewMode(true);
        webview.getSettings().setAllowContentAccess(true);
        webview.requestFocus();
        webview.setWebViewClient(new WebClient());
        webview.setWebChromeClient(new MyWebChromeClient());
    }
    /**选择后,回传值*/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (mUploadMessage == null && mUploadCallbackAboveL == null) {
            return;
        }
        Uri uri = null;
        switch (requestCode) {
        case RESULT_CODE_PICK_FROM_ALBUM_BELLOW_LOLLILOP:
            uri = afterChosePic(data);
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(uri);
                mUploadMessage = null;
            }
            break;
        case RESULT_CODE_PICK_FROM_ALBUM_ABOVE_LOLLILOP:
            try {
                uri = afterChosePic(data);
                if (uri == null) {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[] { });
                    mUploadCallbackAboveL = null;
                    break;
                }
                if (mUploadCallbackAboveL != null && uri != null) {
                    mUploadCallbackAboveL.onReceiveValue(new Uri[] { uri });
                    mUploadCallbackAboveL = null;
                }
            } catch (Exception e) {
                mUploadCallbackAboveL = null;
                e.printStackTrace();
            }
            break;
        }
    }
    /**
     * 选择照片后结束
     * @param data
     */
    private Uri afterChosePic(Intent data) {
        if (data == null) {
            return null;
        }
        String path = getRealFilePath(data.getData());
        String[] names = path.split("\\.");
        String endName = null;
        if (names != null) {
            endName = names[names.length - 1];
        }
        if (endName != null) {
            compressPath = compressPath.split("\\.")[0] + "." + endName;
        }
        File newFile;
        try {
            newFile = FileUtils.compressFile(path, compressPath);
        } catch (Exception e) {
            newFile = null;
        }
        return Uri.fromFile(newFile);
    }
    /**
     * 根据Uri获取图片文件的绝对路径
     */
    public String getRealFilePath(final Uri uri) {
        if (null == uri) {
            return null;
        }
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            Cursor cursor = getContentResolver().query(uri,
                    new String[] { ImageColumns.DATA }, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndexOrThrow(ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if(webview.canGoBack()){
            webview.goBack();
        }else{
            finish();
        }
    }
    private class WebClient extends WebViewClient {

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }
    }
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {
            webview.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    /**打开图库,同时处理图片(项目业务需要统一命名)*/
    private void selectImage(int resultCode) {
        compressPath = Environment.getExternalStorageDirectory().getPath() + "/QWB/temp";
        File file = new File(compressPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        compressPath = compressPath + File.separator + "compress.png";
        File image = new File(compressPath);
        if (image.exists()) {
            image.delete();
        }
        Intent intent = new Intent(
                Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(intent, resultCode);

    }
    /**
     * 内部类
     */
    class MyWebChromeClient extends WebChromeClient {
        //openFileChooser(隐藏方法)仅适用android5.0以下的环境,android5.0及以上使用onShowFileChooser

        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                String acceptType) {
            if (mUploadMessage != null)
                return;
            mUploadMessage = uploadMsg;
            selectImage(RESULT_CODE_PICK_FROM_ALBUM_BELLOW_LOLLILOP);
        }

        // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, "");
        }

        // For Android > 4.1.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                String acceptType, String capture) {
            openFileChooser(uploadMsg, acceptType);
        }

        // For Android 5.0+
        public boolean onShowFileChooser(WebView webView,
                ValueCallback<Uri[]> filePathCallback,
                FileChooserParams fileChooserParams) {
            mUploadCallbackAboveL = filePathCallback;
            selectImage(RESULT_CODE_PICK_FROM_ALBUM_ABOVE_LOLLILOP);
            return true;
        }

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }
    }
}

 FileUtils.java

package com.lwd.webviewupimg;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.text.TextUtils;
import android.util.Log;

public class FileUtils {

    /**
     * 把图片压缩到200K
     * 
     * @param oldpath
     *            压缩前的图片路径
     * @param newPath
     *            压缩后的图片路径
     * @return
     */
    public static File compressFile(String oldpath, String newPath) {
        Bitmap compressBitmap = FileUtils.decodeFile(oldpath);
        Bitmap newBitmap = ratingImage(oldpath, compressBitmap);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        newBitmap.compress(CompressFormat.PNG, 100, os);
        byte[] bytes = os.toByteArray();

        File file = null ;
        try {
            file = FileUtils.getFileFromBytes(bytes, newPath);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(newBitmap != null ){
                if(!newBitmap.isRecycled()){
                    newBitmap.recycle();
                }
                newBitmap  = null;
            }
            if(compressBitmap != null ){
                if(!compressBitmap.isRecycled()){
                    compressBitmap.recycle();
                }
                compressBitmap  = null;
            }
        }
        return file;
    }

    private static Bitmap ratingImage(String filePath,Bitmap bitmap){
        int degree = readPictureDegree(filePath);
        return rotaingImageView(degree, bitmap);
    }

    /**
     *  旋转图片
     * @param angle
     * @param bitmap
     * @return Bitmap
     */
    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();;
        matrix.postRotate(angle);
        System.out.println("angle2=" + angle);
        // 创建新的图片
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizedBitmap;
    }

    /**
     * 读取图片属性:旋转的角度
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    public static int readPictureDegree(String path) {
        int degree  = 0;
        try {
                ExifInterface exifInterface = new ExifInterface(path);
                int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                        degree = 90;
                        break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                        degree = 180;
                        break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                        degree = 270;
                        break;
                }
        } catch (IOException e) {
                e.printStackTrace();
        }
        return degree;
    }

    /**
     * 把字节数组保存为一个文件
     * 
     * @param b
     * @param outputFile
     * @return
     */
    public static File getFileFromBytes(byte[] b, String outputFile) {
        File ret = null;
        BufferedOutputStream stream = null;
        try {
            ret = new File(outputFile);
            FileOutputStream fstream = new FileOutputStream(ret);
            stream = new BufferedOutputStream(fstream);
            stream.write(b);
        } catch (Exception e) {
            // log.error("helper:get file from byte process error!");
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    // log.error("helper:get file from byte process error!");
                    e.printStackTrace();
                }
            }
        }
        return ret;
    }

    /**
     * 图片压缩
     * 
     * @param fPath
     * @return
     */
    public static Bitmap decodeFile(String fPath) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        opts.inDither = false; // Disable Dithering mode
        opts.inPurgeable = true; // Tell to gc that whether it needs free
        opts.inInputShareable = true; // Which kind of reference will be used to
        BitmapFactory.decodeFile(fPath, opts);
        final int REQUIRED_SIZE = 200;
        int scale = 1;
        if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {
            final int heightRatio = Math.round((float) opts.outHeight
                    / (float) REQUIRED_SIZE);
            final int widthRatio = Math.round((float) opts.outWidth
                    / (float) REQUIRED_SIZE);
            scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
        }
        Log.i("scale", "scal ="+ scale);
        opts.inJustDecodeBounds = false;
        opts.inSampleSize = scale;
        Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(Config.ARGB_8888, false);
        return bm;
    }



    /**
     * 创建目录
     * @param path
     */
    public static void setMkdir(String path)
    {
        File file = new File(path);
        if(!file.exists())
        {
            file.mkdirs();
            Log.e("file", "目录不存在  创建目录    ");
        }else{
            Log.e("file", "目录存在");
        }
    }

    /**
     * 获取目录名称
     * @param url
     * @return FileName
     */
    public static String getFileName(String url)
    {
        int lastIndexStart = url.lastIndexOf("/");
        if(lastIndexStart!=-1)
        {
            return url.substring(lastIndexStart+1, url.length());
        }else{
            return null;
        }
    }

    /**
     * 删除该目录下的文件
     * 
     * @param path
     */
    public static void delFile(String path) {
        if (!TextUtils.isEmpty(path)) {
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
        }
    }
}

 

分享到:
评论

相关推荐

    WebView上传图库图片

    本文将深入探讨如何完美解决WebView上传图库图片的兼容性问题。 首先,我们来理解WebView的基本用法。WebView是Android SDK中的一个类,它通过加载HTML、CSS和JavaScript代码,可以在应用程序内部显示网页。为了...

    H5 webview上传图片

    本知识点主要聚焦于H5 Webview中实现图片上传的功能,包括用户点击上传、图片转为Base64显示、Android版本兼容性处理以及解决浏览取消后二次浏览无效的问题。 首先,`webview file点击上传`是指在Webview中通过file...

    webView选择图片并上传

    综上所述,要在Android的WebView中实现图片选择并上传的功能,需要完成以下几个步骤: 1. 添加读取存储权限。 2. 启用WebView的JavaScript支持。 3. 创建自定义WebChromeClient并处理图片选择。 4. 在服务器端编写...

    Android webview打开相册选择图片并上传到服务器,(亲测可用)

    本文将详细讲解如何在Android的WebView中实现打开本地相册选择图片,并将其上传到服务器的功能。 首先,我们需要理解WebView的基本用法。WebView是Android SDK中的一个类,它提供了一个用于加载和显示网页的控件。...

    解决RN 的 webview 组件不支持android客户端上传图片文件问题

    通过以上步骤,你应该能够成功地解决React Native的Webview组件在Android客户端上不支持上传图片的问题。这个过程涉及到RN组件、HTML交互以及Android权限管理等多个方面,理解和掌握这些知识点对于提升RN应用的用户...

    Android webview 上传图片

    本文将详细讲解如何在Android的WebView中实现图片上传功能,并与HTML5 JavaScript进行交互。 1. **WebView基本使用** - 首先,我们需要在XML布局文件中添加WebView组件,通过`&lt;WebView&gt;`标签来定义。 - 在...

    androidwebview图片上传 源码

    代码中没有直接涉及到具体的图片上传逻辑,但从描述“完美解决各个Android系统的上传问题”来看,这部分逻辑应该会涉及以下几个方面: - **图片获取**:通过系统文件选择器获取用户选择的图片文件。 - **文件上传**...

    webview 调用手机相机和图库demo(亲测好用)

    webview 调用手机相机和图库demo(亲测好用) webview.setWebChromeClient(new WebChromeClient() public boolean onShowFileChooser (WebView webView, ValueCallback[]&gt; uploadMsg, FileChooserParams ...

    webView加载本地的图库

    本篇文章将深入探讨如何在WebView中加载本地图库中的图片。 首先,我们来理解`webView`的基本概念。WebView是Android SDK提供的一种用于在应用程序内部展示网页内容的控件。它可以直接加载URL,也可以加载本地HTML...

    android webview 图片上传 4.4解决方案 防js注入webview

    Android Webview upload 图片上传 ! 导读: Android HTML 打开相册上传照片 扩充 webview 防止js注入 解决 android webview 在4.4系统上无法使用情况 博客地址 : ...

    webview 设置cookie 拍照上传图片

    在`onActivityResult()`方法中,我们可以获取到用户选取或拍摄的图片,并将其转换为适合Webview上传的格式,比如Base64编码的字符串: ```java protected void onActivityResult(int requestCode, int ...

    android使用webview上传文件兼容问题解决支持5.0以上系统

    本文将深入探讨如何解决Android Webview中的文件上传兼容问题。 首先,我们需要了解在Android 5.0之前,文件上传通常是通过`&lt;input type="file"&gt;`标签实现的。但是,从Android 5.0开始,系统引入了更严格的权限管理...

    android webview上传文件

    然而,有时我们需要在WebView中处理更复杂的交互,比如上传文件,特别是上传图片。本文将深入探讨如何在Android的WebView中实现文件上传功能,特别是图片上传,并涉及到服务端和客户端的实现细节。 首先,我们要...

    移动端webview实现图片上传功能

    用html写图片上传功能,在移动端点击选择文件没有效果,需要在WebChromeClient中增加openFileChooser方法.

    WebView实现拍照及选择图片功能

    在一些场景下,如社交媒体、在线教育或者内容分享应用,用户可能需要通过WebView上传图片,这涉及到与H5页面的深度集成。本教程将详细介绍如何在Android的WebView中实现拍照及选择本地图片的功能。 首先,我们需要...

    解决React-Native的WebView不支持Android选择图片和拍照

    然而,由于React Native的WebView组件与原生Android系统的交互限制,有时会出现无法从Android设备的相册或相机选择图片并上传的问题。这个问题可能会导致用户体验下降,因为用户无法充分利用手机的功能。本文将深入...

    Android-为了修复ReactNative的WebView组件在安卓端不支持文件上传而包装的一个Webview组件

    标题中提到的"Android-为了修复ReactNative的WebView组件在安卓端不支持文件上传而包装的一个Webview组件"就是一个专门针对此问题的解决方案。这个组件可能包含了以下关键知识点: 1. **React Native WebView组件**...

    webview显示图片并下载

    本文将详细讲解如何在Webview中显示图片以及实现图片的下载功能。 1. **Webview基本使用** 首先,我们需要在布局文件中添加Webview组件,并在Java代码中实例化并设置相关属性。比如设置WebViewClient和...

    Android实现WebView图片缓存,替换加载前默认图片的样式

    通过以上步骤,我们就成功地实现了在Android的WebView中进行图片缓存、替换加载前的默认图片样式以及图片点击事件的处理。这不仅提升了用户体验,还能有效地减少网络资源的消耗。同时,这些技术也可以作为基础,...

Global site tag (gtag.js) - Google Analytics