当前位置:   article > 正文

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

startrecordvoicebuffer

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

1.开始录音

2.暂停录音

3.取消录音

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

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

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

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:orientation="vertical">
  7. <ProgressBar
  8. android:id="@+id/progressBar"
  9. style="@android:style/Widget.ProgressBar.Horizontal"
  10. android:layout_width="match_parent"
  11. android:layout_height="3dp"
  12. android:max="100"
  13. android:progressDrawable="@drawable/progress_bar_bg" />
  14. <com.github.lzyzsd.jsbridge.BridgeWebView
  15. android:id="@+id/webview"
  16. android:layout_width="match_parent"
  17. android:layout_height="match_parent"
  18. android:paddingLeft="5dp"
  19. android:paddingRight="5dp" />
  20. </LinearLayout>

代码方面:

  1. /**
  2. * create by
  3. * on 2020/5/27
  4. * explain${聊天}
  5. */
  6. public class ChatFragment extends BaseFragment {
  7. private String mFrom;
  8. private ProgressBar progressbar;
  9. private BridgeWebView webView;
  10. private String baseurl = BaseHttpsUrl.NEW_BASE_LIVE_CHAT_WEBVIEW;
  11. /**
  12. * 被用户拒绝的权限列表
  13. */
  14. private List<String> mPermissionList = new ArrayList<>();
  15. private boolean isRecording;
  16. private AudioRecord audioRecord;
  17. public String encodedString;
  18. public final static int FILECHOOSER_RESULTCODE = 1;
  19. public final static int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 2;
  20. private static final int MY_PERMISSIONS_REQUEST = 1001;
  21. /**
  22. * 需要申请的运行时权限
  23. */
  24. private String[] permissions = new String[]{
  25. Manifest.permission.RECORD_AUDIO,
  26. Manifest.permission.WRITE_EXTERNAL_STORAGE
  27. };
  28. static ChatFragment newInstance(String from) {
  29. ChatFragment fragment = new ChatFragment();
  30. Bundle bundle = new Bundle();
  31. bundle.putString("from", from);
  32. fragment.setArguments(bundle);
  33. return fragment;
  34. }
  35. @Override
  36. public void onCreate(@Nullable Bundle savedInstanceState) {
  37. super.onCreate(savedInstanceState);
  38. if (getArguments() != null) {
  39. mFrom = getArguments().getString("from");
  40. }
  41. //录音授权
  42. Authorization();
  43. }
  44. @Override
  45. protected int setLayoutId() {
  46. return R.layout.chat_layout;
  47. }
  48. @Override
  49. protected void initView() {
  50. webView = (BridgeWebView) mRootView.findViewById(R.id.webview);
  51. progressbar = (ProgressBar) mRootView.findViewById(R.id.progressBar);
  52. String request_url = BaseCacheUtil.getString(getActivity(), "webview_url");
  53. baseurl = BaseHttpsUrl.NEW_BASE_LIVE_CHAT_WEBVIEW;
  54. initWebView();
  55. }
  56. private void initWebView() {
  57. WebSettings settings = webView.getSettings();
  58. settings.setJavaScriptEnabled(true);// 让WebView能够执行javaScript
  59. settings.setDomStorageEnabled(true);
  60. settings.setJavaScriptCanOpenWindowsAutomatically(true);// 让JavaScript可以自动打开windows
  61. settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 设置缓存模式,一共有四种模式
  62. // 开启 DOM storage API 功能
  63. //开启 database storage API 功能
  64. settings.setDatabaseEnabled(true);
  65. //开启 Application Caches 功能
  66. settings.setAppCacheEnabled(true);
  67. settings.setSupportZoom(true);// 支持缩放(适配到当前屏幕)
  68. settings.setUseWideViewPort(true); // 将图片调整到合适的大小
  69. settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); // 支持内容重新布局,一共有四种方式 默认的是NARROW_COLUMNS
  70. settings.setDisplayZoomControls(true); // 设置可以被显示的屏幕控制
  71. settings.setDefaultFontSize(12); // 设置默认字体大小
  72. settings.setAllowFileAccessFromFileURLs(true);
  73. settings.setAllowUniversalAccessFromFileURLs(true);
  74. settings.setMediaPlaybackRequiresUserGesture(false);
  75. webView.loadUrl(baseurl);
  76. //实现:按手机回退键,如果浏览器有上一个网页,则返回上一个网页
  77. webView.setOnKeyListener((v, keyCode, event) -> {
  78. if (event.getAction() == KeyEvent.ACTION_DOWN) {
  79. if (keyCode == KEYCODE_BACK && webView.canGoBack()) {
  80. webView.goBack();
  81. return true;
  82. }
  83. }
  84. return false;
  85. });
  86. webView.setWebChromeClient(new WebChromeClient() {
  87. @Override
  88. public void onProgressChanged(WebView view, int newProgress) {
  89. progressbar.setProgress(newProgress);
  90. if (newProgress == 100) {
  91. progressbar.setVisibility(View.GONE);
  92. } else {
  93. progressbar.setVisibility(View.VISIBLE);
  94. }
  95. super.onProgressChanged(view, newProgress);
  96. }
  97. @Override
  98. public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
  99. result.confirm();
  100. return true;
  101. }
  102. @Override
  103. public void onPermissionRequest(PermissionRequest request) { //webview自带录音授权(重点!!!)
  104. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  105. request.grant(request.getResources());
  106. request.getOrigin();
  107. }
  108. }
  109. //扩展浏览器上传文件
  110. //3.0++版本
  111. public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
  112. openFileChooserImpl(uploadMsg);
  113. }
  114. //3.0--版本
  115. public void openFileChooser(ValueCallback<Uri> uploadMsg) {
  116. openFileChooserImpl(uploadMsg);
  117. mUploadMessage = uploadMsg;
  118. }
  119. public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
  120. openFileChooserImpl(uploadMsg);
  121. }
  122. @Override
  123. public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
  124. onenFileChooseImpleForAndroid(filePathCallback);
  125. return true;
  126. }
  127. });
  128. //下载文件
  129. webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> {
  130. // TODO: 2017-5-6 处理下载事件
  131. Uri uri = Uri.parse(url);
  132. Intent intent = new Intent(Intent.ACTION_VIEW, uri); //跳转浏览器下载
  133. startActivity(intent);
  134. });
  135. //开始录音
  136. webView.registerHandler("startRecord", (data, function) -> {
  137. checkPermissions();
  138. startRecordVoice();
  139. String str = "这是html返回给java的数据:" + data;
  140. //回调返回给Js
  141. // function.onCallBack();
  142. });
  143. //暂停录音
  144. webView.registerHandler("stopRecord", (data, function) -> {
  145. stopRecordVoice();
  146. });
  147. //删除录音
  148. webView.registerHandler("cancelRecord", (data, function) -> {
  149. delete();
  150. });
  151. //发送录音
  152. webView.registerHandler("sendRecord", (data, function) -> {
  153. sendRecord1();
  154. });
  155. }
  156. /**
  157. * 录音授权
  158. */
  159. private void Authorization() {
  160. Objects.requireNonNull(getActivity()).runOnUiThread(this::checkPermissions);
  161. }
  162. private void checkPermissions() {
  163. // Marshmallow开始才用申请运行时权限
  164. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  165. for (int i = 0; i < permissions.length; i++) {
  166. if (ContextCompat.checkSelfPermission(getActivity(), permissions[i]) !=
  167. PackageManager.PERMISSION_GRANTED) {
  168. mPermissionList.add(permissions[i]);
  169. }
  170. }
  171. if (!mPermissionList.isEmpty()) {
  172. String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);
  173. ActivityCompat.requestPermissions(getActivity(), permissions, MY_PERMISSIONS_REQUEST);
  174. }
  175. }
  176. }
  177. @Override
  178. protected void setListener() {
  179. webView.setWebViewClient(new MyWebViewClient(webView) {
  180. @Override
  181. public void onPageStarted(WebView view, String url, Bitmap favicon) {
  182. super.onPageStarted(view, url, favicon);
  183. }
  184. @Override
  185. public void onPageFinished(WebView view, String url) {
  186. super.onPageFinished(view, url);
  187. }
  188. });
  189. webView.setDefaultHandler(new myHadlerCallBack());
  190. }
  191. /**
  192. * 自定义的WebViewClient
  193. */
  194. class MyWebViewClient extends BridgeWebViewClient {
  195. public MyWebViewClient(BridgeWebView webView) {
  196. super(webView);
  197. }
  198. }
  199. /**
  200. * 自定义回调
  201. */
  202. class myHadlerCallBack extends DefaultHandler {
  203. @Override
  204. public void handler(String data, CallBackFunction function) {
  205. if (function != null) {
  206. // Toast.makeText(WebViewTest.this, data, Toast.LENGTH_SHORT).show();
  207. }
  208. }
  209. }
  210. public ValueCallback<Uri> mUploadMessage;
  211. private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
  212. mUploadMessage = uploadMsg;
  213. Intent i = new Intent(Intent.ACTION_GET_CONTENT);
  214. i.addCategory(Intent.CATEGORY_OPENABLE);
  215. i.setType("image/*");
  216. startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
  217. }
  218. public ValueCallback<Uri[]> mUploadMessageForAndroid5;
  219. private void onenFileChooseImpleForAndroid(ValueCallback<Uri[]> filePathCallback) {
  220. mUploadMessageForAndroid5 = filePathCallback;
  221. Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
  222. contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
  223. contentSelectionIntent.setType("image/*");
  224. Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
  225. chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
  226. chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
  227. startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_ANDROID_5);
  228. }
  229. @Override
  230. public void onActivityResult(int requestCode, int resultCode, Intent intent) {
  231. super.onActivityResult(requestCode, resultCode, intent);
  232. if (requestCode == FILECHOOSER_RESULTCODE) {
  233. if (null == mUploadMessage)
  234. return;
  235. Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
  236. mUploadMessage.onReceiveValue(result);
  237. mUploadMessage = null;
  238. } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) {
  239. if (null == mUploadMessageForAndroid5)
  240. return;
  241. Uri result = (intent == null || resultCode != RESULT_OK) ? null : intent.getData();
  242. if (result != null) {
  243. mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});
  244. } else {
  245. mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
  246. }
  247. mUploadMessageForAndroid5 = null;
  248. }
  249. }
  250. /**
  251. * 申请权限
  252. *
  253. * @param permission
  254. */
  255. private void requestPermission(String permission) {
  256. if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) {
  257. ActivityCompat.requestPermissions(getActivity(), new String[]{permission}, 0);
  258. }
  259. }
  260. /**
  261. * 删除录音
  262. */
  263. private void delete() {
  264. File mp3File = new File(getActivity().getExternalFilesDir(Environment.DIRECTORY_MUSIC), "test.mp3");
  265. if (mp3File.exists()) {
  266. mp3File.delete();
  267. }
  268. }
  269. /**
  270. * 当前录音文件
  271. */
  272. private File audioFile;
  273. /**
  274. * 文件存储目录
  275. */
  276. private File mVoiceDir;
  277. public ChatFragment() {
  278. mVoiceDir = FileUtil.getChatVoiceDir();
  279. }
  280. /**
  281. * 按下录音
  282. */
  283. public void startRecordVoice() {
  284. try {
  285. recorder = new MediaRecorder();
  286. recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频采集原
  287. recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// 内容输出格式
  288. recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 音频编码方式
  289. audioFile = new File(mVoiceDir, DateUtil.formatDatetime(new Date(), "yyyyMMddHHmmss") + ".mp3");
  290. if (!audioFile.exists()) {
  291. boolean flag = audioFile.createNewFile();
  292. Log.i("speak", String.valueOf(flag));
  293. }
  294. ABLELogUtils.e("m_tag_", "文件路劲为:" + audioFile.getAbsolutePath() + "=====" + audioFile.getPath());
  295. recorder.setOutputFile(audioFile.getAbsolutePath());
  296. recorder.prepare(); // 预期准备
  297. recorder.start();//开始录音
  298. } catch (IllegalStateException e) {
  299. recorder = null;
  300. } catch (IOException e) {
  301. recorder = null;
  302. }
  303. }
  304. /**
  305. * 停止录音
  306. */
  307. public void stopRecordVoice() {
  308. try {
  309. recorder.stop();// 停止刻录
  310. recorder.reset();// 重设
  311. recorder.release();// 刻录完成一定要释放资源
  312. recorder = null;
  313. } catch (Exception e) {
  314. ABLELogUtils.e("RecordVoice", e.getMessage());
  315. }
  316. }
  317. /**
  318. * sendRecord()
  319. * 發送錄音
  320. */
  321. private void sendRecord1() {
  322. try {
  323. FileInputStream inputFile = new FileInputStream(audioFile);
  324. byte[] buffer = new byte[(int) audioFile.length()];
  325. inputFile.read(buffer);
  326. inputFile.close();
  327. encodedString = Base64.encodeToString(buffer, Base64.DEFAULT);
  328. Log.e("m_tag_Base64", "Base64--后的MP3文件-->" + encodedString);
  329. if (!TextUtils.isEmpty(encodedString)) {
  330. String file_type = "audio/mp3";
  331. String sender = "operator";
  332. RecordData(getActivity(), xxxx, encodedString, file_type, xxxx);
  333. }
  334. } catch (Exception e) {
  335. e.printStackTrace();
  336. }
  337. }
  338. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/175208
推荐阅读
相关标签
  

闽ICP备14008679号