使用的引擎工具:

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 mIatResults = new LinkedHashMap();

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 ("".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文件

xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.mylibrary">

android:allowBackup="true"

android:supportsRtl="true">

android:exported="true">

tools:ignore="ProtectedPermissions" />

第六步:

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

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

arr生成路径是

结果如下

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

下面这个是从arr包里取出来的AndroidManifest文件,把删掉

第七步:

下面就是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("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().text = "已结束,点击聆听";

StartButton.interactable = true;

}

public void OnBeginOfSpeech()

{

StartButton.GetComponentInChildren().text = "聆听ing";

StartButton.interactable = false;

}

}

最后就是打包了

注:这里的包名必须跟你配置文件里面的一致才行,还有就是再重复一遍,Classes.jar用mono还是IL2CPP得和Unity-PlayerSetting-ScriptBackend一致。

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

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: