Android Webview录音功能与原生录音实现

近日项目集成了个带聊天功能的Webview,一开始只是文字聊天后来增加需求要可以发文字/图片/语音等,一开始使用Webview自带的授权来实现录音功能的,只要授权即可,后面由于IOS的不支持,导致要跟IOS一致,本地写几个方法.

1.开始录音

2.暂停录音

3.取消录音

4.发送转换后的数据到后台,后台在处理.

先来看下webview的本地录音实现方法,

老规矩,界面就一个进度条和webview,webview采用的是BridgeWebView方便交互,BridgeWebView库

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


            <ProgressBar
                android:id="@+id/progressBar"
                style="@android:style/Widget.ProgressBar.Horizontal"
                android:layout_width="match_parent"
                android:layout_height="3dp"
                android:max="100"
                android:progressDrawable="@drawable/progress_bar_bg" />

            <com.github.lzyzsd.jsbridge.BridgeWebView
                android:id="@+id/webview"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="5dp"
                android:paddingRight="5dp" />

   

</LinearLayout>

代码方面:



/**
 * create by 
 * on 2020/5/27
 * explain${聊天}
 */
public class ChatFragment extends BaseFragment  {
    private String mFrom;
    private ProgressBar progressbar;
    private BridgeWebView webView;

    private String baseurl = BaseHttpsUrl.NEW_BASE_LIVE_CHAT_WEBVIEW;

    /**
     * 被用户拒绝的权限列表
     */
    private List<String> mPermissionList = new ArrayList<>();
    private boolean isRecording;
    private AudioRecord audioRecord;
    public String encodedString;

    public final static int FILECHOOSER_RESULTCODE = 1;
    public final static int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 2;
    private static final int MY_PERMISSIONS_REQUEST = 1001;

    /**
     * 需要申请的运行时权限
     */
    private String[] permissions = new String[]{
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };



    static ChatFragment newInstance(String from) {
        ChatFragment fragment = new ChatFragment();
        Bundle bundle = new Bundle();
        bundle.putString("from", from);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mFrom = getArguments().getString("from");
        }
    
        //录音授权
        Authorization();
    }

    @Override
    protected int setLayoutId() {
        return R.layout.chat_layout;
    }

    @Override
    protected void initView() {
        webView = (BridgeWebView) mRootView.findViewById(R.id.webview);
     progressbar = (ProgressBar) mRootView.findViewById(R.id.progressBar);
        String request_url = BaseCacheUtil.getString(getActivity(), "webview_url");

        baseurl = BaseHttpsUrl.NEW_BASE_LIVE_CHAT_WEBVIEW;  
        initWebView();
    }

    private void initWebView() {
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);// 让WebView能够执行javaScript
        settings.setDomStorageEnabled(true);
        settings.setJavaScriptCanOpenWindowsAutomatically(true);// 让JavaScript可以自动打开windows
        settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 设置缓存模式,一共有四种模式
        // 开启 DOM storage API 功能
//开启 database storage API 功能
        settings.setDatabaseEnabled(true);
//开启 Application Caches 功能
        settings.setAppCacheEnabled(true);
        settings.setSupportZoom(true);// 支持缩放(适配到当前屏幕)
        settings.setUseWideViewPort(true);      // 将图片调整到合适的大小
        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); // 支持内容重新布局,一共有四种方式 默认的是NARROW_COLUMNS
        settings.setDisplayZoomControls(true);   // 设置可以被显示的屏幕控制
        settings.setDefaultFontSize(12);   // 设置默认字体大小

        settings.setAllowFileAccessFromFileURLs(true);
        settings.setAllowUniversalAccessFromFileURLs(true);
        settings.setMediaPlaybackRequiresUserGesture(false);
        webView.loadUrl(baseurl);


        //实现:按手机回退键,如果浏览器有上一个网页,则返回上一个网页
        webView.setOnKeyListener((v, keyCode, event) -> {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                if (keyCode == KEYCODE_BACK && webView.canGoBack()) {
                    webView.goBack();
                    return true;
                }
            }
            return false;
        });

        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                progressbar.setProgress(newProgress);
                if (newProgress == 100) {
                    progressbar.setVisibility(View.GONE);
                } else {
                    progressbar.setVisibility(View.VISIBLE);
                }
                super.onProgressChanged(view, newProgress);
            }

            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                result.confirm();
                return true;
            }

            @Override
            public void onPermissionRequest(PermissionRequest request) {   //webview自带录音授权(重点!!!)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    request.grant(request.getResources());
                    request.getOrigin();
                }
            }

            //扩展浏览器上传文件
            //3.0++版本
            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
                openFileChooserImpl(uploadMsg);
            }

            //3.0--版本
            public void openFileChooser(ValueCallback<Uri> uploadMsg) {
                openFileChooserImpl(uploadMsg);
                mUploadMessage = uploadMsg;
            }

            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                openFileChooserImpl(uploadMsg);
            }

            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                onenFileChooseImpleForAndroid(filePathCallback);
                return true;
            }


        });

        //下载文件
        webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> {
            // TODO: 2017-5-6 处理下载事件
            Uri uri = Uri.parse(url);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);  //跳转浏览器下载
            startActivity(intent);
        });

        //开始录音
        webView.registerHandler("startRecord", (data, function) -> {
            checkPermissions();
            startRecordVoice();
            String str = "这是html返回给java的数据:" + data;
            //回调返回给Js
//                function.onCallBack();
        });

        //暂停录音
        webView.registerHandler("stopRecord", (data, function) -> {
            stopRecordVoice();
        });

        //删除录音
        webView.registerHandler("cancelRecord", (data, function) -> {
            delete();
        });
        //发送录音
        webView.registerHandler("sendRecord", (data, function) -> {
            sendRecord1();
        });
    }


    /**
     * 录音授权
     */
    private void Authorization() {
        Objects.requireNonNull(getActivity()).runOnUiThread(this::checkPermissions);
    }

    private void checkPermissions() {
        // Marshmallow开始才用申请运行时权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            for (int i = 0; i < permissions.length; i++) {
                if (ContextCompat.checkSelfPermission(getActivity(), permissions[i]) !=
                        PackageManager.PERMISSION_GRANTED) {
                    mPermissionList.add(permissions[i]);
                }
            }
            if (!mPermissionList.isEmpty()) {
                String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);
                ActivityCompat.requestPermissions(getActivity(), permissions, MY_PERMISSIONS_REQUEST);
            }
        }
    }

 
    @Override
    protected void setListener() {
        webView.setWebViewClient(new MyWebViewClient(webView) {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }
        });
        webView.setDefaultHandler(new myHadlerCallBack());
    }

    /**
     * 自定义的WebViewClient
     */
    class MyWebViewClient extends BridgeWebViewClient {
        public MyWebViewClient(BridgeWebView webView) {
            super(webView);
        }
    }

    /**
     * 自定义回调
     */
    class myHadlerCallBack extends DefaultHandler {
        @Override
        public void handler(String data, CallBackFunction function) {
            if (function != null) {
//                Toast.makeText(WebViewTest.this, data, Toast.LENGTH_SHORT).show();
            }
        }
    }

    public ValueCallback<Uri> mUploadMessage;

    private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
    }

    public ValueCallback<Uri[]> mUploadMessageForAndroid5;

    private void onenFileChooseImpleForAndroid(ValueCallback<Uri[]> filePathCallback) {
        mUploadMessageForAndroid5 = filePathCallback;
        Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
        contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
        contentSelectionIntent.setType("image/*");

        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
        chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
        chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");

        startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_ANDROID_5);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage)
                return;
            Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;

        } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) {
            if (null == mUploadMessageForAndroid5)
                return;
            Uri result = (intent == null || resultCode != RESULT_OK) ? null : intent.getData();
            if (result != null) {
                mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});
            } else {
                mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
            }
            mUploadMessageForAndroid5 = null;
        }
    }

   

 


    /**
     * 申请权限
     *
     * @param permission
     */
    private void requestPermission(String permission) {
        if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), new String[]{permission}, 0);
        }
    }
  

    /**
     * 删除录音
     */
    private void delete() {
        File mp3File = new File(getActivity().getExternalFilesDir(Environment.DIRECTORY_MUSIC), "test.mp3");
        if (mp3File.exists()) {
            mp3File.delete();
        }
    }

  
    /**
     * 当前录音文件
     */
    private File audioFile;
    /**
     * 文件存储目录
     */
    private File mVoiceDir;

    public ChatFragment() {
        mVoiceDir = FileUtil.getChatVoiceDir();
    }

    /**
     * 按下录音
     */
    public void startRecordVoice() {
        try {
            recorder = new MediaRecorder();
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频采集原
            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 内容输出格式
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 音频编码方式

            audioFile = new File(mVoiceDir, DateUtil.formatDatetime(new Date(), "yyyyMMddHHmmss") + ".mp3");
            if (!audioFile.exists()) {
                boolean flag = audioFile.createNewFile();
                Log.i("speak", String.valueOf(flag));
            }
            ABLELogUtils.e("m_tag_", "文件路劲为:" + audioFile.getAbsolutePath() + "=====" + audioFile.getPath());
            recorder.setOutputFile(audioFile.getAbsolutePath());

            recorder.prepare(); // 预期准备
            recorder.start();//开始录音

        } catch (IllegalStateException e) {
            recorder = null;
        } catch (IOException e) {
            recorder = null;
        }
    }

    /**
     * 停止录音
     */
    public void stopRecordVoice() {
        try {
            recorder.stop();// 停止刻录
            recorder.reset();// 重设
            recorder.release();// 刻录完成一定要释放资源
            recorder = null;
        } catch (Exception e) {
            ABLELogUtils.e("RecordVoice", e.getMessage());
        }
    }

    /**
     * sendRecord()
     * 發送錄音
     */
    private void sendRecord1() {
        try {
            FileInputStream inputFile = new FileInputStream(audioFile);
            byte[] buffer = new byte[(int) audioFile.length()];
            inputFile.read(buffer);
            inputFile.close();
            encodedString = Base64.encodeToString(buffer, Base64.DEFAULT);
            Log.e("m_tag_Base64", "Base64--后的MP3文件-->" + encodedString);

            if (!TextUtils.isEmpty(encodedString)) {
                String file_type = "audio/mp3";
                String sender = "operator";
                RecordData(getActivity(), xxxx, encodedString, file_type, xxxx);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

两种实现方式都实现了,由于本地实现的录音在本地正常播放传到后台后播放不了,后面就空置了,还是采取了第一种自带的录音方式...

猜你喜欢

转载自blog.csdn.net/qq_19714505/article/details/108750191
今日推荐