Determine se o aplicativo Android está sendo usado pela primeira vez

112

Atualmente, estou desenvolvendo um aplicativo Android. Preciso fazer algo quando o aplicativo é iniciado pela primeira vez, ou seja, o código só é executado na primeira vez que o programa é iniciado.

Boardy
fonte
1
Quando comecei a fazer aplicativos, estava pensando apenas na primeira execução após a instalação de um aplicativo. Mais tarde, percebi que também precisava lidar e diferenciar as primeiras execuções após as atualizações. A resposta de @chnatterer abaixo e minha resposta aqui mostram como fazer isso. Tenha cuidado com as respostas que não levam em consideração as atualizações.
Suragch
@Suragch, você está agindo como se não fosse uma prática ruim não levar as atualizações em consideração, mas em alguns casos, como a introdução de um aplicativo, você NÃO quer fazer :)
creativecreatorormaybenot
@creativecreatorormaybenot, isso é verdade. Há momentos em que você só se preocupa com a instalação inicial e não com as atualizações subsequentes. Um booleano simples é suficiente para essas situações. No entanto, e se em algum momento no futuro você quiser adicionar uma introdução diferente para os usuários atuais sobre todos os novos recursos que acabou de adicionar na última atualização? Na minha opinião, é mais perspicaz verificar o número da versão do que um booleano. Isso pelo menos lhe dá a opção no futuro de responder de uma forma para uma nova instalação e outra para uma atualização.
Suragch
1
Então você apenas adiciona para esta versão, mas eu recebo yoz
creativecreatorormaybenot
Você pode verificar stackoverflow.com/a/7217834/2689076
Vaibhav

Respostas:

56

Outra ideia é usar uma configuração nas Preferências compartilhadas. A mesma ideia geral que verificar se há um arquivo vazio, mas você não tem um arquivo vazio flutuando por aí, não sendo usado para armazenar nada

Kevin Dion
fonte
3
cuidado, pois esse tipo de abordagem não funcionaria em um Samsung Galaxy S com Android Froyo. Isso se deve a um bug no salvamento de SharedPreferences. Aqui está um link para uma pergunta do SO sobre isso: stackoverflow.com/questions/7296163/… e aqui está o tíquete no código do google: code.google.com/p/android/issues/detail?id=14359
Francesco Rigoni
4
Cuidado com o Android 6.0 (API 23 - Marshmallow) ou backup automático superior ( developer.android.com/guide/topics/data/autobackup.html)está habilitado por padrão. Se o usuário desinstalar e reinstalar o aplicativo, as preferências compartilhadas serão recuperadas. Portanto, nas reinstalações, você não pode verificar se está sendo executado pela primeira vez após a reinstalação, se isso for motivo de preocupação.
Alan
1
@Alan você está certo, esta resposta não é mais válida para o Android Marshmallow.
Ioane Sharvadze
1
@Alan você não pode imaginar quanto tempo eu estive procurando por uma resposta como a sua. Você fez meu dia. Obrigado!
Antonio
@Alan Mas o backup automático também salva a maioria dos outros dados. Portanto, é provável que o aplicativo reinstalado não esteja em um estado de não execução inicial. E o usuário já usou o aplicativo antes, então não há necessidade de orientação. Portanto, na maioria dos casos, eu diria que é uma coisa boa que isso aconteça.
smdufb
112

Você pode usar o SharedPreferences para identificar se é a "primeira vez" que o aplicativo é iniciado. Apenas use uma variável booleana ("my_first_time") e altere seu valor para false quando sua tarefa pela "primeira vez" terminar.

Este é o meu código para detectar a primeira vez que você abrir o aplicativo:

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
fonte
17
Será que ele aguentará quando o aplicativo será atualizado para a próxima versão na loja do Google Play?
Shajeel Afzal
4
SharedPreferences são mantidos durante a atualização. Portanto, presumo que, ao ser atualizado da PlayStore, o valor antigo estará disponível. Na verdade, é aplicável para outros métodos, ou seja, verificar a existência do arquivo também. Portanto, o método de atalho nesse caso é usar uma preferência / nome de arquivo ou valor diferente.
Tejasvi Hegde de
@ShajeelAfzal algo como isso pode ajudá-lo public void CheckAndInitAppFirstTime () {final String PREFS_NAME = "TheAppVer"; final String CHECK_VERSION = "1"; // Ver necessário ... final String KEY_NAME = "CheckVersion"; Configurações de SharedPreferences = getSharedPreferences (PREFS_NAME, 0); if (! settings.getString (KEY_NAME, "0"). equals (CHECK_VERSION)) {// o aplicativo está sendo iniciado pela primeira vez, faça algo ou CHECK_VERSION é diferente // ... settings.edit (). putString ( KEY_NAME, CHECK_VERSION) .commit (); }}
Tejasvi Hegde
@aman verma: de acordo com a descrição getBoolean em developer.android.com/reference/android/content/… o segundo parâmetro de getBoolean é o valor padrão se o primeiro parâmetro não sair, portanto, se "my_first_time" não tiver sido definido a expressão padrão é verdadeira.
user2798692
62

Eu sugiro não apenas armazenar um sinalizador booleano, mas o código de versão completo. Desta forma, você também pode consultar no início se é o primeiro início de uma nova versão. Você pode usar essas informações para exibir uma caixa de diálogo "O que há de novo", por exemplo.

O código a seguir deve funcionar em qualquer classe Android que "seja um contexto" (atividades, serviços, ...). Se você preferir tê-lo em uma classe separada (POJO), pode considerar o uso de um "contexto estático", conforme descrito aqui, por exemplo.

/**
 * 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;
    }
}

Pode ser usado a partir de uma atividade 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;
        }

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

A lógica básica pode ser verificada usando este teste 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));
}

Com um pouco mais de esforço, você provavelmente poderá testar as coisas relacionadas ao Android (PackageManager e SharedPreferences) também. Alguém está interessado em escrever o teste? :)

Observe que o código acima só funcionará corretamente se você não mexer no seu android:versionCodeAndroidManifest.xml!

schnatterer
fonte
2
Explique como usar este método. Onde você está inicializando o objeto SharedPreferences?
Shajeel Afzal
1
não funciona para mim - sempre inicia meu tutorial pela primeira vez
pzo
1
este código é muito mais direto, sem os efeitos colaterais de declarar o contexto e as preferências em outro lugar, public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)é uma assinatura de método muito melhor
Will
2
Fiz uma atualização da essência desta resposta aqui gist.github.com/williscool/2a57bcd47a206e980eee. Tive um problema com o código original em que ele ficava preso no meu loop de orientação para sempre porque o número da versão nunca estava sendo recalculado no primeiro checkAppStartbloco. então decidi compartilhar meu código atualizado e ver se alguém tem sugestões sobre ele
Will
1
@Agradecemos por sua contribuição. Você está certo, o código poderia ser simplificado e tornado mais robusto. Quando postei a resposta pela primeira vez, extraí o código de um cenário mais complexo , onde queria acessar AppStartde diferentes atividades. Portanto, coloquei a lógica em um método de serviço separado. É por isso que havia uma contextvariável e AppStartfoi armazenada em uma variável estática para facilitar chamadas de métodos idempotentes.
Schnatterer
4

Resolvi determinar se o aplicativo é a primeira vez ou não, dependendo se é uma atualização.

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

Resultados do cálculo:

  • 0: Se for a primeira vez.
  • 1: Isso já começou.
  • 2: Foi iniciado uma vez, mas não naquela versão, ou seja, é uma atualização.
Webserveis
fonte
3

Você pode usar Android SharedPreferences .

O Android SharedPreferences nos permite armazenar dados de aplicativos primitivos privados na forma de par de valores-chave.

CÓDIGO

Crie uma classe 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;
    }

}

Agora abra sua atividade e inicialize .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Agora chame isso na seção OnCreate

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Verificando agora

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
fonte
2

Aqui está um código para isso -

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

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

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

Você pode simplesmente verificar a existência de um arquivo vazio, se ele não existir, executar seu código e criar o arquivo.

por exemplo

if(File.Exists("emptyfile"){
    //Your code here
    File.Create("emptyfile");
}
MechMK1
fonte
Eu estava pensando em fazer isso, mas pensei que deveria haver uma maneira melhor
Boardy
Não conheço nenhum, mas qual é a falta de recursos que você recebe com isso? 4 bytes para o arquivo e um "if" no início. Rotinas de sistema fariam o mesmo, fariam exatamente o mesmo ou
criariam
De maneira semelhante, você pode usar as preferências compartilhadas, que se não existirem, você mostra uma tela inicial, etc ... e apenas a cria quando o programa é executado pela primeira vez (obviamente após a verificação). Veja a resposta de Kevin acima
stealthcopter
1

Fiz uma aula simples para verificar se seu código está rodando pela primeira vez / n vezes!

Exemplo

Crie preferências únicas

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Use runTheFirstTime, escolha uma chave para verificar seu evento

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

Use runTheFirstNTimes, escolha uma chave e quantas vezes execute

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

FirstTimePreference.java

Alu84
fonte
1

Há suporte apenas para isso na revisão da biblioteca de suporte 23.3.0 (na v4, que significa compatibilidade com o Android 1.6).

Em sua atividade do Launcher, primeiro chame:

AppLaunchChecker.onActivityCreate(activity);

Então ligue:

AppLaunchChecker.hasStartedFromLauncher(activity);

Que retornará se esta foi a primeira vez que o aplicativo foi iniciado.

Lucas arrefelt
fonte
A ordem dessas chamadas deve ser invertida, depois que AppLaunchChecker.onActivityCreate () for chamado, AppLaunchChecker.hasStartedFromLauncher () retornará verdadeiro.
Gary Kipnis
Isso é bastante enganador. Não diz se o aplicativo "já foi lançado"; em vez disso, diz se o aplicativo "já foi iniciado por um usuário a partir do inicializador". Portanto, existe a possibilidade de que outros aplicativos ou links diretos já tenham iniciado o aplicativo.
Farid de
1

Se procura uma forma simples, aqui está.

Crie uma classe de utilitário 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);
 }

}

Em sua atividade 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
fonte
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
fonte
Muito obrigado por responder em Kotlin
MMG
0

Por que não usar o Database Helper? Isso terá um onCreate agradável que só é chamado na primeira vez que o aplicativo é iniciado. Isso ajudará as pessoas que desejam rastrear isso depois que o aplicativo inicial for instalado sem rastreamento.

Slott
fonte
Isso cria um banco de dados? Como usar o DatabaseHelper sem criar um banco de dados real? E eu acho que onCreate()é chamado para cada nova versão. Além disso, não seria considerado supérfluo ou usar algo para um propósito não intencional?
ADTC de
onCreate só é acionado quando o aplicativo é instalado pela primeira vez. Quando a versão do banco de dados é incrementada, onUpdated é acionado.
Slott de
Bem, supérfluo é uma palavra tão dura :) - Se você tiver a opção ou seja. seu aplicativo ainda não está ativo, então configure um sinalizador SharedPrefs e use-o para determinar se é a primeira inicialização ou não. Tive um caso em que o aplicativo estava em uso há algum tempo e estávamos usando um banco de dados, então o onCreate era uma combinação perfeita para mim.
Slott de
0

Gosto de ter uma "contagem de atualização" em minhas preferências compartilhadas. Se não estiver lá (ou o valor padrão zero), este é o "primeiro uso" do meu aplicativo.

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

Agora, sempre que houver uma atualização do aplicativo que os usuários devam conhecer, eu incremento UPDATE_COUNT

Edward Falk
fonte
-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);
AZ_
fonte
-2

Olá pessoal, estou fazendo algo assim. E funciona para mim

crie um campo booleano na preferência compartilhada. O valor padrão é verdadeiro {isFirstTime: verdadeiro} após definir pela primeira vez como falso. Nada pode ser simples e confiável do que isso no sistema Android.

DropAndTrap
fonte
Uh, não codifique o caminho assim! Se você simplesmente fizer Context.getSharedPreferences(), terminará no mesmo lugar, exceto que funcionará em qualquer lugar
Takhion
concordo com você :)
DropAndTrap