web-dev-qa-db-fra.com

Comment écrire un horodatage de construction dans apk

  1. Apporter quelques modifications dans Android Package de contacts
  2. Utilisation de la commande mm (make) pour créer cette application

Parce que je dois changer et créer cette application encore et encore, je veux donc ajouter un horodatage de génération dans le Contacts.apk pour vérifier le temps de construction lorsque nous l'avons exécuté dans le combiné.

Comme nous le savons, lorsque nous exécutons la commande mm, la commande Android.mk (makefile) dans le package Contacts sera appelé.

Et maintenant, nous pouvons obtenir le temps de construction en utilisant la macro date-.

Mais comment pouvons-nous écrire cet horodatage de construction dans un fichier que notre application peut lire au moment de l'exécution?

Aucune suggestion?

54
FallingRain

Si vous utilisez Gradle, vous pouvez ajouter buildConfigField avec l'horodatage mis à jour au moment de la construction.

Android {
    defaultConfig {
        buildConfigField "long", "TIMESTAMP", System.currentTimeMillis() + "L"
    }
}

Lisez-le ensuite lors de l'exécution.

Date buildDate = new Date(BuildConfig.TIMESTAMP);
122
Aleksejs Mjaliks

Méthode qui vérifie la date de dernière modification de classes.dex, cela signifie la dernière fois que le code de votre application a été construit:

  try{
     ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), 0);
     ZipFile zf = new ZipFile(ai.sourceDir);
     ZipEntry ze = zf.getEntry("classes.dex");
     long time = ze.getTime();
     String s = SimpleDateFormat.getInstance().format(new Java.util.Date(time));
     zf.close();
  }catch(Exception e){
  }

Testé et fonctionne très bien, même si l'application est installée sur la carte SD.

94
Pointer Null

Depuis l'API version 9, il y a:

PackageInfo.lastUpdateTime

Heure de la dernière mise à jour de l'application.

try {
    PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
    //TODO use packageInfo.lastUpdateTime
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

Sur les versions d'API inférieures, vous devez faire vous-même le temps de construction. Par exemple, placer un fichier dans le dossier d'actifs contenant la date. Ou en utilisant la macro __ DATE__ dans le code natif. Ou vérifier la date de création de votre classes.dex (date du fichier dans votre APK).

24
Pointer Null

Un conseil pour la solution "dernière heure de modification du fichier classes.dex" et les versions plus récentes d'AndroidStudio: Dans la configuration par défaut, l'horodatage n'est plus écrit dans les fichiers du fichier apk. L'horodatage est toujours "30 novembre 1979".

Vous pouvez changer ce comportement en ajoutant cette ligne au fichier

% userdir% /. gradle/gradle.properties (créer s'il n'existe pas)

Android.keepTimestampsInApk = true

Voir problème 220039

(Doit être dans userdir, gradle.properties dans le répertoire de construction du projet ne semble pas fonctionner)

12
allofmex

dans votre build.gradle:

Android {
    defaultConfig {
        buildConfigField 'String', 'BUILD_TIME', 'new Java.text.SimpleDateFormat("MM.dd.yy HH:mm", Java.util.Locale.getDefault()).format(new Java.util.Date(' + System.currentTimeMillis() +'L))'
    }
}
7
Marco Schmitz
Install time : packageInfo.lastUpdateTime
build time   : zf.getEntry("classes.dex").getTime()

Les deux sont différents. Vous pouvez vérifier avec le code ci-dessous.

public class BuildInfoActivity extends Activity {

    private static final String TAG = BuildInfoActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {

            PackageManager pm = getPackageManager();
            PackageInfo packageInfo = null;
            try {
                packageInfo = pm.getPackageInfo(getPackageName(), 0);
            } catch (NameNotFoundException e) {
                e.printStackTrace();
            }

            // install datetime
            String appInstallDate = DateUtils.getDate(
                    "yyyy/MM/dd hh:mm:ss.SSS", packageInfo.lastUpdateTime);

            // build datetime
            String appBuildDate = DateUtils.getDate("yyyy/MM/dd hh:mm:ss.SSS",
                    DateUtils.getBuildDate(this));

            Log.i(TAG, "appBuildDate = " + appBuildDate);
            Log.i(TAG, "appInstallDate = " + appInstallDate);

        } catch (Exception e) {
        }

    }

    static class DateUtils {

        public static String getDate(String dateFormat) {
            Calendar calendar = Calendar.getInstance();
            return new SimpleDateFormat(dateFormat, Locale.getDefault())
                    .format(calendar.getTime());
        }

        public static String getDate(String dateFormat, long currenttimemillis) {
            return new SimpleDateFormat(dateFormat, Locale.getDefault())
                    .format(currenttimemillis);
        }

        public static long getBuildDate(Context context) {

            try {
                ApplicationInfo ai = context.getPackageManager()
                        .getApplicationInfo(context.getPackageName(), 0);
                ZipFile zf = new ZipFile(ai.sourceDir);
                ZipEntry ze = zf.getEntry("classes.dex");
                long time = ze.getTime();

                return time;

            } catch (Exception e) {
            }

            return 0l;
        }

    }
}
6
pretty angela

J'utilise la même stratégie que Pointer Null sauf que je préfère le fichier MANIFEST.MF. Celui-ci est régénéré même si une mise en page est modifiée (ce qui n'est pas le cas pour classes.dex). Je force également la date à être formatée en GMT pour éviter toute confusion entre les TZ du terminal et du serveur (si une comparaison doit être faite, ex: vérifier la dernière version).

Il en résulte le code suivant:

  try{
     ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), 0);
     ZipFile zf = new ZipFile(ai.sourceDir);
     ZipEntry ze = zf.getEntry("META-INF/MANIFEST.MF");
     long time = ze.getTime();
     SimpleDateFormat formatter = (SimpleDateFormat) SimpleDateFormat.getInstance();
     formatter.setTimeZone(TimeZone.getTimeZone("gmt"));
     String s = formatter.format(new Java.util.Date(time));
     zf.close();
  }catch(Exception e){
  }
5
Damien

Je sais que c'est vraiment vieux, mais voici comment je l'ai fait en utilisant ant dans Eclipse:

build.xml dans la racine du projet

<project name="set_strings_application_build_date" default="set_build_date" basedir=".">
    <description>
        This ant script updates strings.xml application_build_date to the current date
    </description>

    <!-- set global properties for this build -->
    <property name="strings.xml"  location="./res/values/strings.xml"/>

    <target name="init">
        <!-- Create the time stamp -->
        <tstamp/>
    </target>

    <target name="set_build_date" depends="init" description="sets the build date" >

        <replaceregexp file="${strings.xml}"
            match="(&lt;string name=&quot;application_build_date&quot;&gt;)\d+(&lt;/string&gt;)"
            replace="&lt;string name=&quot;application_build_date&quot;&gt;${DSTAMP}&lt;/string&gt;" />

    </target>
</project>

Ajoutez ensuite une chaîne application_build_date à votre strings.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="app_name">your app name</string>
    <string name="application_build_date">20140101</string>
    ...
</resources>

Assurez-vous que le script ant est exécuté en tant qu'activité de pré-génération et vous aurez toujours une date de construction valide à votre disposition dans R.string.application_build_date.

4
ShellDude

Donc Développeur Android - Android Studio - Astuces et recettes Gradle - Simplifiez le développement d'applications documente réellement ce qu'il faut ajouter afin d'avoir un horodatage de version disponible pour votre application:

Android {
  ...
  buildTypes {
    release {
      // These values are defined only for the release build, which
      // is typically used for full builds and continuous builds.
      buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"")
      resValue("string", "build_time", "${minutesSinceEpoch}")
      ...
    }
    debug {
      // Use static values for incremental builds to ensure that
      // resource files and BuildConfig aren't rebuilt with each run.
      // If they were dynamic, they would prevent certain benefits of
      // Instant Run as well as Gradle UP-TO-DATE checks.
      buildConfigField("String", "BUILD_TIME", "\"0\"")
      resValue("string", "build_time", "0")
    }
  }
}
...

Dans votre code d'application, vous pouvez accéder aux propriétés comme suit:

...
Log.i(TAG, BuildConfig.BUILD_TIME);
Log.i(TAG, getString(R.string.build_time));

J'inclus ceci ici car toutes les autres solutions semblent être antérieures à l'exemple officiel.

2
Morrison Chang