Android如何使用Flutter实现录音插件

本篇内容主要讲解“Android如何使用Flutter实现录音插件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android如何使用Flutter实现录音插件”吧!安卓部分

本篇内容主要讲解“Android如何使用Flutter实现录音插件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android如何使用Flutter实现录音插件”吧!

安卓部分

手动注册

Flutter 官方的做法,就是自动注册插件,

很方便

手动注册,体现本文的不同

插件是 AudioRecorderPlugin

  1. class MainActivity: FlutterActivity() {
  2.     override fun onCreate(savedInstanceState: Bundle?) {
  3.         super.onCreate(savedInstanceState)
  4.         flutterEngine!!.plugins.add(AudioRecorderPlugin())
  5.     }
  6. }

Android和Dart的通讯

主要是消息回调

下文依次是,

  • 开始录音

  • 结束录音

  • 正在录音

  • 是否有录音权限

注意,这里的录音权限包含两个,麦克风的权限,和存储权限

  1. @Override
  2. public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
  3.   switch (call.method) {
  4.     case "start":
  5.       Log.d(LOG_TAG, "Start");
  6.       Log.d(LOG_TAG, "11111____");
  7.       String path = call.argument("path");
  8.       mExtension = call.argument("extension");
  9.       startTime = Calendar.getInstance().getTime();
  10.       if (path != null) {
  11.         mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + path;
  12.       } else {
  13.         Log.d(LOG_TAG, "11111____222");
  14.         String fileName = String.valueOf(startTime.getTime());
  15.         mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileName + mExtension;
  16.       }
  17.       Log.d(LOG_TAG, mFilePath);
  18.       startRecording();
  19.       isRecording = true;
  20.       result.success(null);
  21.       break;
  22.     case "stop":
  23.       Log.d(LOG_TAG, "Stop");
  24.       stopRecording();
  25.       long duration = Calendar.getInstance().getTime().getTime() - startTime.getTime();
  26.       Log.d(LOG_TAG, "Duration : " + String.valueOf(duration));
  27.       isRecording = false;
  28.       HashMap<String, Object> recordingResult = new HashMap<>();
  29.       recordingResult.put("duration", duration);
  30.       recordingResult.put("path", mFilePath);
  31.       recordingResult.put("audioOutputFormat", mExtension);
  32.       result.success(recordingResult);
  33.       break;
  34.     case "isRecording":
  35.       Log.d(LOG_TAG, "Get isRecording");
  36.       result.success(isRecording);
  37.       break;
  38.     case "hasPermissions":
  39.       Log.d(LOG_TAG, "Get hasPermissions");
  40.       Context context = _flutterBinding.getApplicationContext();
  41.       PackageManager pm = context.getPackageManager();
  42.       int hasStoragePerm = pm.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context.getPackageName());
  43.       int hasRecordPerm = pm.checkPermission(Manifest.permission.RECORD_AUDIO, context.getPackageName());
  44.       boolean hasPermissions = hasStoragePerm == PackageManager.PERMISSION_GRANTED && hasRecordPerm == PackageManager.PERMISSION_GRANTED;
  45.       result.success(hasPermissions);
  46.       break;
  47.     default:
  48.       result.notImplemented();
  49.       break;
  50.   }
  51. }

安卓录音

使用 wav 的封装格式,用 AudioRecord;

其他封装格式,用 MediaRecorder

上面两个播放器,有开始录音和结束录音功能;

暂停录音和恢复录音,则多次开始和结束,再把文件拼接在一起

Android如何使用Flutter实现录音插件

Dart module部分

建立 MethodChannel, 异步调用上面的原生功能

  1. class AudioRecorder {
  2.   static const MethodChannel _channel = const MethodChannel('audio_recorder');
  3.   static LocalFileSystem fs = LocalFileSystem();
  4.   static Future start(String path, AudioOutputFormat audioOutputFormat) async {
  5.     String extension;
  6.     if (path != null) {
  7.       if (audioOutputFormat != null) {
  8.         if (_convertStringInAudioOutputFormat(p.extension(path)) !=
  9.             audioOutputFormat) {
  10.           extension = _convertAudioOutputFormatInString(audioOutputFormat);
  11.           path += extension;
  12.         } else {
  13.           extension = p.extension(path);
  14.         }
  15.       } else {
  16.         if (_isAudioOutputFormat(p.extension(path))) {
  17.           extension = p.extension(path);
  18.         } else {
  19.           extension = ".m4a"; // default value
  20.           path += extension;
  21.         }
  22.       }
  23.       File file = fs.file(path);
  24.       if (await file.exists()) {
  25.         throw new Exception("A file already exists at the path :" + path);
  26.       } else if (!await file.parent.exists()) {
  27.         throw new Exception("The specified parent directory does not exist");
  28.       }
  29.     } else {
  30.       extension = ".m4a"; // default value
  31.     }
  32.     return _channel
  33.         .invokeMethod('start', {"path": path, "extension": extension});
  34.   }
  35.   static Future<Recording?> stop() async {
  36.     // 把原生带出来的信息,放入字典中
  37.     Map<String, dynamic> response =
  38.         Map.from(await _channel.invokeMethod('stop'));
  39.     if (response != null) {
  40.       int duration = response['duration'];
  41.       String fmt = response['audioOutputFormat'];
  42.       AudioOutputFormat? outputFmt = _convertStringInAudioOutputFormat(fmt);
  43.       if (fmt != null && outputFmt != null) {
  44.         Recording recording = new Recording(
  45.             new Duration(milliseconds: duration),
  46.             response['path'],
  47.             outputFmt,
  48.             response['audioOutputFormat']);
  49.         return recording;
  50.       }
  51.     } else {
  52.       return null;
  53.     }
  54.   }

iOS部分

手动注册插件

这里的插件名, 为 SwiftAudioRecorderPlugin

  1. public class SwiftAudioRecorderPlugin: NSObject, FlutterPlugin {
  2.     var isRecording = false
  3.     var hasPermissions = false
  4.     var mExtension = ""
  5.     var mPath = ""
  6.     var startTime: Date!
  7.     var audioRecorder: AVAudioRecorder?
  8.   public static func register(with registrar: FlutterPluginRegistrar) {
  9.     let channel = FlutterMethodChannel(name: "audio_recorder", binaryMessenger: registrar.messenger())
  10.     let instance = SwiftAudioRecorderPlugin()
  11.     registrar.addMethodCallDelegate(instance, channel: channel)
  12.   }
  13.   public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
  14.     switch call.method {
  15.         case "start":
  16.             print("start")
  17.             let dic = call.arguments as! [String : Any]
  18.             mExtension = dic["extension"] as? String ?? ""
  19.             mPath = dic["path"] as? String ?? ""
  20.             startTime = Date()
  21.             let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
  22.             if mPath == "" {
  23.                 mPath = documentsPath + "/" + String(Int(startTime.timeIntervalSince1970)) + ".m4a"
  24.             }
  25.             else{
  26.                 mPath = documentsPath + "/" + mPath
  27.             }
  28.             print("path: " + mPath)
  29.             let settings = [
  30.                 AVFormatIDKey: getOutputFormatFromString(mExtension),
  31.                 AVSampleRateKey: 12000,
  32.                 AVNumberOfChannelsKey: 1,
  33.                 AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
  34.             ]
  35.             do {
  36.                 try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
  37.                 try AVAudioSession.sharedInstance().setActive(true)
  38.  
  39.                 let recorder = try AVAudioRecorder(url: URL(string: mPath)!, settings: settings)
  40.                 recorder.delegate = self
  41.                 recorder.record()
  42.                 audioRecorder = recorder
  43.             } catch {
  44.                 print("fail")
  45.                 result(FlutterError(code: "", message: "Failed to record", details: nil))
  46.             }
  47.             isRecording = true
  48.             result(nil)
  49.         case "pause":
  50.             audioRecorder?.pause()
  51.             result(nil)
  52.         case "resume":
  53.             audioRecorder?.record()
  54.             result(nil)
  55.         case "stop":
  56.             print("stop")
  57.             audioRecorder?.stop()
  58.             audioRecorder = nil
  59.             let duration = Int(Date().timeIntervalSince(startTime as Date) * 1000)
  60.             isRecording = false
  61.             var recordingResult = [String : Any]()
  62.             recordingResult["duration"] = duration
  63.             recordingResult["path"] = mPath
  64.             recordingResult["audioOutputFormat"] = mExtension
  65.             result(recordingResult)
  66.         case "isRecording":
  67.             print("isRecording")
  68.             result(isRecording)
  69.         case "hasPermissions":
  70.             print("hasPermissions")
  71.         switch AVAudioSession.sharedInstance().recordPermission{
  72.             case AVAudioSession.RecordPermission.granted:
  73.                 print("granted")
  74.                 hasPermissions = true
  75.             case AVAudioSession.RecordPermission.denied:
  76.                 print("denied")
  77.                 hasPermissions = false
  78.             case AVAudioSession.RecordPermission.undetermined:
  79.                 print("undetermined")
  80.                 AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
  81.                     DispatchQueue.main.async {
  82.                         if allowed {
  83.                             self.hasPermissions = true
  84.                         } else {
  85.                             self.hasPermissions = false
  86.                         }
  87.                     }
  88.                 }
  89.             default:()
  90.             }
  91.             result(hasPermissions)
  92.         default:
  93.             result(FlutterMethodNotImplemented)
  94.         }
  95.       }
  96.     }

iOS插件

逻辑与安卓插件类似,

因为 iOS 的 AVAudioRecorderpauseresume 操作,支持友好,

所以增添了暂停和恢复录音功能

iOS 端的权限比安卓权限,少一个

仅需要录音麦克风权限

  1. public class SwiftAudioRecorderPlugin: NSObject, FlutterPlugin {
  2.     var isRecording = false
  3.     var hasPermissions = false
  4.     var mExtension = ""
  5.     var mPath = ""
  6.     var startTime: Date!
  7.     var audioRecorder: AVAudioRecorder?
  8.   public static func register(with registrar: FlutterPluginRegistrar) {
  9.     let channel = FlutterMethodChannel(name: "audio_recorder", binaryMessenger: registrar.messenger())
  10.     let instance = SwiftAudioRecorderPlugin()
  11.     registrar.addMethodCallDelegate(instance, channel: channel)
  12.   }
  13.   public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
  14.     switch call.method {
  15.         case "start":
  16.             print("start")
  17.             let dic = call.arguments as! [String : Any]
  18.             mExtension = dic["extension"] as? String ?? ""
  19.             mPath = dic["path"] as? String ?? ""
  20.             startTime = Date()
  21.             let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
  22.             if mPath == "" {
  23.                 mPath = documentsPath + "/" + String(Int(startTime.timeIntervalSince1970)) + ".m4a"
  24.             }
  25.             else{
  26.                 mPath = documentsPath + "/" + mPath
  27.             }
  28.             print("path: " + mPath)
  29.             let settings = [
  30.                 AVFormatIDKey: getOutputFormatFromString(mExtension),
  31.                 AVSampleRateKey: 12000,
  32.                 AVNumberOfChannelsKey: 1,
  33.                 AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
  34.             ]
  35.             do {
  36.                 try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
  37.                 try AVAudioSession.sharedInstance().setActive(true)
  38.                 let recorder = try AVAudioRecorder(url: URL(string: mPath)!, settings: settings)
  39.                 recorder.delegate = self
  40.                 recorder.record()
  41.                 audioRecorder = recorder
  42.             } catch {
  43.                 print("fail")
  44.                 result(FlutterError(code: "", message: "Failed to record", details: nil))
  45.             }
  46.             isRecording = true
  47.             result(nil)
  48.         case "pause":
  49.             audioRecorder?.pause()
  50.             result(nil)
  51.         case "resume":
  52.             audioRecorder?.record()
  53.             result(nil)
  54.         case "stop":
  55.             print("stop")
  56.             audioRecorder?.stop()
  57.             audioRecorder = nil
  58.             let duration = Int(Date().timeIntervalSince(startTime as Date) * 1000)
  59.             isRecording = false
  60.             var recordingResult = [String : Any]()
  61.             recordingResult["duration"] = duration
  62.             recordingResult["path"] = mPath
  63.             recordingResult["audioOutputFormat"] = mExtension
  64.             result(recordingResult)
  65.         case "isRecording":
  66.             print("isRecording")
  67.             result(isRecording)
  68.         case "hasPermissions":
  69.             print("hasPermissions")
  70.         switch AVAudioSession.sharedInstance().recordPermission{
  71.             case AVAudioSession.RecordPermission.granted:
  72.                 print("granted")
  73.                 hasPermissions = true
  74.             case AVAudioSession.RecordPermission.denied:
  75.                 print("denied")
  76.                 hasPermissions = false
  77.             case AVAudioSession.RecordPermission.undetermined:
  78.                 print("undetermined")
  79.                 AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
  80.                     DispatchQueue.main.async {
  81.                         if allowed {
  82.                             self.hasPermissions = true
  83.                         } else {
  84.                             self.hasPermissions = false
  85.                         }
  86.                     }
  87.                 }
  88.             default:()
  89.             }
  90.             result(hasPermissions)
  91.         default:
  92.             result(FlutterMethodNotImplemented)
  93.         }
  94.       }
  95.     }

Dart调用部分

通过判断平台,Platform.isIOS,

给 iOS 设备,增加完善的功能

  1. @override
  2. Widget build(BuildContext context) {
  3.   final VoidCallback tapFirst;
  4.   if (Platform.isAndroid && name == kEnd) {
  5.     tapFirst = _audioEnd;
  6.   } else {
  7.     tapFirst = _audioGoOn;
  8.   }
  9.   List<Widget> views = [
  10.     ElevatedButton(
  11.       child: Text(
  12.         name,
  13.         style: Theme.of(context).textTheme.headline4,
  14.       ),
  15.       onPressed: tapFirst,
  16.     )
  17.   ];
  18.   if (Platform.isIOS && name != kStarted) {
  19.     views.add(SizedBox(height: 80));
  20.     views.add(ElevatedButton(
  21.       child: Text(
  22.         kEnd,
  23.         style: Theme.of(context).textTheme.headline4,
  24.       ),
  25.       onPressed: _audioEnd,
  26.     ));
  27.   }
  28.   return Scaffold(
  29.     appBar: AppBar(
  30.       // Here we take the value from the MyHomePage object that was created by
  31.       // the App.build method, and use it to set our appbar title.
  32.       title: Text(widget.title),
  33.     ),
  34.     body: Center(
  35.       // Center is a layout widget. It takes a single child and positions it
  36.       // in the middle of the parent.
  37.       child: Column(
  38.         mainAxisAlignment: MainAxisAlignment.center,
  39.         children: views,
  40.       ),
  41.     ), // This trailing comma makes auto-formatting nicer for build methods.
  42.   );
  43. }

到此,相信大家对“Android如何使用Flutter实现录音插件”有了更深的了解,不妨来实际操作一番吧!这里是恰卡网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

本站部分文章来自网络或用户投稿,如无特殊说明或标注,均为本站原创发布。涉及资源下载的,本站旨在共享仅供大家学习与参考,如您想商用请获取官网版权,如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
开发者

mysql多实例如何部署

2022-8-3 21:14:48

开发者

docker安装nacos实例分析

2022-8-3 21:14:51

搜索