当前位置: 代码网 > it编程>App开发>Android > Unity2021接入讯飞语音听写(Android)

Unity2021接入讯飞语音听写(Android)

2024年08月06日 Android 我要评论
Unity 讯飞语音听写 Android

使用的引擎工具:

unity2021.3.19

android-studio-2021.1.21

第一步:

新建一个android项目(工程名字随便啦)

然后新建一个library

(同上,库名自己命名吧)

android环境目前就算是初步建立好了。

第二步:

导包

libs文件夹里面放入这4个文件,arm64-v8a,armeabi-v7a,msc.jar这三个文件是讯飞官网下载下来的demo项目里面的,直接复制到libs里面就好,classes.jar包是在下面这个路径下的

注:classes.jar用mono还是il2cpp得和unity-playersetting-scriptbackend一致

第三步

倒入unityplayeractivity

最新版本unity里面的classes.jar包文件里面以及不包含unityplayeractivity了,所以我们需要自己导入unityplayeractivity(或者自己编写一个也可以,回头可以再出一篇)

文件位置:

第四步

在androidstudio实现供unity调用的接口方法,直接上代码了(讯飞appid自己填写)

package com.example.mylibrary;

import android.content.context;
import android.os.bundle;
import android.util.log;
import android.widget.toast;

import com.iflytek.cloud.errorcode;
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.speechrecognizer;
import com.iflytek.cloud.speechutility;
import com.unity.upa.unityplayeractivity;
import com.unity3d.player.unityplayer;

import org.json.jsonexception;
import org.json.jsonobject;

import java.util.hashmap;
import java.util.linkedhashmap;

public class xunfeisdk extends unityplayeractivity {

private hashmap<string, string> miatresults = new linkedhashmap<string, string>();
    speechrecognizer miat;
    @override
    protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);

        speechutility.createutility(this, speechconstant.appid + "=xxxxxx");//这里是你在讯飞官网上的appid
        miat=speechrecognizer.createrecognizer(this,null);
        miat.setparameter(speechconstant.domain,"iat");
        // 语言
        miat.setparameter(speechconstant.language,"zh_cn");
        // 接收语言的类型
        miat.setparameter(speechconstant.accent,"mandarin");
        // 使用什么引擎
        miat.setparameter(speechconstant.engine_type,speechconstant.type_cloud);
    }

public void startlistening() {

miat.startlistening(recognizerlistener);
    }

    recognizerlistener recognizerlistener = new recognizerlistener() {
@override
        public void onvolumechanged(int i, byte[] bytes) {
            unityplayer.unitysendmessage("xfmanager","onvolumechanged","");
        }

@override
        public void onbeginofspeech() {
            unityplayer.unitysendmessage("xfmanager","onbeginofspeech","");
        }

@override
        public void onendofspeech() {
            unityplayer.unitysendmessage("xfmanager","onendofspeech","");
        }

@override
        public void onresult(recognizerresult recognizerresult, boolean b) {
            printresult(recognizerresult);
        }

@override
        public void onerror(speecherror speecherror) {
            unityplayer.unitysendmessage("xfmanager","onerror",speecherror.geterrordescription());
        }

@override
        public void onevent(int i, int i1, int i2, bundle bundle) {

        }
    };

    private void printresult(com.iflytek.cloud.recognizerresult results) {
// jsonparser是一个工具类
        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);
        // resultbuffer 为最终返回的结果

        stringbuffer resultbuffer = new stringbuffer();
        for (string key : miatresults.keyset()) {
            resultbuffer.append(miatresults.get(key));
        }
// 把得到的结果返回给unity  第一个参数为unity种的游戏物体 第二个参数为 这个游戏物体身上脚本的方法   第三个参数为讯飞返回的最终结果
        unityplayer.unitysendmessage("xfmanager","onresult",resultbuffer.tostring());
    }

public  void voidtest()
    {
        unityplayer.unitysendmessage("xfmanager","fromandroid","android:消息发送至unity");
    }
}

json类(这个是讯飞demo里面的)

package com.example.mylibrary;

import org.json.jsonarray;
import org.json.jsonobject;
import org.json.jsontokener;

/**
 * json结果解析类
 */
public class jsonparser {

public static string parseiatresult(string json) {
        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"));
//          如果需要多候选结果,解析数组其他字段
//          for(int j = 0; j < items.length(); j++)
//          {
//             jsonobject obj = items.getjsonobject(j);
//             ret.append(obj.getstring("w"));
//          }
            }
        } catch (exception e) {
            e.printstacktrace();
        }
return ret.tostring();
    }

public static string parsegrammarresult(string json, string engtype) {
        stringbuffer ret = new stringbuffer();
        try {
            jsontokener tokener = new jsontokener(json);
            jsonobject joresult = new jsonobject(tokener);

            jsonarray words = joresult.getjsonarray("ws");
            // 云端和本地结果分情况解析
            if ("cloud".equals(engtype)) {
for (int i = 0; i < words.length(); i++) {
                    jsonarray items = words.getjsonobject(i).getjsonarray("cw");
                    for (int j = 0; j < items.length(); j++) {
                        jsonobject obj = items.getjsonobject(j);
                        if (obj.getstring("w").contains("nomatch")) {
                            ret.append("没有匹配结果.");
                            return ret.tostring();
                        }
                        ret.append("【结果】" + obj.getstring("w"));
                        ret.append("【置信度】" + obj.getint("sc"));
                        ret.append("\n");
                    }
                }
            } else if ("local".equals(engtype)) {
                ret.append("【结果】");
                for (int i = 0; i < words.length(); i++) {
                    jsonobject wsitem = words.getjsonobject(i);
                    jsonarray items = wsitem.getjsonarray("cw");
                    if ("<contact>".equals(wsitem.getstring("slot"))) {
// 可能会有多个联系人供选择,用中括号括起来,这些候选项具有相同的置信度
                        ret.append("【");
                        for (int j = 0; j < items.length(); j++) {
                            jsonobject obj = items.getjsonobject(j);
                            if (obj.getstring("w").contains("nomatch")) {
                                ret.append("没有匹配结果.");
                                return ret.tostring();
                            }
                            ret.append(obj.getstring("w")).append("|");
                        }
                        ret.setcharat(ret.length() - 1, '】');
                    } else {
//本地多候选按照置信度高低排序,一般选取第一个结果即可
                        jsonobject obj = items.getjsonobject(0);
                        if (obj.getstring("w").contains("nomatch")) {
                            ret.append("没有匹配结果.");
                            return ret.tostring();
                        }
                        ret.append(obj.getstring("w"));
                    }
                }
                ret.append("【置信度】" + joresult.getint("sc"));
                ret.append("\n");
            }

        } catch (exception e) {
            e.printstacktrace();
            ret.append("没有匹配结果.");
        }
return ret.tostring();
    }

public static string parsegrammarresult(string json) {
        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");
                for (int j = 0; j < items.length(); j++) {
                    jsonobject obj = items.getjsonobject(j);
                    if (obj.getstring("w").contains("nomatch")) {
                        ret.append("没有匹配结果.");
                        return ret.tostring();
                    }
                    ret.append("【结果】" + obj.getstring("w"));
                    ret.append("【置信度】" + obj.getint("sc"));
                    ret.append("\n");
                }
            }
        } catch (exception e) {
            e.printstacktrace();
            ret.append("没有匹配结果.");
        }
return ret.tostring();
    }

public static string parselocalgrammarresult(string json) {
        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");
                for (int j = 0; j < items.length(); j++) {
                    jsonobject obj = items.getjsonobject(j);
                    if (obj.getstring("w").contains("nomatch")) {
                        ret.append("没有匹配结果.");
                        return ret.tostring();
                    }
                    ret.append("【结果】" + obj.getstring("w"));
                    ret.append("\n");
                }
            }
            ret.append("【置信度】" + joresult.optint("sc"));

        } catch (exception e) {
            e.printstacktrace();
            ret.append("没有匹配结果.");
        }
return ret.tostring();
    }

public static string parsetransresult(string json, string key) {
        stringbuffer ret = new stringbuffer();
        try {
            jsontokener tokener = new jsontokener(json);
            jsonobject joresult = new jsonobject(tokener);
            string errorcode = joresult.optstring("ret");
            if (!errorcode.equals("0")) {
return joresult.optstring("errmsg");
            }
            jsonobject transresult = joresult.optjsonobject("trans_result");
            ret.append(transresult.optstring(key));
         /*jsonarray words = joresult.getjsonarray("results");
         for (int i = 0; i < words.length(); i++) {
            jsonobject obj = words.getjsonobject(i);
            ret.append(obj.getstring(key));
         }*/
        } catch (exception e) {
            e.printstacktrace();
        }
return ret.tostring();
    }
}

代码就是以上这些了,接下来就是修改androidmanifest

第五步:

androidmanifest.xml文件

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

    <application
        android:allowbackup="true"
        android:supportsrtl="true">
        <activity android:name=".xunfeisdk"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.main" />

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


    <uses-permission android:name="android.permission.record_audio" />
    <uses-permission android:name="android.permission.internet" />
    <uses-permission android:name="android.permission.access_network_state" />
    <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.access_fine_location" />
    <uses-permission android:name="android.permission.read_contacts" />
    <uses-permission android:name="android.permission.write_external_storage" />
    <uses-permission android:name="android.permission.write_settings"
        tools:ignore="protectedpermissions" />
    <uses-permission android:name="android.permission.read_external_storage" />
    <uses-permission android:name="android.permission.access_fine_location" />
    <uses-permission android:name="android.permission.access_coarse_location" />
</manifest>

第六步:

完成以上这些步骤就可以打包成arr文件了

选中你的库文件然后点击build-make module,如图所示

arr生成路径是

结果如下

把mylibrary.arr文件根目录里的classes.jar和androidmanifest复制出来(拖出来)

下面这个是从arr包里取出来的androidmanifest文件,把<uses-sdk android:minsdkversion="26" />删掉

第七步:

下面就是unity这边了,unity端比较简单,直接看图吧

这个androidmanifest文件就是第六步的androidmanifest文件,

classes.jar文件放在plugins-android-bin目录下

libs目录下放的是同第二步一样的3个文件

然后unity测试界面

using system;
using system.collections;
using system.collections.generic;
using tmpro;
using unityengine;
using unityengine.ui;

public class xfmanager : monobehaviour
{
    private androidjavaclass ajc;
    private androidjavaobject ajo;
    //private androidjavaobject xunfeisdk;
    public button startbutton,testbtn;
    public textmeshprougui resulttext;

    private void start()
    {
         ajc = new androidjavaclass("com.unity3d.player.unityplayer");
         ajo = ajc.getstatic<androidjavaobject>("currentactivity");
        //xunfeisdk = new androidjavaobject("com.example.mylibrary.xunfeisdk");
        testbtn.onclick.addlistener(testconnect);
        if (startbutton)
        {
            startbutton.onclick.addlistener(() => { startlistening(); });
        }
    }

    private void testconnect()
    {
        ajo.call("voidtest");
    }


    public void fromandroid(string s) 
    {
        resulttext.text = s;
    }

    public void startlistening()
    {
        ajo.call("startlistening");
    }

    public void onstartlistening(string ret)
    {
        int result = int.parse(ret);
        startbutton.interactable = result == 0;
    }

    public void onresult(string result)
    {
        resulttext.text = result;
    }

    public void onerror(string errormessage)
    {
        resulttext.text = errormessage;
    }

    public void onendofspeech()
    {
        startbutton.getcomponentinchildren<textmeshprougui>().text = "已结束,点击聆听";
        startbutton.interactable = true;
    }

    public void onbeginofspeech()
    {
        startbutton.getcomponentinchildren<textmeshprougui>().text = "聆听ing";
        startbutton.interactable = false;
    }
}

最后就是打包了

注:这里的包名必须跟你配置文件里面的一致才行,还有就是再重复一遍,classes.jar用mono还是il2cpp得和unity-playersetting-scriptbackend一致。

打包成功,测试正常(注意开启权限哦)

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com