5

我正在使用 Unity 构建一个 android 应用程序,并且进展顺利。但是,我遇到了一个与屏幕超时和锁屏不显示有关的奇怪问题。

应该发生什么

  • 用户停止播放
  • 屏幕超时并关闭
  • 稍后,玩家返回并重新打开手机
  • 锁屏显示,用户可以输入他们的密码,或者解锁他们的手机
  • 应用程序重新获得焦点并继续

怎么了

  • 用户停止播放
  • 屏幕超时并关闭
  • 稍后,玩家返回并重新打开手机
  • 锁屏不显示!该应用程序是正确的焦点,一起绕过锁屏
  • 用户会因为他们的安全受到损害而生气:(

笔记

  • 无论我是否使用 Android 插件,都会发生这种情况
  • 我正在使用 Unity 4.2.0f4(尽管更新版本的更新日志与此问题无关)
  • 它甚至发生在一个空白的 Android 项目上
  • 我已经在 5 种不同的设备上测试过,都有相同的问题

我怀疑这是由 Unity 在屏幕超时时不会放弃的唤醒锁引起的。这会导致应用程序保持焦点,并且锁屏永远不会“加载”。这是一个相当严重的问题。

有谁知道解决这个问题的任何方法?

注意:一个多星期前,我已经在 Unity Answers 上问过这个问题,但还没有得到任何回复。我想也许我会在这里有更好的运气。

4

3 回答 3

2

首先,我要感谢MichaelTaylor3D 的回答为我指明了正确的方向。

他解决问题的方式存在一些问题,我认为我已经纠正了:

第一个问题是KeyguardManager锁定屏幕的方法。这在 API 版本 8 中已被贬值,并且不适用于 API 9+。新的解决方案使用了 Device Admin API,这对游戏来说似乎非常具有侵入性。

我查看了 Eclipse 中的 UnityPlayer 定义,发现了一个名为 setWakeLock(boolean) 的函数,但它是私有的。

我做了一个自定义的 android 活动。在其中,我访问了一个受保护的 UnityPlayer 函数setWakeLock(boolean)并在函数中调用它onPause

我承认这不太理想,但它似乎确实没有副作用。我已经向 Unity 提交了一个错误报告,所以希望这项工作不需要很长时间。

public class UnityPlayerWithLockscreen extends UnityPlayerNativeActivity {


    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
         super.onCreate(savedInstanceState);
    }

    //Provides access to the private UnityPlayer.setWakeLock(boolean) method.
    public void setWakeLock(boolean useWakelock) {
        Method setWakeLockMethod;

        //Use Reflection to get the setWakeLock(boolean) method from the UnityPlayer class
        setWakeLockMethod = mUnityPlayer.getClass().getDeclaredMethod("setWakeLock");

        //Set the method to me accessible
        setWakeLockMethod.setAccessible(true);

        //Invoke the method with our argument
        setWakeLockMethod.invoke(mUnityPlayer, useWakelock);
    }


    @Override
    protected void onPause()
    {
        super.onPause();

        //Force unity to release the wakelock
        setWakeLock(false);     
    }
}

然后你需要在 AndroidManifest 文件中将此活动设置为主要活动:

<?xml version="1.0" encoding="utf-8"?>
<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".UnityPlayerWithLockscreen"
              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>

此解决方案也不需要任何 C# 脚本或 C# <-> Java 互操作。

同样,我知道这是一种 hacky 解决方案,但它似乎可以在多个设备上运行,无论 API 级别如何,并且没有副作用。希望 Unity 很快就能解决这个问题,并且不再需要丑陋的修复。

于 2013-11-12T14:33:12.707 回答
0

这是未经测试的,但你可以试试这个,

基本上你想尝试直接访问 Android SDK,Unity 有一些类允许你这样做。

尝试编写一个外部 Java 类并将其放在 Plugins/Android 文件夹中。

Java 类方法可能是这样的:从这个问题引用 确保将其编译为 .jar 文件

package com.yourcompany.yourgamename;

import com.unity3d.player.UnityPlayerActivity;

import android.content.Context;
import android.os.Bundle;
import android.util.Config;
import android.util.Log;
import android.app.Activity;   

public class MainActivity extends UnityPlayerActivity 
{    
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
         super.onCreate(savedInstanceState);
    }

    public static void lockScreen()
    {
        KeyguardManager keyguardManager = (KeyguardManager)getSystemService(Activity.KEYGUARD_SERVICE); 
        KeyguardLock lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);  
        lock.reenableKeyguard();  
    }
}

还要确保它在 Android Manifest 文件中,以便 Unity 加载此活动而不是主要活动并将其放在 \Plugins\Android 文件夹中:

<?xml version="1.0" encoding="utf-8"?>

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".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>

然后创建一个调用外部 Java 类的 Unity C# 脚本:在此处引用

public static void InvokeAndroidLockScreen()
{
    #if UNITY_ANDROID
    using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
    {
         using (AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
         {
              obj_Activity .CallStatic("lockScreen");
         }
    }
    #else
    Debug.LogWarning("Cant invoke lockscreen on a non Android Device");
    #endif

}

然后最后在一个活动的单一行为中调用应用程序暂停事件上的锁屏:在此处引用

void OnApplicationPause(bool pauseStatus)
{
     InvokeAndroidLockScreen();
}

您必须确保将以下标志设置为 false

Application.runInBackground = false;

我会认为,否则设备关闭时不会触发暂停事件。(默认关闭)

即使这是一种解决方法,我仍然认为这是一个应该向他们报告的 Unity Bug。

于 2013-11-11T15:00:12.693 回答
0

我没有任何 Unity 经验,但尝试使用此http://developer.android.com/reference/android/os/PowerManager.WakeLock.html

用 isHeld() 查看统一是否以某种方式强制唤醒锁;并尝试在您的活动中覆盖它

编辑:我在下载时使用了唤醒锁,这会使屏幕变黑但不会锁定设备,所以可能是这种情况,所以尝试释放它,这可能会产生某种冲突,但它总是值得一试。

于 2013-11-11T12:02:45.407 回答