Apps vorbereiten für iPhone 5-Auflösung (640 x 1136)

Mit dem iPhone 5 liefert Apple nun auch einen „längeren“ Bildschirm aus, diese hat eine Auflösung von 640 x 1136 Pixel.

Wenn Ihr zur App eine Datei namens „Default-568h@2x.png“ hinzufügt wird diese auch in der neuen Auflösung lauffähig sein. Ansonsten seht ihr oben und unten immer 2 schwarze Balken.

Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

PassKit Tutorial – Teil 4: Die „Companion“-App auf dem iPhone

In diesem letzten Teil meines PassKit-Tutorials schreiben wir eine „Comapnion“-App welche die Passes noch einmal in einer eigenen App auflistet (also nicht in der PassKit-App).

Bitte habt Verständnis dass diese App ein wirklich „unschönes“ Design hat, dies könnt Ihr selbstverständlich selber „aufmöbeln“. Ich will hier vor allem zeigen wie man gut an die Daten der Passes kommt und auf diese zugreifen kann. Ich baue hier auch lediglich eine App mit einer Liste von Passes. Ihr solltet noch einen DetailViewController für die Passes implementieren wo man noch einmal alle Daten einsehen kann.

App erstellen

Los geht’s. Einfach ein neues Projekt erstellen, ich habe das „Master-Detail“ Template in XCode verwendet:

Passes holen

Wie können wir nun auf die Passes zugreifen? wir nehmen eigentlich nur Änderungen am „MasterViewController“ vor, und zwar in der Datei „MasterViewController.m“.

Wir müssen zunächst erst das PassKit-Framework einbinden. Klickt hierzu links in der Leiste mit den Dateinamen ganz oben auf das Projekt, rechts dann unter „Build Phases“, „Link Binary with Libraries“ und fügt dort „PassKit.framework“ hinzu:

Das Framework muss ganz oben im MasterViewController.m eingebunden werden:

#import <PassKit/PassKit.h>

Wir definieren auch neben zwei weiter private Variable namens _passLibrary und _passes. In _passLibrary wird eine Instanz auf die „Pass-Bibliothek“ instanziert. Hier sind alle Passes gespeichert. In _passes lesen wir aus der Bibliothek gleich die Passes aus:

@interface MasterViewController () {
    PKPassLibrary *_passLibrary;
    NSArray *_passes;
}
@end

In der Methode zum Initialisieren (awakeFronNib oder initWithNibName:bundle:) erweitern wir den Code dass die Passes in der Variable _passes gespeichert werden:

    _passLibrary = [[PKPassLibrary alloc] init];
    _passes = [_passLibrary passes];

In diesen Methode geben wir an wie viele Zeilen angezeigt werden und wie die Zeilen in der Table auszusehen haben. Die Zeile in unserem Beispiel sehen nicht wirklich schön aus, mir geht es hier hauptsächlich darum zu zeigen wie man auf Daten des Passes zugreifen kann:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _passes.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    
    PKPass *pass = [_passes objectAtIndex:indexPath.row];
    cell.textLabel.text = [NSString stringWithFormat:@"%@, Tisch: %@",
                           [pass localizedValueForFieldKey:@"member"],
                           [pass localizedValueForFieldKey:@"tisch"]];
    return cell;
}

Ihr könnt die App aufrufen und müsstet nun einen Pass dort sehen (Name des Teilnehmers inkl. Tisch-Nr.).

Auf Änderungen am Pass reagieren

Durch eine leichte Veränderung können wir auch auf eingehende Veränderungen am Pass reagieren wenn man selbst in der App ist.

Hierzu erweitern wir erst einmal den „MasterViewController.h“ und fügen folgende Methoden-Signatur hinzu:

- (void)passesWurdenGeaendert:(NSNotification *)notification;

In der „MasterViewController.m“ erweitern wir die „Initialisierungs-Methode“ (awakeFronNib oder initWithNibName:bundle:) mit folgender Zeile:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(passesWurdenGeaendert:)
                                                 name:PKPassLibraryDidChangeNotification
                                               object:_passLibrary];

Es wird also im Notification-Center angegeben dass wenn eine „PKPassLibraryDidChangeNotification“ eintrifft die Methode passesWurdenGeaendert: aufgerufen werde soll.

Als letztens sagen wir noch was zu tun ist und implementieren die eigentliche Methode:

- (void)passesWurdenGeaendert:(NSNotification *)notification
{
    dispatch_async(dispatch_get_main_queue(), ^{
        _passes = [_passLibrary passes];
        [self.tableView reloadData];
    });
}

Hier ist auch kein großes Hexenwerk vorhanden. Zuerst wird lediglich sichergestellt dass Änderungen auf dem „Main Thread“ ausgeführt werden da das UI aktualisiert wird (dispatch_async). Als nächstes werden die aktuellen Passes aus der Bibliothek geholt und zuguterletzt wird die Tabelle aktualisiert.

Ihr könnt ja folgendes Testen: Startet die App und lasst Euch so die Passes anzeigen. Nun ändert im Web-Frontend den Tisch eines Tieilnehmers. Wenn das mit den Psuh-Notifications korrekt eingerichtet ist sollte eine solche auf dem iPhone erscheinen und sich auch die Listen-Anzeige mit dem neuen Tisch ändern.

So… nun sind wir am Ende meines kleinen PassKit-Tutorials. Ich hoffe Ihr konntet einige nütlziche Dinge daraus herausziehen die Ihr auch in Euren Apps verwenden könnt. Falls einiges unklar sein sollte schreibt dies bitte in den Kommentaren, so können alle Leser davon profitieren 🙂

Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

PassKit Tutorial – Teil 3: PHP Webservice und Push-Aktualisierung

In diesem Teil meines PassKit Tutorials will ich erklären wie die Passes auf Eurem iPhone mit dem Webservice kommunizieren um Daten auszutauschen.

Es setzt voraus dass Ihr mein Skript aus dem vorherigen Tutorial-Teil auf einem Webserver mit sicherer Verbindung am laufen habt und dies komplett konfiguriert ist (inkl. Datenbanken etc.).

Pass wird auf dem Gerät gespeichert

Der erste Schritt passiert wenn der Pass auf Eurem iPhone gespeichert wird.

Hier der genaue Ablauf was Schritt für Schritt passiert:

Anfragen von Passkit an den Webservice erfolgen alle über die URL welche in der pass.json-Datei unter „webserviceUrl“ angegeben wurde.

Die Anfrage um ein Pass zu registrieren lautet also z.B. https://webservice.url.de/passes/v1/devices/GERAETEID/registrations/pass.de.rhd.ticket/BC-15J-00001

Alle Anfragen laufen in meinem Skript über die index.php-Datei im Ordner passes. Die URL ist ja etwas länger – wird aber mittels der ModRewrite-Regel auf die index.php umgeleitet, die URL dann „zerteilt“ und geschaut welche Aktion aufgerufen werden soll.

Ein weiterer wichtiger Wert ist die Authentifizierung. Apple sendet das authToken mit, daran soll unser Webservice erkennen dass es sicht um eine autorisierte Anfrage handelt. Diesen Header-Wert auszulesen ist auch etwas trickreich. Wir kommen per PHP nicht direkt dazu diesen Wert auszulesen, hierbei müssen wir uns ebenfalls einer ModRewrite-Regel bedienen und den Header in eine Umgebungs-Variable auslesen. Die Zeile RewriteRule ^.*$ index.php [NC,L,E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] in der .htaccess-Datei leitet den Header in die Umgebugs-Variable REDIRECT_HTTP_AUTHORIZATION um welche wir unter PHP mittels $_SERVER[‚REDIRECT_HTTP_AUTHORIZATION‘] auslesen können.

Als letzten Wert sendet das Gerät noch ein Push-Token an den Webservice. Diesen Wert müssen wir in der Datenbank speichern um später Push-Nachrichten senden zu können. Das Push-Token wird als sog. „Payload“ an das PHP-Skript gesendet. Wir kommen an diesen Wert nicht per GET- oder POST-Wert sondern mittels file_get_contents(„php://input“). Der enthaltene Wert ist ein einfaches JSON-Dictionary welches wir mit json_decode() auswerten können.

Wenn alle Werte eingelesen und überprüft sind können die Werte in der Datenbank gespeichert werden. In der Tabelle „passes“ sind ja bereits die Daten zum Pass gespeichert.
Neu hinzugefügt (mit diesem Request) werden nun ein Eintrag in der Tabelle „geraete_passes“ – nämlich auf welchem Gerät der Pass gespeichert ist. Zudem wird noch in der Tabelle „geraete“ gespeichert welches Gerät mit welchem Push-Token erreichbar ist. Diese Information benötigen wir nämlich im nächsten Schritt:

Der Pass wird verändert und muss auf den Geräten aktualisiert werden

Hier beginnt nun etwas „Magie“ zu wirken 🙂 Mit Hilfe des Admin-Tools können wir ja Werte wie den Namen oder die Tisch-Nr. eines Teilnehmers ändern. Und wie von Zauberhand kann sich dann von unserem PHP-Tool aus der Pass auf das Gerät übertragen. Der Teilnehmer bekommt sofort eine Meldung dass sich der Pass geändert hat und sieht auch grafisch welcher Wert sich geändert hat.
Vorstellbar wäre so auch die Uhrzeit und Datum zu ändern, dies würde der Teilnehmer ebenfalls sehen und informiert werden falls sich die Feier z.B. um eine Woche verschiebt.

Aber hier nun eine grafische Übersicht wie das Ganze funktioniert:

Die „Kette“ begint mit dem Ändern eine Passes. In meinem Skript habe ich dann eingebaut dass direkt nachdem sich etwas geändert hat eine Push-Nachricht an die mit dem Pass verknüpften Geräte gesendet wird. Das Versenden der Push-Nachricht läuft über die Methode FJPassDevice::sendePushNotification(), hier könnt Ihr sehen wie eine leere Push-Nachricht an das Gerät gesendet wird. Eine ausführliche Beschreibung zum Senden von Push-Nachrichten findet Ihr auch hier auf der Seite: .

Nachdem das iPhone die „leere“ Push-Nachricht bekommen hat weiß es dass sich etwas an mindestens einem Pass geändert haben muss. Daher fragt es den Webservice nun ab welche Passes auf dem Gerät gespeichert sind und erhält ein Array mit den Seriennummern der Passes zurück welche in der Datenbank gespeichert sind.

Für jede Seriennummer wird eine extra Abfrage an den Webservice gesendet um die aktuellste Version des Passes abzuholen. Nachdem der aktuelle Pass aufs Gerät übertragen wurde bekommt man eine Benachrichtigung angezeigt mit einer Meldung welche Werte sich geändert haben.

Der Pass wird auf dem Gerät gelöscht

Der „letzte“ Schritt bzw. die letzte mögliche Interaktio zwischen iPhone und Webservice ist das Löschen des Passes.

Folgendes geschieht wenn man den Pass vom Gerät löscht:

Deas Gerät sendet also quasi die gleiche Anfrage wie beim „Registrieren“ eines Passes, nur Handelt es sich nicht um eine POST sonder DELETE „Request-Methode“. Auch das Push-Token wird nicht im Payload mitgesendet.

Wenn diee Anfrage beim Webservice eintrifft und die Authentifizierung stimmt sorgt das Webservice-Skript dafür dass die Einträge aus den Tabellen „geraete“ und „geraete_passes“ gelöscht werden.

Ich hoffe ich konnte Euch die Kommunikation zwischen iPhone und Webservice hier etwas näher erläutern – dieser Teil war eine kleine Erklärung zu diese Abläufen. Die genau Implementierung auf PHP-Seite könnt Ihr in meinem Beispiel-Skript finden. Ihr könnt auch selbst damit herumexperimentieren und Euch eigene Klassen erstellen um dort noch mehr Infos zu speichern. Ihr könnt auch gerne dieses Skript in eigenen Projekten verwenden, es ist absolut „Free-to-use“.

Im nächsten und letzten Teil werden wir eine kleine „Companion-App“ für’s iPhone schreiben welches einfach nur die Passes in einer eigenen App auflistet.

Veröffentlicht unter iOS, PHP | Verschlagwortet mit | 5 Kommentare

PassKit Tutorial – Teil 2: PHP Server-Skript inkl. Webservice

Willkommen im zweiten Teil meines PassKit-Tutorial. In diesem Teil zeige ich wie man Passes mit einem kleinen PHP-Skript verwaltet und so automatisiert erstellen kann.
Dann wird noch ein Webservice beschrieben welcher sich um das Registrieren und Aktualisieren der Passes kümmert.

Die Beispiel-Anwendung welche ich hier entwickelt habe soll eine Verwaltung von Eintrittskarten für eine 15-Jahres-Feier unserer früheren Online-Spielegemeinschaft BodyCount sein. In dem Skript kann man Eintrittskarten für die Teilnehmer erstellen, die PKPASS-Dateien generieren und dem Teilnehmer zumailen. In den Passes wird außerdem noch gespeichert an welchem Tisch die Teilnehmer sitzen.

Schaut Euch die Anwendung an, ich denke Ihr könnt diese auch gut erweitern und an Eure Bedürfnisse anpassen. Hier könnt Ihr das Skript herunterladen:

FJPass Bibliothek v1.0

Voraussetzungen

Um das Skript nutzen zu können benötigt Ihr einen Webserver mit PHP und MySQL (Für Windows am besten ein XAMPP bzw. MAMP für Mac). Für den Webservice wird ModRewirte benötigt, dieses Modul sollte aber bei der MAMP-Installation mitgeliefert sein so dass man nichts mehr konfigurieren muss.

Entpackt mein Skript in ein Unterverzeichnis auf Euren Webserver. Auf gewisse Verzeichnisse wird Schreibzugriff benötigt:

  • passes/temp
  • admin/smarty/cache
  • admin/smarty/templates_c

Unter PHP wird die „zip“-Erweiterung (Extension) benötigt welche für das Komprimieren der Dateien und Erstellen der pkpass-Datei verantwortlich ist.

Es wird ebenfalls vorausgesetzt dass der Befehl „openssl“ über die Kommandozeile aufgerufen werden kann. Dies wird für das Signieren des Passes benötigt. In der Regel ist dies auf MAC oder LINUX-Systemen kein Problem.

In das Verzeichnis „passes“ muss eine .htaccess-Datei erstellt werden indem die Rewrite-Regeln definiert sind. Diese ist im Package enthalten, hier aber noch einmal der Inhalt dieser Datei:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L,E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Zuguterletzt würde ich noch das Verzeichnis „admin“ mit einer .htaccess-Datei schützen dass man sich nur per Passwort einloggen kann. Dies ist aber zum Testen nicht notwendig.

Datenbank / Tabellen erstellen

Erstellt in Eurem phpMyAdmin eine leere Datenbank und legt dort folgende Tabellen an:

CREATE TABLE `passes` (
`serial` varchar(64) NOT NULL,
`passTypeID` varchar(64) NOT NULL,
`authToken` varchar(64) NOT NULL,
`lastUpdate` int(11) NOT NULL,
`teilnehmer` varchar(100) NOT NULL,
`tischNr` tinyint(4) NOT NULL,
PRIMARY KEY (`serial`)
);

In der Tabelle passes werden die eigentlichen Teilnehmer bzw. „Pass“ Informationen gespeichert. Alle Felder bis auf „teilnehmer“ und „tischNr“ sind Standard-Felder, man kann diese Tabelle ggf. mit eigenen Infos erweitern und soch später Unterklassen von FJPassStore erstellen.

Ein Beispiel einer solchen Unter-Klasse ist „BCTeilnehmer“, welche unter admin/lib/class.teilnehmer.php zu finden ist.

CREATE TABLE `pass_typen` (
`passTypeID` varchar(40) NOT NULL,
`klasse` varchar(40) NOT NULL,
PRIMARY KEY (`passTypeID`,`klasse`)
);
INSERT INTO `pass_typen` VALUES('pass.de.rhd.ticket', 'BCTeilnehmer');

In der Tabelle pass_typen wird gespeichert welcher Pass-Typ-Identifiert welche PHP-Klasse erstellen soll.
Wichtig: In meinem beispiel nutze ich den PassTypIdentifier „pass.de.rhd.ticket“, diesen müsst Ihr mit Eurem PassType-Identifier ersetzten.

CREATE TABLE `geraete_passes` (
`geraetID` varchar(64) NOT NULL,
`serial` varchar(64) NOT NULL,
PRIMARY KEY (`geraetID`,`serial`)
);

In der Tabelle geraete_passes wird gespeichert welcher Pass auf welchem Gerät gespeichert ist.

CREATE TABLE `geraete` (
`geraetID` varchar(64) NOT NULL,
`tokenID` varchar(64) NOT NULL,
PRIMARY KEY (`geraetID`,`tokenID`)
);

In der Tabelle geraete wird gespeichert welches Gerät mit welchem Push-Token zu benachrichtigen ist.

Nachdem alle Tabellen generiert wurden solltet Ihr einen MySQL-Benutzer anlegen welcher auf Eure Datenbank (mit diesen Tabellen) Zugriff haben soll (verwendet alternativ den root-Benutzer). Die MySQL-Zugangsdaten müsst Ihr später in die Konfigurations-Datei eingeben.

Verzeichnisstruktur

Wenn Ihr mein Dateien-Archiv heruntergeladen habt seht Ihr im Hauptverzeichnis folgende Dateien / Verzeichnisse:

  • admin (Verzeichnis): Hier befinden sich die Skript zum Verwalten der Passes. Schützt dieses Verzeichnis am besten mit einer .htaccess-Datei !!
  • passes (Verzeichnis): In diesem Verzeichnis befinden sich alle Haupt-Klassen, Zertifikate und der Webservice zum Verwalten der Passes. Der Aufruf von Webseiten wird per ModRewrite geregelt um den WebService so zu realisieren wie von Apple vorgegeben
  • config.inc.php: Konfigurations-Datei, tragt hier Eure MySQL-Zugangsparameter ein
  • beispiel.php: Ein einfaches Beispiel wie Ihr einfach nur einen PKPass erstellen könnt (falls Ihr nur das benötigt).

Wichtig ist auch dass Ihr die Datei config.inc.php anpasst und dort alle Werte angebt. Vor allem sind die Werte für die Datenbank-Anbindung wichtig.

Um die Passes generieren zu können müsst Ihr noch die Zertifikate in den Ordner passes/certs ablegen. Wie diese erstellt werden wurde in Teil 1 dieses Tutorials erklärt. Wichtig ist das Zertifikat (als PEM-Datei) sowie der private Key ohne Passwort – ebenfalls als PEM-Datei. Diese müssen so genannt werden wie der zugehörige PassType-Identifier.

Als Beispiel habe ich für meine Passes „pass.de.rhd.ticket“ verwendet. Wenn dies der Fall ist so müssen die beiden Dateien wie folgt im Verzeichnis „passes/certs“ liegen:

  • pass.de.rhd.ticket_cert.pem (Zerifikat)
  • pass.de.rhd.ticket_key.pem (privater Schlüssel)

Für die Push-Benachrichtigung wird noch ein Bundle benötigt welches Zertifikat und priv. Schlüssel enthält. Dies wird ganz einfach folgendermaßen erzeugt:

cat pass.de.rhd.ticket_cert.pem pass.de.rhd.ticket_key.pem > pass.de.rhd.ticket_bundle.pem

Also wird dann noch eine dritte Datei in dem Ordner passes/certs benötigt, nämlich das Bundle:

  • pass.de.rhd.ticket_bundle.pem (Bundle aus Zertifikat und Key)

Mit dem Skript könnt Ihr bereits problemlos Passes erstellen. Wenn allerdings der Webservice genutzt werden soll dann müsst Ihr dieses Skript auf einen Webserver mit sicherer Übertragung (https:// mit gültigem Zertifikat) hosten. Der Admin-Teil der Skripte ist dann beispielsweise erreichbar unter https://pass.meine-domain.de/admin und der Webservice unter https://pass.meine-domain.de/passes.

Pass Administration

Wenn Ihr alles korrekt konfiguriert habt so könnt Ihr auf Eurem Webserver die Url mit /admin aufrufen und solltet folgende Maske erhalten:

Man sieht also … nix .. jedenfalls noch nix, es gibt noch keine Teilnehmer für unsere kleine Feier. Also versuchen wir direkt einen Teilnehmer anzulegen um dann einen Pass für diesen Benutzer zu erstellen:

Die „serial“, also „Seriennummer“ des Passes könnt Ihr selbst definieren. In meinem Beispiel habe ich ein Format „BC-15J-xxxxx“ vorgegeben welches immer um 1 erhöht wird.

Das System genriert auch selbständig ein sog. „Auth Token“. Diese Zeichenkette speichern wir in der Datenbank – es wird nämlich dafür genutzt um sich am WebService zu authentifizieren. Wenn der Pass vom Benutzer auf dem iPhone gespeichert wird sendet das iPhone eine Anfrage an Euren Webservice und versucht sich mit genau diesem Athentifizierungs-Token anzumelden.

Speichern wir den Eintrag ab und navigieren wieder zurück ins Hauptmenü, dort habe ich nun einige Teilnehmer angelegt:

Um nun den Pass für „Hans Mustermann“ zu erstellen klickt einfach auf die Seriennummer BC-15J-00003, danach kann man den Pass herunterladen und dem Benutzer zu mailen.

So sieht es auf dem iPhone aus wenn man den Pass als Mail-Attachment erhält:

Wenn man den Pass öffnet sieht es folgendermaßen aus:

Nun einfach noch auf „Hinzufügen“ klicken um den Pass zu speichern. Danach ist er jederzeit in der „PassKit“ App auf dem iPhone zu betrachten.

Wenn der WebService nun korrekt eingerichtet wurde hat das iPhone auch Informationen an den WebService gesendet um ihm mitzuteilen dass der Pass auf dem Gerät installiert wurde. Ebenfalls wurden Informationen übertragen welche es dem WebService erlaubt den Pass jederzeit per Push zu aktualisieren. Schaut einfach in dem Admin-Skript ob sich in der Liste was getan hat, auf der rechten Seite sollte unter „Geräte“ etwas stehen:

Erstellen eines Passes in PHP erklärt

Zum Generieren eines Passes ist vor allem die Klasse FJPass verantwortlich. Im Prinzip erledigt diese Klasse alles was in Teil 1 des Tutorials erklärt wurde, also:

  • Erstellen der pass.json-Datei
  • Kopieren aller Bilder in den Pass
  • Erstellt die manifest.json.Datei (inkl. Berechnen der SHA1-Hashes)
  • Erstellt die Signatur (anhand Zertifikat und Key)
  • Zippt die Dateien erstellt so die pkpass-Datei

Schauen wir uns einmal die Datei beispiel.php an um zu schauen wie der Pass in unserem Beispiel erstellt wird (die gleiche Methode wird auch in BCTeilnehmer::createPass() verwendet):

/**
 * Includen der Klassen
 */
require_once 'passes/lib/class.fj_pass.php';
include 'config.inc.php';

/**
 * Erstellen eines Beispiel-Passes
 */
$pass = new FJPass(FJPass::TYP_EVENT_TICKET, $passTypeID, "BC-15J-00001", $teamIdentifier);
$pass->setDescription('Eintritskarte für BC-Jubiläum');
$pass->setRelevantDate(mktime(18, 0, 0, 4, 14, 2012));
$pass->setOrganizationName("Clan BodyCount");
if ($webServiceURL != '')
{
  $pass->setWebServiceUrlAndToken($webServiceURL, $this->authToken);
}
$pass->setForegroundColor(255, 255, 255);
$pass->setBackgroundColor(60, 65, 76);
$pass->addBarcode(new FJPassBarcode(FJPassBarcode::FORMAT_PDF417, "BC-15J-00001"));
$pass->addPrimaryField(new FJPassField('event', '15-Jahres-Feier !', 'EINTRITTSKARTE FÜR'));
$pass->addSecondaryField(new FJPassField('loc', 'Altes Schalthaus / Darmstadt', 'VERANSTALTUNGSORT', 'Der Ort hat sich geändert auf: %@'));
$pass->addAuxiliaryField(new FJPassField('datum', "14.04.2012, 18:00 Uhr", 'DATUM', 'Die 15-Jahres-Feier findet nun am %@ statt'));
$pass->addAuxiliaryField(new FJPassField('member', "BC-Fasty", 'MITGLIED'));
$pass->addAuxiliaryField(new FJPassField('tisch', "1", 'TISCH NR.', 'Dein neuer Sitzplatz für die 15-Jahres-Feier ist nun an Tisch-Nr. %@'));
$pass->addBackField(new FJPassField('infos', 'Fuer Essen und Getraenke ist gesorgt, bitte bringt gute Laune mit !!!', 'Allgemeine Infos'));
$pass->setImageSet('bodycount');
$pass->createPass();

In den ersten beiden Zeilen wird die Konfigurationsdatei gelesen, hier habt Ihr ja Angaben zu Euren Pass-Einstellungen hinterlegt.

$pass = new FJPass(FJPass::TYP_EVENT_TICKET, $passTypeID, "BC-15J-00001", $teamIdentifier);

Hier wird ein Pass-Objekt erstellt welches wir nach und nach mit Informationen füllen. Hier legen wr zunächst fest dass es sich um eine Eintrittskarte handelt (FJPass::TYP_EVENT_TICKET), die PassTypeID wird aus der Konfig-Datei geladen, die Seriennummer ist „BC-15J-00001“ und der Team-Identifier wird ebenfalls aus der Konfig-Datei gelesen.

$pass->setDescription('Eintritskarte für BC-Jubiläum');

Setzt die Beschreibung für den Pass.

$pass->setRelevantDate(mktime(18, 0, 0, 4, 14, 2012));

Hier wird ein Datum angegeben zu dem der Pass „aktiviert“ werden soll. Er ist an diesem Datum besser zugänglich.

$pass->setOrganizationName("Clan BodyCount");

Setzt den „Organisations-Namen“ für den Pass. Dieser wird in der Vorschau angezeigt.

if ($webServiceURL != '')
{
  $pass->setWebServiceUrlAndToken($webServiceURL, $this->authToken);
}

Falls in der Konfig-Datei ein Webservice angegeben ist und Ihr Euer Skript auf einem Webserver liegen habt könnt Ihr dies hier angeben. Dies wird auf jeden Fall benötigt wenn Ihr den Webservice nutzen wollt (wird im nächsten Teil des Tutorials genauer erklärt).

$pass->setForegroundColor(255, 255, 255);
$pass->setBackgroundColor(60, 65, 76);

Setzt die Vorder- und Hintergrundfarbe des Passes.

$pass->addBarcode(new FJPassBarcode(FJPassBarcode::FORMAT_PDF417, "BC-15J-00001"));

Dies sind Angaben zum Barcode des Passes. Auf dem Barcode wird „BC-15J-00001“ stehen, also die Seriennummer des Passes.

$pass->addPrimaryField(new FJPassField('event', '15-Jahres-Feier !', 'EINTRITTSKARTE FÜR'));

Nun kommen Informationen über Felder die auf dem Pass stehen. Als erstes kommt das „primäre Feld“ welches ganz oben steht: „EINTRITTSKARTE FÜR“ … „15-Jahres-Feier !“.

$pass->addSecondaryField(new FJPassField('loc', 'Altes Schalthaus / Darmstadt', 'VERANSTALTUNGSORT', 'Der Ort hat sich geändert auf: %@'));

Das sekundäre Feld steht unter dem primären Feld. Hier steht der Veranstaltungsort.

$pass->addAuxiliaryField(new FJPassField('datum', "14.04.2012, 18:00 Uhr", 'DATUM', 'Die 15-Jahres-Feier findet nun am %@ statt'));
$pass->addAuxiliaryField(new FJPassField('member', "BC-Fasty", 'MITGLIED'));
$pass->addAuxiliaryField(new FJPassField('tisch', "1", 'TISCH NR.', 'Dein neuer Sitzplatz für die 15-Jahres-Feier ist nun an Tisch-Nr. %@'));

Als nächstes kommen 3 Felder „Datum“, „Mitglied“ und „Tisch-Nr.“. Es werden jeweils auch Texte angegeben fals sich die Werte ändern. Hier dient die Zeichenkette %@ als Platzhalter für den neuen Wert. Wenn das Skript voll funktionsfähig ist seht ihr auf dem Gerät dann deutlich welcher Wert sich im Pass geändert hat.

$pass->addBackField(new FJPassField('infos', 'Fuer Essen und Getraenke ist gesorgt, bitte bringt gute Laune mit !!!', 'Allgemeine Infos'));

Dies sind Informationen die auf der Rückseite des Passes abgedruckt werden.

$pass->setImageSet('bodycount');

Hier wird ein Satz von Bildern genutzt. Diese „Image Sets“ liegen unter „passes/imageset“. Gebt hier das Verzeichnis an in dem die Bilder drin liegen.

$pass->createPass();

Zuguterletzt wird der Pass generiert und im Browser erscheint eine Meldung ob die PKPass-Datei gespeichert werden soll. Ihr könnt Euch ja die Routine in der Klasse FJPass genau anschauen, dort sieht man wie ich mit PHP die PKPass-Datei genau erstelle.

Das war’s nun für den 2. Teil meines PassKit-Tutorials. Im dritten Teil erkläre ich genau den PassKit-Webservice und wie dieser mit den Passes kommuniziert.

Veröffentlicht unter iOS, PHP | Verschlagwortet mit | Hinterlasse einen Kommentar

PassKit Tutorial – Teil 1: Grundlagen, Pass erstellen

Ein neues Feature in iOS6 ist das sog. „PassKit“, also die Möglichkeit z.B. Eintrittskarten oder Gutschein-Codes auf dem iPhone (bzw. iPod-Touch) zu speichern.

In dieser Mehrteiligen Tutorial-Reihe möchte ich dieses Thema ausführlich erklären – von der einfachen Generierung eines „Pass“ zur Entwicklung eines PHP-Servers welcher die Passes generiert und verteilt.

Also fangen wir mal beim Anfang an 🙂

PassKit Typ im Provisioning Portal erstellen

Um überhaupt einen Pass erstellen zu können müsst Ihr Euch im „iOS Provisioning Portal“ einloggen (https://developer.apple.com/ios/manage/overview/index.action) und unter „Pass Type IDs“ einen neuen Eintrag anlegen. Am besten verwendet Ihr einen Eintrag welcher ungefähr die „umgekerte“ DNS-Reihenfolge Eurer Domain widerspiegelt – und danach noch ein Bezeichner wie z.B. „Eintrittskarte“. In meinem Beispiel verwende ich pass.de.rhd.ticket (pass muss immer am Anfang stehen):

Zertifikat erstellen

Als nächsten Schritt ist es ganz wichtig das Zertifikat zu erstellen. Man hat zwar einen neuen „Pass Type“ angelegt, doch noch kein Zertifikat hierfür.

Der nächste Schritt ist identisch mit dem Erstellen eines Zertifikats für den „Apple Push Service“:

  • Öffnet bei Eurem Mac die „Schlüsselbundverwaltung“
  • Unter „Schlüsselbundverwaltung“ – „Zertifikatsassisten“ – „Zertifikat einer Zertifizierungsinstanz anfordern…“ auswählen
  • Hier Eure E-Mail-Adresse angeben, als Name am besten „Pass Key für …(Pass Type ID)“ und dann „Auf Festplatte speichern“ aktivieren
  • Nun habt Ihr eine Zertifizierungs-anforderung auf der Festplatte liegene
  • Im Provsioning Profile dann unter „Pass Type IDs“ und dem kürzlich angelegten „Pass Type“ gibt es eine Option „Configure“
  • Hier werdet Ihr aufgefordert die Zertifizierungsanforderung hochzuladen
  • Nachdem diese hochgeladen wurde könnt Ihr Euch auch danach das Zertifikat herunterladen, dieses dann Doppelklicken um es zu installieren

Nachdem dies alles erledigt wurde sollte es ungefähr so aussehen:

Pass erstellen

So nun wird’s knackig, wir kommen zum Erstellen des eigentlichen Pass. Woraus besteht ein Pass eigentlich? Im Prinzip ist dies ganz einfach: ein Pass ist eine Ansammlung einiger Dateien, zu denen eine Konfiguration gehört (pass.json), einige Icon- und Hintergrund-Dateien, eine Datei welche die Prüfsummen enthält (manifest.json) sowie einer Signatur (signature). Alle Dateien werden einfach „gezippt“ nur dass die Endung dieses Archivs nicht „zip“ sondern „pkpass“ ist.

All diese Dateien legen wir in einen beliebigen Ordner auf der Festplatte. Dass Ihr dieses Tutorial besser „nachspielen“ könnt habe ich diese Dateien mit einigen Beispielgrafiken hier zum Download bereit gestellt:

Eintrittskarte-Tutorial-Pass

In meinem Beispiel will ich eine Eintrittskarte für die 15-Jahres-Feier unserer Spielegemeinschaft „BodyCount“ erstellen.

pass.json

Wichtig ist die Datei und der Aufbau der Datei „pass.json“. In der Beispiel-Datei kann man gut sehen wie die Felder vorbelegt sind. Hier gehe ich auf die wichtigsten Felder ein:

  • description: Eine kurze Beschreibung des Passes (erforderlich)
  • formatVersion: Diese ist (im Moment noch) immer 1
  • passTypeIdentifier: Hier schreibt Ihr Eure Pass Type ID hin
  • serialNumber: Eine beliebige Seriennummer welche Ihr verwendet um den Pass zu identifizieren
  • teamIdentifier: Den „teamIdentifier“ findet Ihr im unter „Your Account“
  • relevantDate: Hier könt Ihr angeben zu welchem Zeitpunkt der Pass aktiviert wird
  • barcode: Hier stehen Informationen zum Barcode
  • organizationName: Die Firma welch auf dem Pass angezeigt wird
  • foregroundColor: Vordergrund-Farbe des Passes
  • backgroundColor: Hintergrund-Farbe des Passes
  • eventTicket: Es handelt sich in unserem Beispiel um ein „Event-Ticket“, hier finden sich div. Infos über Felder welche auf dem Pass angezeigt werden.

Am besten Ihr editiert die pass.json aus meinem ZIP-File und ersetzt dann die Werte für „teamIdentifier“ und „passTypeID“

Grafiken

In dem Ordner gibt es mehrere Grafiken welche hier platziert werden können. Die wichtigsten sind:

  • icon.png: Das „icon“ wird angezeit wenn man einen Pass per Mail bekommt.
  • logo.png: Das „logo“ ist auf der linken oberen Ecke zu finden.
  • thumbnail.png (otional): Diese Grafik wird beim Event-Ticket auf der rechten Seite angezeigt

Zu jeder Grafik sollte auch eine @2x-Version mit in das Package gelegt werden (für Retina-Displays).

manifest.json

In dem Ordner liegt eine weitere Datei namens „manifest.json“. In dieser Datei stehen die SHA1-Hash-Codes der vorhandenen Dateien in dem Ordner.

Den SHA1-Hash der Datei „pass.json“ könnt Ihr durch Eingabe folgendes Befehls im Terminal bekommen:

openssl sha1 pass.json

In meiner Beispiel-Datei sind bereits alle SHA1-Codes in der manifest.json eingetragen, den SHA1-Code der pass.json müsst Ihr noch ersetzen.

Signatur erstellen

Um sicherzustellen dass der Pass auch wirklich von Euch ausgestellt wurde müsst Ihr eine Signatur erstellen. Und zwar handelt es sich hierbei um eine signierte Version der „manifest.json“-Datei (in der alle Prüfsummen der Dateien vorhanden sind).

Man benötigt hierzu zuerst einmal eine .p12-Datei des Zertifikats. In der Schlüsselbundverwaltung also das Zertifikat auswählen und Rechtsklick – exportieren klicken und irgendwo auf der Festplatte speichern. Aus dieser .p12-Datei extrahiert man nun Zertifikat und Key als .pem-Datei. Diese .pem-Dateien kann man aufheben da man sie später noch benötigt. (Dies ähnelt der Methode welche bei dem Push-Dienst benötigt wird). Hier die Kommandos (in meinem Beispiel habe ich das exportierte Zertifikat pass.p12 genannt):

openssl pkcs12 -in pass.p12 -clcerts -nokeys -out pass_certificate.pem
openssl pkcs12 -in pass.p12 -nocerts -out pass_key.pem

Desweiteren wird noch das „Zwischenterzifikat“ von Apple benötigt. Dies sollte in der Schlüsselbundverwaltung unter „Apple Worldwide Developer Relations Certification Authority“ zu finden sein. Diese Zertifikat exportieren als pem-Datei unter den Namen wwdr.pem.

Nun da wir die .pem-Dateien haben können wir die .p12-Datei löschen. Die .pem-Dateien kopiere ich nun in den gleichen Ordnier wie die manifest.json-Datei und führe zum signieren folgendes Kommando aus:

openssl smime -binary -certfile wwdr.pem -sign -signer pass_certificate.pem -inkey pass_key.pem -in manifest.json -out signature -outform DER

Hier muss man noch die „PEM Passphrase“ eingeben, also sein persönliches MAC OSX Passwort. Danach wird eine Datei namens „signature“ erstellt.

Alle Dateien zippen und Pass erstellen

Nun entfernt auf jeden Fall aus dem Verzeichnis alle unnötigen Dateien wie Zertifikate, so dass nur noch die Dateien enthalten sind die auch im Manifest aufgeführt sind PLUS die Signatur (also alle Icons, Bilder, pass.json, manifest.json, signature etc. sollen enthalten sein).

Mit diesem Befehl wird aus allen Dateien eine einzelne ZIP-komprimierte Datei mit der Endung .pkpass erstellt:

zip -r ../Ticket.pkpass -x *.DS_Store -q .

In diesem Beispiel befinden wir uns im Terminal im Verzeichnis und generieren den Pass eine Ebene höher. Warnung: ich habe hier viel Zeit investiert da ich das ZIP-Kommando versucht habe eine Ebene höher auszuführen und Dateien anstatt in dem aktuellen Ordner (.) in einem Unterordner (Ticket/*) komprimiert habe. Das Resultat war immer ein PKPass welcher nicht gelesen werden konnte 🙁

Pass verteilen

Die erstellt .pkpass-Datei kann nun z.B. per Mail an ein iPhone gesendet werden. Der Empfänger erhält eine E-Mail mit einer „Eintrittskarte“ als Anhang.

Im nächsten Teil des Tutorials werden wir einen kompletten Webservice für PHP erstellen welcher Passes verwaltet. Man kann damit also Passes erstellen und diese einem Benutzer senden (im Moment nur manuell). Beim Speichern „meldet“ sich der Pass auf Eurem Webservice und gibt ein Token zurück. Damit kann man den Pass jederzeit über Push-Notifications aktualisieren. Ein wirklich spannendes Thema, freut Euch schon mal 🙂

Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

Bildschirm reagiert in einem bestimmten Bereich nicht mehr

Ein sehr merkwürdiges Phänomen, dennoch … falls Ihr einmal darauf stoßt könnte Euch diese Lösung helfen.

Zuerst zum Problem: Heute habe ich eine meiner Apps auf die höhere iPhone 5-Auflösung angepasst. Ich habe festgestellt dass keine Reaktion vom Gerät erfolgte wenn man auf den unteren Bereich drückt. Da sich dort eine TabBar befindet reagiert das System auf keine Klicks (genau wie untere Zeilen einer UITableView).

In meiner appDelegate habe ich an den Anfang der Methode application:ddidFinishLaunchingWithOptions: folgendes gesetzt:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}

Danach konnte ich auch die TabBar wieder „wie gewohnt“ benutzten.

Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

Eigene UUID erstellen

Mit iOS5 wurde die Methode [[UIDevice currentDevice] uniqueIdentifier]
ja „deprecated“ oder „veraltet“. Apps mit diesem Code werden von Apple auch immer mehr abgelehnt.

Mit folgendem Code-Schnipsel kann man seine eigene „UUID“ erzeugen und diese dann z.B. in den UserDefaults speichern:

+ (NSString *)CreateOwnUUID
{
  CFUUIDRef _UUIDref = CFUUIDCreate(NULL);
  CFStringRef _UUIDstring = CFUUIDCreateString(NULL, _UUIDref);
  CFRelease(_UUIDref);
  return [(NSString *)_UUIDstring autorelease];
}
Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

Probleme mit htmlspecialchars() und htmlentities() nach Upgrade auf PHP 5.4

Wenn Ihr auch das Problem haben solltet dass htmlspecialchars() oder htmlentities() nichts anzeigt wenn Ihr eine Zeichenkette mit Sonderzeichen ausgeben wollt dann liegt das an folgenden:

In PHP 5.4 ist UTF8 der Standard-Zeichensatz, Euer projekt wird aber in ISO-8859-1 erstellt worden sein. Es wird dann einfach eine leere Zeichenkette ausgegeben.

Um htmlspecialchars() und htmlentities() „kompatibel“ zu machen müsst Ihr z.B. anstellen von htmlentities($text) folgendes Kommando nutzen:

htmlentities($text, ENT_COMPAT | ENT_HTML401, „ISO-8859-1“);

Veröffentlicht unter PHP | 4 Kommentare

Fehlerhafte Darstellung bei zu großen TableViewCells

Heute traf ich auf ein merkwürdiges Problem: In einer TableViewCell hatte ich ein UILabel eingebettet – in diesem befand sich ein sehr sehr langer Text.

Das Label wurde mittels sizeToFit dynamisch vergrößert und bei der TableViewCell wurde auch die Größe angepasst. Nur danach wurde der Hintergrund der Zelle nicht mehr angezeigt und auch das UILabel verschwand.

Ich fand heraus dass die maximale Größe / Höhe eines UIViews bei 16383 liegt. Ist der UIView höher wird er nicht angezeigt.

Nachdem ich folgendes eingebaut habe wurde alles korrekt angezeigt:

        if (size.height > 16383)
        {
            size.height = 16383;
        }

Dies ist keine „schöne“ Lösung da ein Teil des Textes abgeschnitten wird – jedoch im Moment die einzige die mir einfällt. Falls jemand eine bessere Lösung hat hinterlasst bitte ein Kommentar 🙂

Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

UILabel schneidet Text ab bei [label sizeToFit]

Ich hatte heute ein merkwürdiges Phänomen: Und zwar nutze ich in einer TableViewCell Labels mit unterschiedlicher Höhe.

Allerdings kommt es ab und an vor (vor allem bei wenig Text) dass Zeichen abgeschnitten werden. Aus „1234“ wird z.B. „12..“.

Dies liegt daran dass wohl ein Rechenfehler in der Größenberechnung des Labels erfolgt.

Hier eine Zwischenlösung wie dies behoben werden kann:

textLabel.inhaltLabel.numberOfLines = 0;
[textLabel sizeToFit];
       
// Bugfix für UILabel View (Breite um 1 erhöhen)
CGRect rect = textLabel.bounds;
textLabel.bounds = CGRectMake(0,0,rect.size.width+1, rect.size.height);
Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar