Определите, используется ли приложение Android в первый раз

112

В настоящее время я разрабатываю приложение для Android. Мне нужно что-то сделать при первом запуске приложения, т.е. код запускается только при первом запуске программы.

Boardy
источник
1
Когда я впервые начал создавать приложения, я думал только о первом запуске после установки приложения. Позже я понял, что мне также необходимо обрабатывать и различать первые запуски после обновлений. Ответ @ schnatterer ниже, и мой ответ здесь покажет, как это сделать. Будьте осторожны с ответами, которые не принимают во внимание обновления.
Suragch
@Suragch, ты ведешь себя так, как будто это плохая практика - не принимать во внимание обновления, но в некоторых случаях, например, когда ты представляешь приложение, ты НЕ ХОТИТЕ этого делать :)
creativecreatorormaybenot
@creativecreatorormaybenot, это правда. Бывают случаи, когда вам нужна только первоначальная установка, а не последующие обновления. Для таких ситуаций достаточно простого логического значения. Однако что, если в какой-то момент в будущем вы захотите добавить другое введение для текущих пользователей обо всех новых функциях, которые вы только что добавили в последнем обновлении? На мой взгляд, более дальновидно проверять номер версии, а не логическое значение. Это, по крайней мере, дает вам возможность в будущем ответить одним способом для новой установки и другим способом для обновления.
Suragch
1
Тогда вы просто добавляете его для этой версии, но я получаю yoz
creativecreatorormaybenot
Вы можете проверить это stackoverflow.com/a/7217834/2689076
Vaibhav

Ответы:

56

Другая идея - использовать настройку в общих настройках. Та же общая идея, что и проверка пустого файла, но тогда у вас нет пустого файла, плавающего вокруг, не используемого для хранения чего-либо.

Кевин Дион
источник
3
имейте в виду, что такой подход не может работать на Samsung Galaxy S с Android Froyo. Это из-за ошибки в сохранении SharedPreferences. Вот ссылка на SO-вопрос по этому поводу : stackoverflow.com/questions/7296163/… и вот билет в коде Google: code.google.com/p/android/issues/detail?id=14359
Francesco Rigoni
4
Остерегайтесь Android 6.0 (API 23 - Marshmallow) или выше, автоматическое резервное копирование ( developer.android.com/guide/topics/data/autobackup.html) включено по умолчанию. Если пользователь удалит, а затем переустановит приложение, общие настройки будут восстановлены. Таким образом, при переустановке вы не можете проверить, запускается ли он в первый раз после переустановки, если это вызывает какие-либо проблемы.
Алан
1
@Alan, вы правы, этот ответ больше не действителен для Android Marshmallow.
Иоанн Шарвадзе
1
@ Алан, ты не представляешь, как долго я искал такой ответ, как твой. Вы сделали мой день. Спасибо!
Антонио
@Alan Но автоматическое резервное копирование также сохраняет большинство других данных. Таким образом, вероятно, что переустановленное приложение не будет запускаться первым. И пользователь уже использовал приложение раньше, поэтому в руководстве нет необходимости. Так что в большинстве случаев я считаю, что это хорошо.
smdufb 08
112

Вы можете использовать SharedPreferences, чтобы определить, запускается ли приложение «впервые». Просто используйте логическую переменную («my_first_time») и измените ее значение на false, когда ваша задача «в первый раз» завершится .

Это мой код, который нужно поймать при первом открытии приложения:

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
источник
17
Сможет ли он справиться, когда приложение будет обновлено до следующей версии в магазине Google Play?
Шажил Афзал
4
SharedPreferences сохраняется во время обновления. Итак, я предполагаю, что при обновлении из PlayStore будет доступно старое значение. Фактически, это применимо и к другим методам, т.е. проверке существования файла. Итак, метод ярлыка в этом случае заключается в использовании другого предпочтения / имени файла или значения.
Tejasvi Hegde
@ShajeelAfzal что-то вроде этого может помочь вам public void CheckAndInitAppFirstTime () {final String PREFS_NAME = "TheAppVer"; последняя строка CHECK_VERSION = "1"; // Обязательная версия ... final String KEY_NAME = "CheckVersion"; Настройки SharedPreferences = getSharedPreferences (PREFS_NAME, 0); if (! settings.getString (KEY_NAME, "0"). equals (CHECK_VERSION)) {// приложение запускается в первый раз, сделайте что-нибудь или CHECK_VERSION отличается // ... settings.edit (). putString ( KEY_NAME, CHECK_VERSION) .commit (); }}
Tejasvi Hegde
@aman verma: согласно описанию getBoolean на сайте developer.android.com/reference/android/content/… 2-й параметр getBoolean является значением по умолчанию, если первый параметр не завершается, поэтому, если "my_first_time" не было установлено по умолчанию выражение истинно.
user2798692 08
63

Я предлагаю хранить не только логический флаг, но и полный код версии. Таким образом, вы также можете запросить в начале, является ли это первым запуском в новой версии. Вы можете использовать эту информацию, например, для отображения диалогового окна «Что нового».

Следующий код должен работать с любым классом Android, который «является контекстом» (действия, услуги, ...). Если вы предпочитаете иметь его в отдельном (POJO) классе, вы можете рассмотреть возможность использования «статического контекста», как описано здесь, например.

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

Его можно использовать в таком действии:

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

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

Базовую логику можно проверить с помощью этого теста 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));
}

Приложив немного больше усилий, вы, вероятно, сможете протестировать и все, что связано с Android (PackageManager и SharedPreferences). Кому-нибудь интересно написать тест? :)

Обратите внимание, что приведенный выше код будет работать правильно только в том случае, если вы не возитесь со своим android:versionCodeв AndroidManifest.xml!

schnatterer
источник
2
Объясните, пожалуйста, как пользоваться этим методом. Где вы инициализируете объект SharedPreferences?
Шажил Афзал
1
не работает для меня - он всегда запускает мой первый учебник
pzo
1
этот код намного более прямолинейный, без побочных эффектов объявления контекста и предпочтений в другом месте public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)- гораздо лучшая сигнатура метода
Will
2
Суть обновления этого ответа здесь gist.github.com/williscool/2a57bcd47a206e980eee. У меня возникла проблема с исходным кодом, из-за которой он навсегда застрял в моем цикле пошагового руководства, потому что номер версии никогда не пересчитывался в первом checkAppStartблоке. поэтому я решил поделиться своим обновленным кодом и посмотреть, есть ли у кого-нибудь предложения по этому поводу
Will
1
@ Спасибо за ваш вклад. Вы правы, код можно упростить и сделать более надежным. Когда я впервые опубликовал ответ, я извлек код из более сложного сценария , к которому я хотел получить доступ AppStartиз различных действий. Поэтому я вынес логику в отдельный сервисный метод. Вот почему существует contextпеременная, которая AppStartхранилась в статической переменной для облегчения вызовов идемпотентных методов.
schnatterer
4

Решил определить, приложение у вас первое или нет, в зависимости от того, обновление ли.

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

Вычислить результаты:

  • 0: Если это впервые.
  • 1: Это началось когда-либо.
  • 2: Он запускался один раз, но не в этой версии, т.е. это обновление.
Webserveis
источник
3

Вы можете использовать Android SharedPreferences .

Android SharedPreferences позволяет нам хранить частные примитивные данные приложения в виде пары ключ-значение.

КОД

Создайте собственный класс 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;
    }

}

Теперь откройте свою деятельность и инициализируйте .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Теперь вызовите это в разделе OnCreate

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Сейчас проверяю

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
источник
2

Вот код для этого -

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

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

if (!exists) {
    doSomething();                                      
}
else {
    doSomethingElse();
}
Арунабх Дас
источник
2

Именно для этого есть поддержка в версии библиотеки поддержки 23.3.0 (в версии 4, что означает совместимость с Android 1.6).

В своей деятельности Launcher сначала вызовите:

AppLaunchChecker.onActivityCreate(activity);

Тогда звоните:

AppLaunchChecker.hasStartedFromLauncher(activity);

Что вернется, если это был первый запуск приложения.

Лукас Аррефельт
источник
Порядок этих вызовов должен быть изменен на обратный, после вызова AppLaunchChecker.onActivityCreate () AppLaunchChecker.hasStartedFromLauncher () вернет true.
Гэри Кипнис
Это вводит в заблуждение. Он не говорит, было ли приложение когда-либо запущено; он, скорее, говорит, «запускалось ли приложение когда-либо пользователем из модуля запуска». Таким образом, есть вероятность, что другие приложения или внешние ссылки уже запустили приложение.
Фарид
1

Вы можете просто проверить наличие пустого файла, если он не существует, затем выполнить свой код и создать файл.

например

if(File.Exists("emptyfile"){
    //Your code here
    File.Create("emptyfile");
}
MechMK1
источник
Я думал об этом, но подумал, что должен быть лучший способ
Boardy
Я не знаю ни одного, но что за недостаток ресурсов вы получаете из-за этого? 4 байта для файла и одно «если» в начале. Системные процедуры будут делать то же самое, они будут делать то же самое или составить таблицу с приложениями, которые уже были
запущены
Аналогичным образом вы можете использовать общие настройки, которые, если они не существуют, вы показываете экран-заставку и т. Д. И просто создаете его при первом запуске программы (obv после проверки). См. Ответ Кевина выше
Stealthcopter
1

Я сделал простой класс, чтобы проверить, запускается ли ваш код в первый раз / n раз!

пример

Создайте уникальные предпочтения

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Используйте runTheFirstTime, выберите ключ, чтобы проверить ваше событие

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

Используйте runTheFirstNTimes, выберите ключ и сколько раз выполните

if(prefFirstTime.runTheFirstNTimes("anotherKey" , 5)) {
    Toast.makeText(this, "ciccia Test coutdown: "+ prefFirstTime.getCountDown("anotherKey"),
                   Toast.LENGTH_LONG).show();
}
  • Используйте getCountDown (), чтобы лучше обрабатывать ваш код

FirstTimePreference.java

Alu84
источник
1

Если вы ищете простой способ, вот он.

Создайте такой служебный класс,

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

}

В вашей основной деятельности 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
источник
1

для котлина

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

}
К. Хаоев
источник
Большое спасибо за ответ на Котлине
MMG
0

Почему бы не использовать помощник по базам данных? У этого будет хороший onCreate, который вызывается только при первом запуске приложения. Это поможет тем людям, которые хотят отслеживать это после того, как первоначальное приложение было установлено без отслеживания.

Слотт
источник
Это создает базу данных? Как использовать DatabaseHelper без создания реальной базы данных? И я думаю, onCreate()вызывается для каждой новой версии. Кроме того, не будет ли это считаться излишним или использованием чего-либо не по назначению?
ADTC
onCreate срабатывает только при первой установке приложения. Когда версия db увеличивается, запускается onUpdated.
slott
Ну излишне такое резкое слово :) - Если есть возможность т.е. ваше приложение еще не запущено, затем установите флаг SharedPrefs и используйте его, чтобы определить, загружается оно сначала или нет. У меня был случай, когда приложение какое-то время было в дикой природе, и мы использовали БД, поэтому onCreate мне идеально подошел.
slott
0

Мне нравится иметь "счетчик обновлений" в моих общих предпочтениях. Если его там нет (или нулевое значение по умолчанию), то это «первое использование» моего приложения.

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

Итак, теперь, когда есть обновление приложения, о котором должны знать пользователи, я увеличиваю UPDATE_COUNT

Эдвард Фальк
источник
-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_
источник
-2

Привет, ребята, я делаю что-то вроде этого. И это работает для меня

создать логическое поле в общих предпочтениях. Значение по умолчанию - истина {isFirstTime: true} после первого раза, когда оно установлено в ложь. В системе Android нет ничего проще и надежнее, чем это.

DropAndTrap
источник
Э, не надо так жестко указывать путь! Если вы просто сделаете Context.getSharedPreferences()это, он окажется в одном и том же месте, за исключением того, что он будет работать везде
Takhion 07
согласен с вами :)
DropAndTrap 09