网上有很多关于讯飞Sdk植入到Unity3d的博客教程,这里做一个总结,专为超级初学者。

第一步,在科大讯飞官网上下载语音Sdk包

参考这篇博客:

获得Sdk:

android studio修改工程名_android studio修改工程名

第二步:生成Android Jar包

参考这篇博客:,

Android版本为24,可以根据需要适当更改。

流程如下:

1、AS新建工程,EmptyActivity,这样省了在AndroidManifest添加权限的步骤,同时可以删除layout文件夹中的布局文件,因为导入到unity中用不到。

2、File-New-New Module,新建AndroidLibrary,命名随意,在这里命名为speechrecognizer2。

3、将讯飞SDK文件夹中的MSC.jar考到libs文件夹下。在main文件夹下新建文件夹jinLibs,将SDK中的so文件考进来,如图:

 


android studio修改工程名_移动开发_02

 

 

4、在Unity安装目录下找到classes.jar文件。同样,考到libs文件夹下。路径:

\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes

5、此时需要在工程中关联jar。File-Project Structure。左侧选中步骤二中新建的Library。点击右方加号,选择Files dependency。将步骤3、4中加入的jar包关联到module。如图:

 

android studio修改工程名_移动开发_03

 

 

6、设置Android studio 的Android Sdk位置和Java jdk位置,File-Project Structure-SDK Location;

android studio修改工程名_移动开发_04

 

7、环境搭建完成后,开始写代码。

MainActivity中的代码和网上其他的方法大同小异,直接上源码:

package com.ssm.ssm.speechrecognizer;

        import android.os.Bundle;
        import android.util.Log;
        import android.widget.Toast;

        import com.iflytek.cloud.InitListener;
        import com.iflytek.cloud.RecognizerListener;
        import com.iflytek.cloud.RecognizerResult;
        import com.iflytek.cloud.SpeechConstant;
        import com.iflytek.cloud.SpeechError;
        import com.iflytek.cloud.SpeechSynthesizer;
        import com.iflytek.cloud.SpeechUtility;
        import com.iflytek.cloud.SpeechRecognizer;

        import com.iflytek.cloud.SynthesizerListener;
        import com.unity3d.player.UnityPlayer;
        import com.unity3d.player.UnityPlayerActivity;

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

public class MainActivity extends UnityPlayerActivity {

    public SpeechRecognizer speechRecognizer;
    public SpeechSynthesizer speechSynthesizer;
    private String ttsSpeakerName = "yefang";
    private String ttsSpeakerPitch = "50";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注意这里的appid为自己的sdk id
        SpeechUtility.createUtility(getApplicationContext(),"appid=59dccd45");

        initRecognizer();
    }

    //初始化
    private void initRecognizer(){
        speechRecognizer = SpeechRecognizer.createRecognizer(getApplicationContext(),mInitListener);

        speechSynthesizer = SpeechSynthesizer.createSynthesizer(getApplicationContext(),mInitListener);
    }

    public InitListener mInitListener = new InitListener() {
        @Override
        public void onInit(int i) {
            UnityPlayer.UnitySendMessage("Manager", "Result", "init success!");
        }
    };

    public void setTTSSpeaker(String targetName) {
        ttsSpeakerName = targetName;
    }

    public void setTTSPitch(String targetPitch) {
        ttsSpeakerPitch = targetPitch;
    }

    public void doTTS(String ttsStr){
        UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "doTTS");

        //设置发音人
        speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME,ttsSpeakerName);
        //设置音调
        speechSynthesizer.setParameter(SpeechConstant.PITCH,ttsSpeakerPitch);
        //设置音量
        speechSynthesizer.setParameter(SpeechConstant.VOLUME,"50");
        int code = speechSynthesizer.startSpeaking(ttsStr, mTTSListener);
    }

    private SynthesizerListener mTTSListener = new SynthesizerListener() {
        @Override
        public void onSpeakBegin() {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onSpeakBegin ");
        }

        @Override
        public void onBufferProgress(int i, int i1, int i2, String s) {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onBufferProgress ");
        }

        @Override
        public void onSpeakPaused() {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onSpeakPaused ");
        }

        @Override
        public void onSpeakResumed() {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onSpeakResumed ");
        }

        @Override
        public void onSpeakProgress(int i, int i1, int i2) {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onSpeakProgress ");
        }

        @Override
        public void onCompleted(SpeechError speechError) {
//            UnityPlayer.UnitySendMessage("Manager", "IsSpeaking", "onCompleted ");
        }

        @Override
        public void onEvent(int i, int i1, int i2, Bundle bundle) {

        }
    };

    //开始听写
    public void startSpeechListener(){

        UnityPlayer.UnitySendMessage("Manager", "Result", "");

        speechRecognizer.setParameter(SpeechConstant.DOMAIN, "iat");
        speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        speechRecognizer.setParameter(SpeechConstant.ACCENT, "mandarin");
        speechRecognizer.startListening(mRecognizerListener);
    }

    public RecognizerListener mRecognizerListener = new RecognizerListener(){

        @Override
        public void onBeginOfSpeech() {
            // TODO Auto-generated method stub
//            UnityPlayer.UnitySendMessage("Manager", "Result", "onBeginOfSpeech ");
        }

        @Override
        public void onEndOfSpeech() {
            // TODO Auto-generated method stub
//            UnityPlayer.UnitySendMessage("Manager", "Result", "onEndOfSpeech ");
            //startSpeechListener();
            //UnityPlayer.UnitySendMessage("Manager", "SpeechEnd","");
        }

        @Override
        public void onError(SpeechError arg0) {
            // TODO Auto-generated method stub
//            UnityPlayer.UnitySendMessage("Manager", "Result", "onError ");
        }

        @Override
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
            // TODO Auto-generated method stub
//            UnityPlayer.UnitySendMessage("Manager", "Result", "onEvent ");
        }

        @Override
        public void onResult(RecognizerResult recognizerResult, boolean isLast) {
//            UnityPlayer.UnitySendMessage("Manager", "Result", "listener ");
            printResult(recognizerResult);

            //if(isLast)
                //startSpeechListener();
        }

        @Override
        public void onVolumeChanged(int arg0, byte[] arg1) {
//            UnityPlayer.UnitySendMessage("Manager", "Result", "onVolumeChanged ");
            // TODO Auto-generated method stub
        }
    };

    //解析
    private void printResult(RecognizerResult results) {
        String json = results.getResultString();

        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                // 转写结果词,默认使用第一个结果
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                JSONObject obj = items.getJSONObject(0);
                ret.append(obj.getString("w"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //将解析结果“"result:" + ret.toString()”发送至“Manager”这个GameObject,中的“Result”函数
        UnityPlayer.UnitySendMessage("Manager", "Result", ret.toString());
    }

    public void ShowToast(final String mStr2Show){

        UnityPlayer.UnitySendMessage("Manager", "Result", "toast");

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(),mStr2Show,Toast.LENGTH_LONG).show();
            }
        });
    }
}

特别注意几个地方:

(1)此位置名字必须与unity打包Apk id位置一样。

android studio修改工程名_人工智能_05

(2)输出解析语音后的代码,unity scene必须有一个名为Manager的对象,且脚本有一个Result的函数。

android studio修改工程名_游戏_06

 

AndroidManifest中添加权限,同样,和其他教程大同小异,源码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ssm.ssm.speechrecognizer">

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:supportsRtl="true">
        <activity android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>

    <!--连接网络权限,用于执行云端语音能力 -->
    <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"/>
    <!--摄相头权限,拍照需要用到 -->
    <uses-permission android:name="android.permission.CAMERA" />

</manifest>

此段权限用于在unity交互,不添加在unity打包时会有警告信息出现(如下图);

android studio修改工程名_游戏_07

 

 

 

此时,作为AS,为了导出jar,需要在build.gradle底部添加以下两段代码:

task makeJar(type: Copy) {
    delete 'build/libs/speechrecognizer.jar'
    from('build/intermediates/bundles/release/')
    into('build/libs/')
    include('classes.jar')
    rename ('classes.jar', 'speechrecognizer.jar')
}

makeJar.dependsOn(build)

// 在终端执行生成JAR包
// gradlew makeJar

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile files('libs/classes.jar')
}

 

 

8、至此,jar包已经编写完成。现在导出jar。在Terminal中输入 gradlew makejar。如图:

  

android studio修改工程名_游戏_08

 

 

9、等待完成后即可在libs下看到jar文件:

 

android studio修改工程名_人工智能_09

 第三步:新建Unity项目,生成Apk

 

10、新建Unity项目,在Asset文件夹下新建如下结构: 

 

android studio修改工程名_游戏_10

android studio修改工程名_游戏_11

android studio修改工程名_人工智能_12

 

 

11、如步骤9,在bin文件夹下拷贝AS导出的jar。libs文件夹下拷贝SDK中的MSC.jar,和os文件,注意,安卓5.0以上系统需要armeabi-v7a,不然会出现21002的错误。

最后在Android文件夹下拷贝AndroidManifest文件。

 

12、新建编写Manger脚本文件,取名为XunFeiTest。源码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class XunFeiTest : MonoBehaviour {

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

}

private string showResult = "";
public Text shurukuang;

public void Kaishi ()
{
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
jo.Call ("startSpeechListener");
}

public void Result (string recognizerResult)
{
showResult += recognizerResult;
showResult += '\n';
shurukuang.text = showResult;
}
}

 

android studio修改工程名_人工智能_13

13、新建一个开始录音启动button,和显示text,修改main camera相机名字为Manger,并拖动上述脚本到Manger对象。

android studio修改工程名_android_14

android studio修改工程名_人工智能_15

将场景中的Result Text关联到脚本中text对象上。

关联button onclick为脚本的kaishi函数

android studio修改工程名_游戏_16

 

 

14、场景与脚本已经配置完毕,下面开始打包生成Apk,File-Build Setting

android studio修改工程名_移动开发_17

 

 

android studio修改工程名_人工智能_18

15、点击Build-选择生成位置和名字,就可以生成安装文件啦。发布手机截图

android studio修改工程名_android_19