NSString (HTML-Inhalt) in UIWebView laden

Wenn man in einem NSString den HTML-Ingalt gespeichert hat kann man dies folgendermaßen in eine UIWebView laden:

NSString *imagePath = [[NSBundle mainBundle] resourcePath];
imagePath = [imagePath stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
imagePath = [imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"file:/%@//", imagePath]];

[webView loadHTMLString:htmlString baseURL:baseURL];
Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

Fixed und Flexible Space UIBarButtonItems erstellen

Hier der Code um UIBarButtonItems mit Fixed und Flexible Space zu erstellen:

UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

How-To: Apple Push Notification Tutorial (inkl. PHP Skript)

Ich hatte heute etwas Zeit mich mit den Apple Push Notifications (APN) zu beschäftigen und eine meiner Apps damit “aufzurüsten”. Ich muss sagen diese steigern deutlich den Wert einer App, vor allem wenn der Benutzer sofort benachrichtigt werden kann wenn er z.B. eine neue Nachricht im System bekommen hat.

Falls ihr noch nicht viel damit gemacht habt möchte ich Euch ein wenig die “Angst” nehmen und hier Schritt für Schritt zeigen wie dieses Feature eingerichtet wird. Abschließend habe ich auch ein kleines PHP-Skript abgedruckt welches dann eine Test-Notification an das iOS-Gerät sendet.

Zuerst geht Ihr natürlich im Developer Center in Euer iOS Provisioning Portal. Hier dann auf “App IDs” klicken und bei der entsprechenden App dann “Configure” aufrufen. Die folgende Maske sieht so aus:

Hier muss man bei “Development Push SSL Certificate” ebenfalls auf “Configure” klicken, wir wollen erstmal ein Entwickler-Zertifikat erstellen mit dem man etwas rumspielen kann. Danach erscheint folgender hinweis / Anleitung:

Halten wir uns mal an diese Anleitung. Also noch nicht auf “Continue” klicken sondern erst ein Zertifikats-Request erstellen (Dies ist das gleiche wie im letzten Artikel beschrieben wurde).
Öffnet das Programm “Schlüsselbundverwaltung” und klickt dort im Menü “Schlüsselbundverwaltung” auf “Zertifikatsassistent” und dann auf “Zertifikat einer Zertifizierungsstelle anfordern…”:

Im folgenden Fenster Eure E-Mail-Adresse angeben und den Namen (am besten noch vermerken dass es ein APN Key ist, bei sehr vielen privaten Schlüsseln im Schlüsselbund kann man diese einfach auseinanderhalten). Wichtig ist noch die Option “Auf Festplatte speichern” zu aktivieren:

Die Zertifikatsanforderung dann einfach irgendwo speichern. Nachdem diese gespeichert wurde kann man im “Provisioning Portal” dann weitermachen. In der Maske auf “Continue” klicken und in der nächsten Maske dann die Zertifikatsanforderung hochladen:

Danach erscheint dann zuerst die Meldung dass das Zertifikat erstellt wird:

Kurze Zeit später ist das Zertifikat generiert und man kann es sich irgendwo auf der Festplatte abspeichern:

Wen Ihr Euch das Zertifikat heruntergeladen habt einfach einen Doppelklick darauf ausführen, es wird dann ebenfalls in Euren Schlüsselbund kopiert. Man sieht dies dann unter dem entsprechenden privaten Schlüssel:

Dies war der erste Teil der Prozedur. Kurze Zusammenfassung bisher: wir haben für unsere App im Provisioning Portal ein Zertifikat für die Push Notification Dienste erzeugt und dies in unseren Schlüsselbund aufgenommen.

Im folgenden Teil erzeugen wir ein kleines Bundle bestehend aus dem Zertifikat plus privaten Schlüssel. Dies wird nämlich für den Webserver benötigt der die Benachrichtigungen an das iOS-Gerät senden soll.

Also.. weiter geht’s. Öffnet Eure Schlüsselbundverwaltung, klickt dann links auf “Schlüssel” und sucht den privaten Schlüssel für die APN Dienste (den wir im ersten Schritt erstellt haben). Ihr könnt dies auch gut sehen: Wenn Ihr diesen aufklappt sollte ein Eintrag mit dem Zertifikat “Apple Development Push Service …” enthalten sein.

Dieser Schlüssel muss als erstes exportiert werden. Einfach ein Rechtsklick auf den Schlüssel ausführen und auf “… Key exportieren” klicken:

Gebt als Namen einfach “apsKey” ein:

Das “Kennwort” für den Export kann leergelassen werden:

Nun müsst Ihr Euer MAC OS Kennwort eingeben um zu erlauben dass der Key exportiert wird:

Nun wurde der private Schlüssel als apsKey.p12 exportiert. Das gleiche muss noch für das Zertifikat erledigt werden. Wiederholt diese Schritte noch für das Zertifikat, also zuerst ein Rechtsklick auf das Zertifikat ausführen und dann auf “… exportieren” aufrufen:

Als Name hier “apsCert” eingeben:

Die letzten beiden Schritte sind identisch wie beim Export des Schlüssels. nun haben wir also irgendwo (z.B. auf dem Desktop) einen exportierten Schlüssel (apsKey.p12) und ein exportiertes Zertifikat (apsCert.p12) liegen.

Das nächste Ziel ist es beide als .pem-Datei “zusammenzuschnüren”. Dies kann man mit Hilfe des Programms “terminal” durchführen. Startet also das Terminal, wechselt dann in das Verzeichnis in dem die .p12-Dateien liegen und ruft folgende Befehle auf:

openssl pkcs12 -clcerts -nokeys -out apsCert.pem -in apsCert.p12
openssl pkcs12 -nocerts -out apsKey.pem -in apsKey.p12

Dies wandelt die .p12 in .pem-Dateien um. Danach entfernen wir das Passwort von der apsKey.pem-Datei (nur wenn noch ein Passwort vorhanden ist!):

openssl rsa -in apsKey.pem -out apsKeyOhnePW.pem

Nun führen wir beide Dateien zusammen:

cat apsCert.pem apsKeyOhnePW.pem > apsDevBundle.pem

Dies Datei “apsDevBundle.pem” ist für unseren Webserver wichtig. In ihr sind alle nötigen Zertifikate und Schlüssel enthalten um mit unserem PHP-Skript eine Nachricht an ein iOS-Gerät zu senden.

Ok, hier nochmal eine kurze Pause. Im zweiten Teil haben wir die generierten Zertifikate und Schlüssel exportiert und in ein für den Webserver verwertbares Format umgewandelt. Bevor der Webserver aber an unser iOS-Gerät etwas senden kann muss das Gerät die App ausführen welche etwas Code enthält und sich erstmal bei Apple “anmeldet” dass Push-Benachrichtigungen empfangen werden können.

In der App einfach folgenden Eintrag in die applicationDidFinishLaunching: Methode einfügen:

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound)];

Und ins AppDelegate außerdem noch folgende Methoden einfügen:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
	NSLog(@"devToken=%@",deviceToken);
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
	NSLog(@"Error in registration. Error: %@", err);
}

In diesem Fall wird kein spezielle Code ausgeführt nachdem sich die App registriert hat. Apple gibt bei erfolgreicher Registrierung ein “Device Token” zurück welches in diesem Beispiel in der Konsole angezeigt wird. Dieses Token merken wir uns – es wird im PHP-Skript benötigt um die Notification an ein bestimmtes Gerät zu senden! (Das Token besteht aus 64 Zeichen und ein paar Leerzeichen – die aber weggelassen werden können).

Kommen wir nun zu dem PHP-Skript welches ausgeführt werden kann um die Notification an das Gerät zu senden. Erstellt auf Eurem Webserver einfach eine Datei und kopiert die Datei apsDevBundle.pem in diesen Ordner hinein.

<?php
// APNs Push testen auf Token
$deviceToken = "XXXXXXXXX"; // Hier das Device-Token angeben, ist 64-stellig

// Payload erstellen und JSON codieren
$payload['aps'] = array('alert' => 'Hallo Sven!', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);

$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apsDevBundle.pem';

// Stream erstellen
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if ($apns)
{
  // Nachricht erstellen und senden
  $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
  fwrite($apns, $apnsMessage);

  // Verbindung schliessen
  fclose($apns);
}
else
{
  echo "Fehler!";
  var_dump($error);
  var_dump($errorString);
}
?>

Geschafft! Denkt aber dran wenn Ihr dies in produktiven System einsetzt des .pen-Bundle an einen sicheren Ort zu kopieren von dem es nicht “heruntergeladen” werden kann, also am besten in einen .htaccess-geschützten Ordner.

Veröffentlicht unter iOS | Verschlagwortet mit | 8 Kommentare

How-To: Apple Entwickler-Zertifikat abgelaufen – verlängern

Heute ist es passiert … ich wollte eine neue Version meiner App auf mein iPhone spielen, da kam folgende Meldung:
“Code sign error: The identity … doesn’t match any valid certificate/private key pair in the default keychain”

Ich habe mich gefragt was ich wieder am System geändert habe dass der Build nicht funktionere. Doch alles war OK, das erste Jahr des Entwickler-Programms war abgelaufen und somit das Entwickler-Zertifikat abgelaufen. Im Programm “Schlüsselbundverwaltung” sieht man das auch:

Doch wie ging das nochmal mit dem neuen Zertifikat erstellen? Apple hat da gute Anleitungen, sind halt alle in englisch. Für die Such-Faulen unter Euch (wie mich) habe ich den Vorgang hier nochmal zusammengefasst, ist eigentlich relativ einfach.

Ruft das Programm “Schlüsselbundverwaltung” auf undgeht im Menü auf folgenden Punkt:

Im folgenden Fenster gebt Ihr Eure E-Mail-Adresse und Namen ein, am besten so wie Ihr im Entwickler-Programm von Apple angemeldet seid:

Diese Zertifikats-Anforderung einfach auf der Festplatte speichern:

Meldet Euch nun im Developer-Center (Provisioning Portal) an und geht dort links unter “Certificates” – “Development”, dort ist nämlich kein Zertifikat mehr enthalten (da abgelaufen). Hier auf “Request Certificate” klicken:

Im folgenden Fenster unten auf “Durchsuchen” klicken, die Datei von der Festplatte auswählen (Zertifikats-Anforderung) und per “Submit” hochladen:

Nun seht Ihr dass Euer Zertifikat erstellt wird:

Wenn Ihr die Seite refresht sollte es auch schon bereit zum Download sein, speichert diese Datei dann auch irgendwo auf der Festplatte:

Das Einspielen des Zertifikats geht ganz einfach: Einfach Doppelklicken – schon ist das Zertifikat in der “Schlüsselbundverwaltung” unter dem privaten Schlüssel zu sehen! Das sollte es eigentlich gewesen sein :-)

Im Provision Portal soltet Ihr aber Eure Developer Provisioning Zertifikate mit dem neuen Zertifikat verknüpfen und nochmals installieren. Im Projekt auch darauf achten dass die neuen Zertifikate dort eingestellt sind.

Es kann jedoch dazu kommen dass z.B. noch folgender Fehler beim Build Eueres Projektes auftritt:
“Certificate identity … appears more than once in the keychain”

Das liegt daran dass in Eurem Schlüsselbund das alte Zertifikat noch enthalten ist – obwohl es abgelaufen ist. Dies muss an zwei Stellen gelöscht werden:
Links unter “Schlüssel” ist unter einem privaten Schlüssel das abgelaufene Zertifikat enthalten. Rechtsklick auf das Zertifikat und auf “löschen” klicken.

Und noch links unter “Zertifikate” das abgelaufene Zertifikat löschen:

Danach sollte alles in Butter sein. Ich hoffe dieser Artikel hat Euch geholfen diese Probleme zu beseitigen ;-)

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

XCode4: Framework hinzufügen

Habe mich heute gefragt wie man “Existing Framework” einem Projekt hinzufügt. Dies hat sich im Vergleich zu XCode3 etwas geändert:

  • Links im Projekt-Explorer auf das Target klicken
  • Dann auf “Build Phases” klicken
  • Dort “Link Binary with Libraries” aufklappen
  • Auf das “+” klicken und Framework auswählen
Veröffentlicht unter iOS | Verschlagwortet mit , | Hinterlasse einen Kommentar

Zahlen, Währungen formatieren

Um Zahlen zu formatieren bedient man sich dem NSNumberFormatter Objekt. Hier ein Beispiel wie man einen Betrag formatieren kann:

NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *preis = [NSNumber numberWithFloat:2];
currencyLabel.text = [nf stringFromNumber:preis];

Wenn man nur das Währungssymbol benötigt ruft man einfach auf:

currencyLabel.text = [nf currencySymbol];
Veröffentlicht unter iOS | Verschlagwortet mit | Hinterlasse einen Kommentar

Bilder per NSMutableURLRequest / NSURLConnection versenden

In einem etwas älteren Artikel habe ich erklärt wie man einfache Web-Requests erstellt, z.B. Daten wie in einem Web-Formular per POST zu übermitteln.

Hier ein Beispiel wie man z.B. Bild-Daten überträgt:

- (void)bildHochladen:(UIImage *)bild zuURL:(NSString *)urlString {

    // Das Bild in ein NSData Objekt umwandeln, die Qualität auf 0.9 stellen
    NSData *imageData = UIImageJPEGRepresentation(bild, 0.9);

    // Das URLRequest-Objekt erstellen
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];

    // Für den URL-Request benötigen wir ein Boundary, hier erstelle ich einen zufälligen Boundary
    NSString *boundary = [NSString stringWithString:@"---------------------------94712889831966399282116247425"];
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

    // Hier wird der BODY erstellt
    NSMutableData *body = [NSMutableData data];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"bild.jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithData:imageData]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // Den Body dem Request-Objekt zuweisen
    [request setHTTPBody:body];

    // Connection ins Web herstellen und Daten synchron senden
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    // Rückgabe vom Server auslesen
    NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

    // Ggf. protokollieren
    NSLog(@"Rückgabe: %@", returnString);
    [returnString release];
    [request release];
}
Veröffentlicht unter iOS | Verschlagwortet mit , | Hinterlasse einen Kommentar

Inhalt in UIWebView laden mit Fortschrittsanzeige (UIProgressView)

Im letzten Artikel habe ich ein Beispiel gegeben wie man ganz einfach Inhalte aus dem Web in einem UIWebView anzeigen kann. Der Nachteil hiervon ist -gerade bei größeren Dateien- dass man solange die Seite läd nur eine weiße Seite ohne Inhalt sieht, und irgendwann erscheint dann lötzlich der Inhalt.

Ich habe hier ein Beispiel wie ich es gelöst habe einen Inhalt in einen UIWebView zu laden und für die Dauer des Lade-Vorgangs eine Fortschrittsanzeige anzuzeigen, dies erfordert aber einige Zusatz-Methoden und -Variablen.

So sieht mein ViewController grob im Interface-Builder aus, ich habe ganz einfach einen UIWebView reingezogen, darauf habe ich ein UIProgressView platziert, darunter jeweils links und rechts ein Label:

In meiner .h Datei habe ich einige Instanz-Variablen und Outlets definiert:

@interface ProgressViewController : UIViewController {
    UIWebView *webView;
    UIProgressView *progressBar;
    UILabel *prozentLabel;
    UILabel *groesseLabel;
    NSMutableData *responseData;
    NSString *mimeType, *textEncoding;
    NSInteger dateiGroesse;
    NSURLConnection *urlConnection;
}

@property (nonatomic, retain) IBOutlet UIWebView *webView;
@property (nonatomic, retain) IBOutlet UIProgressView *progressBar;
@property (nonatomic, retain) IBOutlet UILabel *prozentLabel;
@property (nonatomic, retain) IBOutlet UILabel *groesseLabel;
@property (nonatomic, retain) NSURLConnection *urlConnection;

- (NSString *)groessenFormatierung:(NSInteger)size;

Die Labels, den ProgressView und den WebView müsst Ihr natürlich mit den entsprechenden Outlets verbinden.

In der .m-Datei geht es nun etwas kompexer zu, allerdings auch nicht so tragisch wenn man es genauer anschaut :-)

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.webView.scalesPageToFit = YES;

    // Progress etc. erst einmal verstecken
    self.progressBar.hidden = YES;
    self.prozentLabel.hidden = YES;
    self.groesseLabel.hidden = YES;

    // NSURLConnection erstellen
    NSURL *url = [NSURL URLWithString:@"http://www.domain.de/testDatei.pdf"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

In der viewDidLoad-Methode habe ich die 2 Labels und den ProgressView versteckt. Anschliessend wird erst eine NSURL, dann ein NSMutableURLRequest und schließlich eine NSURLConnection erstellt und der Delegate auf sich selbst gesetzt. Das Programm fängt gleich an Daten zu laden und feuert dann folgende Delegate-Methode ab wenn eine Response vom Server empfangen wird:

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    responseData = [[NSMutableData alloc] init];
    mimeType = [[response MIMEType] retain];
    textEncoding = [[response textEncodingName] retain];
    dateiGroesse = [response expectedContentLength];
    self.groesseLabel.hidden = NO;
    if (dateiGroesse > 0) {
        self.progressBar.hidden = NO;
        self.prozentLabel.hidden = NO;
    }
}

In dieser Methode connection:didReceiveResponse: erstelle ich zunächst ein NSMutableData-Objekt und weise es der Instanz-Variablen responseData zu (hier werden nach und nach die Daten empfangen). Da uns die Response auch noch nützliche Infos wie den MIME-Typ und die Text-Kodierung zurückgeben (und diese später beim Befüllen des WebViews benötigt werden) speichere ich diese auch in den Variablen mimeType und textEncoding.

Nun kommen wir zu dem Teil der nur ab und an klappt: mittels [response expectedContentLength] versuche ich die geschätze Größe des Downloads / der Daten zu bekommen. Bei meinen Versuchen hat das nicht geklappt, Ihr müsst testen ob das bei Euch hinhaut. Ich habe mir vorher mit einer anderen Methode die Gesamtgröße der Datei geholt und in der Variablen “dateiGroesse” gespeichert. Es ist natürlich wichtig zu wissen wie groß der Download insgesamt ist, daraus berechnen wir ja dann den aktuellen Fortschritt.

Abschliessend zeige ich die 2 Labels und den ProgressView an, denn in den nächsten Delegate-Methoden geht es um das Empfangen von Daten:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];

    // Wenn Größe vorhanden ist dann Fortschritt aktualisieren
    if (dateiGroesse > 0) {
        NSInteger aktuelleBytes = [responseData length];
        float prozent = 100 * aktuelleBytes / dateiGroesse;
        if (prozent > 100) {
            prozent = 100.0;
        }
        self.prozentLabel.text = [NSString stringWithFormat:@"%.1f %@", prozent, @"%"];
        self.groesseLabel.text = [NSString stringWithFormat:@"%@ / %@", [self groessenFormatierung:aktuelleBytes], [self groessenFormatierung:dateiGroesse]];
        self.progressBar.progress = prozent / 100;
    }
}

Diese Methode connection:didReceiveData: wird jedesmal aufgerufen wenn ein Teil der Daten empfangen wird. Genau dann soll auch der ProgressView aktualisiert werden. Der wichtigste Teil aber ist erst einmal die empfangenen Daten (data) den insgesamt empfangenen Daten hinzuzufügen (responseData).

Danach kommen einfache mathematische Berechnungen über den aktuellen Fortschritt. In den Varablen aktuelleBytes und dateiGroesse sind jeweils die bereits empfangenen Bytes bzw. die Gesamtgroesse des Downloads hinterlegt – anhand diesen kann man den Fortschritt (in Prozent) ermitteln.

Ich bediene mich noch einer kleinen Hilfsmethode groessenFormatierung: welche ich ganz unten abdrucke. Diese stellt einfach nur eine Anzahl Bytes in einer Formatierung xx kB oder xx MB dar.

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self _connectionFinished];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Netzwerk-Fehler"
                                                    message:@"Probleme beim Abrufen der Datei"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
}

In der Methode connection:didFailWithError: wird ein Fehler ausgegeben falls z.B. die Verbindung abbricht. Hierzu gibt es nicht viel zu sagen :-)

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self _connectionFinished];
    if (dateiGroesse > 0) {
        self.progressBar.hidden = YES;
        self.prozentLabel.hidden = YES;
        self.groesseLabel.hidden = YES;
    }
    [self.webView loadData:responseData
                  MIMEType:mimeType
          textEncodingName:textEncoding
                   baseURL:[NSURL URLWithString:@"http://www.domain.de/testDatei.pdf"]];
}

Last but not least wird die Methode connectionDidFinishLoading: aufgerufen wenn alle Daten empfangen wurden. Hier werden die beiden Labels und der ProgressView versteckt so dass der UIWebView angezeigt werden kann. In dem letzten Methoden-Aufruf wird der WebView gefüllt mit den empfangenen Daten. Es wird der MIME-Typ und die Text-Kodierung benötigt, diese haben wir ja aber weiter oben in 2 Variablen gespeichert. Etwas unschön an meinem Beispiel ist dass ich die URL nicht in einer weiteren Instanz-Variable gespeichert habe, das könnt Ihr ja bei Euch noch ändern.

Update:
Die Methoden welche die Verbindung abbrechen rufen diese Hilfsfunktion auf welche die Connection abbricht und released. So werden Memory Leaks vermieden:

- (void)_connectionFinished {
    if (self.urlConnection != nil) {
        [self.urlConnection cancel];
        self.urlConnection = nil;
    }
}

Hier noch die Hilfsfunktion um die Anzahl der Bytes etwas schöner dazustellen:

- (NSString *)groessenFormatierung:(NSInteger)size {
    NSString *ret = @"";
    if (size > 0) {
        // Größer als 1024? -> dann in kB anzeigen
        if (size > 1024) {
            // Größer als 1048576? -> dann in MB anzeigen
            if (size > 1048576) {
                // in MB anzeigen
                float inMB = size / 1048576;
                ret = [NSString stringWithFormat:@"%.1f MB", inMB];
            } else {
                // in kB anzeigen
                float inKB = size / 1024;
                ret = [NSString stringWithFormat:@"%.1f kB", inKB];
            }
        } else {
            // In Bytes anzeigen
            ret = [NSString stringWithFormat:@"%i B", size];
        }
    } else {
        ret = [NSString stringWithFormat:@"0 MB"];
    }
    return ret;
}

Ich hoffe das war einigermaßen verständlich. Falls Ihr Probleme bei dem einabauen in Eure Projekte habt könnt Ihr Euch gerne mit mir in Verbindung setzen bzw. diesen Beitrag kommentieren.

Veröffentlicht unter iOS | Verschlagwortet mit , , | 1 Kommentar

Dateien (z.B. PDF) in UIWebView anzeigen

In einem kürzlich erschienenen Artikel habe ich gezeigt wie man ganz einfach Bilder per Web laden kann und in einem UIImageView anzeigen lassen kann.

Nun musste ich in eine App einbauen dass ich Text-Dateien oder PDFs per Web anzeigen lassen kann.

Um dies zu lösen bedient man sich der Klasse UIWebView, mit der normalerweise Webseiten dargestellt werden. Glücklicherweise erkennt die iOS SDK auch wenn es sich um anderer darstellbare Formate handelt wie z.B. PDFs.

Hier mein Beispiel-Code wie ein PDF (oder Text-Datei) in einem UIWebView angezeigt wird:

self.webView.scalesPageToFit = YES;
NSString *urlString = @"http://www.domain.de/testpdf.pdf";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:urlRequest];

Ihr seht es ist ganz einfach dies umzusetzen ;-)
Sogar das zoomen / scrollen wird dadurch aktiviert (wenn scalesPageFit aktiviert ist) !

Im nächsten Artikel seht Ihr wie man das Skript so erweitert dass während des Ladens ein Fortschritts-Balken angezeigt wird. Ihr könnt das in diesem Artikel nachlesen.

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

UIImageView übers Web laden, in UIScrollView anzeigen

Heute musste ich Bilder aus dem Web in einem ImageView darstellen. Ich habe das folgendermaßen gelöst:

NSString *urlString = @"http://www.domain.de/image.jpg";
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];

Mit diesem Beispiel wird ein Bild in einem ImageView dargestellt, allerdings kann man dies noch nicht scrollen. Hierzu muss man den Aufbau der Datei etwas umgestalten. Man legt zuerst einen ScrollView an und in diesen ScollView wird dann der ImageView “geschoben”. Im Program muss man dann nur noch (am besten in der viewDidLoad-Methode) folgendes schreiben:

self.scrollView.contentSize = slef.imageView.size;

Nun geht schon einmal das scrollen im ImageView. Was noch nicht funktioniert ist das zoomen. Aber das ist auch kein Problem. Wir erweitern die viewDidLoad-Methode mit folgendem Code:

scrollView.delegate = self;
scrollView.maximumZoomScale = 4.0;
scrollView.minimumZoomScale = 0.1;

Und da wir die Klasse als UIScrollViewDelegate deklariert haben müssen wir noch folgende Protokoll-Methode einfügen die einfach nur den ImageView zurückgibt:

-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return self.imageView;
}

Das war’s :-)

Im nächsten Artikel zeige ich wie man Dateien im WebView anzeigt, dies kann auch genutzt werden um Bilder anzuzeigen.

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