短視訊開發,Android和JS互調實現圖片傳遞

zhibo系統開發發表於2022-04-06

短視訊開發,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即可。

以上就是 短視訊開發,Android和JS互調實現圖片傳遞,更多內容歡迎關注之後的文章


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69978258/viewspace-2885795/,如需轉載,請註明出處,否則將追究法律責任。

相關文章