赞
踩
本案例使用Unity 2020.3.39f1c1与Android Studio 2021.3.1
前提条件:
1.你的Unity已经安装好Android平台模块,可以在UnityHub中查看。
2.Android Studio IDE已经安装好了,测试工程项目能正常运行。(如果未安装Android Studio 可以查看我的另外一篇文章《Android Studio IDE安装指南》)
首先创建一个Unity空项目,在空场景中创建一个空物体名字为UnityGameDataMgr
注意:这个名字是等会再Android中向Unity发送消息时的API中必须要传的参数
然后在UnityGameDataMgr空物体上添加一个脚本,脚本中的代码如下:
using UnityEngine; using System; using UnityEngine.UI; public class GameDataMgr : MonoBehaviour { public Button Btn_UnityExit; public Button Btn_ShowMainActivityQuit; public Button Btn_ShowMainActivityUnload; public Text Txt_FormAndroidMessage; string userData = "用户信息(UseData):张三,22,男"; private void Awake() { DontDestroyOnLoad(this); } private void Start() { Btn_UnityExit.onClick.AddListener(OnQuitUnity); // 点击ShowMainActivityUnload按钮调用 Btn_ShowMainActivityUnload.onClick.AddListener(() => { CallAndroidMethod("showMainActivity", false, ("UnloadSend:" + userData)); }); // 点击ShowMainActivityQuit按钮调用 Btn_ShowMainActivityQuit.onClick.AddListener(() => { CallAndroidMethod("showMainActivity", true, ("QuitSend:" + userData)); }); } /// <summary> /// 调用UnityGameActivity的方法 /// </summary> /// <param name="methodName">Android方法名称</param> /// <param name="isFinish">方法参数1:是否结束UnityGameActivity</param> /// <param name="data">方法参数2:具体数据</param> private void CallAndroidMethod(string methodName, bool isFinish, string data) { #if UNITY_ANDROID try { AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); jo.Call(methodName, isFinish, data); } catch (Exception e) { Debug.LogError(e.Message); } #endif } /// <summary> /// Android调用方法 在安卓UnityGameActivity OnCreate调用 /// </summary> /// <param name="str"></param> public void sendMessageToUnity(string str) { Debug.Log("Unity获取Android MainActivity发送过来的Token信息: " + str); Txt_FormAndroidMessage.text = "来自Android MainActivity信息:" + str; } #region Unity程序原生方法 void OnQuitUnity() { Application.Quit(); } #endregion }
Unity UGUI Canvas布局层级结构如下:
然后在File->Build Settings中将平台切换到Android
按照上图的指示操作然后在Player Settings中配置Other Settings其中的选项
1.设置Package Name。这个必须要与Android中的包名一致(不一致好像也可以)。
2.设置Minimum API Level 。这个一定要与Android Studio中保持一致,如果不一致,在Android Studio中发布时会报错。
3.设置Scripting Backed为IL2CPP,设置Api Compatibility Level 为**.NET Standard 2.0**。
4.4.设置Target Architectures。选择 ARMv7和ARM64(可选)
4.设置签名(非必要)。我这里没有设置,但是之前设置了也能正常运行,这里跟签名应该没有太大关系,我的都没有设置,看下图(如果使用IL2CPP打包APK出错可能就需要设置)
5.最后就是点击Build Settings中的Export导出Android中需要的项目,导出的文件夹与Unity项目的关系,如果你是第一次看着我的博客教程跟着做,那么请按照我的文件夹的命名与结构来做,因为在Android Studio中需要根据路径引入Unity发布出来的安卓项目。
Unity项目目录与安卓项目目录之间的关系
至此,Unity中设置已经完成。
创建安卓项目,选择Empty Activity->Next
注意:Minimum SDK版本与Unity两者保持一致
注意:创建出来的Android项目下方没有任何报错才可以,像下图一样
创建完成后,开始导入Unity Build出来的包
这里有两种做法,
第一种,直接打开刚刚用Unity导出的项目文件夹做为一个Android项目;
第二种,把导出的项目里面的unityLibrary文件夹做为一个模块来用;
这里选择第二种方式导入
1.导入unityLibrary模块
File -> New -> Import Module
不出意外这个时候应该会报错
导入之后会出现一系列的错误提示,不过不要慌,问题不大,下面开始进行配置。
2.unityLibrary模块配置
2.1.项目settings.gradle文件配置
在项目settings.gradle文件里添加两行代码
include ':app',':unityLibrary'
rootProject.name = "AndroidAPP"
//--上面两句应该本身就有不需要添加--
//括号里的是你的unityLibrary所在的路径
project(':unityLibrary').projectDir=new File('..\\UnityAndroidBuild\\unityLibrary')
在项目settings.gradle文件里添加
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
项目settings.gradle文件最终配置就是上面这样的。
2.2.app模块文件配置
在app模块下的build.gradle文件里面加上
implementation project(':unityLibrary')
implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])
同时还是在app模块下的build.gradle文件里面添加引入SO库架构,如下代码
注意:添加引入SO库架构,如果不添加,构建出来的app运行时会闪退,并且报错:can not find ‘libmain.so’
ndk {
// 设置支持的SO库架构,第三方给的so库哪几种架构,就配置这几种架构
abiFilters 'armeabi', 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
在app模块下的strings.xml文件里加上
<string name="game_view_content_description">Game view</string>
点击蓝色字体 Sync Now按钮,结果
如果出现上面这个错误在上图序号①所指 项目的gradle.properties文件加入一下代码(没有报错的不用加)
unityStreamingAssets=.unity3d, google-services-desktop.json, google-services.json, GoogleService-Info.plist
继续点击 Sync Now 按钮,编译成功,无报错!
4.简单交互Demo创建与运行
首先更改app模块的MainActivity.java类
MainActivity类完整代码如下:
package com.test.androidapp;//自己的APP包名 import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private Button btn; private TextView textView; private String tokenStr="这是一个tokenStr数据"; private String unityDataStr=""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = findViewById(R.id.button); textView=findViewById(R.id.textView); //注册监听器 btn.setOnClickListener(this::onClickStartGameBtn); handleIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleIntent(intent); setIntent(intent); } int i=0; //按键点击进入UNITY private void onClickStartGameBtn(View view) { System.out.println("触发点击进入游戏的按钮事件"); Intent intent=new Intent(this, UnityGameActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); i=i+1;//模拟点击进入Unity次数 每次点击+1 intent.putExtra("TokenCode", tokenStr+"{"+i+"}"); //startActivity(intent); startActivityForResult(intent, 1);//requestCode >=0即可 } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1) { Bundle extras = data.getExtras(); if (extras!=null){ unityDataStr=extras.getString("UnityData"); } textView.setText(unityDataStr); System.out.println(unityDataStr); } } //当UnityActivityGame结束后返回 //这个是处理来自UnityGameActivity传过来的信息 private void handleIntent(Intent intent) { if(intent == null || intent.getExtras() == null) return ; if(intent.getExtras().containsKey("UnityData")) { unityDataStr = intent.getStringExtra("UnityData"); textView.setText(unityDataStr); } } }
在activity_main.xml里面新建一个Button按钮和TextView组件
MainActivity类中的R.id.button为activity_main.xml中的Button控件id属性的值,R.id.textView同理。
在app模块新建UnityGameActivity类作为进入Unity的入口
UnityGameActivity类完整代码如下:
package com.test.androidapp; import android.content.Intent; import android.os.Bundle; import android.util.Log; import com.unity3d.player.UnityPlayer; import com.unity3d.player.UnityPlayerActivity; //进入到这个类就进入了unity游戏画面 public class UnityGameActivity extends UnityPlayerActivity { private String tokenStr; private static final String TAG = "UnityGameActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); GetTokenFromMainActivity(); } //进入UnityGameActivity就调用sendMessageToUnity给Unity Text组件赋值 private void GetTokenFromMainActivity(){ Bundle bundle=getIntent().getExtras(); if (bundle!=null) tokenStr= bundle.getString("TokenCode"); sendMessageToUnity(tokenStr); } //发送给Unity的数据 Android-》Unity private void sendMessageToUnity(String str) { Log.i(TAG, "Android传给unity的信息: " + str); //其中GameDataMgr是unity生成的gameobject,脚本要挂在上面。AndroidToUnity是unity里实现的方法。str是传过去的值。 UnityPlayer.UnitySendMessage("UnityGameDataMgr", "sendMessageToUnity", str); } //返回MainActivity并将unityData数据传递给MainActivity显示( Unity-》Android) //unity 退出应用之前将Unity的数据传递给MainActivity //isFinish为false 直接返回MainActivity;当为true,结束此活动返回MainActivity public void showMainActivity(boolean isFinish,String unityDataStr) { if (!isFinish){ Intent intent=new Intent(this,MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.putExtra("UnityData",unityDataStr); startActivity(intent); } else{ Bundle bundle=new Bundle(); bundle.putString("UnityData",unityDataStr); Intent intent=new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); setResult(1,intent); intent.putExtras(bundle); finish(); } } }
还需要配置,才能找到这个类,在app模块的AndroidManifest.xml文件添加这段代码
<activity android:name="com.test.androidapp.UnityGameActivity"
android:theme="@style/UnityThemeSelector"
android:screenOrientation="userPortrait"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:hardwareAccelerated="false">
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="android.notch_support" android:value="true" />
</activity>
然后运行到自己的手机上就行了(不会运行的可以找找看android基础教程学习下)
如果是游戏模拟器运行的话,先打开模拟器,再点击下图标识①按钮同步下gradle文件,再点击②运行按钮,就可以在模拟器上运行了。
运行结果如下:
演示步骤:
点击 进入UNITY->跳转到Unity界面同时传递数据显示在Unity中;
点击Unity中的 ShowMainActivity(Quit)或者 ShowMainActivity(Unload)按钮返回APP首页并同时将Unity数据传递给TextView组件;
其他问题:
1.NDK路径配置问题
在项目的Local.proporties文件下添加
我这里是用的Unity3D编辑器下载的NDK路径
ndk.dir=自己ndk路径
2.构建出包出现两个APP图标
找到unityLibrary模块的AndroidManifest.xml文件,删除里面的代码
3.从Unity返回其他APP页面闪退应用的问题
操作:点击Exit按钮( Application.Quit();)
在app模块的AndroidManifest.xml文件添加如下代码
android:process=":UnityActivity"
参考文章:
1.(Unity官方)Unity作为库的方式嵌入原生Android/IOS/tvOS案例
2.Unity2020.2.6导出项目到Android Studio4.1.2中
3.Android内嵌Unity并实现互相跳转的实例代码
4.Unity游戏嵌入Android应用(融合为一个应用)
十分感谢上述博客作者的帮助!~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。