Android Studio集成讯飞语音导出可供Unity使用的jar/aar

来源:互联网 发布:仿凡科 源码 编辑:程序博客网 时间:2024/05/20 12:47

Android Studio集成讯飞语音导出可供Unity使用的jar/aar插件

版本信息

  Unity 2017.1.03,

  Android Studio 2.3.3

    Win 7

因工作需要,把讯飞语音听写集成到unity,因为没有直接给unity调用的讯飞语音SDK,就想着通过android studio打包jar给unity调用

也是查了不少资料和demo,否则也无法完成需求,所以要感谢下其它的作者,但是因为过了一段时间才写的,所以参考了那个房个文章也不太记得了。如果有些看到部分相同资料的其它来源,请告诉我,我把出处加进来。

过了一遍就清晰很多,最后还加了些要注意的地方。

原码:https://github.com/yaopin002/ASXunFeiToUnity#as-unity


一、 创建Android Studio工程

  1)第一步,点击File->New->New Project,打开"Create New Project"对话框,选择合适的Application name与Company Domain,保证Package name与Unity项目中的Bundle Idenifier一致
       
  2)第二步,选择Phone and Tablet,并选择合适的Minimum SDK(也可以在创建后的build.gradle中设置)
       
     3)第三步,选择“Empty Activity”
       
     4)第四步,保持默认的Activity Name与Layout Name即可
   5)最后,点击"Finish"创建工程
**以上是直接使用新创建的空activity,然后就需要下面第四个步骤--修改gradle把这个Application改成一个library
**另一个办法是直接创建一个Android Library,就不需要修改gralde了,但是空的library是不带空的activity的,所以需要手动创建activity

二、添加Unity的classes.jar引用和讯飞SDK及.so文件

  1)把Unity引擎目录下中的”Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar“文件拷贝至Android Studio工程中的libs目录

      2)把讯飞语音MSC.jar也拷贝至Android Studio工程中的libs目录

        3)把以上jar报进行添加依赖动作

  4)把讯飞语音armeabi和armeabi-v7a的so文件拷贝到main目录下的jniLibs文件夹下(没有就新建jniLibs)

     5)在gradle的android目录下添加一段代码指定库文件(这个动作运行AS时需要,如果只是做Jar/aar包就可以不用),代码如下:

    sourceSets.main{

        jniLibs.srcDir 'src/main/jniLibs'

    }

三、编写Android侧代码(修改MainActivity代码)

    public SpeechRecognizer speechRecognizer;
    public SpeechSynthesizer speechSynthesizer;
    private String ttsSpeakerName = "yefang";
    private String ttsSpeakerPitch = "50";

  MainActivity
       // 写在onCreate这里面的代码,在unity初始化时一样会自动执行
        //注意这里的appid为
        SpeechUtility.createUtility(getApplicationContext(),"appid=58880d30");
        initRecognizer();
    }
    //初始化
    private void initRecognizer(){
        //1.创建SpeechRecognizer对象,第二个参数:本地听写时传InitListener
        speechRecognizer = SpeechRecognizer.createRecognizer(getApplicationContext(),mInitListener);
        speechSynthesizer = SpeechSynthesizer.createSynthesizer(getApplicationContext(),mInitListener);
    }
    //初始化SpeechRecognizer对象的监听器
    public InitListener mInitListener = new InitListener() {
        @Override
        public void onInit(int i) {
            UnityPlayer.UnitySendMessage("Manager", "Result", "init success!");
        }
    };
    public void setTTSSpeaker(String targetName) {
        ttsSpeakerName = targetName;
    }
    public void setTTSPitch(String targetPitch) {
        ttsSpeakerPitch = targetPitch;
    }
    public void doTTS(String ttsStr){
        UnityPlayer.UnitySendMessage("MotionManager", "IsSpeaking", "true");
        //设置发音人
        speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME,ttsSpeakerName);
        //合成语调 通过此参数,设置合成返回音频的语调。
        speechSynthesizer.setParameter(SpeechConstant.PITCH,ttsSpeakerPitch);
        //设置音量
        speechSynthesizer.setParameter(SpeechConstant.VOLUME,"50");
        int code = speechSynthesizer.startSpeaking(ttsStr, mTTSListener);
    }
    private SynthesizerListener mTTSListener = new SynthesizerListener() {
        @Override
        public void onSpeakBegin() {
        }
        @Override
        public void onBufferProgress(int i, int i1, int i2, String s) {
        }
        @Override
        public void onSpeakPaused() {
        }
        @Override
        public void onSpeakResumed() {
        }
        @Override
        public void onSpeakProgress(int i, int i1, int i2) {
        }
        @Override
        public void onCompleted(SpeechError speechError) {
            UnityPlayer.UnitySendMessage("MotionManager", "IsSpeaking", "false");
        }
        @Override
        public void onEvent(int i, int i1, int i2, Bundle bundle) {
        }
    };
    //开始听写
    public void startSpeechListener(){
        UnityPlayer.UnitySendMessage("Manager", "Result", "");
        speechRecognizer.setParameter(SpeechConstant.DOMAIN, "iat");
        speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        speechRecognizer.setParameter(SpeechConstant.ACCENT, "mandarin");
        speechRecognizer.startListening(mRecognizerListener);
    }
    public RecognizerListener mRecognizerListener = new RecognizerListener(){
        @Override
        public void onBeginOfSpeech() {
            // TODO Auto-generated method stub
            //UnityPlayer.UnitySendMessage("Manager", "Result", "onBeginOfSpeech");
        }
        @Override
        public void onEndOfSpeech() {
            // TODO Auto-generated method stub
            //UnityPlayer.UnitySendMessage("Manager", "Result", "onEndOfSpeech");
            //startSpeechListener();
            UnityPlayer.UnitySendMessage("Manager", "SpeechEnd","");
        }
        @Override
        public void onError(SpeechError arg0) {
            // TODO Auto-generated method stub
            //UnityPlayer.UnitySendMessage("Manager", "Result", "onError");
        }
        @Override
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
            // TODO Auto-generated method stub
            //UnityPlayer.UnitySendMessage("Manager", "Result", "onEvent");
        }
        @Override
        public void onResult(RecognizerResult recognizerResult, boolean isLast) {
            //UnityPlayer.UnitySendMessage("Manager", "Result", "listener");
            printResult(recognizerResult);
            //if(isLast)
                //startSpeechListener();
        }
        @Override
        public void onVolumeChanged(int arg0, byte[] arg1) {
            //UnityPlayer.UnitySendMessage("Manager", "Result", "onVolumeChanged");
            // TODO Auto-generated method stub
        }
    };
    //解析
    private void printResult(RecognizerResult results) {
        String json = results.getResultString();
        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"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将解析结果“"result:" + ret.toString()”发送至“Manager”这个GameObject,中的“Result”函数
        UnityPlayer.UnitySendMessage("Manager", "Result", ret.toString());
    }
    public void ShowToast(final String mStr2Show){
        UnityPlayer.UnitySendMessage("Manager", "Result", "toast");
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(),mStr2Show,Toast.LENGTH_LONG).show();
            }
        });
    }

 四、修改build.gradle,设置工程导出为aar

  1)apply plugin: 'com.android.application'  修改为     apply plugin: 'com.android.library'

  2)删除 applicationId "com.zcode.unityandroidplugindemo"

  3)修改后的build.gradle为

复制代码
apply plugin: 'com.android.library' android {    compileSdkVersion 24    buildToolsVersion "24.0.1"    defaultConfig {        minSdkVersion 18        targetSdkVersion 24        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }
} dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        exclude group: 'com.android.support', module: 'support-annotations'    })    compile 'com.android.support:appcompat-v7:24.1.1'    testCompile 'junit:junit:4.12'    compile files('libs/classes.jar')}
复制代码

五、修改AndroidManifest.xml

     1)修改样式
          我们需要在 AndroidManifest 中的 application 结点修改应用的主样式为系统样式,因为导出的 AAR 文件将不带自定义的样式,在我们的 Unity 项目中生成最终 apk 的时候会出现样式找不到的错误。
          android:theme="@android:style/Theme.NoTitleBar"
          同时需要删除res\Values目录下的styles.xml文件
        备注:如果是直接创建的Android Library就不需要这一步。
 
     2)在主 activity 结点下添加<meta-data>信息,否则在 Unity 导出 APK 时会报找不到manifest 文件的错误信息
            <meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
          
        备注:如果是直接创建的Android Library就需要添加activity节点,包括里面的intent-filter、action、category(但是上面那行meta-data可以不要)

六、导出供Unity使用的*.aar/jar文件

     1)点击右上角的gradle projects找到对应module的Task里的other下的makeJar,双击运行,等一会儿后就完成


备注:要在gradle根目录下添加如下两个方法才会在gradle projects出现makeJar(内容依照需要进行修改):
 task makeJar(type: Copy) {
    delete 'build/libs/speechrecognizer.jar'
    from('build/intermediates/bundles/release/')
    into('build/libs/')
    include('classes.jar')
    rename ('classes.jar', 'speechrecognizer.jar')
}
makeJar.dependsOn(build)

2)也可以通过Terminal执行命令:gradlew makeJar,会使所有Module都执行,如下图:


如下目录找到aar(aar文件里最外层就有一个classes.jar)


如下目录直接找到jar包


3)如果是要调用aar文件,就需使用压缩软件打开aar文件删除libs目录下unity的classes.jar文件(因为会和unity自带的classes.jar冲突),并且要删除其它jar文件和jni目录下的so文件(因为要拷贝到unity指定的目录下,下面步骤会介绍)
如果使用classes.jar就直接拷贝到Unity(拷贝前建议改个名)

Unity导入插件,并调用

一、创建Unity工程

二、导入插件到Unity工程中

     1)新建目录:Plugins-Android-bin/libs
     2)拷贝aar/jar文件、AndroidManifest.xml文件、so文件至如下目录  注意:安卓5.0以上系统需要armeabi-v7a,不然会出现21002的错误



三、编写测试代码

     1)新建一个cs脚本文件

     2)在脚本中编写调用Android侧代码


using UnityEngine;
using System.Collections;
public class XunFeiTest : MonoBehaviour
{
    private string showResult = "";
    //UnityGUI控制是利用一类被称为OnGUI()的函数,只要在控制脚本激活的状态下
    //OnGUI()函数可以在每帧调用,就像Update( )函数一样。
    void OnGUI ()
    {
        //新建一个button,指定文本和高度
        if (GUILayout.Button ("startRecognizer", GUILayout.Height (100))) {
            //这两行代码一般不用改
            AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
            AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity");
            //调用方法
            jo.Call ("startSpeechListener");
        }
        //创建一个TextArea,参数一:显示的内容,参数二:指定宽度
        GUILayout.TextArea (showResult, GUILayout.Width (200));
    }
    //这是AS中指定的方法名,AS一旦有发送消息,这里就会传进来结果
    public void Result (string recognizerResult)
    {
        showResult += recognizerResult;  //把结果连接起来
    }
}

四、设置并运行APK

     1)设置Bundle Identifier(保持与插件的包名+类名一致)
     2)设置合适的Minimum API Level(保持与插件)

五、测试


结尾

                1.确定所有的aar库中的android:minSdkVerion与android:targetSdkVersion一致

                2.android studio包名要和unity包名一致

                3.unity的OnGUI()启动方法要大写

                4.theme要改为android系统样式android:theme="@android:style/Theme.NoTitleBar",或者不要theme也可以

                5.删除res下的style.xml

                6.修改build.gradle:一改一删

                7.务必真机测试,虚拟机会报错

                8.res下activity_main.xml里的这种代码"app:layout_constraintBottom_toBottomOf="parent""要删除,不然会报错

                9.AS不需要添加动态权限申请,否则会报activity找不到的错


原创粉丝点击