使用的引擎工具:
Unity2021.3.19
android-studio-2021.1.21
第一步:
新建一個Android項目(工程名字隨便啦)


然后新建一個library


(同上,庫名自己命名吧)
Android環(huán)境目前就算是初步建立好了。
第二步:
導包
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:消息發(fā)送至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"))) {
// 可能會有多個聯(lián)系人供選擇,用中括號括起來,這些候選項具有相同的置信度
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一致。文章來源:http://www.zghlxwxcb.cn/news/detail-735452.html

打包成功,測試正常(注意開啟權限哦)文章來源地址http://www.zghlxwxcb.cn/news/detail-735452.html
到了這里,關于Unity2021接入訊飛語音聽寫(Android)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!