knuspermagier.de
Since 2005.

Optimizing your iOS workflow with fastlane

Last week I finally had some time to improve the building and distribution workflow for an iOS app we built for a client. The whole development process was a bit messy — we started with Testflight, switched to Hockeyapp when Testflight was shut down and later moved to a self hosted Enterprise distribution, because the client wanted to test the product in-house with more testers.

While the process now is a bit easier with only three different targets (dev, mainly used on my devices, test as Enterprise distribution and, of course, the App Store build) it always was a big hassle to juggle around bundle identifiers and API endpoint URLs.

So I tried to optimize the workflow. At first I tried to be extra smart and built a small Ruby script using the xcodeproj gem to change bundle identifiers and stuff, but I quickly discovered that I’m reinventing the wheel — most of the work can be done via build configurations and schemes directly in Xcode. This blog post finally helped me to understand everything. mindblown.gif

This at least made the error-prone manual editing not necessary anymore, but I still had to compile the app, export it, upload it to the test server via Transmit, tell my coworkers that a new build is available for testing, push everything to git, etc etc.

Fortunately I rediscovered fastlane. With fastlane the work is reduced to typing “fastlane testbuild” and it does everything from compiling the app to sending a slack message with the download link.

My Fastfile looks like this and was pretty easy to create:

platform :ios do
  before_all do
    ENV["SLACK_URL"] = "https://hooks.slack.com/services/..."
  end

  desc "Upload test build"
  lane :testbuild do
    increment_build_number
    bundle_version = `/usr/libexec/PlistBuddy -c Print:CFBundleVersion ../Files/Info.plist`.strip
    version = `/usr/libexec/PlistBuddy -c Print:CFBundleShortVersionString ../Files/Info.plist`.strip
    filename = "Testbuild-" + version + "-" + bundle_version + ".ipa"

    gym(
      scheme: "Testbuild",
      configuration: "Testbuild Release",
      export_method: "enterprise",
      output_directory: "build",
      output_name: filename,
      clean: true
    )
    sh "./upload.sh \"" + filename + ".ipa\""

    slack(
      message: "Testbuild-" + version + "-" + bundle_version + " is now available at XYZ",
      channel: "#alerts",
      success:  true
    )

  end
end

(Sadly I did not find a way to upload to a SFTP server without writing a shell script, but that wasn't a big deal either.)

In addition to the two or three small features I’m using fastlane provides a whole bunch more. Automatic generation of screenshots, uploading them, submitting to the App store, Certificate management, etc. I hope I get to use more of them in the future.

Musikupdate (1)

Werde ich jetzt regelmäßig über Musik posten, die ich in der letzten Zeit gehört habe? Man weiß es nicht. Anfangen kann man ja mal! Hier schonmal die passende Spotify-Playlist:


Anfang Oktober kam, für mich völlig unerwartet, ein neues Album von Samsas Traum raus. Ich bin zwar am 14.11. auf dem Konzert in Hamburg, hatte aber gar nicht auf dem Schirm, dass es dafür auch ein neues Album gibt.

“Poesie: Friedrichs Geschichte” behandelt die Zeit von 1933 — 1945 und ist textlich daher nicht unbedingt das, was ich mir zur Entspannung anhören will. Davon abgesehen, sind die Songs aber eigentlich ganz gut. Eine schwierige Platte, schade.

***

Im krassen Gegensatz dazu hörte ich letzte Woche viel von Joris, den ich über die Discover Weekly von Spotify entdeckte. Das ist einfach nur sanfte und eingängige Popmusik.


Durch einen Tweet vom @HerrBertling wurde auf Caspian aufmerksam. Die machen so… atmosphärische Instrumentalmusik. Ich hörte das glaub ich am Donnerstag den ganzen Tag beim Arbeiten und es war sehr gut.


Damit ihr total von meinem Musikgeschmack verwirrt seid, erwähne ich jetzt noch, dass am Freitag das MTV Unplugged von Revolverheld rauskam.

Ich mag die Stimme von dem Sänger, hörte mir dem Kram bisher einmal an und fand es “gut”, entdeckte jetzt aber noch noch kein Highlight.


Letzte Woche waren wir ja beim Westernhagen-Konzert in der ehemaligen o2 World in Hamburg. Am Tag danach suchte ich ein bisschen bei Youtube und fand eine Reihe von Videos mit Westernhagen und Sido. Eine komische Kombination, kann man sicher aber mal kurz anschauen.

Language Identifiers in iOS 9

Yay. In iOS 9 you may have noticed some language related issues. All my Instagram push notifications are in German instead of English, for example. After a similar problem appeared in an app we developed, I did some googling and found this technical note, which states:

With iOS 9, the results returned by NSLocale.preferredLanguages() can differ from previous releases.

TL;DR: NSLocale.preferredLanguages() now returns en-US instead of en. Update your code if you check for isEqualToString:@"en".

Erste Schritte mit Ansible

Seit Monaten bin ich auf der Suche nach einer Art Server automatisch zu konfigurieren, für die ich mich nicht drei Wochen in ein dickes Regelwerk einarbeiten muss.

Meine Anforderungen waren ja ganz einfach:

  1. Ich will bestimmen welche Pakete und Services auf dem Server sein sollen und welche Konfigurationsdateien wo rumliegen sollen. Diese sollen aus entsprechenden Templates mit Variablen generiert werden.

  2. Ich will nicht zwei Millionen verschachtelte Ordner mit tausend Dateien anlegen nur um nginx auf einem Server zu installieren.

  3. Ich will nicht auf meinem Rechner und auf dem Server zwanzig neue Services installieren müssen, damit alles automagisch zusammenfindet.

  4. Ich will eine Doku, mit der ich mir in 15 Minuten ein einfaches “nginx + PHP + mysql”-Setup-Script zusammenbauen kann, ohne von den Möglichkeiten total überwältigt zu werden.

Vor ein paar Wochen unternahm ich dann, weil ich beruflich mal wieder Server administrieren musste, einen neuen Versuch, etwas zu finden.

Folgende Sachen erfüllten meine Anforderungen leider nicht: Puppet, Chef, SaltStack.

(Das bedeutet nicht, dass sie nicht vielleicht auch dafür geeignet waren, aber ich fand in meiner Kurzrecherche nicht die nötigen Anhaltspunkte)

Zuerst dachte ich, dass auch Ansible den Test nicht bestehen wird, nach kurzem Studium der Dokumentation waren die Bedenken allerdings wie weggeblasen.

Dank des Getting Started-Guides bekam ich einen guten ersten Einblick und war tatsächlich in der Lage schnell und problemlos ein Playbook zu erstellen, mit dem ich die Server einrichten konnte.

Um diesem Post jetzt noch etwas mehr Inhalt als “Ansible ist toll” zu geben, hier ein wirklich kurzes Playbook.

Ziel soll es sein, einen Ubuntu-EC2-Server mit nginx, PHP und MySQL auszustatten.

---
- hosts: all
  gather_facts: false
  remote_user: ubuntu
  sudo: yes
  vars:
    http_port: 80
    api_root: /var/www/ansibletest.com/
  tasks:
  - name: update apt
    apt: update_cache=yes upgrade=full
  - name: install tools
    apt: name={{item}} state=present
    with_items:
      - vim
      - wget
      - curl
      - python-setuptools
      - screen

Jap. Ihr seht richtig. Yaml. Keine Ahnung was das soll, aber diesen einen Minuspunkt kann man wohl verkraften. Anscheinend startet man ein Playbook (so heißen diese Vorschriften bei Ansible) mit drei Minussen.

Dieser erste Block hier sorgt jedenfalls dafür, dass essentielle Dinge wie vim, wget und screen installiert sind. Vorher wird apt geupdated. Außerdem werden ein paar Variablen gesetzt, die später in die Konfigurations-Templates eingefügt werden. Diese können aber z.B. auch in der Host-Konfiguration pro Host, oder pro Gruppe von Hosts angegeben werden.

Sieht alles ziemlich verständlich aus, oder?

  - name: install nginx
     apt: name=nginx state=present
  - name: install php5 and modules
    apt: name={{item}} state=present
    with_items:
      - php5-fpm
      - php5-cli
      - php5-mcrypt
      - php5-curl
      - php5-mysql
      - php5-json
      - php5-readline
  - name: enable php5 modules
    shell: php5enmod mcrypt curl mysql json readline
  - name: install mysql
    apt: name=mysql-server state=present

Auch hier nur ganz einfache Anweisungen, hauptsächlich für apt. Spannender wird’s im letzten Teil, der die Konfigurationen erzeugt.

  - name: delete default config
    file: path=/etc/nginx/sites-available/default state=absent
    notify:
    - restart webserver
  - name: copy nginx config for api
    notify:
    - restart webserver
    template: src=templates/nginx-site.j2 dest=/etc/nginx/sites-available/ansibletest.conf
  - name: activate config
    file: src=/etc/nginx/sites-available/ansibletest.conf dest=/etc/nginx/sites-enabled/ansibletest.conf state=link
    notify:
    - restart webserver
  - name: ensure nginx is running
    service: name=nginx state=started enabled=yes
  - name: ensure php5-fpm is running
    service: name=php5-fpm state=started enabled=yes
handlers:
  - name: restart webserver
    service: name=nginx state=restarted
    service: name=php5-fpm state=restarted

(Die Templates spare ich mir hier jetzt mal, das sind einfache Jinja2-Templates mit {{ solchen Replacements }})

Das sieht dann schon ein bisschen unübersichtlicher aus, ist aber auch ganz einfach. Die Handler am Ende sind dann noch Tasks, die über das notify nur getriggert werden, wenn auch wirklich was passiert ist. So wird der Webserver nicht 200x neugestartet, sondern nur, wenn die Konfigurationsdatei ausgetauscht wurde.

Das ganze speichern wir jetzt als playbook.yaml.

Ansible will jetzt noch wissen, wo der Kram ausgeführt werden soll, dafür gibt es Inventory-Files. Die können auch ganz einfach aussehen:

[testserver]
ansibletest.com

Fertig. Das ganze dann mit ansible-playbook playbook.yaml -i inventory aufrufen und die Magie mit anschauen.

(Das Playbook gibt es hier nochmal am Stück als Gist)

Das war jetzt natürlich nur ein sehr kleiner Ausschnitt von dem, was mit Ansible möglich ist, und man könnte die Frage stellen, ob es sich schon für so kleine Aufgabenstellungen lohnt — ich finde aber schon. In meinem bisherigen Leben habe ich schon soviel Server aufgesetzt und immer wieder an den gleichen Stellen gegoogelt, was ich nun in die Konfiguration schreiben muss, damit PHP funktioniert, etc — hätte ich mich nur schon früher damit beschäftigt, hätte ich wohl einige Zeit gespart.

Ich freue mich auf jeden Fall darauf, Server in Zukunft nicht mehr anders vorzubereiten.

(Abgesehen vom Yaml, darauf freue ich mich nicht.)

Narcos

Vor ein paar Tagen, auf dem Rückweg vom Sport, entdeckte ich an einer Bushaltestelle mal wieder ein Netflix-Werbebanner, welches mich auf Narcos aufmerksam machte.

Ich glaube, Netflix ist die einzige Firma, deren Offline-Werbung bei mir Erfolg hat. Gerade Netflix!

Naja, ich schrieb es also auf meine Liste und schaute es jetzt am Wochenende komplett. In letzter Zeit habe ich mich echt mit Serien angefreundet, die man an ein oder zwei Wochenenden durchgucken kann. Zehn Folgen sind perfekt.

(Eventuell leichte Spoilerwarnung.)

Narcos erzählt die Geschichten von Pablo Escobar, einem übergewichtigen Drogenbaron und Steve Murphy, einem amerikanischen DEA-Agenten.

In den ersten Folgen erfährt man relativ schnell, was so von 1970-1990 passiert. Große Teile werden hier von Murphy als Off-Stimme begleitet, so dass man sich manchmal fühlt, als wäre man im Geschichtsunterricht. Durch die schnelle Reise durch die Jahre und die verschiedenen Schauplätze ging etwas das Zeitgefühl verloren und man sieht recht viele verschiedene Charaktere, so dass es schwer fällt eine Bindung aufzubauen.

Im zweiten Teil der ersten Staffel verringert sich die Geschwindigkeit dann etwas und man hat mehr Zeit durchzuatmen.

Ich weiß nicht genau, wie viel zur Story hinzugedichtet wurde, die vielen Originalaufnahmen, die zwischendurch eingespielt werden, lassen das ganze aber auf jeden Fall sehr real wirken.

(Und wenn man sich mal die Wikipedia-Seite zu Escobar und seinen ganzen Freunden durchliest, merkt man, dass es wohl nicht stark übertrieben ist.)

Narcos zeigt ganz gut, zu was für Scheiße Menschen in der Lage sind, wenn es um Geld und Macht geht. Das und die Tatsache, dass man sich auch mit keinem der Charaktere so richtig anfreunden kann, hinterlässt sie einen am Ende etwas deprimiert.

Es ist wirklich keine schöne Serie an der man Spaß hat. Trotzdem war ich spätestens nach der dritten Folge dann doch ziemlich gehooked und musste es zu Ende gucken, um zu erfahren was passiert. Wenn man sich also grundlegend für sowas interessiert, und etwas abgehärtet ist, was Gewalt in TV-Serien angeht (ich würde sagen, es ist knapp unter Daredevil-Niveau), sollte man Narcos auf jeden Fall anschauen.

Es ist wieder mal eine sehr sehr gute Netflix-Produktion und ich freue mich auf die zweite Staffel, die von Netflix bereits wenige Tage nach dem Release der ersten beauftragt wurde. Ich freue mich auf das nächste Werbebanner von Netflix.

Noch ein paar Random Facts:

  • Bestimmt 75% der Dialoge sind auf Spanisch, man ist also die ganze Zeit damit beschäftigt Untertitel zu lesen, wenn man kein Spanisch kann. Das wirkt natürlich stimmiger, ist aber auch etwas nervig.
  • Pablo guckt die ganze Zeit sooo traurig, dass man eigentlich Mitleid haben müsste
  • Ich hab etwas gebraucht um Oberyn Martell in seiner Rolle als Peña zu erkennen, freute mich dann aber umso mehr!

watched.li-2.3

(Die interne Versionsnummer ist 0.2. Ich bin schlecht in Versionsnummern.)

Heute vor einer Woche veröffentlichte ich ein Update für watched.li, welches endlich das letzte fehlende Feature aus der Alpha-Phase zurückbringt. Mit den öffentlichen Profilen könnt ihr nun euren Serien-Status überall rumzeigen, verlinken oder Ausdrucken und an die Pinnwand hängen.

U6pJqrUhAcejQzFRT.png

Neben den aktuell verfolgten und abgeschlossenen Serien gibt's eine Zusammenfassung der letzten Aktivitäten und eine Einordnung in die Rangliste aller watched.li-User. Wie interessant das ist, wird sich herausstellen.

Auch dieses mal wieder ein Danke an Hannah für die Designanpassungen und das Logo!

Flugzeuge

IMG_9316.jpg
IMG_9339.jpg

Scheint als würden die Flugzeuge an manchen Tagen so starten, dass ich sie aus dem Schlafzimmerfenster beobachten kann. Da musste ich doch direkt das alte 100-300mm-Objektiv nochmal rauskramen.

Wordpress kopieren

Ihr wollt ein Wordpress kopieren, kommt auf die glorreiche Idee, einfach die Tabellen zu exportieren, mit einem Text-Editor den Tabellen-Prefix wp durch wpneu zu ersetzen?

Vorsicht ist hier geboten. Denn spannender weise fangen auch die Keys in der options-Tabelle (z.b. wp_role und sowas...) mit dem entsprechenden Prefix an. Warum auch nicht?

Da ich jetzt nicht irgendwas kaputt machen wollte, indem ich in der gesamten .sql-Datei wp durch wpneu ersetze, legte ich einfach eine neue Datenbank an. Könnte aber auch einfach klappen. Weiß ich nicht.