La schermata di blocco Android Unity3D non viene visualizzata quando lo schermo va in timeout.(Wakelock?)

StackOverflow https://stackoverflow.com/questions/19846822

Domanda

Sto costruendo un'app Android utilizzando Unity e sta andando molto bene.Tuttavia, sto riscontrando uno strano problema relativo al timeout dello schermo e alla mancata visualizzazione della schermata di blocco.

Cosa dovrebbe succedere

  • L'utente smette di giocare
  • Lo schermo va in timeout e si spegne
  • Successivamente, il giocatore ritorna e riaccende il telefono
  • Viene visualizzata la schermata di blocco, l'utente può inserire la password o sbloccare in altro modo il telefono
  • L'app riacquista il focus e continua

Che cosa sta accadendo

  • L'utente smette di giocare
  • Lo schermo va in timeout e si spegne
  • Successivamente, il giocatore ritorna e riaccende il telefono
  • La schermata di blocco sì NON spettacolo!L'app è perfettamente a fuoco, bypassando del tutto la schermata di blocco
  • Gli utenti si arrabbiano perché la loro sicurezza è compromessa :(

Appunti

  • Ciò accade indipendentemente dal fatto che utilizzi o meno i plug-in Android
  • Sto usando Unity 4.2.0f4 (sebbene i log delle modifiche per le versioni più recenti non contengano nulla su questo problema)
  • Succede anche su un progetto Android vuoto
  • L'ho provato su 5 dispositivi diversi, tutti hanno lo stesso problema

Sospetto che ciò sia causato da un wakelock a cui Unity non si arrende quando lo schermo va in timeout.Ciò fa sì che l'app mantenga il focus e la schermata di blocco non venga mai "caricata".Questo è un problema piuttosto serio.

Qualcuno conosce un modo per risolvere questo problema?

Nota:L'ho già chiesto questa domanda su Unity Answers poco più di una settimana fa e non ho ancora ricevuto alcuna risposta.Pensavo che forse avrei avuto più fortuna qui.

È stato utile?

Soluzione

Per prima cosa vorrei dire grazie a La risposta di MichaelTaylor3D per avermi indicato la giusta direzione.

Ci sono stati alcuni problemi nel modo in cui ha risolto il problema che penso di aver corretto:

Il primo problema riguarda il KeyguardManager approccio per bloccare lo schermo.Questo è stato deprezzato nella versione API 8 e non funzionerà sull'API 9+.La nuova soluzione utilizza l'API Device Admin che sembra molto invadente per un gioco.

Ho esaminato la definizione di UnityPlayer in Eclipse e ho trovato una funzione chiamata setWakeLock(boolean), tuttavia è privata.

Ho creato un'attività Android personalizzata.In esso accedo a una funzione protetta di UnityPlayer setWakeLock(boolean) e lo chiama nel onPause funzione.

Ammetto che questo non è proprio l'ideale, ma sembra funzionare senza effetti collaterali.Ho inviato una segnalazione di bug a Unity, quindi spero che questa soluzione non sia necessaria a lungo.

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

Quindi devi impostare questa attività come attività principale nel file 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>

Inoltre, questa soluzione non richiede script C# o interoperabilità C# <-> Java.

Ancora una volta, so che si tratta di una soluzione un po' complicata, ma sembra funzionare su diversi dispositivi indipendentemente dal livello API senza effetti collaterali.Si spera che questo venga risolto presto da Unity e non richieda più una brutta soluzione.

Altri suggerimenti

Non ho alcuna esperienza con Unity, ma prova a usarlo http://developer.android.com/reference/android/os/PowerManager.WakeLock.html

Per vedere se l'unità sta forzando il wakelock in qualche modo con isHeld();e prova a sovrascriverlo all'interno della tua attività

MODIFICARE:Sto utilizzando wakelock durante il download e questo fa sì che lo schermo diventi nero ma non blocchi il dispositivo, quindi probabilmente è così, quindi prova a rilasciarlo, questo potrebbe causare qualche tipo di conflitto ma vale sempre la pena provare.

Questo non è stato testato ma puoi provarlo,

Fondamentalmente vuoi provare ad accedere direttamente all'SDK di Android, Unity ha alcune classi che ti consentono di farlo.

Prova a scrivere una classe Java esterna e inseriscila nella cartella Plugin/Android.

Il metodo della classe Java potrebbe essere qualcosa del genere: a cui si fa riferimento da questa domandaassicurati che sia compilato in un file .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();  
    }
}

Assicurati inoltre che sia nel file Manifest di Android in modo che Unity carichi questa attività invece di quella principale e la inserisca nella cartella \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>

Quindi crea uno script Unity C# che richiama la classe Java esterna: qui citato

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

}

Quindi, infine, in un comportamento mono attivo richiama la schermata di blocco sull'evento di pausa dell'applicazione: qui citato

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

Dovresti assicurarti che il seguente flag sia impostato su false

Application.runInBackground = false;

Penserei altrimenti che l'evento di pausa non verrà attivato quando il dispositivo si spegne.(Questo è disattivato per impostazione predefinita)

Anche se si tratta di una soluzione, penso ancora che questo sia un bug di Unity che dovrebbe esserlo riferito loro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top