23. Okt

Automatische Buildnummern/Version-Codes mit dem Ionic Framework

Heute wollen wir uns einmal mit einem eher technischen Problem befassen: Der automatischen Generierung von Buildnummern im Ionic Framework. Wir wollen also bei jeder Kompilierung unseres Quellcodes die Buildnummer, bzw. besser gesagt den Versions-Code inkrementieren. Das ist sinnvoll, um vor allem bei der Verteilung von verschiedenen Test-/Betaversionen die genaue Version ermitteln zu können. Darüber hinaus lernen wir gleich die Unterschiede zwischen Versions-Name und Versions-Code (Buildnummer) kennnen.

Einführung zu Versions-Name, Versions-Code und Buildnummer

Bei der Versionierung von Apps im Ionic Framework (aber auch generell bei der Entwicklung von iOS und/oder Android Apps) unterscheiden wir zwischen zwei Angaben. Zum Einen gibt es den Versions-Name (z.B. 1.1.0 oder 1.3.1), der die Version für den Benutzer/Endverbraucher wiederspiegelt und zum Anderen den Versions-Code, der die interne Buildnummer darstellt. Während der Entwicklung einer Version ändert sich in der Regel der Versions-Name nicht, während sich sinnvollerweise der Versions-Code bei jeder Kompilierung (bei jedem „Build“) um Eins erhöhen sollte.

Versions-Name

Der Versions-Name ist quasi die sprechende Bezeichnung der Programmversion, die auch in den App-Stores sichtbar ist. Jedes Mal wenn ihr eine neue App-Version veröffentlicht, sollte der Versions-Name höher sein, als beim letzten Mal. Beispiele:

  • 1.0.0 – Erste Version der App
  • 1.0.1 – Kritischer Fehler in der App wurde behoben
  • 1.1.0 – Neue Funktion hinzugefügt

Die erste Zahl spiegelt die Hauptversion (Major Release) wieder. Bei einer Änderung der Hauptversion sind größere bis gravierende Änderungen in der App erfolgt, z.B. Anpassung der Oberfläche, komplett neues Layout, andere Pozesse oder ähnliches. Die zweite Zahl repäsentiert die Nebenversion (Minor Release). Bei Änderungen der Nebenversion sind in der Regel neue Funktionen hinzugekommen, der generelle Ablauf und die Handhabung der App aber gleich bis ähnlich geblieben. Die dritte Zahl bezieht sich auf das Bugfixing. Bei einer Änderungen dieser Zahl sind Fehler in der App behoben oder Sicherheitspatches eingespielt worden.

Versions-Code

Der Versions-Code ist die interne Versionsnummer oder die Buildnummer, die auch bei der Veröffentlichung von Apps maßgebend ist. Ihr habt zum Beispiel eine App mit dem Versions-Name 1.0.0 und dem Versions-Code 1 veröffentlicht und merkt, dass ihr einen kleinen Fehler gemacht hat. Vielleicht ein kleiner Schreibfehler, für den es sich nicht lohnt einen neuen Versions-Namen (z.B. 1.0.1) zu veröffentlichen. Dann könnt ihr den Versions-Namen 1.0.0 beibehalten, den Fehler beheben und mit dem Versions-Code 2 veröffentlichen. Der Versions-Code muss sich also bei jeder Veröffentlichung ändern/erhöhen, sonst wird das Update bei Apple/Google abgelehnt.

Während der Entwicklung einer Version möchte man sicherlich einmal den Stand der Version 1.1.0 mit einem Kunden teilen. In der Regel wird es in diesem Prozess – je nach Rückmeldungen – einige bis viele Testupdates geben. Damit der Kunde genau weiss, mit welcher Testversion er gerade arbeitet, ist es auch hier sinnvoll bei jeder Kompilierung (einer Testversion) den Versions-Code zu erhöhen und in der App natürlich auch entsprechend auszuweisen.

Versions-Name und Versions-Code verwalten

Im Ionic Framework setzen wir die beiden Versions-Informationen in der config.xml

<widget id="de.test.appname" android-versionCode="8" ios-CFBundleVersion="8" version="1.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
...
</widget>

Die Attribute android-VersionCode und ios-CFBundeVersion entsprechen jeweils dem Version-Code, bzw. der Buildnummer für die beiden Plattformen, das Attribut version entspricht dem sprechenden Versions-Name.

Ausgabe der Version im Ionic Framework

App Version Plugin und Typescript-Code

Um Versions-Name und Versions-Code in einer Ionic App ausgeben zu können, benötigen wir das Plugin App Version, dieses müssen wir über die Kommandozeile installieren

ionic cordova plugin add cordova-plugin-app-version
npm install --save @ionic-native/app-version

und im Anschluss in der app.module.ts bekanntmachen:

import {AppVersion} from "@ionic-native/app-version";

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    ...
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: [
    AppVersion,
    ...
  ]
})
export class AppModule {}

Danach können wir die Version auf einer beliebigen Seite, zum Beispiel pages/information/information.ts ausgeben. In der Typescript-Datei laden wir die Informationen in zwei Variablen, die wir dann im Template entsprechend ausgeben können:

import {AppVersion} from "@ionic-native/app-version";

@IonicPage()
@Component({
  selector: 'page-settings',
  templateUrl: 'settings.html',
})

export class SettingsPage {

  appVersionName : string = '';
  appVersionCode : string | number = 0;

  constructor(public appVersionModule : AppVersion, public navCtrl: NavController, public navParams: NavParams) {
   
    this.appVersionModule.getVersionCode().then((code) => {
      this.appVersionCode = code;
    });
  
    this.appVersionModule.getVersionNumber().then((number) => {
      this.appVersionName = number;
    });

  }

}.

Automatische Inkrementierung des Versions-Codes, bzw. der Buildnummer

Während wir den Version-Name in der config.xml manuell verwalten möchten, soll der Versions-Code automatisch bei jedem Build hochgezählt werden – daher auch der Name Buildnummer. Dafür bedienen wir uns einem Shell-Skript, das die entsprechenden Werte in der config.xml vor der Kompilierung ändert und speichern dieses unter hooks/increment_version_code.sh ab:

#!/usr/bin/env node

var fs = require('fs');
var xml2js = require('xml2js');

fs.readFile('config.xml', 'utf8', function(err, data) {
  if(err) {
    return console.log(err);
  }

  var xml = data;
  xml2js.parseString(xml, function (err, result) {
    if(err) {
      return console.log(err);
    }

    var obj = result;

    if(typeof obj['widget']['$']['ios-CFBundleVersion'] === 'undefined') {
      obj['widget']['$']['ios-CFBundleVersion'] = 1;
    }

    if(typeof obj['widget']['$']['android-versionCode'] === 'undefined') {
      obj['widget']['$']['android-versionCode'] = 1;
    }

    obj['widget']['$']['ios-CFBundleVersion']++;
    obj['widget']['$']['android-versionCode']++;
   
    var builder = new xml2js.Builder();
    var xml = builder.buildObject(obj);

    fs.writeFile('config.xml', xml, function(err) {
      if(err) {
        return console.log(err);
      }

      console.log('Version-Code auf ' + obj['widget']['$']['ios-CFBundleVersion'] + ' aktualisiert.');
    });

  });
});

Achtung: Damit das Skript erfolgreich ausgeführt werden kann, muss das Node-Packe xml2js am besten als Dev-Dependency zum Projekt installiert werden:

npm install xml2js --save-dev

Zu guter Letzt müssen wir nur noch einen Hook auf das neuen Skript in der config.xml registrieren:

<widget id="de.test.appname" android-versionCode="8" ios-CFBundleVersion="8" version="1.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
  <hook src="hooks/increment_version_code.sh" type="before_prepare" />
</widget>

Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu.