Android

Webview视频压缩上传

2021-05-21  本文已影响0人  霁逸lei

1.视频文件选择、上传

package com.example.myapplication;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.RuntimePermissions;

@RuntimePermissions
public class WebActivity extends Activity {

    private static final int REQUEST_CODE_FILE_CHOOSER = 0x01;
    private ValueCallback<Uri> mUploadCallBack;
    private ValueCallback<Uri[]> mUploadCallBackAboveL;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
        WebView mWebView = findViewById(R.id.mWebView);
    }

    private void initWebViewSetting(WebView mWebView){
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setUseWideViewPort(true); // 关键点
        webSettings.setAllowFileAccess(true); // 允许访问文件
        webSettings.setSupportZoom(true); // 支持缩放
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // 不加载缓存内容
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
        webSettings.setDomStorageEnabled(true);
        //传图片
//        mWebView.loadUrl("http://m.54php.cn/demo/h5_upload");
        //传视频
        mWebView.loadUrl("file:///android_asset/video/index.html");
        mWebView.setWebChromeClient(new WebChromeClient() {

            // For Android < 3.0
            public void openFileChooser(ValueCallback<Uri> valueCallback) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            // For Android  >= 3.0
            public void openFileChooser(ValueCallback valueCallback, String acceptType) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            //For Android  >= 4.1
            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            // For Android >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                mUploadCallBackAboveL = filePathCallback;
                WebActivityPermissionsDispatcher.showFileChooserWithPermissionCheck(WebActivity.this);
                return true;
            }
        });
    }

    /**
     * 打开选择文件/相机
     * intent.setType("image/*");  //选择图片
     * intent1.setType("file/*");//文件上传
     * intent.setType("audio/*"); //选择音频
     * intent.setType("video/*"); //选择视频 (mp4 3gp 是android支持的视频格式)
     * intent.setType("video/*;image/*");//同时选择视频和图片
     */
    @NeedsPermission({Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE})
    public void showFileChooser() {
        //打开系统的文件选择界面
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_FILE_CHOOSER) {
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (result != null) {
                //直接选取文件返回
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (mUploadCallBackAboveL != null) {
                        mUploadCallBackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                        mUploadCallBackAboveL = null;
                        return;
                    }
                } else if (mUploadCallBack != null) {
                    mUploadCallBack.onReceiveValue(result);
                    mUploadCallBack = null;
                    return;
                }
            }
        }
        clearUploadMessage();
        return;
    }

    /**
     * webview没有选择文件也要传null,防止下次无法执行
     */
    private void clearUploadMessage() {
        if (mUploadCallBackAboveL != null) {
            mUploadCallBackAboveL.onReceiveValue(null);
            mUploadCallBackAboveL = null;
        }
        if (mUploadCallBack != null) {
            mUploadCallBack.onReceiveValue(null);
            mUploadCallBack = null;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        WebActivityPermissionsDispatcher.onRequestPermissionsResult(this,requestCode,grantResults);
    }
}

2.视频压缩处理

压缩后会返回视频的path,根据path获取URI然后返回上传接口

找到两个开源压缩库,实测可用,20s的视频压缩了80%多,就是压缩时间7~8s
https://github.com/fishwjy/VideoCompressor
https://github.com/Tourenathan-G5organisation/SiliCompressor

build.gradle
implementation 'com.iceteck.silicompressorr:silicompressor:2.2.4'
implementation 'com.googlecode.mp4parser:isoparser:1.1.22'

manifest xml声明,android7.0以下不需要
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.example.myapplication"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

res目录创建xml文件夹,创建filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="hm_video" path="Movies/Silicompressor/videos" />
</paths>


package com.example.myapplication;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;

import com.iceteck.silicompressorr.SiliCompressor;

import java.io.File;
import java.net.URISyntaxException;

import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.RuntimePermissions;

@RuntimePermissions
public class WebActivity extends Activity {

    private static final int REQUEST_CODE_FILE_CHOOSER = 0x01;
    private ValueCallback<Uri> mUploadCallBack;
    private ValueCallback<Uri[]> mUploadCallBackAboveL;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
        WebView mWebView = findViewById(R.id.mWebView);
    }

    private void initWebViewSetting(WebView mWebView){
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setUseWideViewPort(true); // 关键点
        webSettings.setAllowFileAccess(true); // 允许访问文件
        webSettings.setSupportZoom(true); // 支持缩放
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // 不加载缓存内容
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
        webSettings.setDomStorageEnabled(true);
        //传图片
//        mWebView.loadUrl("http://m.54php.cn/demo/h5_upload");
        //传视频
        mWebView.loadUrl("file:///android_asset/video/index.html");
        mWebView.setWebChromeClient(new WebChromeClient() {

            // For Android < 3.0
            public void openFileChooser(ValueCallback<Uri> valueCallback) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            // For Android  >= 3.0
            public void openFileChooser(ValueCallback valueCallback, String acceptType) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            //For Android  >= 4.1
            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
                mUploadCallBack = valueCallback;
                showFileChooser();
            }

            // For Android >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                mUploadCallBackAboveL = filePathCallback;
                WebActivityPermissionsDispatcher.showFileChooserWithPermissionCheck(WebActivity.this);
                return true;
            }
        });
    }

    boolean compressVideoFlag= false;
    
    /**
     * 打开选择文件/相机
     * intent.setType("image/*");  //选择图片
     * intent1.setType("file/*");//文件上传
     * intent.setType("audio/*"); //选择音频
     * intent.setType("video/*"); //选择视频 (mp4 3gp 是android支持的视频格式)
     * intent.setType("video/*;image/*");//同时选择视频和图片
     */
    @NeedsPermission({Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE})
    public void showFileChooser() {
        //打开系统的文件选择界面
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(Intent.createChooser(intent, "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_FILE_CHOOSER) {
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (result != null) {
                if (compressVideoFlag){
                    //压缩后返回对应URI
                    handleCompressVideo(result);
                    return;
                }
                //直接选取文件返回
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (mUploadCallBackAboveL != null) {
                        mUploadCallBackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                        mUploadCallBackAboveL = null;
                        return;
                    }
                } else if (mUploadCallBack != null) {
                    mUploadCallBack.onReceiveValue(result);
                    mUploadCallBack = null;
                    return;
                }
            }
        }
        clearUploadMessage();
        return;
    }
    
    private void handleCompressVideo(final Uri videoContentUri){
        final String authority = getPackageName();
        new Thread(new Runnable() {
            @Override
            public void run() {
                File f = getExternalFilesDir(Environment.DIRECTORY_MOVIES);
                try {
                    //视频缓存
                    String filePath = SiliCompressor.with(WebActivity.this).compressVideo(
                            videoContentUri,
                            f.getPath());
                    Log.d("TestWebActivity", filePath);
                    //Android 7.0后URI获取 权限更改
                    File resultFile = new File(filePath);
                    Uri uri;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                        uri = FileProvider.getUriForFile(WebActivity.this, authority, resultFile);
                    }else {
                        uri = Uri.fromFile(resultFile);
                    }
                    mUploadCallBackAboveL.onReceiveValue(new Uri[]{uri});
                    mUploadCallBackAboveL = null;
                    resultFile.delete();
                    clearUploadMessage();
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * webview没有选择文件也要传null,防止下次无法执行
     */
    private void clearUploadMessage() {
        if (mUploadCallBackAboveL != null) {
            mUploadCallBackAboveL.onReceiveValue(null);
            mUploadCallBackAboveL = null;
        }
        if (mUploadCallBack != null) {
            mUploadCallBack.onReceiveValue(null);
            mUploadCallBack = null;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        WebActivityPermissionsDispatcher.onRequestPermissionsResult(this,requestCode,grantResults);
    }
}

故障点getUriForFile报错IllegalArgumentException
xml中配置的路径需要跟文件存储路径对应上
如 文件路径为/storage/emulated/0/Android/data/com.example.myapplication/files/Movies
配置的路径root为/storage/emulated/0//Movies

image.png image.png

参考附录,感谢大佬们
Android开发笔记(一百六十六)H5通过WebView录像上传,github查aqi00可以找到本地assert使用的相关H5代码
Android webview 实现h5的input type="file"选择图片调用系统相册/相机并进行图片压缩功能

上一篇下一篇

猜你喜欢

热点阅读