当前位置:网站首页>Develop plug-ins for the recording function of flutter
Develop plug-ins for the recording function of flutter
2022-07-28 01:31:00 【dengjiangszhan】
Native provides functionality ,Dart module adopt method channel Asynchronous call
1, Android part
Manual registration
Flutter Official practice , Is to automatically register plug-ins ,
Very convenient
Manual registration , Reflect the difference of this article
The plug-in is AudioRecorderPlugin
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
flutterEngine!!.plugins.add(AudioRecorderPlugin())
}
}
Android and Dart Communication of
Mainly message callback
The following are ,
- Start the recording
- End of the tape
- Is the tape
- Whether there is recording permission
Be careful , The recording permission here includes two , Microphone permissions , And storage permissions
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
switch (call.method) {
case "start":
Log.d(LOG_TAG, "Start");
Log.d(LOG_TAG, "11111____");
String path = call.argument("path");
mExtension = call.argument("extension");
startTime = Calendar.getInstance().getTime();
if (path != null) {
mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + path;
} else {
Log.d(LOG_TAG, "11111____222");
String fileName = String.valueOf(startTime.getTime());
mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileName + mExtension;
}
Log.d(LOG_TAG, mFilePath);
startRecording();
isRecording = true;
result.success(null);
break;
case "stop":
Log.d(LOG_TAG, "Stop");
stopRecording();
long duration = Calendar.getInstance().getTime().getTime() - startTime.getTime();
Log.d(LOG_TAG, "Duration : " + String.valueOf(duration));
isRecording = false;
HashMap<String, Object> recordingResult = new HashMap<>();
recordingResult.put("duration", duration);
recordingResult.put("path", mFilePath);
recordingResult.put("audioOutputFormat", mExtension);
result.success(recordingResult);
break;
case "isRecording":
Log.d(LOG_TAG, "Get isRecording");
result.success(isRecording);
break;
case "hasPermissions":
Log.d(LOG_TAG, "Get hasPermissions");
Context context = _flutterBinding.getApplicationContext();
PackageManager pm = context.getPackageManager();
int hasStoragePerm = pm.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context.getPackageName());
int hasRecordPerm = pm.checkPermission(Manifest.permission.RECORD_AUDIO, context.getPackageName());
boolean hasPermissions = hasStoragePerm == PackageManager.PERMISSION_GRANTED && hasRecordPerm == PackageManager.PERMISSION_GRANTED;
result.success(hasPermissions);
break;
default:
result.notImplemented();
break;
}
}
Android recording
Use wav The packaging format of , use AudioRecord;
Other packaging formats , use MediaRecorder
The upper two players , It has the function of starting and ending recording ;
Pause recording and resume recording , Then start and end many times , Then put the documents together

2,Dart module part
establish MethodChannel, Call the above native functions asynchronously
class AudioRecorder {
static const MethodChannel _channel = const MethodChannel('audio_recorder');
static LocalFileSystem fs = LocalFileSystem();
static Future start(String path, AudioOutputFormat audioOutputFormat) async {
String extension;
if (path != null) {
if (audioOutputFormat != null) {
if (_convertStringInAudioOutputFormat(p.extension(path)) !=
audioOutputFormat) {
extension = _convertAudioOutputFormatInString(audioOutputFormat);
path += extension;
} else {
extension = p.extension(path);
}
} else {
if (_isAudioOutputFormat(p.extension(path))) {
extension = p.extension(path);
} else {
extension = ".m4a"; // default value
path += extension;
}
}
File file = fs.file(path);
if (await file.exists()) {
throw new Exception("A file already exists at the path :" + path);
} else if (!await file.parent.exists()) {
throw new Exception("The specified parent directory does not exist");
}
} else {
extension = ".m4a"; // default value
}
return _channel
.invokeMethod('start', {"path": path, "extension": extension});
}
static Future<Recording?> stop() async {
// Bring out the original information , Put it in the dictionary
Map<String, dynamic> response =
Map.from(await _channel.invokeMethod('stop'));
if (response != null) {
int duration = response['duration'];
String fmt = response['audioOutputFormat'];
AudioOutputFormat? outputFmt = _convertStringInAudioOutputFormat(fmt);
if (fmt != null && outputFmt != null) {
Recording recording = new Recording(
new Duration(milliseconds: duration),
response['path'],
outputFmt,
response['audioOutputFormat']);
return recording;
}
} else {
return null;
}
}
iOS part
Manually register the plug-in
The plug-in name here , by SwiftAudioRecorderPlugin
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if let register = registrar(forPlugin: "SwiftAudioRecorderPlugin"){
SwiftAudioRecorderPlugin.register(with: register)
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
iOS plug-in unit
Logic is similar to Android plug-ins ,
because iOS Of AVAudioRecorder Yes pause and resume operation , Support friendship ,
So the function of pause and resume recording is added
iOS The permission of the client is greater than that of Android , One less
Only recording microphone permission is required
public class SwiftAudioRecorderPlugin: NSObject, FlutterPlugin {
var isRecording = false
var hasPermissions = false
var mExtension = ""
var mPath = ""
var startTime: Date!
var audioRecorder: AVAudioRecorder?
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "audio_recorder", binaryMessenger: registrar.messenger())
let instance = SwiftAudioRecorderPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "start":
print("start")
let dic = call.arguments as! [String : Any]
mExtension = dic["extension"] as? String ?? ""
mPath = dic["path"] as? String ?? ""
startTime = Date()
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
if mPath == "" {
mPath = documentsPath + "/" + String(Int(startTime.timeIntervalSince1970)) + ".m4a"
}
else{
mPath = documentsPath + "/" + mPath
}
print("path: " + mPath)
let settings = [
AVFormatIDKey: getOutputFormatFromString(mExtension),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
try AVAudioSession.sharedInstance().setActive(true)
let recorder = try AVAudioRecorder(url: URL(string: mPath)!, settings: settings)
recorder.delegate = self
recorder.record()
audioRecorder = recorder
} catch {
print("fail")
result(FlutterError(code: "", message: "Failed to record", details: nil))
}
isRecording = true
result(nil)
case "pause":
audioRecorder?.pause()
result(nil)
case "resume":
audioRecorder?.record()
result(nil)
case "stop":
print("stop")
audioRecorder?.stop()
audioRecorder = nil
let duration = Int(Date().timeIntervalSince(startTime as Date) * 1000)
isRecording = false
var recordingResult = [String : Any]()
recordingResult["duration"] = duration
recordingResult["path"] = mPath
recordingResult["audioOutputFormat"] = mExtension
result(recordingResult)
case "isRecording":
print("isRecording")
result(isRecording)
case "hasPermissions":
print("hasPermissions")
switch AVAudioSession.sharedInstance().recordPermission{
case AVAudioSession.RecordPermission.granted:
print("granted")
hasPermissions = true
case AVAudioSession.RecordPermission.denied:
print("denied")
hasPermissions = false
case AVAudioSession.RecordPermission.undetermined:
print("undetermined")
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.hasPermissions = true
} else {
self.hasPermissions = false
}
}
}
default:()
}
result(hasPermissions)
default:
result(FlutterMethodNotImplemented)
}
}
}
Dart Call part
By judging the platform ,Platform.isIOS,
to iOS equipment , Add perfect functions
@override
Widget build(BuildContext context) {
final VoidCallback tapFirst;
if (Platform.isAndroid && name == kEnd) {
tapFirst = _audioEnd;
} else {
tapFirst = _audioGoOn;
}
List<Widget> views = [
ElevatedButton(
child: Text(
name,
style: Theme.of(context).textTheme.headline4,
),
onPressed: tapFirst,
)
];
if (Platform.isIOS && name != kStarted) {
views.add(SizedBox(height: 80));
views.add(ElevatedButton(
child: Text(
kEnd,
style: Theme.of(context).textTheme.headline4,
),
onPressed: _audioEnd,
));
}
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: views,
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
github repo
边栏推荐
- 华米科技“黄山2号”发布:AI性能提升7倍,功耗降低50%!
- Tear the source code of gateway by hand, and tear the source code of workflow and load balancing today
- Node red interacts with tdengine
- Advanced MySQL -- stored procedures and custom functions
- Arm中国夺权大战的背后:“独立”两年,仍难“自主”?
- C language main function transfer parameters
- 站在数字零售转型的十字路口,我们需要用新的角度来看待它
- Flutter 通话界面UI
- mysql查询条件字段值末尾有空格也能查到数据问题
- Cesium add inundation analysis measurement area
猜你喜欢

【C语言】文件操作

Unknown database ‘xxxxx‘

从功能测试到自动化测试,月薪突破30K+,我的6年测开经验。

数仓搭建——DWS层

Byte monthly salary 28K, share a wave of my automation testing experience

Flutter--密码登录注册界面

Learn how Baidu PaddlePaddle easydl realizes automatic animal recognition in aquarium

Basic concept and classification of i/o equipment

Fabric2.4.4 version building process (complete process)

From functional testing to automated testing, my monthly salary has exceeded 30k+, and I have 6 years of testing experience.
随机推荐
Use of swarm task task
Starfish Os打造的元宇宙生态,跟MetaBell的合作只是开始
Matlab drawing - points and vectors: method and source code of vector addition and subtraction
Centralized management of clusters
C语言main函数传递参数
Codeforces暑期训练周报(7.14~7.20)
At the meeting on June 19, SMIC may set the fastest listing record in China!
国产NB-IoT芯片厂商芯翼信息科技获2亿元A+轮融资
Jingfang Technology: ASML, a lithography machine manufacturer, is one of the main customers of Anterion company, which participated in the merger and acquisition of the company
idea常用的快捷键汇总
6月19日上会,中芯国际或创造国内最快上市记录!
Detailed explanation of swoole memory table
Insider of container network hard core technology (7) sailing on the sea depends on the helmsman
Spreadsheet export excel table
The cooperation between starfish OS and metabell is just the beginning
测试人员需要了解的软件流程
Swoole collaboration
【C语言】文件操作
Opengauss active / standby architecture works with keeplive
4月全球智能手机出货同比下滑41%,华为首次超三星成全球第一