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

article/2025/8/20 21:06:28

使用的引擎工具:

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;@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);SpeechUtility.createUtility(this, SpeechConstant.APPID + "=xxxxxx");//这里是你在讯飞官网上的APPIDmIAT=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() {
@Overridepublic void onVolumeChanged(int i, byte[] bytes) {UnityPlayer.UnitySendMessage("XfManager","OnVolumeChanged","");}@Overridepublic void onBeginOfSpeech() {UnityPlayer.UnitySendMessage("XfManager","OnBeginOfSpeech","");}@Overridepublic void onEndOfSpeech() {UnityPlayer.UnitySendMessage("XfManager","OnEndOfSpeech","");}@Overridepublic void onResult(RecognizerResult recognizerResult, boolean b) {printResult(recognizerResult);}@Overridepublic void onError(SpeechError speechError) {UnityPlayer.UnitySendMessage("XfManager","OnError",speechError.getErrorDescription());}@Overridepublic 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"><applicationandroid: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一致。

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


http://chatgpt.dhexx.cn/article/p5Jlw4d2.shtml

相关文章

vue2中接入讯飞语音听写

首先先登录https://www.xfyun.cn/&#xff0c;在控制台中创建自己的app&#xff0c;并且拿到APPID。 下载crypto-js 与线程worker npm install crypto-js npm install worker-loader 官网中有示例文件&#xff0c;稍微改造一下&#xff0c;封装成组件就能使用了。 transco…

Java 接入讯飞语音听写Speech to Text(STT)功能

标题 讯飞认证配置封装监听器客户端工具 Speech2TextClient.java 对外开放接口对外开放接口实现结果参考 根据官方提供的 WebIATWS 工具扩展修改&#xff0c;接入了讯飞的语音听写(STT)服务 讯飞认证配置 public class XFAuthorityConfig {public static final String hostUr…

html5语音听写流式,iOS 讯飞语音听写(流式版)

最近项目中用到了讯飞的语音识别,然后稍微看了一下,里面有几个值得注意的点,记录一下,先说语音听写(流式版),实时语音转写后期会附上 ,文末有 demo //语音听写(流式版) 语音听写流式版其实没设么好说的,因为直接有 SDK,导入项目就可以了,需要注意的点就是每个创建的 APP 和 SDK…

科大讯飞语音听写(Android)

前面就不废话了&#xff0c;像申请应用&#xff0c;获取SDK等等&#xff0c;我相信大家应该都会的&#xff0c;科大讯飞采用的是两种语音听写功能,一种带有UI&#xff0c;一种没有UI&#xff0c;本人还是比较笨的&#xff0c;所以就写了较为简单的不带UI的语音听写&#xff0c;…

语音转写和语音听写_如何在Windows 10上使用语音听写

语音转写和语音听写 Windows 10’s Fall Creators Update makes voice dictation much easier to use. Now, you can immediately begin dictation by pressing a key WindowsH on your keyboard. You don’t have to dig through the Control Panel and set anything up first…

【超简单】之基于PaddleSpeech搭建个人语音听写服务

一、【超简单】之基于PaddleSpeech搭建个人语音听写服务 1.需求分析 亲们&#xff0c;你们要写会议纪要嘛&#xff1f;亲们&#xff0c;你们要写会议纪要嘛&#xff1f;亲们&#xff0c;你们要写会议纪要嘛&#xff1f; 当您面对成吨的会议录音&#xff0c;着急写会议纪要而…

遥感技术及高分遥感影像在地震中的应用及高分二号获取

长期以来&#xff0c;地震预报监测、灾害调查、灾情信息获取主要依靠实地勘测手段&#xff0c;其获取的数据精度和置信度虽然较高&#xff0c;但存在工作量大、效率低、费用高和信息不直观等缺点。遥感技术手段可在一定程度上克服传统实地勘测手段的缺点&#xff0c;并具有其他…

高分一号(GF-1)-中国高分辨率对地观测系统的第一颗卫星

2013年4月26日12时13分04秒由长征二号丁运载火箭成功发射&#xff0c;开启了中国对地观测的新时代。卫星全色分辨率是2米&#xff0c;多光谱分辨率为8米。高分一号卫星的宽幅多光谱相机幅宽达到了800公里。 “高分一号”的特点是增加了高分辨率多光谱相机&#xff0c;该相机的性…

历年(2017-2022)国产陆地观测卫星(高分1号2号6号等)外场绝对辐射定标系数

国产卫星绝对辐射定标系数&#xff08;2008——2022&#xff09; 2017年 参考博文&#xff1a;高分一号/二号/六号定标系数_desertsTsung的博客-CSDN博客

第059篇:高分二号遥感影像预处理流程(ENVI5.3.1平台+ENVI App Store中最新的中国国产卫星支持工具)

今天被袁老的新闻刷屏&#xff0c;湖南衡水县水稻基地传出好消息&#xff1a; 袁隆平团队第三代杂交水稻测产&#xff0c;测得晚稻平均亩产为911.7公斤 早稻晚稻实现亩产3061斤 伟大&#xff0c;除了伟大&#xff0c;不知道还能用什么词概括袁老的不凡成就&#xff01; 说到这…

envi5.3处理高分二号影像数据详细过程记录

目录 一、多光谱影像处理 1. 辐射定标 2.大气校正 1. 需要准备一些数据: 2.大气校正过程 3、正射校正 二、全色影像处理 1. 辐射定标 2. 正射校正 三、图像融合 1.几何配准 2.图像融合 高分二号处理流程 envi5.3的安装教程&#xff1a; ENVI5.3安装 安装完ENVI5.3后…

我国高分系列卫星遥感影像介绍

继上一篇介绍《遥感图像处理》的文章之后&#xff0c;本篇文章对我国的高分系列卫星遥感影像进行简单的整理。 高分系列卫星是在高分专项的支持下&#xff0c;也就是高分辨率对地观测系统重大专项&#xff0c;由国防科技工业局牵头&#xff0c;组织实施建设的一系列高分辨率对…

高分辨率遥感卫星影像在交通方面的应用及高分二号影像获取

高分辨率遥感影像在城市交通领域具有广泛的应用前景&#xff1a;如遥感交通调查、遥感影像地图与电子地图制作、道路工程地质遥感解译、交通安全与知道抗灾救灾、交通事故现场快速勘察、交通需求预测、车辆与车牌视频识别等等。高分辨率影像比如高分二号卫星、高分一号卫星&…

中国高分系列卫星介绍

中国高分系列卫星 中国高分系列卫星是"高分专项"所规划的高分辨率对地观测的系列卫星。它是《国家中长期科学和技术发展规划纲要&#xff08;2006&#xff5e;2020年&#xff09;》所确定的16个重大专项之一。由于课程汇报&#xff0c;所以作了一个PPT&#xff0c;在…

高分二号(GF-2)号卫星数据的查询下载地址和方法

高分二号卫星是我国自主研制的首颗空间分辨优于1米的民用光学遥感卫星可在平台中查询到&#xff0c;搭载有两台高分辨率1米全色、4米多光谱相机&#xff0c;具有亚米级空间分辨率、高定位精度和快速姿态机动能力等特点&#xff0c;有效地提升了卫星综合观测效能&#xff0c;达到…

遥感科普|中国高分系列卫星综述(2020版)

遥感科普|中国高分系列卫星综述(2020版) 文章来源&#xff1a;卫星遥感大数据公众号 高分系列卫星概述 中国高分系列卫星是"高分专项"所规划的高分辨率对地观测的系列卫星。它是《国家中长期科学和技术发展规划纲要&#xff08;2006&#xff5e;2020年&#xff09…

国产高分系列卫星平台介绍

目录 高分专项 高分一号&#xff08;GF-1&#xff09; 高分二号&#xff08;GF-2&#xff09; 高分三号&#xff08;GF-3) 高分四号&#xff08;GF-4&#xff09; 高分五号&#xff08;GF-5) 高分六号&#xff08;GF-6&#xff09; 高分七号&#xff08;GF-7&#xff09; 高分八…

高分三号卫星介绍

博主现在要用到高分三号卫星&#xff0c;但是因为高三2016年8月才发射&#xff0c;目前网上相关资料较少&#xff0c;便总结了一些相关信息&#xff0c;希望能为大家提供帮助~ 传感器 高分三号卫星搭载的传感器是C频段多极化合成孔径雷达&#xff0c;是迄今为止世界上成像模式…

法国Pleiades高分卫星/遥感影像/卫星影像/高分二号影像

引言 Pliades高分辨率卫星星座由2颗完全相同的卫星Pliades 1和Pliades 2组成。Pliades 1已于2011 年 12 月17 日成功发射并开始商业运营&#xff0c; Pliades2 于2012年12月1日成功发射并已成功获取第一幅影像。双星配合可实现全球任意地区的每日重访&#xff0c;最快速满足客户…

c语言中d1的分辨率是,高分一号(GF-1)、高分一号B、C、D星 卫星介绍

原标题&#xff1a;高分一号(GF-1)、高分一号B、C、D星 卫星介绍 高分一号卫星全色分辨率2米&#xff0c;多光谱分辨率8米。高分一号是国家高分辨率对地观测系统重大专项天基系统中的首发星&#xff0c;其主要目的是突破高空间分辨率、多光谱与高时间分辨率结合的光学遥感技术&…