unity-android 的权限

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:

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,关联点击事件。


 

image.png

 


image.png

方案二: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插件

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值