MUI H5+科大讯飞语音识别功能如何去除默认界面

原创 2017年12月06日 19:21:06

Android上MUI H5+科大讯飞语音识别功能如何去除默认界面

最近MUI的H5+项目需要实现语音识别功能,但是MUI自带的只有科大讯飞语音功能,而且还有默认的界面效果。由于产品原型要求实现自定义界面,所以需要把默认的界面去掉。

  • 本篇博客是通过反编译DCloud提供的jar包,改写源码来实现的

  • 同理可以直接Android原生实现无界面,通过NativeJS调用的方式来实现

  • 如果不懂反编译,也可以直接使用博客内的代码,外壳版本是Android-SDK@1.9.9.35689_20170825,如果版本相差不大,应该可以直接使用

  • 需要具备一定的java代码阅读能力

核心代码
1.HTML代码如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>科大讯飞语音</title>
    <link rel="stylesheet" type="text/css" href="css/mui.min.css" />
</head>
<body>
    <header class="mui-bar mui-bar-nav mui-badge-blue">
        <a class="mui-action-back mui-icon mui-icon-back" style="color: white;"></a>
        <h1 class="mui-title" style="color: white;">科大讯飞语音</h1>
    </header>
    <div class="mui-content">
        <div style="text-align: center; padding:  10px 0;">
            <button id="start" class="mui-btn-royal">开始录音</button>
        </div>
        <div class="mui-table-view">
            <li class="mui-table-view-cell">
                <label class="mui-tab-label">语音内容:</label>
                <span id="talkContent"></span>
            </li>
        </div>
        <p style="padding: 5px;">当前正在使用科大讯飞语音</p>
    </div>
    <script src="js/mui.min.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
        var talkContent = document.getElementById("talkContent");
        document.addEventListener('plusready', function(){
            document.getElementById("start").addEventListener("tap", startRecognize);
        });

        function startRecognize() {
            if(plus.os.name=='Android'&&navigator.userAgent.indexOf('StreamApp')>0){
                plus.nativeUI.toast('当前环境暂不支持语音识别插件');
                return;
            }
            if(plus.os.name=='Android') {
                var options = {};
                options.engine = 'iFly';
                options.punctuation = false;    // 是否需要标点符号 
                talkContent.textContent = "";
                console.log( "开始语音识别:" );
                plus.speech.startRecognize( options, function ( s ) {
                    console.log( s );
                    talkContent.textContent += s;
                }, function ( e ) {
                    console.log( "语音识别失败:"+e.message );
                } );
            }
        }
    </script>
</body>
</html>

界面效果图
这里写图片描述

2.重写的Java代码

package io.dcloud.feature.speech;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;

import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechUtility;

import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.adapter.util.AndroidResources;
import io.dcloud.common.adapter.util.Logger;
import io.dcloud.common.util.JSONUtil;
import io.dcloud.common.util.PdrUtil;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

public class IflySpeechEngine extends AbsSpeechEngine {
    static String sIflyAppid;
    MyRecognizer mRecognizer;

    public IflySpeechEngine() {
    }

    public void init(Context paramContext, IWebview paramIWebview) {
        super.init(paramContext, paramIWebview);
        sIflyAppid = AndroidResources.getMetaValue("IFLY_APPKEY");
        if (!PdrUtil.isEmpty(sIflyAppid)) {
            SpeechUtility.createUtility(paramContext, "appid=" + sIflyAppid);
        }
    }

    public void startRecognize(JSONObject paramJSONObject) {
        /*this.mIsrDialog = new MyRecognizerDialog(this.mContext, null);
        this.mIsrDialog.startRecognize(paramJSONObject);*/
        this.mRecognizer = new MyRecognizer(this.mContext);
        this.mRecognizer.startRecognize(paramJSONObject);

    }

    public void stopRecognize(boolean paramBoolean) {
        /*if (this.mIsrDialog != null) {
            this.mIsrDialog.stopRecognize(paramBoolean);
            this.mIsrDialog = null;
        }*/
        if (this.mRecognizer != null) {
            this.mRecognizer.stopRecognize(paramBoolean);
        }
    }



    class MyRecognizer {
        SpeechRecognizer speechRecognizer;

        RecognizerListener recognizeListener = new RecognizerListener() {

            @Override
            public void onBeginOfSpeech() {
                Log.i("console", "开始说话");
            }

            @Override
            public void onError(SpeechError speechError) {
                if (speechError != null) {
                    IflySpeechEngine.this.mListener.onStateChange(
                            (byte) 7,
                            new String[] {
                                    String.valueOf(speechError.getErrorCode()),
                                            speechError.getErrorDescription() }, false);
                }
            }

            @Override
            public void onEndOfSpeech() {
                Log.i("console", "结束说话");
            }

            @Override
            public void onResult(RecognizerResult recognizerResult,
                    boolean isLast) {
                String str = IflySpeechEngine.MyRecognizer.this
                        .printResult(recognizerResult);
                if (isLast) {
                    Logger.e("IflySpeechEngine", "onResult parsedresult=="
                            + str);
                    IflySpeechEngine.this.mListener.onStateChange((byte) 8,
                            str, false);
                }

            }

            @Override
            public void onVolumeChanged(int arg0, byte[] arg1) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
                // TODO Auto-generated method stub

            }
        };

        public MyRecognizer(Context paramContext) {
            this.speechRecognizer = SpeechRecognizer.createRecognizer(paramContext, null);
        }

        void startRecognize(JSONObject paramJSONObject) {
            String str1 = "zh_cn";
            String str2 = "4000";
            String str3 = "1";
            String str4 = null;
            if (!PdrUtil.isEmpty(paramJSONObject)) {
                String str5 = JSONUtil.getString(paramJSONObject, "lang");
                if (!PdrUtil.isEmpty(str5)) {
                    str5 = str5.toLowerCase(Locale.ENGLISH);
                    if ("zh-cantonese".equals(str5)) {
                        str1 = "zh_cn";
                        str4 = "cantonese";
                    } else if ("zh-henanese".equals(str5)) {
                        str1 = "zh_cn";
                        str4 = "henanese";
                    } else if ("zh-cn".equals(str5)) {
                        str1 = "zh_cn";
                    } else if ("en-us".equals(str5)) {
                        str1 = "en_us";
                    }
                }
                int i = JSONUtil.getInt(paramJSONObject, "timeout");
                if (0 != i) {
                    str2 = String.valueOf(i);
                }
                if ((paramJSONObject == null)
                        || (!paramJSONObject.has("punctuation"))) {
                    str3 = "1";
                } else if (!JSONUtil.getBoolean(paramJSONObject, "punctuation")) {
                    str3 = "0";
                }
            }
            this.mIatResults.clear();

            this.speechRecognizer.setParameter("language", str1);
            this.speechRecognizer.setParameter("accent", str4);

            this.speechRecognizer.setParameter("speech_timeout", str2);

            this.speechRecognizer.setParameter("asr_ptt", str3);

            this.speechRecognizer.startListening(this.recognizeListener);
            IflySpeechEngine.this.mListener
                    .onStateChange((byte) 1, null, false);
        }

        void stopRecognize(boolean paramBoolean) {
            if (paramBoolean) {
                IflySpeechEngine.this.mListener.onStateChange((byte) 2, null,
                        false);
            }
            this.speechRecognizer.stopListening();
        }

        private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();

        private String printResult(RecognizerResult paramRecognizerResult) {
            String str1 = parseIatResult(paramRecognizerResult
                    .getResultString());
            Logger.e("IflySpeechEngine", "text==" + str1);
            String str2 = null;
            try {
                JSONObject localJSONObject = new JSONObject(
                        paramRecognizerResult.getResultString());
                str2 = localJSONObject.optString("sn");
            } catch (JSONException localJSONException) {
                localJSONException.printStackTrace();
            }
            this.mIatResults.put(str2, str1);

            StringBuffer localStringBuffer = new StringBuffer();
            for (String str3 : this.mIatResults.keySet()) {
                Logger.e("IflySpeechEngine", "mIatResults.get(key)"
                        + (String) this.mIatResults.get(str3));
                localStringBuffer.append((String) this.mIatResults.get(str3));
            }
            Logger.e("IflySpeechEngine", "resultBuffer.toString()=="
                    + localStringBuffer.toString());
            return localStringBuffer.toString();
        }

        public String parseIatResult(String paramString) {
            StringBuffer localStringBuffer = new StringBuffer();
            try {
                JSONTokener localJSONTokener = new JSONTokener(paramString);
                JSONObject localJSONObject1 = new JSONObject(localJSONTokener);

                JSONArray localJSONArray1 = localJSONObject1.getJSONArray("ws");
                for (int i = 0; i < localJSONArray1.length(); i++) {
                    JSONArray localJSONArray2 = localJSONArray1
                            .getJSONObject(i).getJSONArray("cw");
                    JSONObject localJSONObject2 = localJSONArray2
                            .getJSONObject(0);
                    localStringBuffer.append(localJSONObject2.getString("w"));
                }
            } catch (Exception localException) {
                localException.printStackTrace();
            }
            return localStringBuffer.toString();
        }
    }
}

3.实现方式
首先声明,上面这种改写的方式是在已经集成好科大讯飞语音识别功能的基础上,做的二次开发。所以此博客只能帮助已经实现MUI H5+科大讯飞语音识别功能,但是想要去掉官方默认界面的开发者。
已经具备上述基础的开发者都知道,科大讯飞语音识别功能调起方法是:

if(plus.os.name=='Android') {
    var options = {};
    options.engine = 'iFly';
    options.punctuation = false;    // 是否需要标点符号 
    talkContent.textContent = "";
    console.log( "开始语音识别:" );
    plus.speech.startRecognize( options, function ( s ) {
        console.log( s );
    }, function ( e ) {
        console.log( "语音识别失败:"+e.message );
    } );
}
从科大讯飞的官方文档里得知,语音识别有带界面RecognizerDialog和不带界面SpeechRecognizer两种实现方式。所以很明显,MUI官方封装了RecognizerDialog来实现的语音识别功能。

我们知道speech_ifly.jar、speech.jar和Msc.jar,这三个jar包是集成语音识别功能时要添加的jar包,所以MUI的封装方法一定在这里面。

通过反编译,我发现了MyRecognizerDialog这个类,在speech_ifly.jar的源码里。speech_ifly.jar反编译出来只有一个文件,IflySpeechEngine.java。MyRecognizerDialog就是IflySpeechEngine的内部类。

所以这里就很简单了,改写IflySpeechEngine.java,用SpeechRecognizer取代RecognizerDialog这种实现方式,就可以实现无界面的语音识别功能。这样就可以定制产品要求的界面和效果了。

改写后的代码上面已经贴出,具体改写方式,有兴趣的同学可以反编译speech_ifly.jar包,将改写前后的代码进行比较就会明白。实现方式其实特别简单,所以不细讲了。

注意,完成改写后我们需要把项目中原本的speech_ifly.jar依赖删除,然后在src目录下新建IflySpeechEngine这个类,包名保持和之前完全一样。这样以后调用科大讯飞的语音识别功能,就是调用的这个类了。
版权声明:本文为博主原创文章,未经博主允许不得转载。

H5调用讯飞语音接口实现在线语音听写测评

韩顺平老师是我的人生导师,所以,老规矩,先看效果,后讲解:下面是效果图(页面较大,分屏效果) 这是在线语音听写: 这是在线语音测评: 下面我们来看...
  • change_on
  • change_on
  • 2016年06月11日 19:54
  • 9557

AngularJS进阶(十八)在AngularJS应用中集成科大讯飞语音输入功能

在AngularJS应用中集成科大讯飞语音输入功能 注:请点击此处进行充电! 前言       根据项目需求,需要在首页搜索框中添加语音输入功能,考虑到科大讯飞语音业务的强大能力,遂决定使用科大...
  • u011537073
  • u011537073
  • 2017年02月07日 00:04
  • 485

Android SpeechRecognizer语音识别

在Cupcake中,Android引入了对语音识别的支持。语音识别主要位于android.speech包中,主要的类包括SpeechRecognizer、RecognitionService、Reco...
  • hanmindi
  • hanmindi
  • 2014年10月18日 09:35
  • 2900

讯飞语音识别RecognizerDialog自定义view

集成语音识别的过程中,语音识别的那个RecognizerDialog下面有 “语音识别能力由讯飞输入法提供”看着很别扭, 想去掉或者完全使用自定义的View,研究了一波。RecognizerDialo...
  • tangyayong
  • tangyayong
  • 2017年12月28日 18:15
  • 84

集成科大讯飞语音听写功能

一、准备工作 1.创建应用,并获取appId; 2.下载科大讯飞语音听写功能的jar包和so包(http://www.xfyun.cn/sdk/dispatcher); 3.将jar包添加到li...
  • hx13651244616
  • hx13651244616
  • 2017年12月08日 16:29
  • 53

在应用中集成科大讯飞的语音识别技术

语音识别技术最近貌似是越来越火了。再前几天科大讯飞还刚刚发布了讯飞语点——一个据说要挑战siri的应用。……好吧,对这些的东西讨论要说起来就多了。 本文主要讲如何在自己的android应用中集成...
  • lyglostangel
  • lyglostangel
  • 2015年04月07日 11:46
  • 1149

讯飞语音开发之语音语音听写

语音听写是讯飞语音的一大组成部分,也是语音开发的一个主要部分。讯飞语音听写分为带ui界面的开发和不带ui界面开发,今天我们要说的是带ui界面的开发。 在开发之前我们需要将我们从讯飞语音开放平台下载的开...
  • sz0268
  • sz0268
  • 2016年06月13日 13:59
  • 1144

微信小程序:nodejs+百度语音识别开发实践

今天,终于成功使用nodejs研究出百度语音识别了。目前使用小程序最新录音管理api测试,小程序录音只支持aac,mp3格式,并且保持的是临时地址。而百度语音识别目前只支持pcm,wav,amr格式。...
  • eadio
  • eadio
  • 2018年01月08日 15:49
  • 164

AngularJS进阶(十八)在AngularJS应用中集成科大讯飞语音输入功能

在AngularJS应用中集成科大讯飞语音输入功能 前言       根据项目需求,需要在首页搜索框中添加语音输入功能,考虑到科大讯飞语音业务的强大能力,遂决定使用科大讯飞语音输入第三方服务。软件首页...
  • sunhuaqiang1
  • sunhuaqiang1
  • 2015年12月06日 10:28
  • 52821

讯飞语音识别DEMO

  • 2015年11月19日 16:03
  • 1.16MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:MUI H5+科大讯飞语音识别功能如何去除默认界面
举报原因:
原因补充:

(最多只允许输入30个字)