近日项目集成了个带聊天功能的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; 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();

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

近日项目集成了个带聊天功能的Webview,一开始只是文字聊天后来增加需求要可以发文字/图片/语音等,一开始使用Webview自带的授权来实现录音功能的,只要授权即可,后面由于IOS的不支持,导致要跟IOS一致,本地写几个方法.1.开始录音2.暂停录音3.取消录音4.发送转换后的数据到后台,后台在处理.先来看下webview的本地录音实现方法,老规矩,界面就一个进度条和webview,webview采用的是BridgeWebView方便交互,BridgeWebView库&lt; 本节给大家介绍的是WebView下载文件的知识点,当我们在使用普通浏览器的时候,比如UC, 当我们点击到一个可供下载链接的时候,就会进行下载,WebView作为一个浏览器般的组件, 当然也是支持下载,我们可以自己来写下载的流程,设置下载后的文件放哪,以什么文件名 保存,当然也可以调用其它内置的浏览器来进行下载,比如Chrome,UC等等! 下面给大家演示下用法! 1.调用其它浏览器下载文件: 这个很简单,我们只需为WebView设置setDownloadListener,然后重写Downlo <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses. @Override public void onPermissionRequest(PermissionRequest request) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { request.grant(request.getResources());
解决android调用录音不成功,h5录音权限问题 <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"></uses-permission> 这两个都需要授权,h5页面的 navigator.media
Android WebView 是一个能够在 Android 应用程序中嵌入网页的组件,它可以开发出能够与 Web 页面进行交互的应用。其中与 Web 页面进行交互的一种方法是与 JavaScript 进行交互。下面简要解释一下 Android WebView 与 JS 交互的方式。 1. 加载本地 HTML 文件 在 Android WebView 中加载本地 HTML 文件时,需要使用 loadUrl() 方法加载。HTML 文件中的 JavaScript 可以通过 WebView 提供的 addJavascriptInterface() 方法注册为 Java 中的一个对象,然后在 Java 中调用该对象的方法,即可实现 JS 与 Java 的交互。 2. 加载远程 Web 页面 在 Android WebView 中加载远程 Web 页面时,需要添加 WebViewClient 和 WebChromeClient,分别是用来管理 WebView 的网络请求和处理页面上的 JavaScript 弹窗等请求。 在远程 Web 页面上,JS 代码可以通过 WebView 提供的 addJavascriptInterface() 方法注册为 Java 中的一个对象,然后在 Java 中调用该对象的方法,即可实现 JS 与 Java 的交互。 同时,在 Android 中处理 JS 的事件需要通过 JavaScriptInterface 向 WebView 注册一个映射对象,来实现 JS、Java 相互调用的机制,静态 HTML 文件是通过 WebView 中的 evaluateJavascript() 方法来调用 JS,来实现双向通信和数据交互。 总结来说,Android WebView 与 JS 交互的方式主要是通过 WebView 提供的 addJavascriptInterface() 方法注册为 Java 中的一个对象,然后在 Java 中调用该对象的方法,来实现 JS 和 Java 的交互。同时,JS 也可以通过 WebView 的 evaluateJavascript() 方法来调用 Java 中的方法,实现双向通信和数据交互。
CSDN-Ada助手: 非常感谢博主分享的这篇“Android 加载Webview链接类型的Youtube视频”,对于我这样的新手来说非常有帮助。博客讲解详细,操作步骤清晰,让我轻松地完成了加载视频的操作。希望博主能够再次创作,分享更多有用的知识,为大家提供更好的学习体验。再次感谢博主的辛勤付出! 为了方便博主创作,提高生产力,CSDN上线了AI写作助手功能,就在创作编辑器右侧哦~(https://mp.csdn.net/edit?utm_source=blog_comment_recall )诚邀您来加入测评,到此(https://activity.csdn.net/creatActivity?id=10450&utm_source=blog_comment_recall)发布测评文章即可获得「话题勋章」,同时还有机会拿定制奖牌。 抛弃FlowLayout吧,RecyclerView结合flexbox简单粗暴实现流式布局 浅行漫漫路: 这里为什么要重写canScrollVertically方法呢? 汽车VIN码识别功能实现资料,轻松实现VIN码识别 yxyyx: 请问有免费的api吗 java的class文件批量反编译成java wwwlinbin888: 公司一个项目,没有java源代码,都是class文件,批量反编码,很多类没有反编译成功,报错: Couldn't fully decompile method JavaClassFileReadException: can't open input file on 请教大神,有什么好的解决办法,着急用这个方法表情包 Android收缩控件,展开,收缩 王哥小跟班发了王菲挖服务费威锋网: R.anim.expand、R.anim.collapse,楼主大哥可以提供下这个小弟们学习下么,感谢表情包