Unity和Android通信以及AndroidManifest的合并

前言:

    Unity和android交互,这个问题,在百度搜一下,解决方案还是蛮多的,起初我也是照着百度出来的帖子一步步实现了.但是!大部分帖子只管功能实现根本不讲缘由,且实现的功能比较死板.看完这样的帖子,对学习完全没有帮助啊喂!想要在项目中使用交互代码相应的也会遇到许多问题(后面会说遇到的问题,以及解决方案).

适用人群:

1.unity开发者,不会使用AndroidStudio,通过本教程,可以了解Android Studio的基本使用.

2.搜索了很多unity,Android交互文章却没找到合适解决方案的同学.


使用jar还是aar进行通信?

Jar中包含了原生java代码,如果我们只是测试通信,一个简单的jar包就能够通信,然而实际开发中,一般不可能只用一个jar包,在android工程中一般都会引用很多jar包,

aar大概是设计出来用来替代jar来进行通信的,不仅包含了jar 还包含了提供的android资源(图片,布局文件等).这也是aar包比jar大的原因,我们可以通过删除不相关内容来降低aar包的大小.

AndroidStudio:

打开AndroidStudio-    NewProject:


新建activity之后,要在activity中引用unity的方法就需要引入unity的jar包,根据以下目录找到unity提供的jar:

根据在unity中选择的打包方式,复制出来文件夹中的jar包

放在android studio中的libs文件夹中

这个classes.Jar是unity给安卓写的脚本,在android中引用了这个jar包,就可以调用里面的方法(各位原生老哥应该比我清楚....),右键classes.jar 最下面有个add as a Library 或者

导入成功后,就可以引入unity提供的package了

根据我想实现的需求,需要引用两个package:

1. 在安卓原生中调用unity方法(向unity传递数据),import com.unity3d.player.UnityPlayer

2. 为了unity中能找到并调用andorid方法( import com.unity3d.player.UnityplayerAcitvity,来继承UnityPlayerActivity)

对默认的activity进行以下更改:

Android Studio端 逻辑代码编写完毕.这里讲解下unity android相互调用API的使用规则:

Android调unity:

 unitySendMessage需要三个参数:s1(string):unity 场景中的的gameobject的name .s2(string):该gameobject上的脚本上的方法名 s3(string):传递的消息内容,可以是json,xml之类的.也就是说unity通过寻找场景中的gameobject,调用unity自己的sendmessage来传递消息(这里使用的是Unity提供的unitysendMessage往unity回调数据,它是通过反射实现的,这个帖子https://www.jianshu.com/p/f5b20d43315a提供了java中反射的实现,可以不用unity的方法直接实现通信).

Unity调用android:

Unity官网提供的死代码以及网上一半帖子的代码如上,大概意思是通过包名找到了java类, 但是是具体哪一个类的对象需要用”currentActivity”获取到.这里我推测我们在android 中新建的MainActivity是继承了UnityPlayerActivity才能被以上两行代码找到(这个必须要继承UnityPlayerActivity 才能被找到 很鸡肋很鸡肋).

接下来导出aar包:

Android Studio默认build会生成apk,此时需要更改build.gradle来让Android studio导出aar包

设置完毕后,点击build-RebuildProject进度走完后,打开build/outputs/aar找到导出的aar

右键,show In Explorer在文件夹中显示它

可以看到它是可以被解压软件打开的,我们可以打开看下,来删除那些我们不需要的内容

由于在Android Studio我无脑build导致build出来一大堆用不到的东西,我又不知道如何在Android studio中不导出这些,所以现在直接操作aar删除,首先要分辨出来哪些是有用的,哪些是无用的.

有用的:我写的两个java类,猜测被自动打入到aar包中外层的Classes.jar中了

无用的:事先从unity导入的jar包(存放在libs/classes.jar,至于它为啥和aar中的classes.jar名字一样,我也不知道),布局文件,dpi文件 删除完毕后,如下

Unity中:

在unity的 Assets目录下新建Plugins/Android(Plugins文件夹必须是在Assets根目录) 文件夹 拖入刚才的aar和AndroidManifest(此处应该有疑问,为什么aar包中有AndroidManifest文件,还要在unity的目录下还放置一个AndroidManifest)

在unity中新建name为AndroidCall的gameobject以及新建脚本,新建方法TestCall.


unity playersettings中packageName和Android activity的package要保持一致

大部分帖子写到这里展示一下调用成功的截图,就结束了帖子...前面讲到的很鸡肋的unity获取Android 对象的方式,就这样鸡肋下去了,准确的来说,目前实现的unity和Android交互只是一个最基础的demo,在实际项目开发过程中根本不可能使用这种单一的方式.我相信这些朋友后面也都发现了它的缺点,一部分网友更新了unity Android交互第二篇...,我认为要想得心应手的使用unity和底层通信就要了解其通信原理,但是在介绍通信原理之前必须要介绍一下AndroidManifest这个东西,它对我们理解如何通信至关重要.

AndroidManifest是什么?他有什么作用?

清单文件(Mainfest)普遍存在于各个平台生成的项目中,是对指定内容的一种描述,提供了指定内容构成有关的所有信息,且有唯一标识作用,就像是一条http请求,header包含了对body体内容的描述.

一般由以下几部分构成:

1.指定内容的版本信息.

2.指定内容对其他内容的依赖

3.指定内容的安全权限

AndroidManifest是Android中打包时生成的一个清单文件,位于根目录:

1.包含了app要在Android系统上运行的基础信息:app图标(Icon),名称(product Name),横屏还是竖屏(orientation),版本号(version)等等,在unity中是通过PlayerSettings的可视化界面配置app的基本信息的.这些内容会在打包的时候写入AndroidManifest中,有了这些基础设置,该app安装在Android设备上才会在桌面中显示出来.

2.设置程序入口.有了上一条说的基础配置之后,虽然能够在Android中显示,但是没有设置要启动的Activity,会直接闪退.(平时正常打包出来的app能运行是因为已经设置好了程序入口Activity),在Android中应该是允许配置多个activity,设置一个mainActivity,然后在activity中切换.unity打的Android只使用一个activity.

3.配置该app需要的Android功能:比如app需要开启摄像机或者麦克风,需要在Manifest中配置权限,否则Android不会弹出权限请求,权限部分需要<uses-permission>标签,再比如需要Android广播接收器功能就需要配置<receiver>标签.

    Android开发的同学都知道,每当新建一个Activity ,就会生成一个Manifest文件,它用来指定当前activity需要的各种配置.然后一个activity就可以通过设置gradle 来生成一个apk,运行在Android设备上,那unity是如何生成apk的呢?我们新建一个unity工程并导出成Android Project来研究一下:

新建一个空的unity工程,将unity 的buildSettings上的export project勾选就可以将项目导出成Android project

使用AndroidStudio打开该工程发现,unity的export过程就是将unity的内容导出成了一个activity,叫做UnityPlayerActivity,这个activity的packageName就是在unity的Android PlayerSettings中设置的packageName

前面说到每个activity都包含Manifest文件,打开Manifest文件如下


Unity打包出来的Manifest文件是根据存放在unity安装目录下的Manifest模板生成一个com.XXX(unity中设置的package).UnityPlayerActivity,所以我们unity的apk在Android设备中是通过Manifest中设置的启动项Activity启动的.

        下面回过头来看刚才那个测试demo的Manifest文件:

主要功能就是设置了com.axin.mylibrary.customActivity这个activity为启动activity,已知unity会自动生成UnityPlayerActivity这个activity作为启动项,如何把咱们的activity替换到Unity生成的Manifest文件中呢?官方文档对此进行了说明:https://docs.unity3d.com/2017.4/Documentation/Manual/android-manifest.html?tdsourcetag=s_pctim_aiomsg

在unity中AndroidManifest文件的合并重点是这一句(已使用谷歌翻译)

在unity中提供的AndroidManifest文件只能有一个,它的目录是Assets/Plugins/Android/AndroidManifest.xml,这也是我们前面在unity目录下导入AndroidManifest的原因,下面展示下unity替我们合并的Manifest文件

    对比之前打包的空工程的AndroidManifest文件,启动项activity已经变成了.customActivity,这就是我们在assets/plugins/Android目录下放置的AndroidManifest文件中的内容覆盖了unity的fest文件模板生成的效果.

    由于unity的playersettings中设置的packageName和 aar包中Android activity的packge一致(此处应该有疑问,我unity中的packageName应该指定的是我司的公司名称和项目名称,怎么能和第三方aar保持一致呢?也不能我用了阿里巴巴的aar,我就要让我unity项目的packageName带上阿里巴巴吧?),所以启动项activity就是com.axin.mylibrary.customactivty,另外customactivty又是继承UnityPlayerActivity的

所以我们的代码

获取的就是这个java类的对象(为了能用上述两行代码找到我们定义的activity,实际上是我们的activity抢占了unity默认的启动activity,这会带来不同程度的后果,但是如果我们没有使用UnityPlayerActivity这个父类的需求的话,我们尽量不要继承它实现通信,下文会提到另一种调用javaclass对象的方法.)


        此时调用AndroidCallUnity方法就会调用unity中的方法了.

        以上简单的解释了下我们的通信demo是如何运行的,但是它仅仅是demo,下面我们分析一下实际项目的需求:

A.在unity中接入一个或者多个第三方sdk,意味着导入多个aar.

B.在Android原生中接入多个原生sdk,然后将数据传回unity.

C.Unity项目最终只作为一个activity来运行,如果各个aar都要抢占Activity入口,都要求unity项目packageName和自己保持一致那该怎么办?(上文的测试demo抢占了Activity入口且要求项目packageName和aar的保持一致.网上搜索的unity Android通信帖子大部分都这样写的)

        情况A多为unity开发者遇到,意味着unity中需要导入多个aar,就可能(我觉得导出的aar都会有Manifest文件,因为我也不是Android开发,不敢说太绝对)会附带多个Manifest.多个AndroidManifest可能存在于unity项目工程中,也可能存在于aar包中.

对于Unity工程里的AndroidManifest:

众多AndroidManifest可能拥有不同的系统权限或不同的APILevel等.这时候就应该合并不同的Manifest.前面说到unity的项目中只能存在一个AndroidManifest(起初我以为AndroidManifest只要放在Android目录下就可以,unity中的editor文件夹,lib文件夹貌似都是这个逻辑,觉得多个Manifest文件unity会帮我们合并,事实上只要assets/Plugins/Android下的fest文件才能被合并,害我在这里卡住了很久),所以就需要手动合并这些Manifest,只保留一份在Plugins/Android目录下.保证手动合并的Manifest中只有一个MainActivity.且这个activity尽量不主动设置,让unity去生成默认的就可以.合并方法是复制粘贴....,即把非指定路径下的Manifest文件中和指定路径下Manifest文件不同的东西复制过去...比如权限什么的,最终文本还是要符合xml结构的.

对于存在于aar包中的Manifest文件: 

        打包过程中会根据谷歌的固定算法进行合并,unity打包apk的流程大概是先打成Android 工程,再利用Android中的Gradle的Task打出apk,谷歌的合并算法应该是在Task里,和unity没什么关系,情况B和这个情况类似,AndroidStudio也是依赖Gradle打包的.关于AndroidStudio中Manifest的合并原理:https://www.jianshu.com/p/0febcb3625d9

AndroidManifest总结:

        根据分析unity中export的Android project分析发现,unity是根据Unity的存放目录下的AndroidManifest模板和Assets/Plugins/Android/AndroidManifest.XML 合并生成一个AndroidManifest,作为unityPlayerActivity的配置文件.unity项目目录下的fset文件和aar包中的fest文件不同之处在于,unity中的fest通常抢占了入口Activity或对unity默认Activity进行了一些修改,而aar包中的fest文件通常只包含该aar需要的系统权限和API Level ,该部分会在Gradle的task中被谷歌算法合并.

情况C的解决方案:

1.如果接入的第三方sdk都是原生Android Sdk,则可以在Android Studio中新建一个和Unity工程packageName一样的Activity,整合众多sdk要使用的API在一个Activity里,然后这个Activity设置为Main入口,放置新的AndroidManifest文件在unity指定文件夹下,下面这个教程贴是这么做的:https://blog.csdn.net/LIQIANGEASTSUN/article/details/78805902

2.不使用activity,直接使用Java类,Unity中可以通过new AndroidJavaObject(“包名”)直接生成一个java对象,来调用其中的方法(直接继承UnityPlayerActivity主要是方便查找到activity ),各个sdk自己各自维护一个java类,提供unity调用的方法,在unity中通过unity的方式直接new这个java类来调用(需要提供包名+类名),在unity中整合各个第三方sdk,此方案不需要在AndroidStudio中新建activity,因为不需要抢占activity所以也不需要在unity文件夹下放置AndroidManifest,打包过程中会自动合并aar包中的fest.

步骤如下:

首先,在AndroidStudio中新建一个java类:customSendMessage

导入unity中包含sendmessage的package(如何导入在上文) ,写一个AndroidCallUnity 方法

将aar导出后直接放到plugins/Android目录下,(导出步骤在上文),在unity中

在java中有可能要用到上下文,这里的上下文(什么是上下文可以百度搜一下,大概指的就是当前运行的程序域吧)指的是当前的Activity,获取当前activity 返回给java


文章完毕,如有错误,还请各位大佬纠正,我会第一时间进行修改,谢谢大家.

我的CSDN地址:

https://blog.csdn.net/weixin_39106746/article/details/103469620

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容