Determine si la aplicación de Android se está utilizando por primera vez

112

Actualmente estoy desarrollando una aplicación para Android. Necesito hacer algo cuando la aplicación se inicia por primera vez, es decir, el código solo se ejecuta la primera vez que se inicia el programa.

Boardy
fuente
1
Cuando comencé a crear aplicaciones, solo pensaba en la primera ejecución después de instalar una aplicación. Más tarde me di cuenta de que también necesitaba manejar y diferenciar las primeras ejecuciones después de las actualizaciones. La respuesta de @ schnatterer a continuación y mi respuesta aquí muestran cómo hacer esto. Tenga cuidado con las respuestas que no tienen en cuenta las actualizaciones.
Suragch
@Suragch estás actuando como es una mala práctica de no tomar en cuenta las actualizaciones pero en algunos casos como tener una introducción aplicación que no quiero hacerlo :)
creativecreatorormaybenot
@creativecreatorormaybenot, eso es cierto. Hay momentos en los que solo le importa la instalación inicial y no las actualizaciones posteriores. Un simple booleano es suficiente para esas situaciones. Sin embargo, ¿qué sucede si en algún momento en el futuro desea agregar una introducción diferente para los usuarios actuales sobre todas las funciones nuevas que acaba de agregar en la última actualización? En mi opinión, es más previsible comprobar el número de versión en lugar de un booleano. Esto al menos le da la opción en el futuro de responder de una forma para una nueva instalación y de otra forma para una actualización.
Suragch
1
Luego, solo lo agrega para esta versión, pero obtengo yoz
creativecreatorormaybenot
Puede consultar esto stackoverflow.com/a/7217834/2689076
Vaibhav

Respuestas:

56

Otra idea es utilizar una configuración en las preferencias compartidas. La misma idea general que buscar un archivo vacío, pero luego no tiene un archivo vacío flotando, no se usa para almacenar nada

Kevin Dion
fuente
3
tenga en cuenta que este tipo de enfoque no podría funcionar en un Samsung Galaxy S con Android Froyo. Eso se debe a un error al guardar SharedPreferences. Aquí hay un enlace a una pregunta SO sobre eso: stackoverflow.com/questions/7296163/… y aquí está el ticket en el código de Google: code.google.com/p/android/issues/detail?id=14359
Francesco Rigoni
4
Tenga cuidado con Android 6.0 (API 23 - Marshmallow) o una copia de seguridad automática superior ( developer.android.com/guide/topics/data/autobackup.html) está habilitada de forma predeterminada. Si los usuarios desinstalan y luego reinstalan la aplicación, se recuperarán las preferencias compartidas. Por lo tanto, en las reinstalaciones no puede verificar si se está ejecutando por primera vez después de la reinstalación si esto le preocupa.
Alan
1
@Alan, tienes razón, esta respuesta ya no es válida desde Android Marshmallow.
Ioane Sharvadze
1
@Alan no puedes imaginar cuánto tiempo estuve buscando una respuesta como la tuya. Me has alegrado el día. ¡Gracias!
Antonio
@Alan Pero la copia de seguridad automática también guarda la mayoría de los datos. Por lo tanto, es probable que se espere que la aplicación reinstalada esté en un estado que no sea de primera ejecución. Y el usuario ya ha utilizado la aplicación antes, por lo que no es necesario que lo oriente. Por lo tanto, diría que en la mayoría de los casos es bueno que esto suceda.
smdufb
112

Puede utilizar SharedPreferences para identificar si es la "primera vez" que se inicia la aplicación. Simplemente use una variable booleana ("my_first_time") y cambie su valor a falso cuando su tarea por "primera vez".

Este es mi código para capturar la primera vez que abre la aplicación:

final String PREFS_NAME = "MyPrefsFile";

SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

if (settings.getBoolean("my_first_time", true)) {
    //the app is being launched for first time, do something        
    Log.d("Comments", "First time");

             // first time task

    // record the fact that the app has been started at least once
    settings.edit().putBoolean("my_first_time", false).commit(); 
}
harrakiss
fuente
17
¿Manejará cuándo la aplicación se actualizará a la próxima versión en Google Play Store?
Shajeel Afzal
4
Las preferencias compartidas se mantienen durante la actualización. Entonces, supongo que cuando se actualiza desde PlayStore, el valor anterior está disponible. De hecho, es aplicable para otros métodos, es decir, también para verificar la existencia del archivo. Por lo tanto, el método de acceso directo en ese caso es usar una preferencia / nombre de archivo o valor diferente.
Tejasvi Hegde
@ShajeelAfzal algo como esto puede ayudarte a public void CheckAndInitAppFirstTime () {final String PREFS_NAME = "TheAppVer"; Cadena final CHECK_VERSION = "1"; // Requerido ver ... final String KEY_NAME = "CheckVersion"; Configuración de SharedPreferences = getSharedPreferences (PREFS_NAME, 0); if (! settings.getString (KEY_NAME, "0"). equals (CHECK_VERSION)) {// la aplicación se inicia por primera vez, haz algo o CHECK_VERSION es diferente // ... settings.edit (). putString ( KEY_NAME, CHECK_VERSION) .commit (); }}
Tejasvi Hegde
@aman verma: según la descripción de getBoolean en developer.android.com/reference/android/content/… El segundo parámetro de getBoolean es el valor predeterminado si el primer parámetro no sale, por lo que si "my_first_time" no se ha configurado la expresión por defecto es verdadera.
user2798692
62

Sugiero no solo almacenar una bandera booleana, sino el código de versión completo. De esta forma también puede consultar al principio si es el primer inicio en una nueva versión. Puede utilizar esta información para mostrar un cuadro de diálogo "Novedades", por ejemplo.

El siguiente código debería funcionar desde cualquier clase de Android que "sea un contexto" (actividades, servicios, ...). Si prefiere tenerlo en una clase separada (POJO), podría considerar usar un "contexto estático", como se describe aquí, por ejemplo.

/**
 * Distinguishes different kinds of app starts: <li>
 * <ul>
 * First start ever ({@link #FIRST_TIME})
 * </ul>
 * <ul>
 * First start in this version ({@link #FIRST_TIME_VERSION})
 * </ul>
 * <ul>
 * Normal app start ({@link #NORMAL})
 * </ul>
 * 
 * @author schnatterer
 * 
 */
public enum AppStart {
    FIRST_TIME, FIRST_TIME_VERSION, NORMAL;
}

/**
 * The app version code (not the version name!) that was used on the last
 * start of the app.
 */
private static final String LAST_APP_VERSION = "last_app_version";

/**
 * Finds out started for the first time (ever or in the current version).<br/>
 * <br/>
 * Note: This method is <b>not idempotent</b> only the first call will
 * determine the proper result. Any subsequent calls will only return
 * {@link AppStart#NORMAL} until the app is started again. So you might want
 * to consider caching the result!
 * 
 * @return the type of app start
 */
public AppStart checkAppStart() {
    PackageInfo pInfo;
    SharedPreferences sharedPreferences = PreferenceManager
            .getDefaultSharedPreferences(this);
    AppStart appStart = AppStart.NORMAL;
    try {
        pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        int lastVersionCode = sharedPreferences
                .getInt(LAST_APP_VERSION, -1);
        int currentVersionCode = pInfo.versionCode;
        appStart = checkAppStart(currentVersionCode, lastVersionCode);
        // Update version in preferences
        sharedPreferences.edit()
                .putInt(LAST_APP_VERSION, currentVersionCode).commit();
    } catch (NameNotFoundException e) {
        Log.w(Constants.LOG,
                "Unable to determine current app version from pacakge manager. Defenisvely assuming normal app start.");
    }
    return appStart;
}

public AppStart checkAppStart(int currentVersionCode, int lastVersionCode) {
    if (lastVersionCode == -1) {
        return AppStart.FIRST_TIME;
    } else if (lastVersionCode < currentVersionCode) {
        return AppStart.FIRST_TIME_VERSION;
    } else if (lastVersionCode > currentVersionCode) {
        Log.w(Constants.LOG, "Current version code (" + currentVersionCode
                + ") is less then the one recognized on last startup ("
                + lastVersionCode
                + "). Defenisvely assuming normal app start.");
        return AppStart.NORMAL;
    } else {
        return AppStart.NORMAL;
    }
}

Podría usarse a partir de una actividad como esta:

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

        switch (checkAppStart()) {
        case NORMAL:
            // We don't want to get on the user's nerves
            break;
        case FIRST_TIME_VERSION:
            // TODO show what's new
            break;
        case FIRST_TIME:
            // TODO show a tutorial
            break;
        default:
            break;
        }

        // ...
    }
    // ...
}

La lógica básica se puede verificar usando esta prueba JUnit:

public void testCheckAppStart() {
    // First start
    int oldVersion = -1;
    int newVersion = 1;
    assertEquals("Unexpected result", AppStart.FIRST_TIME,
            service.checkAppStart(newVersion, oldVersion));

    // First start this version
    oldVersion = 1;
    newVersion = 2;
    assertEquals("Unexpected result", AppStart.FIRST_TIME_VERSION,
            service.checkAppStart(newVersion, oldVersion));

    // Normal start
    oldVersion = 2;
    newVersion = 2;
    assertEquals("Unexpected result", AppStart.NORMAL,
            service.checkAppStart(newVersion, oldVersion));
}

Con un poco más de esfuerzo, probablemente también podría probar las cosas relacionadas con Android (PackageManager y SharedPreferences). ¿Alguien interesado en escribir la prueba? :)

Tenga en cuenta que el código anterior solo funcionará correctamente si no se mete con su android:versionCodeen AndroidManifest.xml.

schnatterer
fuente
2
Explique cómo utilizar este método. ¿Dónde está inicializando el objeto SharedPreferences?
Shajeel Afzal
1
no funciona para mí - siempre
inicia
1
este código es mucho más sencillo sin los efectos secundarios de declarar el contexto y las preferencias en otros lugares public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)es una firma de método mucho mejor
Will
2
Hice una actualización de la esencia de esta respuesta aquí gist.github.com/williscool/2a57bcd47a206e980eee Tuve un problema con el código original en el que se atascaba en mi ciclo de recorrido para siempre porque el número de versión nunca se recalculaba en el primer checkAppStartbloque. así que decidí compartir mi código actualizado y ver si alguien tiene sugerencias al respecto
Will
1
@Will gracias por su aporte. Tiene razón, el código podría simplificarse y hacerse más robusto. Cuando publiqué la respuesta por primera vez, extraje el código de un escenario más complejo , donde quería acceder AppStartdesde diferentes actividades. Así que puse la lógica en un método de servicio separado. Es por eso que había una contextvariable y AppStartse almacenaba dentro de una variable estática para facilitar las llamadas a métodos idempotentes.
schnatterer
4

Resolví determinar si la aplicación es tu primera vez o no, dependiendo de si es una actualización.

private int appGetFirstTimeRun() {
    //Check if App Start First Time
    SharedPreferences appPreferences = getSharedPreferences("MyAPP", 0);
    int appCurrentBuildVersion = BuildConfig.VERSION_CODE;
    int appLastBuildVersion = appPreferences.getInt("app_first_time", 0);

    //Log.d("appPreferences", "app_first_time = " + appLastBuildVersion);

    if (appLastBuildVersion == appCurrentBuildVersion ) {
        return 1; //ya has iniciado la appp alguna vez

    } else {
        appPreferences.edit().putInt("app_first_time",
                appCurrentBuildVersion).apply();
        if (appLastBuildVersion == 0) {
            return 0; //es la primera vez
        } else {
            return 2; //es una versión nueva
        }
    }
}

Calcular resultados:

  • 0: si es la primera vez.
  • 1: Ha comenzado siempre.
  • 2: Ha comenzado una vez, pero no esa versión, es decir, es una actualización.
Webserveis
fuente
3

Puede utilizar Preferencias compartidas de Android .

Android SharedPreferences nos permite almacenar datos de aplicaciones primitivas privadas en forma de par clave-valor.

CÓDIGO

Crear una clase personalizada SharedPreference

 public class SharedPreference {

    android.content.SharedPreferences pref;
    android.content.SharedPreferences.Editor editor;
    Context _context;
    private static final String PREF_NAME = "testing";

    // All Shared Preferences Keys Declare as #public
    public static final String KEY_SET_APP_RUN_FIRST_TIME       =        "KEY_SET_APP_RUN_FIRST_TIME";


    public SharedPreference(Context context) // Constructor
    {
        this._context = context;
        pref = _context.getSharedPreferences(PREF_NAME, 0);
        editor = pref.edit();

    }

    /*
    *  Set Method Generally Store Data;
    *  Get Method Generally Retrieve Data ;
    * */


    public void setApp_runFirst(String App_runFirst)
    {
        editor.remove(KEY_SET_APP_RUN_FIRST_TIME);
        editor.putString(KEY_SET_APP_RUN_FIRST_TIME, App_runFirst);
        editor.apply();
    }

    public String getApp_runFirst()
    {
        String  App_runFirst= pref.getString(KEY_SET_APP_RUN_FIRST_TIME, "FIRST");
        return  App_runFirst;
    }

}

Ahora abra su actividad e inicialice .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Ahora llame a esto en la sección OnCreate

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Ahora comprobando

if(sharedPreferenceObj.getApp_runFirst().equals("FIRST"))
 {
   // That's mean First Time Launch
   // After your Work , SET Status NO
   sharedPreferenceObj.setApp_runFirst("NO");
 }
else
 { 
   // App is not First Time Launch
 }
IntelliJ Amiya
fuente
2

Aquí hay un código para esto:

String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/Android/data/myapp/files/myfile.txt";

boolean exists = (new File(path)).exists(); 

if (!exists) {
    doSomething();                                      
}
else {
    doSomethingElse();
}
Arunabh Das
fuente
1

Simplemente puede verificar la existencia de un archivo vacío, si no existe, luego ejecute su código y cree el archivo.

p.ej

if(File.Exists("emptyfile"){
    //Your code here
    File.Create("emptyfile");
}
MechMK1
fuente
Estaba pensando en hacer eso, pero pensé que debía haber una mejor manera
Boardy
No sé ninguno, pero ¿cuál es la falta de recursos que recibe con eso? 4 bytes para el archivo y un "si" al principio. Las rutinas del sistema harían lo mismo, harían exactamente lo mismo o crearían una tabla con aplicaciones que ya se han lanzado
MechMK1
De manera similar, puede usar las preferencias compartidas, que si no existen, muestra una pantalla de presentación, etc. y simplemente crea cuando el programa se ejecuta por primera vez (obv después de verificarlo). Vea la respuesta de Kevin arriba
stealthcopter
1

¡Hice una clase simple para verificar si su código se está ejecutando por primera vez / n veces!

Ejemplo

Crea preferencias únicas

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Use runTheFirstTime, elija una clave para verificar su evento

if (prefFirstTime.runTheFirstTime("myKey")) {
    Toast.makeText(this, "Test myKey & coutdown: " + prefFirstTime.getCountDown("myKey"),
                   Toast.LENGTH_LONG).show();
}

Use runTheFirstNTimes, elija una clave y cuántas veces ejecutar

if(prefFirstTime.runTheFirstNTimes("anotherKey" , 5)) {
    Toast.makeText(this, "ciccia Test coutdown: "+ prefFirstTime.getCountDown("anotherKey"),
                   Toast.LENGTH_LONG).show();
}
  • Use getCountDown () para manejar mejor su código

FirstTimePreference.java

Alu84
fuente
1

Solo hay soporte para esto en la revisión de la biblioteca de soporte 23.3.0 (en la v4, lo que significa compatibilidad con Android 1.6).

En su actividad de Lanzador, primero llame a:

AppLaunchChecker.onActivityCreate(activity);

Luego llame:

AppLaunchChecker.hasStartedFromLauncher(activity);

Que volverá si esta fue la primera vez que se lanzó la aplicación.

Lucas Arrefelt
fuente
El orden de estas llamadas debe invertirse, una vez que se haya llamado AppLaunchChecker.onActivityCreate (), AppLaunchChecker.hasStartedFromLauncher () devolverá verdadero.
Gary Kipnis
Esto es bastante engañoso. No dice si la aplicación "se lanzó alguna vez"; más bien, dice si la aplicación "alguna vez la lanzó un usuario desde el lanzador". Por lo tanto, existe la posibilidad de que otras aplicaciones o enlaces profundos ya hayan iniciado la aplicación.
Farid
1

Si buscas una forma sencilla, aquí la tienes.

Cree una clase de utilidad como esta,

public class ApplicationUtils {

  /**
  * Sets the boolean preference value
  *
  * @param context the current context
  * @param key     the preference key
  * @param value   the value to be set
  */
 public static void setBooleanPreferenceValue(Context context, String key, boolean value) {
     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
     sp.edit().putBoolean(key, value).apply();
 }

 /**
  * Get the boolean preference value from the SharedPreference
  *
  * @param context the current context
  * @param key     the preference key
  * @return the the preference value
  */
 public static boolean getBooleanPreferenceValue(Context context, String key) {
     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
     return sp.getBoolean(key, false);
 }

}

En su actividad principal, onCreate ()

if(!ApplicationUtils.getBooleanPreferenceValue(this,"isFirstTimeExecution")){
Log.d(TAG, "First time Execution");
ApplicationUtils.setBooleanPreferenceValue(this,"isFirstTimeExecution",true);
// do your first time execution stuff here,
}
Hardian
fuente
1

para kotlin

    fun checkFirstRun() {

    var prefs_name = "MyPrefsFile"
    var pref_version_code_key = "version_code"
    var doesnt_exist: Int = -1;

    // Get current version code
    var currentVersionCode = BuildConfig.VERSION_CODE

    // Get saved version code
    var prefs: SharedPreferences = getSharedPreferences(prefs_name, MODE_PRIVATE)
    var savedVersionCode: Int = prefs.getInt(pref_version_code_key, doesnt_exist)

    // Check for first run or upgrade
    if (currentVersionCode == savedVersionCode) {

        // This is just a normal run
        return;

    } else if (savedVersionCode == doesnt_exist) {

        // TODO This is a new install (or the user cleared the shared preferences)


    } else if (currentVersionCode > savedVersionCode) {

        // TODO This is an upgrade
    }

    // Update the shared preferences with the current version code
    prefs.edit().putInt(pref_version_code_key, currentVersionCode).apply();

}
K.Hayoev
fuente
Muchas gracias por dar respuesta en Kotlin
MMG
0

¿Por qué no utilizar el Asistente de base de datos? Esto tendrá un buen onCreate que solo se llama la primera vez que se inicia la aplicación. Esto ayudará a aquellas personas que quieran realizar un seguimiento de esto después de que se haya instalado la aplicación inicial sin seguimiento.

Slott
fuente
¿Eso crea una base de datos? ¿Cómo utilizar DatabaseHelper sin crear una base de datos real? Y creo que onCreate()se llama para cada nueva versión. Además, ¿no se consideraría superfluo o usar algo para un propósito no deseado?
ADTC
onCreate solo se activa cuando la aplicación se instala por primera vez. Cuando se incrementa la versión de db, se activa onUpdated.
slott
Bueno, superflua es una palabra tan dura :) - Si tiene la opción, es decir. su aplicación aún no está activa, luego configure un indicador SharedPrefs y utilícelo para determinar si es el primer inicio o no. Tuve un caso en el que la aplicación había estado en estado salvaje durante algún tiempo y estábamos usando una base de datos, por lo que onCreate era una combinación perfecta para mí.
slott
0

Me gusta tener un "recuento de actualizaciones" en mis preferencias compartidas. Si no está allí (o el valor cero predeterminado), entonces este es el "primer uso" de mi aplicación.

private static final int UPDATE_COUNT = 1;    // Increment this on major change
...
if (sp.getInt("updateCount", 0) == 0) {
    // first use
} else if (sp.getInt("updateCount", 0) < UPDATE_COUNT) {
    // Pop up dialog telling user about new features
}
...
sp.edit().putInt("updateCount", UPDATE_COUNT);

Así que ahora, cada vez que hay una actualización de la aplicación que los usuarios deben conocer, incremento UPDATE_COUNT

Edward Falk
fuente
-1
    /**
     * @author ALGO
     */
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.util.UUID;

    import android.content.Context;

    public class Util {
        // ===========================================================
        //
        // ===========================================================

        private static final String INSTALLATION = "INSTALLATION";

        public synchronized static boolean isFirstLaunch(Context context) {
            String sID = null;
            boolean launchFlag = false;
            if (sID == null) {
                File installation = new File(context.getFilesDir(), INSTALLATION);
                try {
                    if (!installation.exists()) {

                        writeInstallationFile(installation);
                    }
                    sID = readInstallationFile(installation);
launchFlag = true;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            return launchFlag;
        }

        private static String readInstallationFile(File installation) throws IOException {
            RandomAccessFile f = new RandomAccessFile(installation, "r");// read only mode
            byte[] bytes = new byte[(int) f.length()];
            f.readFully(bytes);
            f.close();

            return new String(bytes);
        }

        private static void writeInstallationFile(File installation) throws IOException {
            FileOutputStream out = new FileOutputStream(installation);
            String id = UUID.randomUUID().toString();
            out.write(id.getBytes());
            out.close();
        }
    }

> Usage (in class extending android.app.Activity)

Util.isFirstLaunch(this);
ARIZONA_
fuente
-2

Hola chicos, estoy haciendo algo como esto. Y funciona para mi

cree un campo booleano en preferencia compartida. El valor predeterminado es verdadero {isFirstTime: true} después de la primera vez, configúrelo en falso. Nada puede ser simple y confiable que esto en el sistema Android.

DropAndTrap
fuente
¡Uh, no codifiques el camino así! Si simplemente lo Context.getSharedPreferences()hace, terminará en el mismo lugar, excepto que funcionará en todas partes
Takhion
Estoy de