// // NDEFVCardRecordViewController.swift // NFCTap // // Created by Vincent LATORRE on 7/18/19. // Copyright © 2019 STMicroelectronics. All rights reserved. // import UIKit import Contacts import ContactsUI import CoreNFC class NDEFVCardRecordViewController: UIViewController, CNContactPickerDelegate,NFCNDEFReaderSessionDelegate,UITextFieldDelegate { // Reference the NFC session private var nfcSession: NFCNDEFReaderSession! var ndefMessage: NFCNDEFMessage? // ST25SDK NDEF Records var mComStSt25sdkNdefVcard:ComStSt25sdkNdefVCardRecord! var cnPicker:CNContactPickerViewController! var sliderValue:Int! var mContactImageTmp:UIImage! @IBOutlet weak var mSliderResolution: UISlider! @IBOutlet weak var mSwitchPhoto: UISwitch! @IBOutlet weak var mPictureResolutionLabel: UILabel! @IBOutlet weak var mContactImageView: UIImageView! @IBOutlet weak var mNameTextField: UITextField! @IBOutlet weak var mNumberTextField: UITextField! @IBOutlet weak var mEmailTextField: UITextField! @IBOutlet weak var mWebSiteTextField: UITextField! @IBOutlet weak var mAddressTextView: UITextView! @IBOutlet weak var mNdefSizeTextField: UITextField! @IBOutlet weak var mPictureSizeTextField: UITextField! @IBAction func handleSwitchPhoto(_ sender: UISwitch) { mSliderResolution.isEnabled = self.mSwitchPhoto.isOn updateNdefVcardRecord(imageView: mContactImageView!) } @IBAction func handleGetContact(_ sender: UIButton) { cnPicker = CNContactPickerViewController() cnPicker.delegate = self self.present(cnPicker, animated: true, completion: nil) } @IBAction func handleWrite(_ sender: UIButton) { if (cnPicker != nil) { cnPicker.dismiss(animated: false, completion: nil) } // Create ST25SDK + coreNFC NDEF Message updateNdefVcardRecord(imageView: mContactImageView!) ndefMessage = updateNDEFMessage() nfcSession = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false) nfcSession?.alertMessage = "Hold your iPhone near an NFC tag for WRITE." nfcSession?.begin() } @IBAction func handleSlider(_ sender: UISlider) { sliderValue = Int(sender.value) mPictureResolutionLabel.text = "Picture Resolution : \(sliderValue ?? 100)" if (mContactImageTmp != nil) { let image = mContactImageTmp let imageResized = resizeImageWithAspect(image: image!, ratio: CGFloat(sliderValue)) mContactImageView.image = imageResized } updateNdefVcardRecord(imageView: mContactImageView) } override func viewDidLoad() { super.viewDidLoad() sliderValue = 100 self.mNameTextField.delegate = self self.mNumberTextField.delegate = self self.mEmailTextField.delegate = self self.mWebSiteTextField.delegate = self mContactImageView.image = resizeImageWithAspect(image: mContactImageView.image!, ratio: 25) mContactImageTmp = mContactImageView.image } private func resizeImageWithAspect(image: UIImage,ratio :CGFloat)->UIImage? { let oldWidth = image.size.width; let oldHeight = image.size.height; let newHeight = (( oldHeight - 10) * ratio / 100 + 10 ) let newWidth = (( oldWidth - 10) * ratio / 100 + 10 ) print(newHeight) print(newWidth) let newSize = CGSize(width: newWidth, height: newHeight) UIGraphicsBeginImageContextWithOptions(newSize,false,UIScreen.main.scale); image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)); let newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage } private func updateNdefVcardRecord(imageView: UIImageView){ mComStSt25sdkNdefVcard = ComStSt25sdkNdefVCardRecord() mComStSt25sdkNdefVcard.setNameWith(mNameTextField.text) mComStSt25sdkNdefVcard.setNickNameWith(mNameTextField.text) mComStSt25sdkNdefVcard.setEmailWith(mEmailTextField.text) mComStSt25sdkNdefVcard.setNumberWith(mNumberTextField.text) mComStSt25sdkNdefVcard.setSPAddrWith(mAddressTextView.text) mComStSt25sdkNdefVcard.setWebSiteWith(mWebSiteTextField.text) mComStSt25sdkNdefVcard.setFormattedNameWith(mNameTextField.text) if (self.mSwitchPhoto.isOn == true){ if (imageView.image != nil){ let imageData = imageView.image!.jpegData(compressionQuality: 0.20) let imageDataString=imageData!.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters) mComStSt25sdkNdefVcard.setPhotoWith(imageDataString) mPictureSizeTextField.text = "["+"\(Int(imageView.image!.size.width))"+" "+"\(Int(imageView.image!.size.height))"+"]" } } updateNDEFMessage() } private func updateNDEFMessage() -> NFCNDEFMessage { // Create coreNFC NDEF Message let TypeArray = (mComStSt25sdkNdefVcard.getType()?.toNSData())! let IdArray = (mComStSt25sdkNdefVcard.getID()?.toNSData())! let PayloadArray = (mComStSt25sdkNdefVcard.getPayload()?.toNSData())! let Payload = NFCNDEFPayload.init(format: NFCTypeNameFormat.media, type: TypeArray, identifier: IdArray, payload: PayloadArray) let ndefMessageTmp = NFCNDEFMessage(records: [Payload]) mNdefSizeTextField.text = "\(ndefMessageTmp.length)"+" bytes" return ndefMessageTmp } // UITextFieldDelegate method func textFieldShouldReturn(_ textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore. { textField .resignFirstResponder() return true; } override func touchesBegan(_ touches: Set, with event: UIEvent?) { self.view.endEditing(true) self.updateNdefVcardRecord(imageView: mContactImageView!) } // CNContactPickerDelegate Method func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { print("Selected a contact") if contact.isKeyAvailable(CNContactFamilyNameKey){ mNameTextField.text = contact.givenName+" "+contact.middleName } else { mNameTextField.text = "" } if contact.isKeyAvailable(CNContactPhoneNumbersKey){ for phoneNumber:CNLabeledValue in contact.phoneNumbers { let a = phoneNumber.value as! CNPhoneNumber mNumberTextField.text = a.stringValue } } else { mNumberTextField.text = "" } if contact.isKeyAvailable(CNContactEmailAddressesKey){ for emailAddress:CNLabeledValue in contact.emailAddresses{ mEmailTextField.text = emailAddress.value as String } } else { mEmailTextField.text = "" } if contact.isKeyAvailable(CNContactPostalAddressesKey){ for postalAddress:CNLabeledValue in contact.postalAddresses{ mAddressTextView.text = postalAddress.value.street } } else { mAddressTextView.text = "" } if contact.isKeyAvailable(CNContactUrlAddressesKey){ for urlWebSite:CNLabeledValue in contact.urlAddresses{ mWebSiteTextField.text = urlWebSite.value as String } } else { mWebSiteTextField.text = "" } if contact.imageDataAvailable { // there is an image for this contact mContactImageView.image = UIImage(data: contact.imageData!)! mContactImageTmp = mContactImageView.image let image = mContactImageTmp let imageResized = resizeImageWithAspect(image: image!, ratio: CGFloat(sliderValue)) mContactImageView.image = imageResized } updateNdefVcardRecord(imageView: mContactImageView) } func contactPickerDidCancel(_ picker: CNContactPickerViewController) { print("Cancel Contact Picker") } /* NFCNDEF session delegate */ func tagRemovalDetect(_ tag: NFCNDEFTag) { // In the tag removal procedure, you connect to the tag and query for // its availability. You restart RF polling when the tag becomes // unavailable; otherwise, wait for certain period of time and repeat // availability checking. self.nfcSession?.connect(to: tag) { (error: Error?) in if error != nil || !tag.isAvailable { self.nfcSession?.restartPolling() return } DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(500), execute: { self.tagRemovalDetect(tag) }) } } func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { print("NFC session become Active") } func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { //self.addMessage(fromUserActivity:messages) session.invalidate() } func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { print(error) print("Error session: \(error.localizedDescription)") } private func readerSessionDidBecomeActive(_ session: NFCReaderSession) { print("NFC session become Active") } func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { if tags.count > 1 { session.alertMessage = "More than 1 tags found. Please present only 1 tag." self.tagRemovalDetect(tags.first!) return } // You connect to the desired tag. let tag = tags.first! session.connect(to: tag) { (error: Error?) in if error != nil { session.restartPolling() return } // You then query the NDEF status of tag. tag.queryNDEFStatus() { (status: NFCNDEFStatus, capacity: Int, error: Error?) in if error != nil { session.invalidate(errorMessage: "Fail to determine NDEF status. Please try again.") return } if status == .readOnly { session.invalidate(errorMessage: "Tag is not writable.") } else if status == .notSupported { session.invalidate(errorMessage: "Tag not supported.") } else if status == .readWrite { if self.ndefMessage!.length > capacity { session.invalidate(errorMessage: "Tag capacity is too small. Maximum size requirement is \(capacity) bytes.") return } // When a tag is read-writable and has sufficient capacity, // write an NDEF message to it. tag.writeNDEF(self.ndefMessage!) { (error: Error?) in if error != nil { session.invalidate(errorMessage: "Update tag failed. Please try again."+error.debugDescription) } else { session.alertMessage = "Write success!" session.invalidate() } } } else { session.invalidate(errorMessage: "Tag is not NDEF formatted.") } } } } }