Extra opdracht 1

Veiligheid is een keuze

Ik wil je voorstellen aan John. Je kent hem vast nog van de Cup a Soup reclame. Tegenwoordig werkt John als hoofd beveiliging van een niet nader te noemen academisch ziekenhuis. Zijn motto is tegenwoordig: “Veiligheid is een keuze”.

John wil graag een app hebben om onveilige situaties te melden. Gewoon fotootje maken en doorsturen naar een centraal meldpunt met e-mail adres melding@onveiligesituatie.nl. Of jij dat even kunt bouwen…

Nu boft John, want na deze workshop heb je er alle vertrouwen in dat dit gaat lukken. Je zoekt eens op Google en vindt deze uitleg op Techotopia. Moet lukken, toch? Let’s go!

Nieuw project

Maak een nieuw project aan met de naam Security op dezelfde manier als vorige keren (Single View dus). Ga naar Main.storyboard en sleep een ImageView en een Toolbar naar je View Controller zodat het er zo uitziet:

Sleep nu een tweede Bar Button Item naar de Toolbar en hernoem ze als Camera resp. Foto’s (dubbelklikken op titel om aan te passen).

Met betrekking tot de Adaptive / Auto Layout: selecteer de Toolbar en klik op het Pin menu rechts onderin beeld. Gebruik Spacing to Nearest Neighbour om de constraints van de zijkanten en onderkant in te stellen met de optie Constrain to Margins uit:

Selecteer nu de Image View, en gebruik Spacing to Nearest Neighbour voor alle randen met Constrain to Margins aan:

Terwijl de Image View nog geselecteerd kies, ga je naar de Attributes Inspector en verander je Mode in Aspect Fit.

Maak nu een Outlet aan voor de Image View in ViewController.swift en noem deze imageView. En als we toch bezig zijn, hernoem ViewController.swift maar even naar SecurityViewController.swift (incl. aanpassen class name en de verwijzing vanuit het storyboard).

Op dezelfde manier als je een outlet aanmaakt, kun je een Action aanmaken. Dit is de link tussen de grafische interface (vooral bij knoppen gebruikt) en de code. In feite is een Action het tegenovergestelde van een Outlet: een Action gaat van grafische interface naar je code, en een outlet van je code naar een grafische interface.

Maak van beide Bar Button Items een Action aan met de namen useCamera en useCameraRoll. Er verschijnt dan de volgende code in je SecurityViewController.swift:

@IBAction func useCamera(sender: AnyObject) {
}

@IBAction func useCameraRoll(sender: AnyObject) {
}

Code toevoegen

Nu gaan we de code toevoegen om met de camera te werken, maar daarvoor moeten we eerst een paar voorbereidende stappen zetten. We hebben namelijk extra functionaliteit nodig in deze app en die gaan we importeren. Onder import UIKit bovenaan in je code voeg je de volgende twee regels toe:

import MobileCoreServices
import MessageUI

De eerste is nodig voor de camera / foto’s en de tweede om de email functionaliteit aan te spreken. Verder maken we onze View Controller een delegate van een aantal klusjes: deze houdt voor ons op de achtergrond in de gaten of een bepaald klusje geklaard is en voorziet dat van de benodigde actie. Dat klusje betreft in dit geval het succesvol laden van een foto of het versturen van een email.

Je class declaratie begint nu als class SecurityViewController: UIViewController en die ga je veranderen in :

class SecurityViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, MFMailComposeViewControllerDelegate {

Onder je outlet van de Image View ga je nog een nieuwe variable toevoegen:

var newMedia: Bool?

De code voor de useCamera functie is deze:

if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = .Camera
            imagePicker.mediaTypes = [kUTTypeImage as String]
            imagePicker.allowsEditing = false
            
            self.presentViewController(imagePicker, animated: true, completion: nil)
            newMedia = true
        }
useCamera

Tip: om de afbeelding in het groot te zien voor een betere leesbaarheid, klik erop met de rechter muisknop en open de afbeelding in een nieuw venster of tabblad.

De code voor useCameraRoll lijkt erop:

if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum) {
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = .PhotoLibrary
            imagePicker.mediaTypes = [kUTTypeImage as String]
            imagePicker.allowsEditing = false
            
            self.presentViewController(imagePicker, animated: true, completion: nil)
            newMedia = false
        }
useCameraRoll

En dan heb je nog deze delegate methods nodig:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        let mediaType = info[UIImagePickerControllerMediaType] as! NSString
        self.dismissViewControllerAnimated(true, completion: nil)
        
        if mediaType.isEqualToString(kUTTypeImage as String) {
            let image = info[UIImagePickerControllerOriginalImage] as! UIImage
            imageView.image = image
            
            if newMedia == true {
                UIImageWriteToSavedPhotosAlbum(image, self, "image:didFinishSavingWithError:contextInfo:", nil)
            }
            
            createMailMessage(image)
        }
    }
    
    
    func image(image: UIImage, didFinishSavingWithError error: NSErrorPointer, contextInfo: UnsafePointer<Void>) {
        if error != nil {
            let alert = UIAlertController(title: "Opslaan mislukt", message: "Afbeelding kon niet worden opgeslagen", preferredStyle: .Alert)
            let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
            alert.addAction(cancelAction)
            self.presentViewController(alert, animated: true, completion: nil)
        }
    }
    
    
    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }

Ofwel:

Een email versturen

Fijn dat we foto’s kunnen maken met de camera of kunnen openen vanaf onze Foto’s applicatie. Maar hoe versturen we ze? Zo!

func createMailMessage(image: UIImage) {
        let email = MFMailComposeViewController()
        email.mailComposeDelegate = self
        email.setToRecipients(["melding@onveiligesituatie.nl"])
        email.setSubject("Onveilige situatie")
        
        let now = NSDate()
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "dd-MM-YYYY hh:mm"
        let formattedDate = dateFormatter.stringFromDate(now)
        
        let messageBodyText =   "<h3>Datum</h3><p>\(formattedDate)</p>" +
                                "<h3>Omschrijving</h3><p><em>Typ omschrijving hier...</em></p>"
        let imageData = UIImagePNGRepresentation(image)
        let imageName = formattedDate + ".png"
        
        email.setMessageBody(messageBodyText, isHTML: true)
        email.addAttachmentData(imageData!, mimeType: "image/png", fileName: imageName)
        
        presentViewController(email, animated: true, completion: nil)
        
    }
    
    func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
        dismissViewControllerAnimated(true, completion: nil)
    }

Als je ’m wilt testen, moet dat op je iOS apparaat (iPhone of iPad zijn beide goed). Have a try! Je moet wel eerst een gratis developer account aanmaken bij Apple. Als je al een email adres hebt dat je gebruikt voor iCloud, kun je hiermee inloggen op de website en de voorwaarden accepteren voor development.

Daarna kun je in XCode naar het project overzicht gaan door op de naam van de app te klikken links boven in beeld:

Klik daarna achter Team op None en kies Add an account:

In het daarop volgende dialoogvenster kun je inloggen, daarna kun je dit afsluiten. Als je de stap herhaalt, zie je je account (in bovenstaande afbeelding zie je de mijne) en deze kun je selecteren.

Als je eigen iOS device via de kabel is aangesloten, kun je deze selecteren links boven in beeld (iPhone, iPad of iPod Touch zijn allemaal goed). Waarschijnlijk starten iTunes en de Foto’s applicatie ook op: je kunt deze direct afsluiten, die heb je niet nodig.

Als je de app runt, krijg je eerst de vraag of het iOS device de computer mag vertrouwen:

Het goede antwoord lijkt me duidelijk: Vertrouw. Het kan zijn dat het daarna direct al werkt, maar als je een foutmelding krijgt op je device moet je even naar Instellingen > Algemeen > Profielen gaan (op het device) en daar toestemming geven om de app te vertrouwen. Dan kun je het icoontje aanklikken en doet ie het. Wel nog even toestemming geven dat de camera of foto toegang gebruikt mag worden!

Over icoontjes gesproken: saai he, dat witte ding? Zullen we daar eens wat aan doen? Klik in de Project Navigator op Assets.xcassets en je ziet dit:

Dat 2x en 3x heeft te maken met een hogere resolutie van de afbeeldingen voor de Retina-schermen (vanaf iPhone 4). Dus het iPhone app icoontje heeft een resolutie van 60x60 pixels, maar het bestand is 120x120 of 180x180 (afhankelijk van welk apparaat je hebt). De afbeeldingsbestanden hebben dus de volgende afmetingen:

icon sizes

De manier waarop ik ze maak, is eenvoudig: maak een afbeelding op 1024x1024 pixels (die heb je nodig bij de indiening voor de App Store) en kopieer / verklein deze naar de gewenste formaten.

Een zip-bestand met de icoon afbeeldingen voor deze app kun je hier downloaden. Je kunt het bestand uitpakken door te dubbelklikken, en de icoontjes middels drag & drop naar de juiste plek te slepen. Ze worden dan ook aan het project toegevoegd.

Als je de app nu opnieuw runt, dan zie je het icoontje op het thuisscherm van je device. Toch wel even beter dit….

Nog iets: in het scherm waarin je ook je developer account hebt toegevoegd bij Team staat iets lager het Deployment target. Je kunt daar het minimale besturingssysteem opgeven waarvan je wilt dat de gebruiker het heeft.

Mocht je iOS device nog niet op iOS9 draaien, wat in XCode7 de standaard is, kun je hier een lagere versie van het systeem kiezen. Het nadeel zou kunnen zijn dat de allerlaatste features niet ondersteund worden, maar als je die toch niet gebruikt in je app (en dat doen we hier niet) dan heeft het vooral een voordeel om een lagere versie te kiezen: je app is dan voor meer mensen toegankelijk.

Zo, om de app te voltooien mag je zelf even aan de slag. Voeg een Bar Button Item en een Flexible Space Button Item toe aan je toolbar:

help button

Ga nu zelf aan de slag om middels de Help button een nieuw venster te openen en daarin wat achtergrond-informatie over de app te geven, als ook de mogelijkheid om contact op te nemen via email. Gebruik hiervoor een Web View. De (HTML) code om een hyperlink te genereren die een email kan versturen, is deze:

<a href=\"mailto:melding@onveiligesituatie.nl\">E-mail ons</a>

Om vanuit dit venster terug te komen in je hoofdvenster, is een Navigation Controller wel handig! Daar heb je inmiddels veel ervaring mee, dus ga je gang!

De volledige code van dit project kun je hier downloaden. Nu alleen nog even submitten naar de App Store en John is helemaal gelukkig!