Pergunta

Estou construindo um aplicativo Android usando o Unity e está indo muito bem. No entanto, estou tendo um problema estranho relacionado ao tempo de tela e à tela de bloqueio que não está sendo exibida.

O que deve acontecer

  • O usuário para de jogar
  • Tela tempos de tela e desliga
  • Mais tarde, o jogador retorna e liga o telefone de volta
  • A tela de bloqueio mostra, o usuário pode inserir sua senha ou desbloquear seu telefone
  • O aplicativo recupera o foco e continua

O que está acontecendo

  • O usuário para de jogar
  • Tela tempos de tela e desliga
  • Mais tarde, o jogador retorna e liga o telefone de volta
  • A tela de bloqueio faz NÃO mostrar! O aplicativo está em foco, ignorando a tela de bloqueio todos juntos
  • Os usuários ficam bravos por sua segurança estar comprometida :(

Notas

  • Isso acontece independentemente de estar ou não usando plugins Android
  • Estou usando o Unity 4.2.0F4 (embora os Changelogs para as versões mais recentes não tenham nada sobre esse problema)
  • Isso até acontece em um projeto em branco Android
  • Eu testei isso em 5 dispositivos diferentes, todos têm o mesmo problema

Suspeito que isso seja causado por um Wakelock que a unidade não desiste quando a tela se aproxima. Isso faz com que o aplicativo mantenha o foco e a tela de bloqueio nunca chegue a 'carregar'. Este é um problema bastante sério.

Alguém sabe de alguma maneira de consertar isso?

Nota: Eu já perguntei Esta pergunta sobre as respostas da unidade Há pouco mais de uma semana e ainda não recebi respostas. Eu pensei que talvez tivesse melhor sorte aqui.

Foi útil?

Solução

Primeiro eu gostaria de agradecer a Resposta de Michaeltaylor3d por me apontar na direção certa.

Houve alguns problemas com a maneira como ele resolveu o problema que acho que corrigi:

A primeira edição é com o KeyguardManager abordagem para travar a tela. Isso foi depreciado na API versão 8 e não funcionará na API 9+. A nova solução usa a API de administrador do dispositivo, que parece muito intrusiva para um jogo.

Eu olhei através da definição do UnityPlayer no Eclipse e encontrei uma função chamada Setwakelock (booleana), no entanto, ela é privada.

Eu fiz uma atividade Android personalizada. Nele, eu acesso uma função de unityplayer protegida setWakeLock(boolean) e chama isso no onPause função.

Admito que isso é menos do que o ideal, mas parece funcionar sem efeitos colaterais. Eu enviei um relatório de bug à Unity, por isso espero que este trabalho não seja necessário por muito tempo.

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);     
    }
}

Então você precisa definir essa atividade como a principal atividade no arquivo 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>

Esta solução também não requer scripts C# ou c# <-> Java Interop.

Novamente, eu sei que isso é uma espécie de solução hacky, mas parece funcionar em vários dispositivos, independentemente do nível da API sem efeitos colaterais. Espero que isso seja corrigido pela Unidade em breve e não exigirá mais uma correção feia.

Outras dicas

Eu não tenho nenhuma experiência da unidade, mas tente usar isso http://developer.android.com/reference/android/os/powermanager.wakelock.html

Para ver se a unidade está forçando o Wakelock de alguma forma com Isheld (); e tente substituí -lo em sua atividade

EDIT: Estou usando o Wakelock ao baixar e isso faz com que a tela fique preta, mas não bloqueando o dispositivo; portanto, esse é provavelmente o caso, então tente liberá -lo, isso pode dar algum tipo de conflito, mas sempre vale a pena tentar.

Isso não foi testado, mas você pode tentar isso,

Basicamente, você deseja tentar acessar o Android SDK diretamente, a Unity tem algumas classes que permitem fazer isso.

Tente escrever uma classe Java externa e coloque -a na pasta Plugins/Android.

O método da classe Java pode ser algo assim: referenciado a partir desta perguntacertifique -se de que é compilado em um arquivo .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();  
    }
}

Verifique também se isso está no arquivo manifesto do Android, para que a unidade carregue essa atividade em vez da principal e coloque -a na pasta 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>

Em seguida, crie um script de unidade C# que invoca a classe Java externa: referenciado aqui

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

}

Finalmente, em um monobehavior ativo, invoca a tela de bloqueio no evento de pausa do aplicativo: referenciado aqui

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

Você teria que garantir que a seguinte bandeira esteja definida como falsa

Application.runInBackground = false;

Eu pensaria que o evento de pausa não será acionado quando o dispositivo desligar. (Isso está desligado por padrão)

Mesmo que este seja um trabalho por aí, ainda acho que esse é um bug da unidade que deve ser relatou a eles.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top