Android与Js互调之传递图片

Android与Js互调的方式

Android与JS通过WebView互相调用方法,实际上是:
1.Android去调用JS的代码
2.JS去调用Android的代码
二者沟通的桥梁是WebView

对于Android调用JS代码的方法有2种:

通过WebView的loadUrl()
通过WebView的evaluateJavascript()

对于JS调用Android代码的方法有3种:

通过WebView的addJavascriptInterface()进行对象映射
通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话alert()、confirm()、prompt() 消息

需求

H5界面调用Android本地录制小视频的方法,H5界面获取首帧图像并展示

添加addJavascriptInterface注解方法

H5VerificationJavascriptInterface 对象映射

public class H5VerificationJavascriptInterface extends BaseJavascriptInterface {
    
    

    private SoftReference<H5VerificationContact.View> contextReference;

    public H5VerificationJavascriptInterface(int titleHeight, int tabButtonHeight,
                                             ActionListener listener) {
    
    
        super(titleHeight,tabButtonHeight,listener);
    }

    public H5VerificationJavascriptInterface setView(H5VerificationContact.View view){
    
    
        contextReference = new SoftReference<>(view);
        return this;
    }

    @Nullable
    private H5VerificationContact.View getView(){
    
    
        if (contextReference.get()!=null){
    
    
            return contextReference.get();
        }
        return null;
    }

    /**
     * 启动视频录制界面
     * 选择成功后会调用js里面的方法
     * chooseLocalFilesCallback
     */
    @JavascriptInterface
    public void chooseLocalFiles(){
    
    
        if (getView()== null)return;
        getView().startTakeASmallVideo();
    }
}

webView 对象映射

mWebView.addJavascriptInterface(new H5VerificationJavascriptInterface(getStatusBarHeight(), 12
                , this::finish).setView(this), "android");

启动录制视频的具体代码

    private final int CHOOSE_VIDEO = 0x102;

    @Override
    public void startTakeASmallVideo() {
    
    
        Intent intent = BaseApplication.getInstance().getIntentUtils().getActivityIntent(this,
                IntentUtils.INTENT_VIDEO_RECORDER);
        //获取外部存储文件夹--指定文件夹
        String videoPath = FilePathProvider.getPublicDir(this, DIR_VIDEO).getAbsolutePath();
        intent.putExtra(ConstantUtils.DIR_PATH, videoPath);
        startActivityForResult(intent, CHOOSE_VIDEO);
    }

录制成功后调用Js方法返回

onActivityResult

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    
    
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CHOOSE_VIDEO && resultCode == RESULT_OK){
    
    
            mPresenter.convertVideoResources(data);
        }
    }

将图片转换成为Base64

	@Override
    public void convertVideoResources(Intent data) {
    
    
        final String videoFilePath = data.getStringExtra(ConstantUtils.VIDEO_FILE_PATH);
        final String firstFrameFilePath = data.getStringExtra(ConstantUtils.CAPTURE_FILE_PATH);
        if (TextUtils.isEmpty(firstFrameFilePath))return;
        if (TextUtils.isEmpty(videoFilePath))return;
        Flowable.just(firstFrameFilePath)
                .subscribeOn(Schedulers.io())
                .map(s -> {
    
    
                    String base64Img = "";
                    try {
    
    
                        byte[] buf = Base64RequestBody.readFile(firstFrameFilePath);
                        base64Img = Base64.encodeToString(buf, Base64.NO_WRAP);
                    } catch (Exception e) {
    
    
                        e.printStackTrace();
                    }
                    return base64Img;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseRequestSubscriber<String>(this,mView) {
    
    
                    @Override
                    protected void onDoRequestSuccess(String result) {
    
    
                        if (!TextUtils.isEmpty(result)){
    
    
                            mView.callJsChooseVideoCallback(videoFilePath,firstFrameFilePath,result);
                        }
                    }
                }.setIgnoreNetwork(true));

    }

    public static byte[] readFile(String file) throws IOException {
    
    
        return readFile(new File(file));
    }

    public static byte[] readFile(File file) throws IOException {
    
    
        // Open file

        RandomAccessFile f = new RandomAccessFile(file, "r");
        try {
    
    
            // Get and check length
            long longlength = f.length();
            int length = (int) longlength;

            if (length != longlength) {
    
    
                throw new IOException("File size >= 2 GB");
            }
            // Read file and return data
            byte[] data = new byte[length];
            f.readFully(data);
            return data;
        } finally {
    
    
            f.close();
        }
    }

回调Js中的方法并传递对应的参数

	@Override
    public void callJsChooseVideoCallback(String videoFilePath, String firstFrameFilePath, String imageBase64) {
    
    
        String sb = "javascript:chooseLocalFilesCallback(" +
                "\"" +
                videoFilePath +
                "\"" +
                "," +
                "\"" +
                firstFrameFilePath +
                "\"" +
                "," +
                "\"" +
                imageBase64 +
                "\"" +
                ")";
        mWebView.evaluateJavascript(sb, value -> {
    
     });
    }

H5界面

<!DOCTYPE html>
<html>
<head>
    <script>
function myFunction() {
     
     
    // document.getElementById("demo").innerHTML = "段落已被更改。";
    android.chooseLocalFiles();
}

function chooseLocalFilesCallback(videoFilePath,firstFrameFilePath,imageBase64) {
     
     
    // document.write('视频地址 = ');
    // document.write(videoFilePath);
    // document.write('首帧地址 = ');
    // document.write(firstFrameFilePath);
    // document.write('Base64 = ');
    // document.write(imageBase64);
    // document.getElementById("demo").innerHTML = imageBase64;
   document.getElementById("demo").innerHTML = imageBase64;
   var obj = document.getElementById("imgdemo");
   obj.src = "data:image/jpg;base64," + imageBase64;
}
</script>
</head>

<body>

<button type="button" onclick="myFunction()">点击调用选择录屏</button>

</br>

<img id="imgdemo" height="200" width="200" src="data:image/jpg;base64,xxxxx"/>

</br>
<p id="demo">数据</p>
</body>
</html>

Activity加载html文件

        mWebView.loadUrl("file:android_asset/text.html");

注意事项

Android调用JS方法的过程中,需要注意不能包含特殊字符,比如换行符。
所以在将图片转换成Base64的过程中,不能够使用默认Base64.encodeToString(buf, Base64.DEFAULT)的Flag,因为默认的生成String会包含换行符,使用Base64.NO_WRAP即可。

猜你喜欢

转载自blog.csdn.net/tao_789456/article/details/115000408