在 unity3d 中实现 Android 6.0 权限 [英] Implementing Android 6.0 permissions in unity3d

查看:29
本文介绍了在 unity3d 中实现 Android 6.0 权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经安装了 Android 支持库,但在 developer.android 站点中说,为了在我的项目中实现它,我需要编辑我没有的 build.gradle 文件,因为它是一个 Unity 项目.

I've installed Android Support Library but in the developer.android site says that for implementing it on my project I need to edit my build.gradle file that I don't have because it's an Unity project.

我创建了一个 build.gradle 文件来复制本网站的内容:http://gradleplease.appspot.com/ 并且我将该文件放在我的 Unity 项目的根目录中,但是当我尝试使用该库时它不起作用

I've created a build.gradle file copying the content of this website: http://gradleplease.appspot.com/ and I put that file on the root of my Unity project but when I try to use the library it does not work

if (ContextCompat.checkSelfPermission(thisActivity,
                                      Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                                                            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                                          new String[]{Manifest.permission.READ_CONTACTS},
        MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

推荐答案

您需要 Java 代码来请求许可,并且您需要从 Unity 的 C# 运行时到所述 Java 代码的接口.您需要创建一个 Unity 插件来执行此操作.

You need Java code to ask for permission, and you need an interface into said Java code from Unity's C# runtime. You need to create a Unity Plugin to do this.

下面是我创建的插件,用于在运行时授予 WRITE_EXTERNAL_STORAGE 权限.

Below is the plugin that I've created to grant the WRITE_EXTERNAL_STORAGE permission at runtime.

您需要这样的项目结构:

You need a project structure like this:

Plugins/
  Android/
    NoodlePermissionGranter/
      project.properties
      AndroidManifest.xml
      NoodlePermissionGranter.cs
      libs/
        NoodlePermissionGranter.jar

NoodlePermissionGranter.cs:

NoodlePermissionGranter.cs:

      ///////////////////////////////////////////////////////////
     ///////////////// NoodlePermissionGranter /////////////////
    /// Implements runtime granting of Android permissions. ///
   /// This is necessary for Android M (6.0) and above. //////
  ///////////////////////////////////////////////////////////   
 //////////////////// Noodlecake Studios ///////////////////
///////////////////////////////////////////////////////////

using UnityEngine;
using System.Collections;
using System;

public class NoodlePermissionGranter : MonoBehaviour {

    // subscribe to this callback to see if your permission was granted.
    public static Action<bool> PermissionRequestCallback;

    // for now, it only implements the external storage permission
    public enum NoodleAndroidPermission
    {
        WRITE_EXTERNAL_STORAGE
    }
    public static void GrantPermission(NoodleAndroidPermission permission) 
    {
        if (!initialized)
            initialize ();

        noodlePermissionGranterClass.CallStatic ("grantPermission", activity, (int)permission);
    }







      //////////////////////////////
     /// Initialization Stuff /////
    //////////////////////////////

    // it's a singleton, but no one needs to know about it. hush hush. dont touch me.
    private static NoodlePermissionGranter instance;
    private static bool initialized = false;

    public void Awake()
    {
        // instance is also set in initialize.
        // having it here ensures this thing doesnt break
        // if you added this component to the scene manually
        instance = this;
        DontDestroyOnLoad (this.gameObject);
        // object name must match UnitySendMessage call in NoodlePermissionGranter.java
        if (name != NOODLE_PERMISSION_GRANTER)
            name = NOODLE_PERMISSION_GRANTER;
    }


    private static void initialize()
    {
        // runs once when you call GrantPermission

        // add object to scene
        if (instance == null) {
            GameObject go = new GameObject();
            // instance will also be set in awake, but having it here as well seems extra safe
            instance = go.AddComponent<NoodlePermissionGranter>();
            // object name must match UnitySendMessage call in NoodlePermissionGranter.java
            go.name = NOODLE_PERMISSION_GRANTER; 
        }

        // get the jni stuff. we need the activty class and the NoodlePermissionGranter class.
        noodlePermissionGranterClass = new AndroidJavaClass("com.noodlecake.unityplugins.NoodlePermissionGranter");
        AndroidJavaClass u3d = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
        activity = u3d.GetStatic<AndroidJavaObject> ("currentActivity");

        initialized = true;
    }







      ///////////////////
     //// JNI Stuff ////
    ///////////////////

    static AndroidJavaClass noodlePermissionGranterClass;
    static AndroidJavaObject activity;
    private const string WRITE_EXTERNAL_STORAGE="WRITE_EXTERNAL_STORAGE";
    private const string PERMISSION_GRANTED = "PERMISSION_GRANTED"; // must match NoodlePermissionGranter.java
    private const string PERMISSION_DENIED = "PERMISSION_DENIED"; // must match NoodlePermissionGranter.java
    private const string NOODLE_PERMISSION_GRANTER = "NoodlePermissionGranter"; // must match UnitySendMessage call in NoodlePermissionGranter.java

    private void permissionRequestCallbackInternal(string message)
    {
        // were calling this method from the java side.
        // the method name and gameobject must match NoodlePermissionGranter.java's UnitySendMessage
        bool permissionGranted = (message == PERMISSION_GRANTED);
        if (PermissionRequestCallback != null)
            PermissionRequestCallback (permissionGranted);
    }
}

NoodlePermissionGranter.java:

NoodlePermissionGranter.java:

package com.noodlecake.unityplugins;


      ///////////////////////////////////////////////////////////
     ///////////////// NoodlePermissionGranter /////////////////
    /// Implements runtime granting of Android permissions. ///
   /// This is necessary for Android M (6.0) and above. //////
  ///////////////////////////////////////////////////////////   
 //////////////////// Noodlecake Studios ///////////////////
///////////////////////////////////////////////////////////

import android.Manifest;
import android.os.Build;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.util.Log;
import android.content.pm.PackageManager;
import java.io.File;
import com.unity3d.player.UnityPlayerActivity;
import com.unity3d.player.UnityPlayer;

public class NoodlePermissionGranter
{
    // Only implements WRITE_EXTERNAL_STORAGE so far.
    // Implement the rest by matching the enum in NoodlePermissionGranter.cs
    // to the getPermissionStringFromEnumInt below.

    private final static String UNITY_CALLBACK_GAMEOBJECT_NAME = "NoodlePermissionGranter";
    private final static String UNITY_CALLBACK_METHOD_NAME = "permissionRequestCallbackInternal";
    private final static String PERMISSION_GRANTED = "PERMISSION_GRANTED"; // this will be an arg to the above method
    private final static String PERMISSION_DENIED = "PERMISSION_DENIED";

    public static String getPermissionStringFromEnumInt(int permissionEnum) throws Exception
    {
        switch (permissionEnum)
        {
            case 0:
                return Manifest.permission.WRITE_EXTERNAL_STORAGE;
            // "and the rest is still unwritten" - Natasha Bedingfield
        }
        Log.e("NoodlePermissionGranter", "Error. Unknown permissionEnum " + permissionEnum);
        throw new Exception(String.format("Error. Unknown permissionEnum %d",permissionEnum));
    }

    public static void grantPermission(Activity currentActivity, int permissionEnum)
    {
        // permission enum must match ordering in NoodlePermissionGranter.cs
        final Activity act = currentActivity;
        Log.i("NoodlePermissionGranter","grantPermission " + permissionEnum) ;
        if (Build.VERSION.SDK_INT < 23) {
            Log.i("NoodlePermissionGranter","Build.VERSION.SDK_INT < 23 (" + Build.VERSION.SDK_INT+")");
            UnityPlayer.UnitySendMessage(UNITY_CALLBACK_GAMEOBJECT_NAME, UNITY_CALLBACK_METHOD_NAME, PERMISSION_GRANTED);
            return;
        }

        try
        {
            final int PERMISSIONS_REQUEST_CODE = permissionEnum;
            final String permissionFromEnumInt = getPermissionStringFromEnumInt(permissionEnum);
            if (currentActivity.checkCallingOrSelfPermission(permissionFromEnumInt) == PackageManager.PERMISSION_GRANTED) {
                Log.i("NoodlePermissionGranter", "already granted");
                UnityPlayer.UnitySendMessage(UNITY_CALLBACK_GAMEOBJECT_NAME, UNITY_CALLBACK_METHOD_NAME, PERMISSION_GRANTED);
                return;
            }

            final FragmentManager fragmentManager = currentActivity.getFragmentManager();
            final Fragment request = new Fragment() {

                @Override public void onStart()
                {
                    super.onStart();
                    Log.i("NoodlePermissionGranter","fragment start");
                    String[] permissionsToRequest = new String [] {permissionFromEnumInt};
                    Log.i("NoodlePermissionGranter","fragment start " + permissionsToRequest[0]);
                    requestPermissions(permissionsToRequest, PERMISSIONS_REQUEST_CODE);
                }

                @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
                {
                    Log.i("NoodlePermissionGranter", "onRequestPermissionsResult");
                    if (requestCode != PERMISSIONS_REQUEST_CODE)
                        return;

                    if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        // permission was granted, yay! Do the
                        // contacts-related task you need to do.
                        Log.i("NoodlePermissionGranter", PERMISSION_GRANTED);
                        UnityPlayer.UnitySendMessage(UNITY_CALLBACK_GAMEOBJECT_NAME, UNITY_CALLBACK_METHOD_NAME, PERMISSION_GRANTED);
                    } else {

                        // permission denied, boo! Disable the
                        // functionality that depends on this permission.
                        Log.i("NoodlePermissionGranter",PERMISSION_DENIED);
                        UnityPlayer.UnitySendMessage(UNITY_CALLBACK_GAMEOBJECT_NAME, UNITY_CALLBACK_METHOD_NAME, PERMISSION_DENIED);
                    }


                    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                    fragmentTransaction.remove(this);
                    fragmentTransaction.commit();

                    // shouldBeOkayToStartTheApplicationNow();
                }
            };

            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(0, request);
            fragmentTransaction.commit();
        }
        catch(Exception error)
        {
            Log.w("[NoodlePermissionGranter]", String.format("Unable to request permission: %s", error.getMessage()));
            UnityPlayer.UnitySendMessage(UNITY_CALLBACK_GAMEOBJECT_NAME, UNITY_CALLBACK_METHOD_NAME, PERMISSION_DENIED);
        }
    }

}

BuildNoodlePermissionGranter.sh

BuildNoodlePermissionGranter.sh

export JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
ClASSPATH=$UNITY_ROOT"/Unity.app/Contents/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes/classes.jar"

javac NoodlePermissionGranter.java -bootclasspath $ANDROID_SDK_ROOT/platforms/android-23/android.jar -classpath $ClASSPATH -d .
javap -s com.noodlecake.unityplugins.NoodlePermissionGranter
jar cvfM NoodlePermissionGranter.jar com/
rm -rf com

您需要 project.properties 和一个虚拟的 AndroidManifest.xml 以便让 Unity 在 Plugins/Android/libs 之外打包一个 jar

You need project.properties and a dummy AndroidManifest.xml in order to have Unity package a jar outside of Plugins/Android/libs

project.properties

project.properties

target=android-9
android.library=true

AndroidManifest.xml

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.noodlecake.unityplugins.noodlepermissiongranter"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:targetSdkVersion="23" />
</manifest>

如果 PermissionRequestCallback 提供请求的权限枚举作为参数就好了,但是 UnityPlayer.UnitySendMessage 只支持单个字符串参数,我决定不实现字符串序列化(使用 JSON 来做这将是一个不错的选择)).

It'd be nice if the PermissionRequestCallback supplied the requested permission enum as a parameter, but UnityPlayer.UnitySendMessage only supports a single string argument and I decided not to implemented the string serialization (using JSON to do this would be a good choice).

这篇关于在 unity3d 中实现 Android 6.0 权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆