Android webview上传图片(调起相册/相机上传)

Posted 码云笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android webview上传图片(调起相册/相机上传)相关的知识,希望对你有一定的参考价值。

概述

默认情况

WebView 不支持<input type=file>,WebView 点击没有反应。

兼容

重写 webview 的 webchromeClient 中的 openFileChooser 方法。android 版本的多样性,就理所当然的各种兼容。

  // For Android < 3.0
    public void openFileChooser(ValueCallback uploadMsg) 
        openFileChooser(uploadMsg, "");
    

    //For Android 3.0 - 4.0
    public void openFileChooser(ValueCallback uploadMsg, String acceptType) 
    

    // For Android 4.0 - 5.0
    public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) 
        openFileChooser(uploadMsg, acceptType);
    

    // For Android > 5.0
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) 
        return true;
    

具体代码实现

网上也有很多实现方式,这边记录一下自己用到的一种
webview 调用时,弹出本地弹框,选择(相册/相机/取消),选择相册跳转到文件选择页面、选择相机注意权限配置,返回照片要做压缩、选择取消注意给webview一个空回应,要不点击没有反应。

  • ZpWebChromeClient
  • public class ZpWebChromeClient extends WebChromeClient 
    
        private OpenFileChooserCallBack mOpenFileChooserCallBack;
    
        // For Android < 3.0
        public void openFileChooser(ValueCallback uploadMsg) 
            openFileChooser(uploadMsg, "");
        
    
        //For Android 3.0 - 4.0
        public void openFileChooser(ValueCallback uploadMsg, String acceptType) 
            if (mOpenFileChooserCallBack != null) 
                mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
            
        
    
        // For Android 4.0 - 5.0
        public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) 
            openFileChooser(uploadMsg, acceptType);
        
    
        // For Android > 5.0
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) 
            if (mOpenFileChooserCallBack != null) 
                mOpenFileChooserCallBack.showFileChooserCallBack(filePathCallback, fileChooserParams);
            
            return true;
        
    
        public void setOpenFileChooserCallBack(OpenFileChooserCallBack callBack) 
            mOpenFileChooserCallBack = callBack;
        
    
        public interface OpenFileChooserCallBack 
    
            void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType);
    
            void showFileChooserCallBack(ValueCallback filePathCallback, FileChooserParams fileChooserParams);
        
    
    
  • ZpWebView
  • public class ZpWebView extends WebView 
    
        private ZpWebChromeClient webChromeClient;
    
        public ZpWebView(Context context) 
            super(context);
            initWebView();
        
    
        public ZpWebView(Context context, AttributeSet attrs) 
            super(context, attrs);
            initWebView();
        
    
        public ZpWebView(Context context, AttributeSet attrs, int defStyleAttr) 
            super(context, attrs, defStyleAttr);
            initWebView();
        
    
        private void initWebView() 
            webChromeClient = new ZpWebChromeClient();
            setWebChromeClient(webChromeClient);
    
            WebSettings webviewSettings = getSettings();
            // 不支持缩放
            webviewSettings.setSupportZoom(false);
            // 自适应屏幕大小
            webviewSettings.setUseWideViewPort(true);
            webviewSettings.setLoadWithOverviewMode(true);
            String cacheDirPath = getContext().getFilesDir().getAbsolutePath() + "cache/";
            webviewSettings.setAppCachePath(cacheDirPath);
            webviewSettings.setAppCacheEnabled(true);
            webviewSettings.setDomStorageEnabled(true);
            webviewSettings.setAllowFileAccess(true);
            webviewSettings.setAppCacheMaxSize(1024 * 1024 * 8);
            webviewSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        
    
        public void setOpenFileChooserCallBack(ZpWebChromeClient.OpenFileChooserCallBack callBack) 
            webChromeClient.setOpenFileChooserCallBack(callBack);
        
    
  • MainActivity
  • public class MainActivity extends AppCompatActivity 
    
        public static final int REQUEST_SELECT_FILE_CODE = 100;
        private static final int REQUEST_FILE_CHOOSER_CODE = 101;
        private static final int REQUEST_FILE_CAMERA_CODE = 102;
        // 默认图片压缩大小(单位:K)
        public static final int IMAGE_COMPRESS_SIZE_DEFAULT = 400;
        // 压缩图片最小高度
        public static final int COMPRESS_MIN_HEIGHT = 900;
        // 压缩图片最小宽度
        public static final int COMPRESS_MIN_WIDTH = 675;
    
        private ValueCallback mUploadMsg;
        private ValueCallback mUploadMsgs;
        // 相机拍照返回的图片文件
        private File mFileFromCamera;
        private File mTakePhotoFile;
        private BottomSheetDialog selectPicDialog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
        
    
        private void initView() 
            ZpWebView webView = findViewById(R.id.webview);
            webView.setOpenFileChooserCallBack(new ZpWebChromeClient.OpenFileChooserCallBack() 
                @Override
                public void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType) 
                    mUploadMsg = uploadMsg;
                    showSelectPictrueDialog(0, null);
                
    
                @Override
                public void showFileChooserCallBack(ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) 
                    if (mUploadMsgs != null) 
                        mUploadMsgs.onReceiveValue(null);
                    
                    mUploadMsgs = filePathCallback;
                    showSelectPictrueDialog(1, fileChooserParams);
                
            );
        
    
        /**
         * 选择图片弹框
         */
        private void showSelectPictrueDialog(final int tag, final WebChromeClient.FileChooserParams fileChooserParams) 
            selectPicDialog = new BottomSheetDialog(this, R.style.Dialog_NoTitle);
            selectPicDialog.setOnDismissListener(new DialogInterface.OnDismissListener() 
                @Override
                public void onDismiss(DialogInterface dialogInterface) 
                    if (mUploadMsgs != null) 
                        mUploadMsgs.onReceiveValue(null);
                        mUploadMsgs = null;
                    
                
            );
            View view = LayoutInflater.from(this).inflate(R.layout.dialog_bottom_select_pictrue, null);
            // 相册
            TextView album = view.findViewById(R.id.tv_select_pictrue_album);
            // 相机
            TextView camera = view.findViewById(R.id.tv_select_pictrue_camera);
            // 取消
            TextView cancel = view.findViewById(R.id.tv_select_pictrue_cancel);
    
            album.setOnClickListener(new View.OnClickListener() 
                @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                @Override
                public void onClick(View view) 
                    if (tag == 0) 
                        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        i.setType("*/*");
                        startActivityForResult(Intent.createChooser(i, "File Browser"), REQUEST_FILE_CHOOSER_CODE);
                     else 
                        try 
                            Intent intent = fileChooserParams.createIntent();
                            startActivityForResult(intent, REQUEST_SELECT_FILE_CODE);
                         catch (ActivityNotFoundException e) 
                            mUploadMsgs = null;
                        
                    
                
            );
            camera.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View view) 
                    takeCameraPhoto();
                
            );
            cancel.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View view) 
                    selectPicDialog.dismiss();
                
            );
    
            selectPicDialog.setContentView(view);
            selectPicDialog.show();
        
    
        public void takeCameraPhoto() 
            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) 
                Toast.makeText(this, "设备无摄像头", Toast.LENGTH_SHORT).show();
                return;
            
    
            String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
            
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            mFileFromCamera = new File(filePath, System.nanoTime() + ".jpg");
    
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) 
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTakePhotoFile));
                startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
             else 
                try 
                    mTakePhotoFile = File.createTempFile("Zp" + System.nanoTime(), ".jpg", filePath);
                    Uri contentUri = FileProvider.getUriForFile(InnerBrowserActivity.this,
                            "com.zp.demo.ZpFileProvider", mTakePhotoFile);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
                 catch (IOException e) 
                    
                
            
        
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) 
            super.onActivityResult(requestCode, resultCode, data);
            switch (requestCode) 
                case REQUEST_SELECT_FILE_CODE:
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
                        if (mUploadMsgs == null) 
                            return;
                        
                        mUploadMsgs.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                        mUploadMsgs = null;
                    
                    break;
                case REQUEST_FILE_CHOOSER_CODE:
                    if (mUploadMsg == null) 
                        return;
                    
                    Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
                    mUploadMsg.onReceiveValue(result);
                    mUploadMsg = null;
                    break;
                case REQUEST_FILE_CAMERA_CODE:
                    takePictureFromCamera();
                    break;
            
        
    
        /**
         * 处理相机返回的图片
         */
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        private void takePictureFromCamera() 
            if (mFileFromCamera != null && mFileFromCamera.exists()) 
                String filePath = mFileFromCamera.getAbsolutePath();
                // 压缩图片到指定大小
                File imgFile = ZpImageUtils.compressImage(this, filePath, COMPRESS_MIN_WIDTH, COMPRESS_MIN_HEIGHT, IMAGE_COMPRESS_SIZE_DEFAULT);
    
                Uri localUri = Uri.fromFile(imgFile);
                Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
                this.sendBroadcast(localIntent);
                Uri result = Uri.fromFile(imgFile);
    
                if (mUploadMsg != null) 
                    mUploadMsg.onReceiveValue(Uri.parse(filePath));
                    mUploadMsg = null;
                
                if (mUploadMsgs != null) 
                    mUploadMsgs.onReceiveValue(new Uri[]result);
                    mUploadMsgs = null;
                
             else 
                if (mUploadMsg != null) 
                    mUploadMsg.onReceiveValue(null);
                    mUploadMsg = null;
                
                if (mUploadMsgs != null) 
                    mUploadMsgs.onReceiveValue(null);
                    mUploadMsgs = null;
                            
            
        
    

    备注:代码不规范的地方,自己抽取一下,这里就不做抽取了。

  • Github 地址

  • WebViewUploadFileDemo

微信小程序excel添加图片

首先要想到微信官方文档给的API,wx.uploadFile( )

通过这个API来达到上传至服务器的效果:代码示例如下

接下来我们先来说说上传图片功能,这个比较简单一些

上传图片:wx.chooseImage( )从本地相册选择图片或使用相机拍照
代码示例如下:

在点击图片触发响应事件函数里写上以上代码,就会调起手机选择相册或者拍照。以上就达到了上传图片的功能

上传word/pdf等文件:
这个功能真是苦恼了我好久,因为项目中要用到上传word文件,找度娘查了半天,发现没有调起手机文件管理器去选择文件上传的API。

于是乎,想办法怎么能把这个功能先实现呢?微信官方文档给出了wx.chooseMessageFile(Object object)这个API。

wx.chooseMessageFile · 小程序

这个API是从微信聊天界面中选择文件上传。

选择文件的类型可以自行设置,这里我项目中只要求上传word文件,所以在设置上传文件类型的时候,给type赋值file

触发上传文件按钮点击事件,就会调起微信的聊天界面,如下图:

然后,找到你聊天界面中的文件,

勾选好文件,点击确定。选择文件上传的功能就完成了

注:如果是用模拟器选择微信会话里的文件,调用wx.chooseMessageFile()API,程序会报错。运行到真机上就没问题了
参考技术A 1步 上传附件

电脑浏览器上打开微件夹(uomo.cc),点击上传附件


第2步 复制直达路径


第3步 粘贴直达路径


经过以上三步,我们可以看到微信公众号文章中出现了一些带图标的蓝色文字,文字内容是附件的标题和后缀,这说明已经成功在公众号图文中插入excel表格了。

为了图文排版的完整性及确认表格是否可以下载,需要利用公众号的预览功能进一步确认。点击公众号的预览按钮,发送图文到手机微信上预览。预览图文时,点击附件链接,打开附件查看。




正常情况下,小程序的文件详情页会出现我们的附件,点击查看文件即可下载附件。

以上是关于Android webview上传图片(调起相册/相机上传)的主要内容,如果未能解决你的问题,请参考以下文章

H5调用本地相册/相机上传图片

Android webview 上传图片为啥 application/octet-stream

微信小程序excel添加图片

android使用webview上传文件(支持相册和拍照),支持最高6.0安卓系统(改进版)

android保存照片到相册的一些事

Android WebView 调用系统拍照和相册