Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法) 1、账号准备工作 2、SDK集成准备工作 3、在 AndroidManifest.xml 文件 添加所需权限 4、SDK初始化 5、调用语音听写功能 总结

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

首先要有一个讯飞的账号啦,为后面申请APPID、APPKey等东西做准备。顺带一提:讯飞对不同认证类型用户开

放的SDK的使用次数是有不同的,详情如下图。

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

账号申请完成后,需要去你自己的控制台注册你的应用,同时也可以看到你的应用对应的 APPID 等属性,开通的功能,调用量剩余次数等信息。

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

本文介绍的是Android SDK的接入,这是Android SDK的下载地址,可以根据项目的具体需求具体分析。

2、SDK集成准备工作

如果参照官方文档中或者官方DEMO的做法,需要把对应架构的文件拷贝到 Android工程的libs目录下 。

而官方提供的DEMO中,它只拷贝了armeabi-v7a架构。如下图所示(我信了它的邪,在我第一次接入时,就因为参考了官方DEMO只导入了armeabi-v7a架构,导致出了一大堆毛病?)

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

为了避免这个坑,我的建议是:把提供的架构都拷贝到工程里。(有特殊设备需求的除外)

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

然后在build.gradle文件中,添加SDK的依赖

    implementation files('libs/Msc.jar')

如果将SDK导入到lib文件夹后,可能还会有无法识别的错误。

可以试下在build.gradle(app)中注释掉以下的代码(玄学操作~~),再继续排查。

//        ndk {
//            //选择要添加的对应cpu类型的.so库。
//            abiFilters 'armeabi-v7a', 'armeabi'
//        }

//    sourceSets {
//        main{
//            jniLibs.srcDirs = ['libs']
//        }
//    }

3、在 AndroidManifest.xml 文件 添加所需权限

静态添加权限部分,参考了官方文档的说法。

<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--读取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--获取当前wifi状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--读取手机信息权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取联系人权限,上传联系人需要用到此权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务-->
<!--定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--如需使用人脸识别,还要添加:摄相头权限,拍照需要用到 -->
<uses-permission android:name="android.permission.CAMERA" />

不过,静态申请了权限,还不够哦。对于现在的手机,很大部分都已经是Android版本678910的了,应用是需要动态申请权限的,得让用户确认同意了,APP才可以使用这些权限。

动态申请权限的方法有很多,也有很多开源的项目,这里就不做介绍了。

4、SDK初始化

SDK初始化建议放在程序入口处(如Application、Activity的onCreate方法),非常简单,就一行语句。

初始化代码如下:

//将“1234567”替换成您申请的APPID
SpeechUtility.createUtility(context, SpeechConstant.APPID +"=1234567");

注意:SpeechConstant.APPID +"=1234567" 采用的是拼接的方式,所以不可以在“=”与appid之间添加任何空字符或者转义符。

5、调用语音听写功能

最重要的来了,前面铺垫这么久,就是为了能调用它的语音听写啊。

离线听写方式,需要购买且下载特定的离线识别SDK,故这里使用的是在线听写。

在线听写的SDK,提供了两种识别方式,分别是带语音对话框识别和无UI识别。

一.无UI识别

//初始化识别无UI识别对象
//使用SpeechRecognizer对象,可根据回调消息自定义界面--自己的语音识别UI
mIat = SpeechRecognizer.createRecognizer(IatDemo.this, mInitListener);

//设置语法ID和 SUBJECT 为空,以免因之前有语法调用而设置了此参数;或直接清空所有参数,具体可参考 DEMO 的示例。
mIat.setParameter( SpeechConstant.CLOUD_GRAMMAR, null );
mIat.setParameter( SpeechConstant.SUBJECT, null );
//设置返回结果格式,目前支持json,xml以及plain 三种格式,其中plain为纯听写文本内容
mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
//此处engineType为“cloud”
mIat.setParameter( SpeechConstant.ENGINE_TYPE, engineType );
//设置语音输入语言,zh_cn为简体中文
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
//设置结果返回语言
mIat.setParameter(SpeechConstant.ACCENT, "mandarin");
// 设置语音前端点:静音超时时间,单位ms,即用户多长时间不说话则当做超时处理
//取值范围{1000~10000}
mIat.setParameter(SpeechConstant.VAD_BOS, "4000");
//设置语音后端点:后端点静音检测时间,单位ms,即用户停止说话多长时间内即认为不再输入, 
//自动停止录音,范围{0~10000}
mIat.setParameter(SpeechConstant.VAD_EOS, "1000");
//设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
mIat.setParameter(SpeechConstant.ASR_PTT,"1");
//开始识别,并设置监听器
mIat.startListening(mRecogListener);

二.带语音对话框识别(SDK自带)

// 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
// 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源
mIatDialog = new RecognizerDialog(IatDemo.this, mInitListener);

//以下为dialog设置听写参数
        mIatDialog.setParameter(SpeechConstant.RESULT_TYPE, "json");
        //设置语音输入语言,zh_cn为简体中文
        mIatDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        //设置结果返回语言
        mIatDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
        // 设置语音前端点:静音超时时间,单位ms,即用户多长时间不说话则当做超时处理
        //取值范围{1000~10000}
        mIatDialog.setParameter(SpeechConstant.VAD_BOS, "4500");
        //设置语音后端点:后端点静音检测时间,单位ms,即用户停止说话多长时间内即认为不再输入,
        //自动停止录音,范围{0~10000}
        mIatDialog.setParameter(SpeechConstant.VAD_EOS, "1500");
        //开始识别并设置监听器
        mIatDialog.setListener(mRecognizerDialogListener);

//开始识别并设置语音UI监听器
mIatDialog.setListener(mRecognizerDialogListener);
//显示听写对话框,show方法实际是内部调用无UI识别方式
mIatDialog.show();

重点来了,也是很多人很困扰的一步,官方文档的说法是使用这个SDK自带的语音识别对话框,需要把对应的布局文件和图片资源放入工程中。然而,很多人这样做了之后, mIatDialog.show(); 调用了还是会出现空指针的异常。。例如:?

java.lang.NullPointerException
      at com.iflytek.cloud.ui.a.a(Unknown Source)
      at com.iflytek.cloud.ui.RecognizerDialog.setParameter(Unknown Source)
      atcom.example.mediaplayer.activity.SearchActivity.setParam(SearchActivity.java:111)
      at com.example.mediaplayer.activity.SearchActivity.onClick(SearchActivity.java:86)
      at android.view.View.performClick(View.java:4438)
      at android.view.View$PerformClick.run(View.java:18422)
      at android.os.Handler.handleCallback(Handler.java:733)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:136)
      at android.app.ActivityThread.main(ActivityThread.java:5045)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:515)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
      at dalvik.system.NativeStart.main(Native Method)

解决方法,如下:

首先,在asset文件内,放入所需的资源。注意:asset文件夹的位置,是要在src/main/ 的下一级,然后在与

asset文件夹同级的地方创建 jniLibs 文件夹,把 libs/文件夹的对应SDK文件拷贝到 jniLibs 中,如图:

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

同时检查下,SDK初始化的 APPId 有无出错的可能。

获取数据

解决了空指针的问题后,接下来调用 show 方法,就可以在自定义的监听器里愉快地获取到返回的听写数据了

 //创建语音识别UI对话框
 mIatDialog = new RecognizerDialog(getActivity(), searchViewModel.mInitListener);
 
 
 
 	/**
     * 初始化听写事件监听器。
     */
    public InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            if (code != ErrorCode.SUCCESS) {
                //Todo
            }
        }
    };
    /**
     * 听写UI监听器 讯飞
     */
    public RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {

        /**
         * 接收语音听写回调信息
         * @param recognizerResult 回调结果
         * @param b 是否翻译
         */
        @Override
        public void onResult(com.iflytek.cloud.RecognizerResult recognizerResult, boolean b) {
        //返回的数据
		String data = recognizerResult.getResultString();
        }
        /**
         * 识别回调错误.
         */
        public void onError(SpeechError error) {
            if(error.getErrorCode() == 14002) {
               //Todo
            } else {
               //Todo
            }
        }

    };

修改默认对话框的文字

//动态更换了讯飞自带对话框的底部文字,必须在dialog的show执行后更换,否则空指针报错
TextView recorderDialogTextView = (TextView)  mIatDialog.getWindow().getDecorView().findViewWithTag("textlink");

recorderDialogTextView.setText(R.string.recorder_dialog_textview_text);

Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
2、SDK集成准备工作
3、在 AndroidManifest.xml 文件 添加所需权限
4、SDK初始化
5、调用语音听写功能
总结

返回的听写数据实例,用于创建实体类:

{
    "sn": 1,
    "ls": true,
    "bg": 0,
    "ed": 0,
    "ws": [
        {
            "bg": 0,
            "cw": [
                {
                    "w": "今天",
                    "sc": 0
                }
            ]
        },
        {
            "bg": 0,
            "cw": [
                {
                    "w": "的",
                    "sc": 0
                }
            ]
        },
        {
            "bg": 0,
            "cw": [
                {
                    "w": "天气",
                    "sc": 0
                }
            ]
        },
        {
            "bg": 0,
            "cw": [
                {
                    "w": "怎么样",
                    "sc": 0
                }
            ]
        },
        {
            "bg": 0,
            "cw": [
                {
                    "w": "。",
                    "sc": 0
                }
            ]
        }
    ]
}

注意:若在SDK中开通了 动态修正的功能,返回的数据会出现格式不一致的情况。官方的说法如下:

动态修正:
  • 未开启动态修正:实时返回识别结果,每次返回的结果都是对之前结果的追加;
  • 开启动态修正:实时返回识别结果,每次返回的结果有可能是对之前结果的的追加,也有可能是要替换之前某次返回的结果(即修正);
  • 开启动态修正,相较于未开启,返回结果的颗粒度更小,视觉冲击效果更佳;
  • 使用动态修正功能需到控制台-流式听写-高级功能处点击开通,并设置相应参数方可使用,参数设置方法:mIat.setParameter(“dwa”, “wpgs”); ;
  • 动态修正功能仅 中文 支持;
  • 未开启与开启返回的结果格式不同,详见下方;

若开通了动态修正功能并设置了dwa=wpgs(仅中文支持),会有如下字段返回:

参数 类型 描述
pgs string 开启wpgs会有此字段 取值为 “apd"时表示该片结果是追加到前面的最终结果;取值为"rpl” 时表示替换前面的部分结果,替换范围为rg字段
rg array 替换范围,开启wpgs会有此字段 假设值为[2,5],则代表要替换的是第2次到第5次返回的结果

PS:一般项目中的语音听写需求,完全可以不使用动态修正功能,但若要使用同步显示语音识别结果或者比较需要比较精准的结果,可以考虑使用此功能。

总结

讯飞语音听写SDK,坑点不少,但是都不是很难,还是适项目快速接入语音听写需求的。。?

如果要更多操作和功能,请参考讯飞语音听写SDK官方文档