更新记录
1.0.240409(2024-04-10)
第一次发布
平台兼容性
Android | iOS |
---|---|
× | 适用版本区间:9 - 17 |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
- 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
- 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
- 开发完毕后正式云打包
付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios
注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择
⠀
⠀
Recorder原生录音插件:实时帧回调、文件流式读写
本原生插件提供Android、iOS双端支持(可单独购买),是前端组件 Recorder-UniCore 的配套插件,搭配使用时可以提供丰富的功能支持;或者直接调用本原生插件接口,不过能做到的功能有限。
推荐搭配Recorder-UniCore
前端组件一起使用,可做到:
- 支持已有的大部分录音格式:mp3、wav、pcm、amr、ogg、g711a、g711u等
- 支持实时处理,包括变速变调、实时上传、ASR语音转文字
- 支持可视化波形显示;可配置回声消除、降噪;注意:不支持通话时录音
- 支持文件流式读写,录音数据可以实时写入到文件
- 支持离线使用,前端组件和本原生插件均不依赖网络
详细文档(含Demo项目): https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_UniApp
Recorder开源库地址: https://github.com/xiangyuecn/Recorder
如果github打不开,可以点此访问Gitee仓库地址 。
⠀
选择适用你的版本
本原生插件支持Android、iOS分开单独到DCloud插件市场购买,均包含了Recorder-UniCore前端组件的商用授权;你可以只购买授权,费用为 ¥199元 ,相当于同时赠送了Android版原生插件(如果用不着这个原生插件可以不使用即可)。
版本 | 价格 | 说明 |
---|---|---|
授权+送Android | ¥199 | 建议只购买授权、或只Android上使用时购买 |
单iOS+补差价 | ¥399 | 只含iOS版原生插件,建议只iOS上使用时购买 |
Android+iOS | ¥598 | 含Android、iOS原生插件 |
购买后可联系客服,同时提供订单信息,客服拉你进入VIP支持QQ群,在群文件中可下载Recorder-UniCore前端组件的app-uni-support.js
文件最新源码;客服联系方式:QQ 1251654593 ,或者直接联系作者QQ 753610399 (回复可能没有客服及时)。
注:VIP支持群的主要作用是代表你已获得授权许可,可以随时获得
app-uni-support.js
文件最新版源码;不作为问答或售后群使用,当然如果你有问题也可以直接群里问,花费时间不多的,作者免费顺带就解答了,如果复杂花费比较久时间的,可能要适当收点人工费用,或者选择进行付费指导。
Recorder-UniCore
组件中自带的app-uni-support.js
文件是压缩版,功能和源码版一致,在VIP支持群中下载得到此文件源码后,可以直接替换组件中的这个文件,也可以不替换。
⠀
测试方法
测试时无需购买插件,试用是免费的,并且原生插件试用是无限制的。
- 先到Recorder-UniCore下载示例项目,在HBuilder中打开后,在项目manifest.json配置中分配一个uni-app应用标识
- 然后点击本插件页面中的试用按钮,在这个应用标识对应的项目中试用
- 然后在项目manifest.json的App原生插件配置中勾选本原生插件
- HBuilder中提交云打包打自定义基座
- 连接手机进行调试,使用自定义基座运行即可测试
⠀
录音权限配置
在uni-app项目的 manifest.json
中配置好Android和iOS的录音权限声明。
//Android需要勾选的权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
//iOS需要声明的权限
NSMicrophoneUsageDescription
注意:iOS需要在 `App常用其它设置`->`后台运行能力`中提供`audio`配置,不然App切到后台后立马会停止录音
⠀
⠀
⠀
使用方法一:搭配Recorder-UniCore前端组件使用
插件集成
- 到插件市场下载安装Recorder-UniCore前端组件
- 试用或购买本原生插件,在项目manifest.json的App原生插件配置中勾选本原生插件
- 参考上面的录音权限配置,在项目manifest.json中配置好权限
- 云打包自定义基座进行测试、或正式打包,即完成集成
⠀
调用录音
/** 详细的录音代码请参考Recorder-UniCore文档:https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_UniApp
RecordApp.RequestPermission(...) 请求录音权限
RecordApp.Start({type:"mp3",sampleRate:16000,bitRate:16}, ...) 开始录音
RecordApp.Stop(...) 停止录音
RecordApp.Pause() 暂停
RecordApp.Resume() 继续
**/
//在调用RecordApp.RequestPermission之前进行配置,建议放到import后面直接配置(全局生效)
//也可以判断一下只在iOS上或Android上启用,不判断就都启用,比如判断iOS:RecordApp.UniIsApp()==2
RecordApp.UniNativeUtsPlugin={ nativePlugin:true };
//只需进行这个配置就行,在RecordApp录音时就会自动使用原生插件来录音;未启用原生插件时App内默认是在renderjs使用H5录音
⠀
手动调用原生插件接口
/**App中集成了原生插件后按下面代码进行调用,注意需要先配置RecordApp.UniNativeUtsPlugin
参数:action 字符串,要调用的功能;args 对象,调用参数
返回:any 根据功能定义返回对应的结果,出错会抛异常
比如将任意数据保存到文件:**/
try{
var result=await RecordApp.UniNativeUtsPluginCallAsync("writeFile",{path:"test.txt", dataBase64:"dGVzdDEyMw=="});
}catch(e){
console.error(e)
}
//更多可用接口请参考下面的《直接调用原生插件接口 - 可用的接口》
⠀
⠀
⠀
使用方法二:直接调用原生插件接口
注意:仅使用原生插件接口来进行录音时,只支持返回pcm格式音频数据,不支持其他格式;pcm数据可以使用Recorder库进行转码成其他格式,或者直接使用Recorder-UniCore前端组件支持更多格式录音。
插件集成
- 试用或购买本原生插件,在项目manifest.json的App原生插件配置中勾选本原生插件
- 参考上面的录音权限配置,在项目manifest.json中配置好权限
- 云打包自定义基座进行测试、或正式打包,即完成集成
⠀
调用插件接口
//加载插件,注意:如果你使用的单独的Android或iOS版,请使用下面带后缀的
var RecNP=uni.requireNativePlugin("Recorder-NativePlugin");
//var RecNP=uni.requireNativePlugin("Recorder-NativePlugin-Android");
//var RecNP=uni.requireNativePlugin("Recorder-NativePlugin-iOS");
//调用插件接口,固定使用request方法进行调用
RecNP.request({
action:"writeFile" //接口名称,这个例子是将任意数据保存到文件
,args:{path:"test.txt", dataBase64:"dGVzdDEyMw=="} //接口参数
},function(data){ //接口调用结果回调
if(data.status!="success"){
console.error(data.message); //调用错误处理
return;
};
console.log(data.value); //接口调用结果
});
//绑定原生层回调
RecNP.request({action:"jsCall",args:{}},function(data){
if(data.action=="onLog"){ //原生层日志输出
var msg="[RecNP]["+data.tag+"]"+data.message;
data.isError? console.error(msg) : console.log(msg);
}else if(data.action=="onRecord"){ //录音pcm数据回调
var sampleRate=data.sampleRate; //采样率
var pcm=new Int16Array(uni.base64ToArrayBuffer(data.pcmDataBase64)); //16位pcm
console.log("onRecord "+sampleRate+" "+pcm.length);
}
});
//建议自行封装一个函数返回Promise来异步调用,方便好使
var RecNP_CallAsync=function(action,args){ return new Promise(function(resolve, reject){
RecNP.request({ action:action,args:args||{} },function(data){
if(data.status!="success"){
reject(new Error(data.message));
return;
};
resolve(data.value);
});
}) };
//调用,这个例子是将任意数据保存到文件
try{
var result=await RecNP_CallAsync("writeFile",{path:"test.txt", dataBase64:"dGVzdDEyMw=="});
}catch(e){
console.error(e)
}
⠀
可用的接口
【文档说明】
下面的action中,开头的名字为RecNP.request的action,“参数”为args,“返回”为接口的返回值data.value
【录音相关action】 注意:在使用Recorder-UniCore组件时会自动调用这些接口,请勿自行调用
jsCall 【这是一个特殊方法】绑定原生层js回调,当原生层需要给js发送消息时,会进行回调(RecNP.request的回调方法会被反复调用)
参数:{}
返回:{ action:"", ... } //原生层会反复调用回调方法,通过其中的action来判断返回的是什么内容
{action:"noop"} //无需处理,多次调用jsCall时原生层释放老的回调
{action:"onLog",isError:false,tag:"xx",message:"xxx"} //原生层日志输出
{action:"onRecord",sampleRate:44100,pcmDataBase64:"base64"} //录音数据回调,pcm为16位单声道,sampleRate是pcm的采样率
recordPermission 请求录音权限
参数:{}
返回:{ code:1 } //权限状态:1有权限,3用户拒绝。(2未用到)
recordStart 开始录音,录音pcm数据会通过jsCall回调,开始后必须每5秒调用一次recordAlive;本方法会获取录音权限,但建议先调用recordPermission提前获取录音权限
参数:{
sampleRate:44100 //必填44100采样率,目前未提供其他有效值,固定返回44100采样率的pcm数据,需在js中编写代码进行采样率转换(加上滤波来抑制混叠),参考Recorder.IIRFilter和Recorder.SampleData采样率转换函数
,appNativePlugin_AEC_Enable:false //可选是否启用回声消除,默认不启用
,android_audioSource:1 //可选Android指定麦克风源 MediaRecorder.AudioSource,0 DEFAULT 默认音频源,1 MIC 主麦克风,5 CAMCORDER 相机方向的麦,6 VOICE_RECOGNITION 语音识别,7 VOICE_COMMUNICATION 语音通信(带回声消除)。配置值除7外,会禁用回声消除
}
返回:{} //空对象
recordStop 停止录音
参数:{}
返回:{} //空对象
recordAlive 定时心跳(开始录音后5秒发一次),如果超过10秒未发心跳,将会停止录音,防止未stop导致泄露
参数:{}
返回:{} //空对象
【其他可用action】
getInfo 获取插件信息
参数:{}
返回:{ info:"" } //插件信息字符串
setSpeakerOff 切换扬声器外放和听筒播放,随时都可以调用;但需注意打开录音时可能会自动切换播放方式,因此在打开录音后需要明确调用一次切换成你需要的播放方式
参数:{ off:true } //必填,true听筒播放,false扬声器播放
返回:{ } //空对象
writeFile 数据写入文件,可新建文件、追加写入(文件流写入)
参数:{
path:"文件路径" //必填,支持的路径请参考下面
,dataBase64:"base64" //必填,写入的任意内容base64编码,可以为空字符串(如仅新建文件)
,append:false //可选,是否追加写入到文件结尾,默认false会新建文件并写入数据
}
返回:{
fullPath:"/文件绝对路径"
}
readFile 读取文件,可流式读取
参数:{
path:"文件路径" //必填,支持的路径请参考下面
,type:"base64" //可选,返回结果类型,默认base64,设为text时将读取成utf-8文本,提供了chunkSize时只支持base64
,chunkSize:0 //可选,本次读取的最大长度,单位字节,默认0读取全部
,chunkOffset:0 //可选,提供了chunkSize时,指定读取的开始位置
}
返回:{
data:"文本或base64" //文件内容,类型取决于提供的type
,isExists:true //文件是否存在;文件不存在时不会返回错误,此时的data为空字符串
,totalSize:0 //文件大小
,fullPath:"/文件绝对路径"
}
deleteFile 删除文件或文件夹
参数:{
path:"文件路径" //必填,支持的路径请参考下面(文件不存在时不会报错)
,isDir:false //可选,true时此路径是文件夹,删除此文件夹,默认false
}
返回:{ fullPath:"/文件绝对路径" }
moveFile 移动或重命名文件
参数:{
fromPath:"源文件路径" //必填,支持的路径请参考下面
,path:"新文件路径" //必填,如果存在会覆盖
}
返回:{ fullPath:"/移动后的文件绝对路径" }
copyFile 复制文件
参数:{
fromPath:"源文件路径" //必填,支持的路径请参考下面
,path:"新文件路径" //必填,如果存在会覆盖
}
返回:{ fullPath:"/复制后的文件绝对路径" }
resolvePath 解析路径成绝对路径
参数:{
path:"文件或文件夹路径" //必填(空字符串时为store目录),支持的路径请参考下面
,pathInfo:false //可选,是否返回路径信息,默认false不返回
}
返回:{
fullPath:"/文件绝对路径"
,pathInfo:{ //可选返回路径信息
isExists:true //文件或文件夹是否存在
,isFile:true //true时path为文件,false时为文件夹
,size:123 //isFile时文件大小,文件夹为0
,date:123456 //isFile时文件更新时间,毫秒,文件夹为0
}
}
listPath 读取文件夹内的文件
参数:{ path:"文件夹路径" } //必填(空字符串时为store目录),支持的路径请参考下面
返回:{
files:[ { //此文件夹下的文件
name:"文件名"
,size:123 //文件大小
,date:123456 //文件更新时间,毫秒
} ]
,dirs:[ "文件夹名" ] //此文件夹下的文件夹
,fullPath:"/文件夹绝对路径" //结尾不带/
}
androidStoragePermission__limited 简易获取Android的外部存储权限,iOS不可调用,当你需要读写当前应用数据以外的文件时(如手机的Download目录文件),需要先获取外部存储权限;注意这个只会请求WRITE_EXTERNAL_STORAGE权限,因此TargetSDK需小于33(Android 13),否则此权限永远是拒绝的(请自行用别的途径获取权限)
参数:{}
返回:{ code:1 } //权限状态:1有权限,3用户拒绝。(2未用到)
【支持的路径】
"store://文件夹/文件.png" 或 "文件夹/文件.png" (开头不带/)
app内部保存文件,文件夹是可选的
Android为app的file目录 + 文件夹/文件.png
iOS为app的Library/Files目录 + 文件夹/文件.png
"__doc://文件夹/文件.png"
app内部保存文件,文件夹是可选的;兼容iOS Documents目录专用的,正常用"store://"就够了
Android为app的file/__doc目录 + 文件夹/文件.png
iOS为app的Documents目录 + 文件夹/文件.png
"cache://文件夹/文件.png"
app内部缓存文件,文件夹是可选的,存储的文件可能会被用户或系统删除
Android为app的cache目录 + 文件夹/文件.png
iOS为app的Library/Caches目录 + 文件夹/文件.png
"file:///绝对路径/文件.png" 或 "/绝对路径/文件.png" (开头有/)
绝对路径,一般只允许读写app自己目录内的文件;Android获取到了外部存储权限时(调用androidStoragePermission__limited),可能可以可读写外部存储中的文件;iOS不支持读写非app自己目录文件
⠀
⠀