Unity与Android之间的交互之AndroidManifest

发表于2019-01-04
评论0 5.1k浏览
AndroidManifest,中文名一般称之为清单文件。它描述了应用程序的组件的活动、服务,广播接收机,内容提供商,应用程序组成、应用程序的Java包命名、权限、特性等。每个安卓应用程序必须有一个AndroidManifest.xml文件,基本内容如下:

<?xml version="1.0" encoding="utf-8"?>  
<!-- <manifest>  
<manifest>AndroidManifest.xml配置文件的根元素,  
必须包含一个<application>元素并且指定xlmns:android和package属性。  
xlmns:android指定了Android的命名空间,默认情况下是“http://schemas.android.com/apk/res/android”;  
package是标准的应用包名,也是一个应用进程的默认名称,我们为了避免命名空间的冲突,一般会以应用的域名来作为包名。  
android:versionCode是给设备程序识别版本用的,必须是一个整数值代表app更新过多少次;  
android:versionName则是给用户查看版本用的,需要具备一定的可读性,  
-->  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.example.android_activitylife"  
    android:versionCode="1"  
    android:versionName="1.0" >  
<!-- <uses-permission>  
为了保证Android应用的安全性,应用框架制定了比较严格的权限系统,一个应用必须声明了正确的权限才可以使用相应的功能  
例如我们需要让应用能够访问网络就需要配置“android.permission.INTERNET”  
而如果要使用设备的相机功能,则需要设置“android.permission.CAMERA”等。  
<uses-permission>就是我们最经常使用的权限设定标签,  
android:name属性来声明相应的权限名,  
 -->  
 <!-- 网络相关功能 -->  
    <uses-permission android:name="android.permission.INTERNET" />  
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
    <!-- 读取电话状态 -->  
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>  
    <!-- 通知相关功能 -->  
    <uses-permission android:name="android.permission.VIBRATE" />  
<!-- <permission>  
权限声明标签,定义了供给<uses-permission>使用的具体权限,  
通常情况下我们不需要为自己的应用程序声明某个权限,除非需要给其他应用程序提供可调用的代码或者数据,这个时候你才需要使用<permission>标签。  
android:name权限名标签,  
android:icon权限图标  
android:description权限描述  
<permission-group>以及<permission-tree>配合使用来构造更有层次的、更有针对性权限系统。  
<permission android:description="string resource"  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:name="string"  
    android:permissionGroup="string"  
    android:protectionLevel=["normal" | "dangerous" | "signature" | "signatureOrSystem"] />  
 -->  
<!-- <instrumentation>  
用于声明Instrumentation测试类来监控Android应用的行为并应用到相关的功能测试中,  
android:functionalTest测试功能开关  
android:handleProfiling profiling调试功能开关,  
android:targetPackage测试用例目标对象。  
Instrumentation对象是在应用程序的组件之前被实例化的,这点在组织测试逻辑的时候需要被考虑到。  
<instrumentation>标签语法范例如下。  
<instrumentation android:functionalTest=["true" | "false"]  
    android:handleProfiling=["true" | "false"]  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:name="string"  
    android:targetPackage="string" />  
 -->  
<!-- <uses-sdk>  
用于指定Android应用中所需要使用的SDK的版本,  
比如我们的应用必须运行于Android 2.0以上版本的系统SDK之上,那么就需要指定应用支持最小的SDK版本数为5;  
当然,每个SDK版本都会有指定的整数值与之对应,比如我们最常用的Android 2.2.x的版本数是8。  
当然,除了可以指定最低版本之外,<uses-sdk>标签还可以指定最高版本和目标版本,语法范例如下。  
<uses-sdk android:minSdkVersion="integer"   
    android:targetSdkVersion="integer"  
    android:maxSdkVersion="integer" /> -->  
    <uses-sdk  
        android:minSdkVersion="8"  
        android:targetSdkVersion="17" />  
<!-- <uses-configuration>与<uses-feature>  
这两个标签都是用于描述应用所需要的硬件和软件特性,以便防止应用在没有这些特性的设备上安装。  
<uses-configuration>标签中,比如有些设备带有D-pad或者Trackball这些特殊硬件,那么android:reqFiveWayNav属性就需要设置为true;  
而如果有一些设备带有硬件键盘,android:reqHardKeyboard也需要被设置为true。  
另外,如果设备需要支持蓝牙,我们可以使用<uses-feature android:name="android.hardware.bluetooth" />来支持这个功能。  
这两个标签主要用于支持一些特殊的设备中的应用,两个标签的语法范例分别如下。  
<uses-configuration android:reqFiveWayNav=["true" | "false"]   
    android:reqHardKeyboard=["true" | "false"]  
    android:reqKeyboardType=["undefined" | "nokeys" | "qwerty" | "twelvekey"]  
    android:reqNavigation=["undefined" | "nonav" | "dpad" | "trackball" | "wheel"]  
    android:reqTouchScreen=["undefined" | "notouch" | "stylus" | "finger"] />  
<uses-feature android:name="string"  
    android:required=["true" | "false"]  
    android:glEsVersion="integer" />  
-->  
<!-- <uses-library>  
用于指定Android应用可使用的用户库,  
除了系统自带的android.app、android.content、android.view和android.widget这些默认类库之外,  
有些应用可能还需要一些其他的Java类库作为支持,  
这种情况下我们就可以使用<uses-library>标签让ClassLoader加载其类库供Android应用运行时用。  
以下是语法范例。  
<uses-library android:name="string"  
    android:required=["true" | "false"] />  
小贴士:  
当运行Java程序时,  
首先运行JVM(Java虚拟机),然后再把Java类加载到JVM里头运行,  
负责加载Java类的这部分就叫做ClassLoader。当然,ClassLoader是由多个部分构成的,每个部分都负责相应的加载工作。  
当运行一个程序的时候,JVM启动,运行BootstrapClassLoader,  
该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),  
然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,  
这就是一个Java程序最基本的加载流程。  
-->  
<!-- <supports-screens>  
对于一些应用或者游戏来说,只能支持某些屏幕大小的设备或者在某些设备中的效果比较好,  
我们就会使用<supports-screens>标签来指定支持的屏幕特征。  
屏幕自适应属性android:resizeable,  
小屏(android:smallScreens)、  
中屏(android:normalScreens)、  
大屏(android:largeScreens)  
特大屏(android:xlargeScreens)支持属性,  
按屏幕渲染图像属性android:anyDensity  
最小屏幕宽度属性android:requiresSmallestWidthDp等。  
<supports-screens>标签的语法范例如下。  
<supports-screens android:resizeable=["true"| "false"]  
    android:smallScreens=["true" | "false"]  
    android:normalScreens=["true" | "false"]  
    android:largeScreens=["true" | "false"]  
    android:xlargeScreens=["true" | "false"]  
    android:anyDensity=["true" | "false"]  
    android:requiresSmallestWidthDp="integer"  
    android:compatibleWidthLimitDp="integer"  
    android:largestWidthLimitDp="integer"/>  
 -->  
 <!-- <application>  
应用配置的根元素,位于<manifest>下层,包含所有与应用有关配置的元素,  
其属性可以作为子元素的默认属性  
应用名android:label,  
应用图标android:icon,  
应用主题android:theme等。  
大家可以打开Android SDK文档来进一步学习,以下是语法范例。  
<application android:allowTaskReparenting=["true" | "false"]  
    android:backupAgent="string"  
    android:debuggable=["true" | "false"]  
    android:description="string resource"  
    android:enabled=["true" | "false"]  
    android:hasCode=["true" | "false"]  
    android:hardwareAccelerated=["true" | "false"]  
    android:icon="drawable resource"  
    android:killAfterRestore=["true" | "false"]  
    android:label="string resource"  
    android:logo="drawable resource"  
    android:manageSpaceActivity="string"  
    android:name="string"  
    android:permission="string"  
    android:persistent=["true" | "false"]  
    android:process="string"  
    android:restoreAnyVersion=["true" | "false"]  
    android:taskAffinity="string"  
    android:theme="resource or theme" >  
... ...  
</application>  
  -->  
    <application  
        android:allowBackup="true"  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name"  
        android:theme="@style/AppTheme" >  
<!-- <activity>  
Activity活动组件(即界面控制器组件)的声明标签,  
Android应用中的每一个Activity都必须在AndroidManifest.xml配置文件中声明,  
否则系统将不识别也不执行该Activity。  
Activity对应类名android:name,  
对应主题android:theme,  
加载模式android:launchMode  
键盘交互模式android:windowSoftInputMode等,  
其他的属性用法大家可以参考Android SDK文档学习。  
另外,<activity>标签还可以包含用于消息过滤的<intent-filter>元素,  
当然还有可用于存储预定义数据的<meta-data>元素,以下是<activity>标签的语法范例。  
<activity android:allowTaskReparenting=["true" | "false"]  
    android:alwaysRetainTaskState=["true" | "false"]  
    android:clearTaskOnLaunch=["true" | "false"]  
    android:configChanges=["mcc", "mnc", "locale",  
        "touchscreen", "keyboard", "keyboardHidden",  
        "navigation", "orientation", "screenLayout",  
        "fontScale", "uiMode"]  
    android:enabled=["true" | "false"]  
    android:excludeFromRecents=["true" | "false"]  
    android:exported=["true" | "false"]  
    android:finishOnTaskLaunch=["true" | "false"]  
    android:hardwareAccelerated=["true" | "false"]  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:launchMode=["multiple" | "singleTop" | "singleTask" | "singleInstance"]  
    android:multiprocess=["true" | "false"]  
    android:name="string"  
    android:noHistory=["true" | "false"]    
    android:permission="string"  
    android:process="string"  
    android:screenOrientation=["unspecified" | "user" | "behind" |  
        "landscape" | "portrait" |  
        "sensor" | "nosensor"]  
    android:stateNotNeeded=["true" | "false"]  
    android:taskAffinity="string"  
    android:theme="resource or theme"  
    android:windowSoftInputMode=["stateUnspecified",  
        "stateUnchanged", "stateHidden",  
        "stateAlwaysHidden", "stateVisible",  
        "stateAlwaysVisible", "adjustUnspecified",  
        "adjustResize", "adjustPan"] >     
... ...  
</activity>  
 -->  
        <activity  
            android:name="com.example.android_activitylife.MainActivity"  
            android:label="@string/app_name" >  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
<!-- <activity-alias>  
Activity组件别名的声明标签,简单来说就是Activity的快捷方式,  
属性android:targetActivity表示的就是其相关的Activity名,当然必须是前面已经声明过的Activity。  
Activity别名名称android:name,  
别名开关android:enabled,  
权限控制android:permission等。  
另外,我们还需要注意的是,Activity别名也是一个独立的Activity,可以拥有自己的<intent-filter>和<meta-data>元素,  
其语法范例如下。  
<activity-alias android:enabled=["true" | "false"]  
    android:exported=["true" | "false"]  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:name="string"  
    android:permission="string"  
    android:targetActivity="string" >  
... ...  
</activity-alias>  
-->  
<!-- <intent-filter>与<action>、<category>、<data>  
<intent-filter>用于Intent消息过滤器的声明,  
Intent消息对于Android应用系统来说,是非常重要的“粘合剂”,  
<intent-filter>元素可以放在<activity>、<activity-alias>、<service>和<receiver>元素标签中,  
来区分可用于处理消息的Activity控制器、Service服务和广播接收器Broadcast Receiver。  
另外,我们还知道Intent消息还包含有名称、动作、数据、类别等几个重要属性。这点与该标签的写法也有一定的关系,  
<category>标签则用于表示能处理消息组件的类别,即该Action所符合的类别;  
<data>元素则用于描述消息需要处理的数据格式,我们甚至还可以使用正则表达式来限定数据来源。  
这些元素和标签的具体用法我们还需要慢慢学习,下面是标准<intent-filter>元素标签的语法范例。  
<intent-filter android:icon="drawable resource"  
    android:label="string resource"  
    android:priority="integer" >  
    <action android:name="string" />  
    <category android:name="string" />  
    <data android:host="string"  
        android:mimeType="string"  
        android:path="string"  
        android:pathPattern="string"  
        android:pathPrefix="string"  
        android:port="string"  
        android:scheme="string" />  
</intent-filter>  
-->  
<!-- <meta-data>  
用于存储预定义数据,和<intent-filter>类似,  
<meta-data>也可以放在<activity>、<activity-alias>、<service>和<receiver>这四个元素标签中。  
Meta数据一般会以键值对的形式出现,个数没有限制,而这些数据都将被放到一个Bundle对象中  
,程序中我们则可以使用ActivityInfo、ServiceInfo甚至ApplicationInfo对象的metaData属性中读取。  
假设我们在一个Activity中定义了一个<meta-data>元素,相关示例用法如下。  
<activity...>  
    <meta-data android:name="testData" android:value="Test Meta Data"></meta-data>  
</activity>  
ActivityInfo info = this.getPackageManager()  
    .getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);  
String testData = info.metaData.getString("testData");  
System.out.println("testData:" + testData);  
-->  
<!-- <service>  
Service服务组件的声明标签,用于定义与描述一个具体的Android服务,  
Service服务类名android:name,  
服务图标android:icon,  
服务描述android:label  
服务开关android:enabled等。  
以下是<service>标签的语法范例。  
<service android:enabled=["true" | "false"]  
    android:exported=["true" | "false"]  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:name="string"  
    android:permission="string"  
    android:process="string" >  
... ...  
</service>  
-->  
<!-- <receiver>  
Boardcast Receiver广播接收器组件的声明标签,用于定义与描述一个具体的Android广播接收器,其主要属性和<service>  
标签有些类似:Boardcast Receiver  
接收器类名android:name,  
接收器图标android:icon,  
接收器描述android:label  
接收器开关android:enabled等。  
<receiver>标签的语法范例。  
<receiver android:enabled=["true" | "false"]  
    android:exported=["true" | "false"]  
    android:icon="drawable resource"  
    android:label="string resource"  
    android:name="string"  
    android:permission="string"  
    android:process="string" >  
... ...  
</receiver>  
-->  
<!-- <provider>与<grant-uri-permission>  
除Activity、Service和Boardcast Receiver之外的另一个“四大组件”,也就是Content Provider内容提供者的声明标签。  
<provider>标签除了和其他组件相同的android:name、android:icon和android:label等基础属性之外,  
还提供了用于支持其功能的特殊属性,以下是<provider>标签的语法范例。  
<provider android:authorities="list"  
    android:enabled=["true" | "false"]  
    android:exported=["true" | "false"]  
    android:grantUriPermissions=["true" | "false"]  
    android:icon="drawable resource"  
    android:initOrder="integer"  
    android:label="string resource"  
    android:multiprocess=["true" | "false"]  
    android:name="string"  
    android:permission="string"  
    android:process="string"  
    android:readPermission="string"  
    android:syncable=["true" | "false"]  
    android:writePermission="string" >  
... ...  
</provider>  
 -->  
</manifest>  
以上的详细说明感谢博主的分享http://blog.csdn.net/zhaoyazhi2129/article/details/27234245

不过从当前的Unity项目生成的Android工程来说,只使用到了四大组件中的Activity,就连Fragment都没用上。

Unity中AndroidManifest

如果还不熟悉Unity如何导出Android工程,请参考上一篇。Unity在导出Android工程的时候会自动生成一个AndroidManifest.xml文件,如果已经存在则使用存在的AndroidManifest.xml文件。Unity生成的时候会自动生成所需要的组件、权限、版本等,当然有些信息是可以在Unity中配置的,比如如下图:

不过这里还是推荐让Unity自动生成清单文件,如果有需要改动的地方在手动修改即可。清单文件存放的位置在Assets/Plugins/Android/AndroidManifest.xml。另外Unity针对Android项目提供了一个固定名称的UnityPlayerActivity类,这个是Unity在生成Android工程的启动类,我们可以直接使用该类或者继承它。清单文件如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">
  <application android:icon="@drawable/app_icon" android:label="@string/app_name">
    <activity 
        android:name="com.xanthuim.UnityPlayerActivity"
        android:label="@string/app_name"
        android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
  </application>
</manifest>

权限

谷歌为了用户的安全隐私,采用权限的机制,让用户明白在使用应用的时候都使用了什么权限,因此开发需要在清单文件中配置相关的权限,否则无法正常使用。比如网络、读写SD卡、位置信息等。不过注意的是在Android低版本的系统配置权限只需要在清单文件中配置即可,而在Android 6.0以上则要复杂些。Android 6.0以上把权限分为普通权限和危险权限,普通权限的使用同低版本一致,而危险权限不仅需要配置还需要在代码运行时做出检查,并且根据不同情况进行相应的操作,否则应用程序出现崩溃,详情请查看谷歌官方文档https://developer.android.google.cn/about/versions/marshmallow/android-6.0-changes.html#behavior-runtime-permissions。

那么Unity中该如何应对Android 6.0中的危险权限呢?答案是不用特殊处理,因为Unity暂时不支持,只需要在清单文件中的Application或Activity做一下配置即可(详情请参考Unity官方文档说明https://docs.unity3d.com/Manual/android-manifest.html):
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />

但是这里需要提醒的是,其实应用程序的权限是否按照Android 6.0以上运行取决于android:targetSdkVersion=”23”。这句话的意思表示当前应用运行的环境是Android 6.0(22代表5.0,23代表7.0等),也就是说只有android:targetSdkVersion的值是23以上(包含23)应用的权限才会有危险权限一说,否则还是按照普通权限执行。那么上面提到的Unity不支持想必就是如此吧,不过我还是不太确定如果这两个参数都设置了那会有什么结果呢?这里就放在程序中去做测试吧。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引