近日项目集成了个带聊天功能的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库<
本节给大家介绍的是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助手:
抛弃FlowLayout吧,RecyclerView结合flexbox简单粗暴实现流式布局
浅行漫漫路:
汽车VIN码识别功能实现资料,轻松实现VIN码识别
yxyyx:
java的class文件批量反编译成java
wwwlinbin888:
Android收缩控件,展开,收缩
王哥小跟班发了王菲挖服务费威锋网: