更新记录

1.0.240409(2024-04-10)

第一次发布


平台兼容性

Android Android CPU类型 iOS
适用版本区间:4.4 - 14.0 armeabi-v7a:未测试,arm64-v8a:未测试,x86:未测试 ×

原生插件通用使用流程:

  1. 购买插件,选择该插件绑定的项目。
  2. 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
  3. 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
  4. 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
  5. 开发完毕后正式云打包

付费原生插件目前不支持离线打包。
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支持群中下载得到此文件源码后,可以直接替换组件中的这个文件,也可以不替换。

测试方法

测试时无需购买插件,试用是免费的,并且原生插件试用是无限制的。

  1. 先到Recorder-UniCore下载示例项目,在HBuilder中打开后,在项目manifest.json配置中分配一个uni-app应用标识
  2. 然后点击本插件页面中的试用按钮,在这个应用标识对应的项目中试用
  3. 然后在项目manifest.json的App原生插件配置中勾选本原生插件
  4. HBuilder中提交云打包打自定义基座
  5. 连接手机进行调试,使用自定义基座运行即可测试

录音权限配置

在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前端组件使用

插件集成

  1. 到插件市场下载安装Recorder-UniCore前端组件
  2. 试用或购买本原生插件,在项目manifest.json的App原生插件配置中勾选本原生插件
  3. 参考上面的录音权限配置,在项目manifest.json中配置好权限
  4. 云打包自定义基座进行测试、或正式打包,即完成集成

调用录音

/** 详细的录音代码请参考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前端组件支持更多格式录音。

插件集成

  1. 试用或购买本原生插件,在项目manifest.json的App原生插件配置中勾选本原生插件
  2. 参考上面的录音权限配置,在项目manifest.json中配置好权限
  3. 云打包自定义基座进行测试、或正式打包,即完成集成

调用插件接口

//加载插件,注意:如果你使用的单独的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自己目录文件

隐私、权限声明

1. 本插件需要申请的系统权限列表:

录音权限

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问