Unity 实战项目 ☀️| 接入科大讯飞语音SDK在Android Studio该如何操作! 系列共两万多字超级新手教程!

Posted 呆呆敲代码的小Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 实战项目 ☀️| 接入科大讯飞语音SDK在Android Studio该如何操作! 系列共两万多字超级新手教程!相关的知识,希望对你有一定的参考价值。

  • 📢博客主页:https://blog.csdn.net/zhangay1998
  • 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
  • 📢未来很长,值得我们全力奔赴更美好的生活✨


📢前言

🍉在android Studio该如何操作讯飞语音SDK

  • 虽然最终效果是在Unity中接入语音识别SDK,但是在Android Studio(下面统称AS)这一步才是最重要的
  • 相关的语音识别的代码和逻辑都是在AS写的,最终实现在Unity中的效果也不过是调用AS端的接口来实现的
  • 所以说这一块接入也是可以在AS中打包成APK直接导出的!

那这里就正式开始在AS端的操作吧!

🏳️‍🌈第一步:打开Android Studio新建一个项目

打开AS,新建一个项目,选择一个Empty Activity,点击Next

然后来到下一步,自己修改工程的名字和路径,其他的忽略即可!
也可以自定义一个最低支持的安卓版本Minimnum SDK,不过无伤大雅!看你心情~


点击Finish之后,一个工程就创建好了,打开就是如下画面。
但是我们并不使用这个Activity,具体接着往下看

🏳️‍🌈第二步:建立最终使用的Module文件夹

然后我们这里新建一个module,起一个名字
File-new-new Module(下图)

然后选中Android Library,点击Next

然后修改一个名字,点击Finish即可!

然后创建完成后就来到了下面这个页面,这个iFlytek项目就是我们要进行操作的文件夹。
红框里面的内容就是我们要操作的地方!


🏳️‍🌈第三步:讯飞SDK集成

这一步较为繁琐,跟配置环境差不多,就是将各种Jar包和so文件添加到AS中去
下面一步一步来看!

1.接入Unity的ckasses.jar包

  • 我们首先需要拿到Unity的class包,这个包在安装Unity的路径下

  • 具体路径:Unity\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\Variations\\mono\\Release\\Classes

  • 比如我的路径就是:D:\\QMDownload\\SoftMgr\\2020.3.8f1c1\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\Variations\\mono\\Release\\Classes


直接选中classes.jar复制到AS中的iflytek-libs文件夹下!
操作如下:


这样就把Unity的Jar包加到AS了,下面再把我们下载的讯飞SDK中的Jar包添加进去

2.接入讯飞语音的classess.jar包

找到我们下载解压的讯飞语音的SDK,进入libs文件夹下,将那三个文件前复制到libs中去!
与上一步Unity的Jar操作一样!


效果如下,我们总共添加了四个文件,分别是从Unity复制过去的Jar包和从讯飞的SDK复制过去的三个文件

3.关联两个classes.jar包

有的小伙伴复制过去是这样的,两个Jar包并不能展开
那是因为还没有关联,下面就来关联一下Jar包

第一种方法:
选中两个.jar包,右键
右键libs文件夹下两个.jar文件,Add As Libray…

第二种方法:
也可以右键 iflyte -> Open Module Settings
将.jar文件手动添加,添加完了记得点apply应用一下

关联之后,还是在 右键 iflyte -> Open Module Settings
这里可以看有没有关联完毕,没关联上的话,这里不会显示这俩个.jar包

4.添加libmsc.so

iflytekmain文件夹下新建一个Jnilibs文件夹,注意字符不能打错!!


然后将libmsc.so添加进去,ibmsc.so在讯飞SDK文件夹里的libs\\armeabi-v7a下,最好连armeabi-v7a文件夹一起复制进去。
效果如下:

这样的话so文件就算是添加进去了,下一步 来修改AndroidManifest文件

5.修改AndroidManifest文件

将 app -> src -> main -> res 下的AndroidManifest中的所有内容
复制到我们iflytek -> src -> main -> res 的AndroidManifest中,如下

复制到我们下面这个iflytek -> src -> main -> res 的AndroidManifes之后会报红
那我们把中间框的报红的都删掉,上面的package也改一下名字,改为:com.example.iflytek

下面的也要改为:android:name=".MainPort",这里要注意哈
我下面写错了,这里一定要改成MainPort(要改成继承UnityPlayerActivity的类,这里是MainPort
如果这里不对,app直接打不开,也算是一个小失误了

改完名字后是下面这样的,但是还没完!

还要在这里加上下面一行代码,注意加入代码的位置别放错了!
加入这一行是为了在Unity中可以正常调用,不加这一行到时候就调用不到啦!

 <meta-data android:name="unityplayer.UnityActivity" android:value="true"/>

最后,再加上权限:

<!--连接网络权限,用于执行云端语音能力 -->
<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" />

AndroidManifes效果如下,我这里是有一行报错,直接右键自动修复就好了!

最终的效果如下,如果出现哪里报错,那应该是哪个地方添加代码的位置不对
或者多删除了某个符号,仔细看看就好了!

到这一步结束,其实算刚配置完环境
真正的代码还没开始写呢!下面一起来看看怎样写代码!


🏳️‍🌈第四步:新建一个class开始写代码

创建类

然后我们选中com.example.iflytek ->New->Java Class
新建一个Class写代码用的

改个名字点击OK即可!第一个asrManager类就建立完成了

然后老样子再来一次,创建一个新的

这里的话,将它改为一个接口,点击中间那个框将class改为Interface即可,点击OK

然后再创建两个类:MainPort和JsonParser


整理一下,我们现在一共有三个类和一个接口,如下所示:

上代码

  • 直接上代码,然后下面再来说一下,每个脚本是干嘛的!

  • 如果复制完一下代码,AS中的import com.unity3d.player.UnityPlayerActivity;这一行会报错

  • 说明Unity的Jar包没有正确的导入关联,我第一次用2020版本的导入就是报红

  • 所以换了一个unity2019的Jar包导入就正常了!

  • asrManager类:这个脚本特别需要注意!!!这个地方一定要换成我们去讯飞官网自己创建的应用

  • 每个应用都有自己的APPID,这里使用我这个肯定会出问题,换成自己的APPID就好了!

  • 之前有的小伙伴出错,很可能就是这里出错了!


package com.example.iflytek;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.example.iflytek.JsonParser;
import com.example.iflytek.MainPort;
import com.example.iflytek.UnityasrEventCallback;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechUtility;
import com.unity3d.player.UnityPlayer;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class asrManager {

    private SpeechRecognizer mIat;
    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
    private static Activity activity;
    private static asrManager asrManager;

    public static asrManager getasrManager(Activity context) {
        if (asrManager == null) {
            asrManager = new asrManager(context);
        }
        return asrManager;
    }
    public asrManager(Activity activity) {
        this.activity=activity;
    }

    //初始化
    public void Initasr() {
        Log.i("@@@", "语音初始化+获取权限 ");
        getPermission();

        SpeechUtility.createUtility(activity, SpeechConstant.APPID + "=60307482");
        mIat = SpeechRecognizer.createRecognizer(activity, null);
        //设置mIat的参数
        //表示是什么服务
        mIat.setParameter(SpeechConstant.DOMAIN, "iat");
        //设置语言
        mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        //接受语言的类型
        mIat.setParameter(SpeechConstant.ACCENT, "mandarin");
        //使用什么样引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);

    }
    RecognizerListener mRecognizerLis=new RecognizerListener() {
        @Override
        public void onVolumeChanged(int i, byte[] bytes) {

        }

        @Override
        public void onBeginOfSpeech() {

        }

        @Override
        public void onEndOfSpeech() {

        }

        @Override
        public void onResult(RecognizerResult recognizerResult, boolean b) {
            printResult(recognizerResult);
        }

        @Override
        public void onError(SpeechError speechError) {

        }

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

        }
    };
    //解析Json的方法
    //方法来自speechDemo->java->voicedemo->IatDemo中的printResult方法
    private void printResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 读取json结果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        mIatResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        //将语音内容回调给Unity
        mCallback.Speechcontent(resultBuffer.toString());
        //显示完语音的Toast
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity,"语音识别完成",Toast.LENGTH_SHORT).show();
            }
        });
    }

    //获取权限
    public void getPermission() {
        Log.d("@@@", "开始获取各类权限 ");
        activity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 0x01);
        Log.d("@@@", "各类权限获取成功 ");
    }

    public void getBeginListen(){
        Log.d("@@@", "开始判断权限是否获取 ");
        //使用录音前首先需要获取权限
        int permissionCheck= activity.checkSelfPermission(android.Manifest.permission.RECORD_AUDIO);
        //如果有权限则返回PackageManager.PERMISSION_GRANTED,否则返回PackageManager.PERMISSION_DENIED。
        if(permissionCheck!= PackageManager.PERMISSION_GRANTED) {//未获取权限时
            //请求获取权限
            Log.d("@@@", "正在请求权限 ");
            activity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 0x01);
            //用new String[]的原因是可以在String[]中存储多个需要的权限,一次过请求
            //将回调onRequestPermissionsResult()方法
        }else{
            //开始识别
            mIat.startListening(mRecognizerLis);

            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(activity,"语音识别开始",Toast.LENGTH_LONG).show();
                }
            });
        }
    }

    public int beginTest(int a, int b){
        //交互测试
        return a+b;
    }
    //把消息发送给Unity场景中iFlytekASRController物体上的tryConnected方法
    public void connected(){
        //UnityPlayer.UnitySendMessage("iFlytekASRController","tryConnected","连通成功了");
        Log.d("@@@", "SetListenerCB start ");
        mCallback.Test1("连通成功了");
        Log.d("@@@", "SetListenerCB end ");
    }


    private UnityasrEventCallback mCallback;
    //获取接口内容
    public void setCallback(UnityasrEventCallback callback){
        Log.d("@@@", "UnitasrEventCallback setCallback start ");
        mCallback = callback;
        Log.d("@@@", "UnityasrEventCallback setCallback end ");
    }

}


UnityasrEventCallback代码:

package com.example.iflytek;

public interface UnityasrEventCallback {
    public void Speechcontent(String content);
    public void Test1(String msg);
}

MainPort代码:

package com.example.iflytek;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.example.iflytek.UnityasrEventCallback;
import com.example.iflytek.asrManager;
import com.iflytek.cloud.SpeechUtility;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

public class MainPort extends UnityPlayerActivity {

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

        //初始化
        masrManager = asrManager.getasrManager(MainPort.this);
        masrManager.Initasr();

        UnityPlayer.UnitySendMessage("iFlytekASRController","InitCallBack","初始化成功了");

    }

    // =========================ASR========================= }
    //得到Unity的回调
    public void setUnityasrEventCallback(UnityasrEventCallback callback){
        Log.d("@@@", "setUnityBatteryEventCallback callback ========= " +callback);
        if(masrManager != null) {
            masrManager.setCallback(callback);
        }
    }

    public void unityStartSpeech(){
        masrManager.getBeginListen();
    }
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 0x01: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0&&  grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d("@@@", "进入获取权限成功的回调了 ");
                    // permission was granted, yay

以上是关于Unity 实战项目 ☀️| 接入科大讯飞语音SDK在Android Studio该如何操作! 系列共两万多字超级新手教程!的主要内容,如果未能解决你的问题,请参考以下文章

Unity 实战项目 ☀️| 接入科大讯飞语音SDK在Android Studio该如何操作! 系列共两万多字超级新手教程!

Unity 实战项目 ☀️| Unity接入 百度语音识别 SDK!一篇文章搞定在Unity中实现语音识别!(万字完整教程)

uniapp - 接入科大讯飞语音评测

uniapp - 接入科大讯飞语音评测

uniapp - 接入科大讯飞语音评测

uniapp - 接入科大讯飞语音评测