https://docs.unity3d.com/Manual/android-manifest.html
Unity会自动添加的权限当调用某些特定的Unity api:
Permissions
Unity automatically adds the necessary permissions to the manifest based on the Android Player Settings and Unity APIs that your app calls from the script. For example:
Network
classes add the INTERNET permission- Using vibration (such as
Handheld.Vibrate
) adds VIBRATE - The
InternetReachability
] property adds ACCESS_NETWORK_STATE - Location APIs (such as
LocationService
) adds ACCESS_FINE_LOCATION WebCamTexture
APIs add CAMERA
permission- The
Microphone
class adds RECORD_AUDIO NetworkDiscovery
andNetworkTransport.SetMulticastLock
add CHANGE_WIFI_MULTICAST_STATE
For more information about permissions, see Android developer documentation on Android Manifest Permissions.
If your plug-ins require a permission by declaring it in their manifests, Unity automatically adds the permission to the resulting Android manifest during the merge stage. All Unity APIs that plug-ins call also contribute to the permissions list.
项目中有过一个ACCESS_FINE_LOCATION 的权限,原因是项目中用了tolua,反射了 UnityEngine.Input 类,其中有个成员是 location,类型是 LocationService。虽然反射了但是项目中也没有用这个接口,所以就单独排除了 location成员的反射。
(ps:ios中对应的权限是 NSLocationWhenInUsageDescription ,在info.plist中,ios声明权限的地方。)
Runtime permissions in Android 6.0 (Marshmallow)
动态权限,app运行的时候弹出给用户选择是同意某些权限,而不是安装的时候就同意。
可以在一开始游戏的时候就弹出所有的权限让用户选择,也可以直接在用到这个功能的时候弹出来让用户选择。如果使用需要权限的功能之前不做判断是否同意,比如当时是禁止的使用的状态,app就会崩溃。
所有的权限都是要申明在 androidmanifest.xml中的
<application> <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" /></application>
如果不加这句,Unity打包运行到Android平台,每次进入Unity模块时,都会弹出一些没有必要的权限提示框(即使是Android6.0以下的手机也会弹出)。
==============================================================================
Unity代码和Android代码交互方案
一、Unity做好项目之后导出为Android Studio项目,导入到Android Studio中进行之后的功能开发。最后由Android Studio打包APK。即Unity辅助Android开发(Android开发为主),对Android技能要求较高。
二、Android Sutido做好项目导出jar或aar包,导入到Unity中作为Unity的插件使用,最后由Unity打包APK。即Android辅助Unity开发(Unity开发为主),对Unity技能要求较高。
Unity打包APK时,调用安卓SDK,把所有游戏内容整合打包出的APK中只有一个MainActivity。
基础
Android端调用Unity的方法:用UnityPlayerJava类的UnitySendMessage() 接口
UnityPlayer.UnitySendMessage() 参数1表示发送给Unity的游戏对象的名称,参数2表示对象绑定的脚本接收该消息的方法,参数3表示本条消息发送的字符串信息
Unity端调用Android插件中实现的方法:用AndroidJavaClass与AndroidJavaObject这两个C#工具类
public class AndroidJavaClass : AndroidJavaObject 可以自行查看一下代码中接口有哪些
AndroidJavaClass主要是读取arr包或者jar包中的类对象,用来读取静态属性或方法
//读取类对象
var playerCls = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
//获取静态属性
var activity = playerCls.GetStatic<AndroidJavaObject>("currentActivity");
//获取静态方法 playerCls.CallStatic
AndroidJavaObject主要作用于生成实例对象,用来读取对象的实例属性或方法
//获取方法 activity.Call<返回类型>("函数名", 输入参数1 , 输入参数2等);
var applicationContext = activity.Call<AndroidJavaObject>("getApplicationContext");
方案一:Android端不新建Activity
详细教程
https://www.jianshu.com/p/86b275da600e
android端:
不需要引用unity下的class.jar,
而是通过Java的反射原理来获取本来导入class.jar类才能引用到的com.unity3d.player.UnityPlayer包下的currentActivity上下文(getActivity函数)。
所以在创建一个AndroidModule以后直接新建一个class类(Unity2Android类),而不是新建activity。
package com.jing.unity;
import android.app.Activity;
import android.widget.Toast;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by Jing on 2018-1-18.
*/
public class Unity2Android {
/**
* unity项目启动时的的上下文
*/
private Activity _unityActivity;
/**
* 获取unity项目的上下文
* @return
*/
Activity getActivity(){
if(null == _unityActivity) {
try {
Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
Activity activity = (Activity) classtype.getDeclaredField("currentActivity").get(classtype);
_unityActivity = activity;
} catch (ClassNotFoundException e) {
} catch (IllegalAccessException e) {
} catch (NoSuchFieldException e) {
}
}
return _unityActivity;
}
/**
* 调用Unity的方法
* @param gameObjectName 调用的GameObject的名称
* @param functionName 方法名
* @param args 参数
* @return 调用是否成功
*/
boolean callUnity(String gameObjectName, String functionName, String args){
try {
Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
Method method =classtype.getMethod("UnitySendMessage", String.class,String.class,String.class);
method.invoke(classtype,gameObjectName,functionName,args);
return true;
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return false;
}
/**
* Toast显示unity发送过来的内容
* @param content 消息的内容
* @return 调用是否成功
*/
public boolean showToast(String content){
Toast.makeText(getActivity(),content,Toast.LENGTH_SHORT).show();
//这里是主动调用Unity中的方法,该方法之后unity部分会讲到
callUnity("Main Camera","FromAndroid", "hello unity i'm android");
return true;
}
}
showToast函数:被unity端调用。获取当前的activity,在其上显示toast。
callUnity函数:调用unity端的函数,通过调用UnitySendMessage接口实现。给unity发消息也是反射原理。
最后Build-MakeProject在output目录下找到aar包,放到Unity的Plugins/Android目录下
unity端:
不用在Unity的/Plugins/Android下放置AndroidManifest.xml文件
Unity打包时PackageName不依赖于引用文件
发布简单,只需要导出arr并直接拷贝到/Plugins/Android目录下即可使用,不用对文件做任何修改
对应android端写的 :
callUnity("Main Camera","FromAndroid", "hello unity i'm android");
所以在Main Camera这个上挂上一个脚本,写一个FromAndroid函数。
using UnityEngine;
using UnityEngine.UI;
public class main: MonoBehaviour {
/// <summary>
/// 场景上的文本框用来显示android发送过来的内容
/// </summary>
public Text text;
/// <summary>
/// android原生代码对象
/// </summary>
AndroidJavaObject _ajc;
void Start () {
//通过该API来实例化导入的arr中对应的类
#if UNITY_ANDROID && !UNITY_EDITOR
_ajc = new AndroidJavaObject("com.jing.unity.Unity2Android");
#else
#endif
}
void Update () {
}
/// <summary>
/// 场景上按点击时触发该方法
/// </summary>
public void OnBtnClick()
{
//通过API来调用原生代码的方法
#if UNITY_ANDROID && !UNITY_EDITOR
bool success = _ajc.Call<bool>("showToast","this is unity");
if(true == success)
{
//请求成功
}
#else
#endif
}
/// <summary>
/// 原生层通过该方法传回信息
/// </summary>
/// <param name="content"></param>
public void FromAndroid(string content)
{
text.text = content;
}
}
new一个java中的类实例,后续调用该类中的方法。
_ajc = new AndroidJavaObject("com.jing.unity.Unity2Android");
bool success = _ajc.Call<bool>("showToast","this is unity");
当然除了脚本之外,自行创建一个ui元素,Text,关联到脚本的Main.text上,以及写一个新建一个ui元素Button,关联点击事件。
方案二:Android端新建一个Activity继承自UnityPlayerActivity
参考教程
https://www.jianshu.com/p/7e46fe7485bb
Android端
我做的是同样在Androidstudio中新建一个Android Library Module,把unity提供的classes.jar放到libs文件夹下,然后修改模块中的build.gradle的依赖,用compileOnly把classes.jar包含进去:
dependencies {
compileOnly files('libs\\classes.jar')
}
新建一个空的Activity,修改.java内容为:
package com.test.mylibrary;
import android.os.Bundle;
import android.widget.Toast;
import android.os.Handler;
import android.os.Looper;
import com.unity3d.player.UnityPlayerActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
// 首先需要让MainActivity继承UnityPlayerActivity,因为unity导出的app的视图展示需要在UnityPlayerActivity下。
// 假如MainActivity继承的是Activity,那么显示的就是Android自己的界面。
public class MainActivity extends UnityPlayerActivity {
private Toast mToast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void showToast(final String text) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
if (mToast == null) {
mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
}
});
}
public String getNowTime() {
long time = System.currentTimeMillis();
return new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss", Locale.CHINESE).format(new Date(time));
}
}
最后同样是打包成aar,放到 Unity的Plugins/Android目录下。
Unity端
找到Editor\Data\PlaybackEngines\AndroidPlayer\Apk文件夹内(mac中存在 unity.app/Contents/PlaybackEngines/AndroidPlayer)找到AndroidManifest.xml这份文件,把它复制一份到Unity工程的Plugins/Android目录下,r然后修改启动Activity——UnityPlayerActivity,改成自己的写的MainActivity。
Unity端调用android端写的getNowTime函数和showToast函数,然后在场景中新建一个ui元素button点击让关联ShowAndroidTime函数即可以打包apk查看效果了,这里只写了unity调用android,android调用unity中的略了:
public class main : MonoBehaviour {
/// <summary>
AndroidJavaObject jo;
void Start()
{
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
#else
#endif
}
/// <summary>
/// 场景上按点击时触发该方法
/// </summary>
public void ShowAndroidTime()
{
#if UNITY_ANDROID && !UNITY_EDITOR
string time = jo.Call<string>("getNowTime");
jo.Call("showToast", new object[] { time });
#else
#endif
}
void Update()
{
}
}
Unity——为Android构建和使用插件:
Unity插件包含托管插件(managed plugins)和本地插件(native plugins,平台相关)。托管插件是指的.Net 代码,如果项目中忘记了添加插件而使用了插件中的函数,那么编译的时候就会出错。但是如果本地插件忘记添加了,而工程中使用了的话,可以正常打包,只有运行的时候才会出错。
Andriod平台的本地插件类型有:
AAR插件和Android库
JAR插件